commit ebb69a35b367c53cebe7b310bbac6d22e72e6fd4 Author: chenweilin1 Date: Wed Sep 3 14:18:54 2025 +0800 feature:提交java后台管理系统 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82927af --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Compiled class file +*.class + +# Log file +logs/ +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +.idea +*.iml +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar +target/ +upload/ + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ca947d --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +## 项目说明 + +- drone-ops 是用SpringBoot3.4、SpringSecurity6.4、Mybatis-Plus、Flowable7.0、Vue3、Element-plus等技术开发的低代码开发平台,旨在为开发者提供一个简洁、高效、可扩展的低代码开发平台。 +- 使用门槛极低,支持国密加密、达梦数据库等,符合信创需求的低代码开发平台。 +- 采用组件模式,扩展不同的业务功能,可以很方便的实现各种业务需求,且不会导致系统臃肿,若想使用某个组件,按需引入即可,反之亦然。 + + + +## 架构图 + +![输入图片说明](images/0.png) + diff --git a/db/mysql/maku.sql b/db/mysql/maku.sql new file mode 100644 index 0000000..ca3288d --- /dev/null +++ b/db/mysql/maku.sql @@ -0,0 +1,502 @@ +CREATE TABLE sys_user +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + username varchar(50) NOT NULL COMMENT '用户名', + password varchar(100) COMMENT '密码', + real_name varchar(50) COMMENT '姓名', + avatar varchar(200) COMMENT '头像', + gender tinyint COMMENT '性别 0:男 1:女 2:未知', + email varchar(100) COMMENT '邮箱', + mobile varchar(20) COMMENT '手机号', + org_id bigint COMMENT '机构ID', + super_admin tinyint COMMENT '超级管理员 0:否 1:是', + status tinyint COMMENT '状态 0:停用 1:正常', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='用户管理'; + +CREATE TABLE sys_user_token +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + user_id bigint COMMENT '用户ID', + access_token varchar(32) COMMENT 'accessToken', + access_token_expire datetime COMMENT 'accessToken 过期时间', + refresh_token varchar(32) COMMENT 'refreshToken', + refresh_token_expire datetime COMMENT 'refreshToken 过期时间', + tenant_id bigint COMMENT '租户ID', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='用户Token'; + +CREATE TABLE sys_third_login +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + open_type varchar(50) COMMENT '开放平台类型', + open_id varchar(100) COMMENT '开放平台,唯一标识', + username varchar(100) COMMENT '昵称', + user_id bigint COMMENT '用户ID', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='第三方登录'; + +CREATE TABLE sys_third_login_config +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + open_type varchar(50) COMMENT '开放平台类型', + client_id varchar(200) COMMENT 'ClientID', + client_secret varchar(200) COMMENT 'ClientSecret', + redirect_uri varchar(200) COMMENT 'RedirectUri', + agent_id varchar(200) COMMENT 'AgentID', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='第三方登录配置'; + +CREATE TABLE sys_org +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + pid bigint COMMENT '上级ID', + name varchar(50) COMMENT '机构名称', + sort int COMMENT '排序', + leader_id bigint COMMENT '负责人ID', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_pid (pid) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='机构管理'; + +create table sys_role +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + name varchar(50) COMMENT '角色名称', + role_code varchar(50) COMMENT '角色编码', + remark varchar(100) COMMENT '备注', + data_scope tinyint COMMENT '数据范围 0:全部数据 1:本机构及子机构数据 2:本机构数据 3:本人数据 4:自定义数据', + org_id bigint COMMENT '机构ID', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_org_id (org_id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色管理'; + +create table sys_user_role +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + role_id bigint COMMENT '角色ID', + user_id bigint COMMENT '用户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_role_id (role_id), + key idx_user_id (user_id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='用户角色关系'; + +CREATE TABLE sys_post +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + post_code varchar(100) COMMENT '岗位编码', + post_name varchar(100) COMMENT '岗位名称', + sort int COMMENT '排序', + status tinyint COMMENT '状态 0:停用 1:正常', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='岗位管理'; + +CREATE TABLE sys_user_post +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + user_id bigint COMMENT '用户ID', + post_id bigint COMMENT '岗位ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_user_id (user_id), + key idx_post_id (post_id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='用户岗位关系'; + +create table sys_menu +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + pid bigint COMMENT '上级ID', + name varchar(200) COMMENT '菜单名称', + url varchar(200) COMMENT '菜单URL', + authority varchar(500) COMMENT '授权标识(多个用逗号分隔,如:sys:menu:list,sys:menu:save)', + type tinyint COMMENT '类型 0:菜单 1:按钮 2:接口', + open_style tinyint COMMENT '打开方式 0:内部 1:外部', + icon varchar(50) COMMENT '菜单图标', + sort int COMMENT '排序', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_pid (pid) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='菜单管理'; + +create table sys_role_menu +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + role_id bigint COMMENT '角色ID', + menu_id bigint COMMENT '菜单ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_role_id (role_id), + key idx_menu_id (menu_id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色菜单关系'; + +create table sys_role_data_scope +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + role_id bigint COMMENT '角色ID', + org_id bigint COMMENT '机构ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id), + key idx_role_id (role_id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色数据权限'; + +create table sys_dict_type +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + dict_type varchar(100) NOT NULL COMMENT '字典类型', + dict_name varchar(255) NOT NULL COMMENT '字典名称', + dict_source tinyint default 0 COMMENT '来源 0:字典数据 1:动态SQL', + dict_sql varchar(500) COMMENT '动态SQL', + remark varchar(255) COMMENT '备注', + sort int COMMENT '排序', + pid bigint COMMENT '上级节点', + has_child tinyint default 0 COMMENT '是否有子节点', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='字典类型'; + +create table sys_dict_data +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + dict_type_id bigint NOT NULL COMMENT '字典类型ID', + dict_label varchar(255) NOT NULL COMMENT '字典标签', + dict_value varchar(255) COMMENT '字典值', + label_class varchar(100) COMMENT '标签样式', + remark varchar(255) COMMENT '备注', + sort int COMMENT '排序', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='字典数据'; + +create table sys_attachment +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + name varchar(255) NOT NULL COMMENT '附件名称', + url varchar(255) NOT NULL COMMENT '附件地址', + size bigint COMMENT '附件大小', + platform varchar(50) COMMENT '存储平台', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='附件管理'; + +create table sys_params +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + param_name varchar(100) COMMENT '参数名称', + param_type tinyint NOT NULL COMMENT '系统参数 0:否 1:是', + param_key varchar(100) COMMENT '参数键', + param_value varchar(2000) COMMENT '参数值', + remark varchar(200) COMMENT '备注', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +)ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT='参数管理'; + +create table sys_log_login +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + username varchar(50) COMMENT '用户名', + ip varchar(32) COMMENT '登录IP', + address varchar(32) COMMENT '登录地点', + user_agent varchar(500) COMMENT 'User Agent', + status tinyint COMMENT '登录状态 0:失败 1:成功', + operation tinyint unsigned COMMENT '操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误', + tenant_id bigint COMMENT '租户ID', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='登录日志'; + +create table sys_log_operate +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + module varchar(100) COMMENT '模块名', + name varchar(100) COMMENT '操作名', + req_uri varchar(200) DEFAULT NULL COMMENT '请求URI', + req_method varchar(20) DEFAULT NULL COMMENT '请求方法', + req_params text COMMENT '请求参数', + ip varchar(32) COMMENT '操作IP', + address varchar(32) COMMENT '登录地点', + user_agent varchar(500) COMMENT 'User Agent', + operate_type tinyint COMMENT '操作类型', + duration int NOT NULL COMMENT '执行时长', + status tinyint COMMENT '操作状态 0:失败 1:成功', + user_id bigint COMMENT '用户ID', + real_name varchar(50) COMMENT '操作人', + result_msg varchar(500) COMMENT '返回消息', + tenant_id bigint COMMENT '租户ID', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT ='操作日志'; + + +CREATE TABLE sys_sms_config +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + platform tinyint COMMENT '平台类型 0:阿里云 1:腾讯云 2:七牛云 3:华为云', + group_name varchar(100) COMMENT '分组名称,发送短信时,可指定分组', + sign_name varchar(100) COMMENT '短信签名', + template_id varchar(100) COMMENT '短信模板', + app_id varchar(100) COMMENT '短信应用ID,如:腾讯云等', + sender_id varchar(100) COMMENT '腾讯云国际短信、华为云等需要', + url varchar(200) COMMENT '接入地址,如:华为云', + access_key varchar(100) COMMENT 'AccessKey', + secret_key varchar(100) COMMENT 'SecretKey', + status tinyint COMMENT '状态 0:禁用 1:启用', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='短信配置'; + +CREATE TABLE sys_sms_log +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + platform_id bigint COMMENT '平台ID', + platform tinyint COMMENT '平台类型', + mobile varchar(20) NOT NULL COMMENT '手机号', + params varchar(200) COMMENT '参数', + status tinyint COMMENT '状态 0:失败 1:成功', + error varchar(2000) COMMENT '异常信息', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='短信日志'; + + +CREATE TABLE sys_mail_config +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + platform tinyint COMMENT '平台类型 -1:本地 0:阿里云', + group_name varchar(100) COMMENT '分组名称,发送邮件时,可指定分组', + mail_host varchar(100) COMMENT 'SMTP服务器', + mail_port int COMMENT 'SMTP端口', + mail_from varchar(100) COMMENT '发件人邮箱', + mail_pass varchar(100) COMMENT '发件人密码', + region_id varchar(100) COMMENT 'regionId', + endpoint varchar(100) COMMENT '阿里云 endpoint', + access_key varchar(100) COMMENT 'AccessKey', + secret_key varchar(100) COMMENT 'SecretKey', + status tinyint COMMENT '状态 0:禁用 1:启用', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='邮件平台'; + +CREATE TABLE sys_mail_log +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + platform_id bigint COMMENT '平台ID', + platform tinyint COMMENT '平台类型', + mail_from varchar(100) COMMENT '发件人邮箱', + mail_tos varchar(1000) COMMENT '接受人邮箱', + subject varchar(200) COMMENT '邮件主题', + content text COMMENT '邮件内容', + status tinyint COMMENT '状态 0:失败 1:成功', + error varchar(2000) COMMENT '异常信息', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='邮件日志'; + +INSERT INTO sys_user (id, username, password, real_name, avatar, gender, email, mobile, status, org_id, super_admin, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (10000, 'admin', 'dc1fd00e3eeeb940ff46f457bf97d66ba7fcc36e0b20802383de142860e76ae6', 'admin', 'https://cdn.maku.net/images/avatar.png', 0, 'babamu@126.com', '13612345678', 1, null, 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1, NULL, '系统设置', NULL, NULL, 0, 0, 'icon-setting', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (2, 1, '菜单管理', 'sys/menu/index', NULL, 0, 0, 'icon-menu', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (3, 2, '查看', '', 'sys:menu:list', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (4, 2, '新增', '', 'sys:menu:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (5, 2, '修改', '', 'sys:menu:update,sys:menu:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (6, 2, '删除', '', 'sys:menu:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (7, 1, '数据字典', 'sys/dict/type', '', 0, 0, 'icon-insertrowabove', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (8, 7, '查询', '', 'sys:dict:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (9, 7, '新增', '', 'sys:dict:save', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (10, 7, '修改', '', 'sys:dict:update,sys:dict:info', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (11, 7, '删除', '', 'sys:dict:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (12, NULL, '权限管理', '', '', 0, 0, 'icon-safetycertificate', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (13, 12, '岗位管理', 'sys/post/index', '', 0, 0, 'icon-solution', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (14, 13, '查询', '', 'sys:post:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (15, 13, '新增', '', 'sys:post:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (16, 13, '修改', '', 'sys:post:update,sys:post:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (17, 13, '删除', '', 'sys:post:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (18, 12, '机构管理', 'sys/org/index', '', 0, 0, 'icon-cluster', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (19, 18, '查询', '', 'sys:org:list', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (20, 18, '新增', '', 'sys:org:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (21, 18, '修改', '', 'sys:org:update,sys:org:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (22, 18, '删除', '', 'sys:org:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (23, 12, '角色管理', 'sys/role/index', '', 0, 0, 'icon-team', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (24, 23, '查询', '', 'sys:role:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (25, 23, '新增', '', 'sys:role:save,sys:role:menu,sys:org:list', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (26, 23, '修改', '', 'sys:role:update,sys:role:info,sys:role:menu,sys:org:list,sys:user:page', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (27, 23, '删除', '', 'sys:role:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (28, 12, '用户管理', 'sys/user/index', '', 0, 0, 'icon-user', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (29, 28, '查询', '', 'sys:user:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (30, 28, '新增', '', 'sys:user:save,sys:role:list', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (31, 28, '修改', '', 'sys:user:update,sys:user:info,sys:role:list', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (32, 28, '删除', '', 'sys:user:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (33, NULL, '应用管理', '', '', 0, 0, 'icon-appstore', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (34, NULL, '日志管理', '', '', 0, 0, 'icon-filedone', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (35, 34, '登录日志', 'sys/log/login', 'sys:log:login', 0, 0, 'icon-solution', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (36, 28, '导入', '', 'sys:user:import', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (37, 28, '导出', '', 'sys:user:export', 1, 0, '', 6, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (38, 1, '参数管理', 'sys/params/index', 'sys:params:all', 0, 0, 'icon-filedone', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (39, 1, '接口文档', '{{apiUrl}}/doc.html', null, 0, 1, 'icon-file-text-fill', 10, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (40, 34, '操作日志', 'sys/log/operate', 'sys:operate:all', 0, 0, 'icon-file-text', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (41, 1, '系统配置', 'sys/config/index', null, 0, 0, 'icon-safetycertificate', 4, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (42, 41, '短信配置', '', 'sys:sms:config', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (43, 41, '邮件配置', '', 'sys:mail:config', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (44, 41, '第三方登录', '', 'sys:third:config', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (45, NULL, '基础工具', '', '', 0, 0, 'icon-wrench-fill', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (46, 45, '短信发送', 'sys/tool/sms/index', 'sys:sms:log', 0, 0, 'icon-message', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (47, 45, '邮件发送', 'sys/tool/mail/index', 'sys:mail:log', 0, 0, 'icon-mail', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (48, 45, '附件管理', 'sys/attachment/index', NULL, 0, 0, 'icon-folder-fill', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (49, 48, '查看', '', 'sys:attachment:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (50, 48, '上传', '', 'sys:attachment:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (51, 48, '删除', '', 'sys:attachment:delete', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (52, NULL, '企业版', 'https://maku.net/price', NULL, 0, 1, 'icon-safetycertificate', 10, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1, 'post_status', '状态', '岗位管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (2, 'user_gender', '性别', '用户管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (3, 'user_status', '状态', '用户管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (4, 'role_data_scope', '数据范围', '角色管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (5, 'enable_disable', '状态', '功能状态:启用 | 禁用 ', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (6, 'success_fail', '状态', '操作状态:成功 | 失败', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (7, 'login_operation', '操作信息', '登录管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (8, 'params_type', '系统参数', '参数管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (9, 'user_super_admin', '用户是否是超管','用户是否是超管', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (10, 'log_operate_type', '操作类型', '操作日志', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (11, 'sms_platform', '短信平台类型', '短信管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (12, 'mail_platform', '邮件平台类型', '邮件管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); + + +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1, 1, '停用', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (2, 1, '正常', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (3, 2, '男', '0', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (4, 2, '女', '1', 'success', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (5, 2, '未知', '2', 'warning', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (6, 3, '正常', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (7, 3, '停用', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (8, 4, '全部数据', '0', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (9, 4, '本机构及子机构数据', '1', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (10, 4, '本机构数据', '2', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (11, 4, '本人数据', '3', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (12, 4, '自定义数据', '4', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (13, 5, '禁用', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (14, 5, '启用', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (15, 6, '失败', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (16, 6, '成功', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (17, 7, '登录成功', '0', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (18, 7, '退出成功', '1', 'warning', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (19, 7, '验证码错误', '2', 'danger', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (20, 7, '账号密码错误', '3', 'danger', '', 3, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (21, 8, '否', '0', 'primary', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (22, 8, '是', '1', 'danger', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (23, 9, '是', '1', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (24, 9, '否', '0', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (25, 10, '其它', '0', 'info', '', 10, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (26, 10, '查询', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (27, 10, '新增', '2', 'success', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (28, 10, '修改', '3', 'warning', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (29, 10, '删除', '4', 'danger', '', 3, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (30, 10, '导出', '5', 'info', '', 4, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (31, 10, '导入', '6', 'info', '', 5, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (32, 11, '阿里云', '0', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (33, 11, '腾讯云', '1', '', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (34, 11, '七牛云', '2', '', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (35, 11, '华为云', '3', '', '', 3, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (36, 12, '本地', '-1', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (37, 12, '阿里云', '0', '', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); + + +INSERT INTO sys_params (param_name, param_type, param_key, param_value, remark, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ('用户登录-验证码开关', 1, 'LOGIN_CAPTCHA', 'false', '是否开启验证码(true:开启,false:关闭)', 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_third_login_config (open_type, client_id, client_secret, redirect_uri, agent_id, tenant_id, version, deleted, create_time) VALUES ('feishu', 'cli_a541d3aa03f8500b', '5Chz39zvEhZtxSVZz3vLjfQHdkvavQaH', 'http://localhost:8090/sys/third/callback/feishu', '', 10000, 0, 0, now()); + +INSERT INTO sys_mail_config (platform, group_name, mail_host, mail_port, mail_from, mail_pass, region_id, endpoint, access_key, secret_key, status, version, deleted, creator, create_time, updater, update_time) VALUES (-1, 'test', NULL, NULL, 'baba_tv@163.com', 'TZNVURLYVBNJUNBB', '', '', NULL, NULL, 1, 1, 0, 10000, now(), 10000, now()); \ No newline at end of file diff --git a/db/mysql/module/maku-module-generator.sql b/db/mysql/module/maku-module-generator.sql new file mode 100644 index 0000000..b008cc8 --- /dev/null +++ b/db/mysql/module/maku-module-generator.sql @@ -0,0 +1,336 @@ +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (33, '代码生成器', '{{apiUrl}}/maku-generator/index.html', '', 0, 0, 'icon-rocket', 2, 0, 0, 10000, now(), 10000, now()); + +CREATE TABLE gen_datasource +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + db_type varchar(200) COMMENT '数据库类型', + conn_name varchar(200) NOT NULL COMMENT '连接名', + conn_url varchar(500) COMMENT 'URL', + username varchar(200) COMMENT '用户名', + password varchar(200) COMMENT '密码', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='数据源管理'; + +CREATE TABLE gen_config +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + config_key varchar(200), + config_value varchar(2000), + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='配置信息'; + +CREATE TABLE gen_field_type +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + column_type varchar(200) COMMENT '字段类型', + attr_type varchar(200) COMMENT '属性类型', + package_name varchar(200) COMMENT '属性包名', + create_time datetime COMMENT '创建时间', + primary key (id), + unique key (column_type) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='字段类型管理'; + +CREATE TABLE gen_base_class +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + package_name varchar(200) COMMENT '基类包名', + code varchar(200) COMMENT '基类编码', + fields varchar(500) COMMENT '基类字段,多个用英文逗号分隔', + remark varchar(200) COMMENT '备注', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='基类管理'; + +CREATE TABLE gen_table +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + table_name varchar(200) COMMENT '表名', + class_name varchar(200) COMMENT '类名', + table_comment varchar(200) COMMENT '说明', + author varchar(200) COMMENT '作者', + email varchar(200) COMMENT '邮箱', + package_name varchar(200) COMMENT '项目包名', + version varchar(200) COMMENT '项目版本号', + generator_type tinyint COMMENT '生成方式 0:zip压缩包 1:自定义目录', + backend_path varchar(500) COMMENT '后端生成路径', + frontend_path varchar(500) COMMENT '前端生成路径', + module_name varchar(200) COMMENT '模块名', + function_name varchar(200) COMMENT '功能名', + form_layout tinyint COMMENT '表单布局 1:一列 2:两列', + table_type tinyint COMMENT '表类型', + sub_table varchar(4000) COMMENT '子表数据', + table_operation varchar(200) COMMENT '生成功能', + auth_level tinyint COMMENT '权限级别 0:页面层级 1:按钮层级', + open_type tinyint COMMENT '新增编辑 0:弹窗 1:右侧栏', + request_url varchar(200) COMMENT '请求URL', + authority varchar(200) COMMENT '权限标识', + tree_id varchar(200) COMMENT '树形ID', + tree_pid varchar(200) COMMENT '树形父ID', + tree_label varchar(200) COMMENT '树展示列', + left_title varchar(200) COMMENT '左侧标题', + left_from tinyint COMMENT '数据来源', + left_table_name varchar(200) COMMENT '左侧树表名', + left_url varchar(200) COMMENT '接口地址', + left_relation_field varchar(200) COMMENT '关联字段', + datasource_id bigint COMMENT '数据源ID', + baseclass_id bigint COMMENT '基类ID', + create_time datetime COMMENT '创建时间', + primary key (id), + unique key (table_name) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='代码生成表'; + +CREATE TABLE gen_table_field +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + table_id bigint COMMENT '表ID', + field_name varchar(200) COMMENT '字段名称', + field_type varchar(200) COMMENT '字段类型', + field_comment varchar(200) COMMENT '字段说明', + attr_name varchar(200) COMMENT '属性名', + attr_type varchar(200) COMMENT '属性类型', + package_name varchar(200) COMMENT '属性包名', + sort int COMMENT '排序', + auto_fill varchar(20) COMMENT '自动填充 DEFAULT、INSERT、UPDATE、INSERT_UPDATE', + primary_pk tinyint COMMENT '主键 0:否 1:是', + base_field tinyint COMMENT '基类字段 0:否 1:是', + form_item tinyint COMMENT '表单项 0:否 1:是', + form_required tinyint COMMENT '表单必填 0:否 1:是', + form_type varchar(200) COMMENT '表单类型', + form_dict varchar(200) COMMENT '表单字典类型', + form_validator varchar(200) COMMENT '表单效验', + grid_item tinyint COMMENT '列表项 0:否 1:是', + grid_sort tinyint COMMENT '列表排序 0:否 1:是', + query_item tinyint COMMENT '查询项 0:否 1:是', + query_type varchar(200) COMMENT '查询方式', + query_form_type varchar(200) COMMENT '查询表单类型', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='代码生成表字段'; + +CREATE TABLE gen_project_modify +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + project_name varchar(100) COMMENT '项目名', + project_code varchar(100) COMMENT '项目标识', + project_package varchar(100) COMMENT '项目包名', + project_path varchar(200) COMMENT '项目路径', + modify_project_name varchar(100) COMMENT '变更项目名', + modify_project_code varchar(100) COMMENT '变更标识', + modify_project_package varchar(100) COMMENT '变更包名', + exclusions varchar(200) COMMENT '排除文件', + modify_suffix varchar(200) COMMENT '变更文件', + modify_tmp_path varchar(100) COMMENT '变更临时路径', + create_time datetime COMMENT '创建时间', + PRIMARY KEY (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='项目名变更'; + + +-- 用于测试代码生成器的表结构 -- +CREATE TABLE gen_test_member +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + name varchar(50) COMMENT '姓名', + gender tinyint COMMENT '性别', + age int COMMENT '年龄', + tenant_id bigint COMMENT '租户ID', + create_time datetime COMMENT '创建时间', + PRIMARY KEY (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='单表测试'; + +CREATE TABLE gen_test_tree +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + parent_id bigint COMMENT '上级ID', + tree_name varchar(100) COMMENT '名称', + tenant_id bigint COMMENT '租户ID', + create_time datetime COMMENT '创建时间', + PRIMARY KEY (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='树表测试'; + +CREATE TABLE gen_test_product +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + name varchar(100) COMMENT '名称', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + PRIMARY KEY (id) +)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='产品测试'; + +CREATE TABLE gen_test_product_info +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + images varchar(2000) COMMENT '图片', + intro varchar(5000) COMMENT '介绍', + product_id bigint COMMENT '产品ID', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + PRIMARY KEY (id) +)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='产品信息'; + +CREATE TABLE gen_test_product_param +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + param_name varchar(200) COMMENT '参数名称', + param_value varchar(200) COMMENT '参数值', + product_id bigint COMMENT '产品ID', + tenant_id bigint COMMENT '租户ID', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + PRIMARY KEY (id) +)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='产品参数'; + +CREATE TABLE gen_test_goods_category +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + name varchar(100) COMMENT '名称', + pid bigint COMMENT '上级ID', + tenant_id bigint COMMENT '租户ID', + deleted tinyint COMMENT '删除标识', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + PRIMARY KEY (id) +)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='商品分类'; + +CREATE TABLE gen_test_goods +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + name varchar(100) COMMENT '名称', + intro varchar(5000) COMMENT '介绍', + category_id bigint COMMENT '分类ID', + tenant_id bigint COMMENT '租户ID', + deleted tinyint COMMENT '删除标识', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + PRIMARY KEY (id) +)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='商品管理'; + + +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('datetime', 'LocalDateTime', 'java.time.LocalDateTime', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('date', 'LocalDateTime', 'java.time.LocalDateTime', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('tinyint', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('smallint', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('mediumint', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('integer', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('bigint', 'Long', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('float', 'Float', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('double', 'Double', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('decimal', 'BigDecimal', 'java.math.BigDecimal', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('bit', 'Boolean', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('char', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('varchar', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('tinytext', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('text', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('mediumtext', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('longtext', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('timestamp', 'LocalDateTime', 'java.time.LocalDateTime', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('NUMBER', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('BINARY_INTEGER', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('BINARY_FLOAT', 'Float', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('BINARY_DOUBLE', 'Double', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('VARCHAR2', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('NVARCHAR', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('NVARCHAR2', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('CLOB', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int8', 'Long', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int4', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int2', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('numeric', 'BigDecimal', 'java.math.BigDecimal', now()); + +INSERT INTO gen_base_class (package_name, code, fields, remark, create_time) VALUES ('com.bdzl.framework.mybatis.entity', 'BaseEntity', 'id,creator,create_time,updater,update_time,version,deleted', '使用该基类,则需要表里有这些字段', now()); + +INSERT INTO gen_project_modify (project_name, project_code, project_package, project_path, modify_project_name, modify_project_code, modify_project_package, exclusions, modify_suffix, create_time) VALUES ('drone-ops', 'maku', 'com.bdzl', 'D:/makunet/drone-ops', 'baba-boot', 'baba', 'com.baba', '.git,.idea,target,logs', 'java,xml,yml,txt', now()); +INSERT INTO gen_project_modify (project_name, project_code, project_package, project_path, modify_project_name, modify_project_code, modify_project_package, exclusions, modify_suffix, create_time) VALUES ('maku-cloud', 'maku', 'com.bdzl', 'D:/makunet/maku-cloud', 'baba-cloud', 'baba', 'com.baba', '.git,.idea,target,logs', 'java,xml,yml,txt', now()); + +INSERT INTO gen_config (config_key, config_value) VALUES ('gen_config', ''); + +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (20, 'gen_test_member', 'GenTestMember', '单表测试', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'member', 1, 0, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\",\"import\"]', 0, 0, '/test/member', 'test:member', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (21, 'gen_test_tree', 'GenTestTree', '树表测试', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'tree', 1, 1, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\"]', 0, 0, '/test/tree', 'test:tree', 'id', 'parent_id', 'tree_name', 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (22, 'gen_test_goods', 'GenTestGoods', '商品管理', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'goods', 1, 2, '[]', '[\"query\",\"insert\",\"update\",\"delete\"]', 0, 0, '/test/goods', 'test:goods', NULL, NULL, NULL, 0, NULL, now(), 0, 'gen_test_goods_category', '/test/category/list', 'category_id', '分类列表'); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (23, 'gen_test_goods_category', 'GenTestGoodsCategory', '商品分类', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'category', 1, 1, '[]', '[\"query\",\"insert\",\"update\",\"delete\"]', 0, 0, '/test/category', 'test:category', 'id', 'pid', 'name', 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (24, 'gen_test_product_info', 'GenTestProductInfo', '产品信息', '阿沐', 'babamu@126.com', 'com.bdzl', '', 0, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'info', 1, 0, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\"]', 0, 0, '/test/info', 'test:info', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (25, 'gen_test_product_param', 'GenTestProductParam', '产品参数', '阿沐', 'babamu@126.com', 'com.bdzl', '', 0, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'param', 1, 0, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\"]', 0, 0, '/test/param', 'test:param', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (26, 'gen_test_product', 'GenTestProduct', '产品测试', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'product', 1, 0, '[{\"tableName\":\"gen_test_product_info\",\"foreignKey\":\"product_id\",\"tableTitle\":\"产品信息\",\"mainRelation\":1,\"sort\":0},{\"tableName\":\"gen_test_product_param\",\"foreignKey\":\"product_id\",\"tableTitle\":\"产品参数\",\"mainRelation\":2,\"sort\":1}]', '[\"query\",\"insert\",\"update\",\"delete\"]', 0, 1, '/test/product', 'test:product', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); + +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (220, 20, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (221, 20, 'name', 'varchar', '姓名', 'name', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (222, 20, 'gender', 'tinyint', '性别', 'gender', 'Integer', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'radio', 'user_gender', NULL, 1, 0, 1, '=', 'select', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (223, 20, 'age', 'int', '年龄', 'age', 'Integer', NULL, 3, 'DEFAULT', 0, 0, 1, 1, 'number', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (224, 20, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (225, 20, 'version', 'int', '版本号', 'version', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (226, 20, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (227, 20, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (228, 21, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (229, 21, 'tree_name', 'varchar', '名称', 'treeName', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (230, 21, 'parent_id', 'bigint', '上级ID', 'parentId', 'Long', NULL, 2, 'DEFAULT', 0, 0, 1, 0, 'treeselect', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (231, 21, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (232, 21, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 4, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 1, '=', 'date', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (233, 22, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (234, 22, 'name', 'varchar', '名称', 'name', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, 'like', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (235, 22, 'intro', 'varchar', '介绍', 'intro', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (236, 22, 'category_id', 'bigint', '分类ID', 'categoryId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (237, 22, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (238, 22, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (239, 22, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (240, 22, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (241, 22, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 8, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (242, 22, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 9, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (243, 23, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (244, 23, 'name', 'varchar', '名称', 'name', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, 'like', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (245, 23, 'pid', 'bigint', '上级ID', 'pid', 'Long', NULL, 1, 'DEFAULT', 0, 0, 1, 0, 'treeselect', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (246, 23, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (247, 23, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 4, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (248, 23, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (249, 23, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 1, '=', 'datetime', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (250, 23, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 7, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (251, 23, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (252, 24, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (253, 24, 'images', 'varchar', '图片', 'images', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'image', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (254, 24, 'intro', 'varchar', '介绍', 'intro', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'editor', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (255, 24, 'product_id', 'bigint', '产品ID', 'productId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (256, 24, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (257, 24, 'version', 'int', '版本号', 'version', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (258, 24, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (259, 24, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (260, 24, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (261, 24, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 9, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (262, 24, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 10, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (263, 25, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (264, 25, 'param_name', 'varchar', '参数名称', 'paramName', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (265, 25, 'param_value', 'varchar', '参数值', 'paramValue', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (266, 25, 'product_id', 'bigint', '产品ID', 'productId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (267, 25, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (268, 25, 'version', 'int', '版本号', 'version', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (269, 25, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (270, 25, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (271, 25, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (272, 25, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 9, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (273, 25, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 10, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (274, 26, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (275, 26, 'name', 'varchar', '名称', 'name', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, 'like', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (276, 26, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 2, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (277, 26, 'version', 'int', '版本号', 'version', 'Integer', NULL, 3, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (278, 26, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 4, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (279, 26, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (280, 26, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 1, '=', 'datetime', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (281, 26, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 7, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (282, 26, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); diff --git a/db/mysql/module/maku-module-iot.sql b/db/mysql/module/maku-module-iot.sql new file mode 100644 index 0000000..c1841f9 --- /dev/null +++ b/db/mysql/module/maku-module-iot.sql @@ -0,0 +1,129 @@ +-- 表结构 +CREATE TABLE iot_device ( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + code varchar(255) NOT NULL COMMENT '编码', + name varchar(255) NOT NULL COMMENT '名称', + type int NOT NULL COMMENT '设备类型,1.手持设备,2.柜体,3传感设备', + uid varchar(255) NOT NULL COMMENT '唯一标识码', + secret varchar(255) DEFAULT NULL COMMENT '设备密钥', + app_version varchar(255) DEFAULT NULL COMMENT 'App版本号', + battery_percent varchar(10) DEFAULT NULL COMMENT '电池电量百分比', + temperature varchar(10) DEFAULT NULL COMMENT '温度', + status tinyint NOT NULL DEFAULT '1' COMMENT '状态,0禁用,1启用', + running_status int NOT NULL DEFAULT '0' COMMENT '运行状态,0.离线状态 1.在线状态 2.正常待机 3.用户使用中 4.OTA升级中', + protocol_type varchar(20) NOT NULL DEFAULT 'MQTT' COMMENT '协议类型', + up_time datetime DEFAULT NULL COMMENT '上线时间', + down_time datetime DEFAULT NULL COMMENT '下线时间', + tenant_id bigint DEFAULT NULL COMMENT '租户ID', + creator bigint DEFAULT NULL COMMENT '创建者', + create_time datetime DEFAULT NULL COMMENT '创建时间', + updater bigint DEFAULT NULL COMMENT '更新者', + update_time datetime DEFAULT NULL COMMENT '更新时间', + version int DEFAULT NULL COMMENT '版本号', + deleted tinyint DEFAULT NULL COMMENT '删除标识 0:正常 1:已删除', + PRIMARY KEY (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT='设备表'; + +CREATE TABLE iot_device_event_log ( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + device_id bigint NOT NULL COMMENT '设备id', + event_type tinyint NOT NULL COMMENT '事件类型', + event_uid varchar(50) DEFAULT NULL COMMENT '事件标识id', + event_payload varchar(1000) DEFAULT NULL COMMENT '事件数据', + event_time datetime DEFAULT NULL COMMENT '事件时间', + tenant_id bigint DEFAULT NULL COMMENT '租户ID', + version int DEFAULT NULL COMMENT '版本号', + deleted tinyint DEFAULT NULL COMMENT '删除标识 0:正常 1:已删除', + creator bigint DEFAULT NULL COMMENT '创建者', + create_time datetime DEFAULT NULL COMMENT '创建时间', + updater bigint DEFAULT NULL COMMENT '更新者', + update_time datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT='设备事件日志'; + +CREATE TABLE iot_device_service_log ( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + device_id bigint NOT NULL COMMENT '设备id', + service_type tinyint NOT NULL COMMENT '服务类型', + service_uid varchar(50) DEFAULT NULL COMMENT '服务标识id', + service_payload varchar(1000) DEFAULT NULL COMMENT '服务数据', + service_time datetime DEFAULT NULL COMMENT '服务时间', + tenant_id bigint DEFAULT NULL COMMENT '租户ID', + version int DEFAULT NULL COMMENT '版本号', + deleted tinyint DEFAULT NULL COMMENT '删除标识 0:正常 1:已删除', + creator bigint DEFAULT NULL COMMENT '创建者', + create_time datetime DEFAULT NULL COMMENT '创建时间', + updater bigint DEFAULT NULL COMMENT '更新者', + update_time datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT='设备服务日志'; + + +INSERT INTO iot_device (id, code, name, type, uid, secret, app_version, battery_percent, temperature, status, running_status, protocol_type, up_time, down_time, tenant_id, creator, create_time, updater, update_time, version, deleted) VALUES (1, 'test-tcp', 'testTCP', 1, 'test12345678', '123456', NULL, NULL, NULL, 1, 1, 'TCP', now(), NULL, NULL, 10000, now(), 10000, now(), 0, 0); + +-- 菜单,权限 +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ( NULL, '物联网平台', NULL, NULL, 0, 0, 'icon-printer-fill', 6, 0, 0, 10000,now(), 10000, now()); + +SET @pid = @@identity; +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @pid) , '设备列表', 'iot/device/index', NULL, 0, 0, 'icon-menu', 0, 0, 0, 10000, now(), 10000, now()); + +SET @menuId = @@identity; +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '查看', '', 'iot:device:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '新增', '', 'iot:device:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '修改', '', 'iot:device:update,iot:device:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '删除', '', 'iot:device:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '下发指令', '', 'iot:device:send', 1, 0, '', 4, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '上报数据', '', 'iot:device:report', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '设备事件日志', '', 'iot:device_event_log:page', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (@menuId, '设备服务日志', '', 'iot:device_service_log:page', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); + +-- 字典数据 +INSERT INTO sys_dict_type (dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUE('device_type', '设备类型', '设备类型', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '手持设备', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '柜体', '2', 'primary', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '传感设备', '3', 'primary', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES('device_running_status', '设备运行状态', '设备运行状态:离线|在线|待机|使用中|OTA升级中', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '离线状态', '0', 'danger', NULL, 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '在线状态', '1', 'success', NULL, 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES('device_command', '设备指令', '设备服务具备的功能', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '远程锁定', 'LOCK', NULL, NULL, 0, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '远程解锁', 'UNLOCK', NULL, NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '登录', 'SIGN_ON', NULL, NULL, 2, NULL, 0, 1, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '登出', 'SIGN_OFF', NULL, NULL, 3, NULL, 0, 1, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'OTA升级', 'OTA_UPGRADE', NULL, NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES('device_protocol_type', '设备协议类型', '设备协议类型', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'MQTT', 'MQTT', NULL, NULL, 0, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'TCP', 'TCP', NULL, NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'UDP', 'UDP', NULL, NULL, 2, NULL, 0, 1, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'BLE', 'BLE', NULL, NULL, 3, NULL, 0, 1, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'CoAP', 'CoAP', NULL, NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'LwM2M', 'LwM2M', NULL, NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'Modbus', 'Modbus', NULL, NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); + + +INSERT INTO sys_dict_type (dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES('device_property', '设备属性', '设备通用属性:运行状态|APP版本|电池电量百分比|温度', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '运行状态', 'RUNNING_STATUS', NULL, NULL, 0, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'APP版本', 'APP_VERSION', NULL, NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '电池电量百分比', 'BATTERY_PERCENT', NULL, NULL, 2, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '温度', 'TEMPERATURE', NULL, NULL, 3, NULL, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES('device_event_type', '事件类型', '事件日志类型', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '下线', 'OFFLINE', 'danger', NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '上线', 'ONLINE', 'primary', NULL, 2, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '登录', 'SIGN_ON', 'primary', NULL, 3, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '退出登录', 'SIGN_OFF', 'danger', NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'OTA升级', 'OTA_UPGRADE', 'primary', NULL, 5, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '设备远程锁定', 'LOCK', 'primary', NULL, 6, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '设备远程解锁', 'UNLOCK', 'primary', NULL,7, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), 'APP版本信息', 'APP_VERSION_REPORT', 'primary', NULL, 8, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '电池电量', 'BATTERY_PERCENT_REPORT', 'primary', NULL, 9, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '温度', 'TEMPERATURE_REPORT', 'primary', NULL, 0, NULL, 10, 0, 10000, now(), 10000, now()); diff --git a/db/mysql/module/maku-module-member.sql b/db/mysql/module/maku-module-member.sql new file mode 100644 index 0000000..00f8fd3 --- /dev/null +++ b/db/mysql/module/maku-module-member.sql @@ -0,0 +1,19 @@ +CREATE TABLE member_user +( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + nick_name varchar(100) NOT NULL COMMENT '昵称', + mobile varchar(20) NOT NULL COMMENT '手机号', + avatar varchar(200) COMMENT '头像', + birthday date COMMENT '出生日期', + gender tinyint COMMENT '性别 0:男 1:女 2:未知', + openid varchar(200) COMMENT '第三方平台,唯一标识', + last_login_ip varchar(100) COMMENT '最后登录IP', + last_login_time datetime COMMENT '最后登录时间', + tenant_id bigint COMMENT '租户ID', + remark varchar(500) COMMENT '备注', + status tinyint COMMENT '状态 0:禁用 1:启用', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + create_time datetime COMMENT '创建时间', + primary key (id) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='会员管理'; \ No newline at end of file diff --git a/db/mysql/module/maku-module-monitor.sql b/db/mysql/module/maku-module-monitor.sql new file mode 100644 index 0000000..fad145a --- /dev/null +++ b/db/mysql/module/maku-module-monitor.sql @@ -0,0 +1,6 @@ +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (33, '系统监控', '', '', 0, 0, 'icon-Report', 10, 0, 0, 10000, now(), 10000, now()); + +set @menuId = @@identity; +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '服务监控', 'monitor/server/index', 'monitor:server:all', 0, 0, 'icon-sever', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '缓存监控', 'monitor/cache/index', 'monitor:cache:all', 0, 0, 'icon-fund-fill', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '在线用户', 'monitor/user/index', 'monitor:user:all', 0, 0, 'icon-user', 3, 0, 0, 10000, now(), 10000, now()); diff --git a/db/mysql/module/maku-module-quartz.sql b/db/mysql/module/maku-module-quartz.sql new file mode 100644 index 0000000..045f2b4 --- /dev/null +++ b/db/mysql/module/maku-module-quartz.sql @@ -0,0 +1,216 @@ +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1, '定时任务', 'quartz/schedule/index', NULL, 0, 0, 'icon-reloadtime', 0, 0, 0, 10000, now(), 10000, now()); + +SET @menuId = @@identity; +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '查看', '', 'schedule:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '新增', '', 'schedule:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '修改', '', 'schedule:update,schedule:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '删除', '', 'schedule:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '立即运行', '', 'schedule:run', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @menuId), '日志', '', 'schedule:log', 1, 0, '', 4, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ('schedule_group', '任务组名', '定时任务', 0, 10000, 0, 0, 10000, now(), 10000, now()); + +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '默认', 'default', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '系统', 'system', '', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ('schedule_status', '状态', '定时任务', 0, 10000, 0, 0, 10000, now(), 10000, now()); + +SET @typeId = @@identity; +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '暂停', '0', 'danger', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ((SELECT @typeId), '正常', '1', 'primary', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); + + +DROP TABLE IF EXISTS schedule_job; +DROP TABLE IF EXISTS schedule_job_log; + +CREATE TABLE schedule_job ( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + job_name varchar(200) COMMENT '名称', + job_group varchar(100) COMMENT '分组', + bean_name varchar(200) COMMENT 'spring bean名称', + method varchar(100) COMMENT '执行方法', + params varchar(2000) COMMENT '参数', + cron_expression varchar(100) COMMENT 'cron表达式', + status tinyint unsigned COMMENT '状态 0:暂停 1:正常', + concurrent tinyint unsigned COMMENT '是否并发 0:禁止 1:允许', + remark varchar(255) COMMENT '备注', + version int COMMENT '版本号', + deleted tinyint COMMENT '删除标识 0:正常 1:已删除', + creator bigint COMMENT '创建者', + create_time datetime COMMENT '创建时间', + updater bigint COMMENT '更新者', + update_time datetime COMMENT '更新时间', + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT='定时任务'; + +CREATE TABLE schedule_job_log ( + id bigint NOT NULL AUTO_INCREMENT COMMENT 'id', + job_id bigint NOT NULL COMMENT '任务id', + job_name varchar(200) COMMENT '任务名称', + job_group varchar(100) COMMENT '任务组名', + bean_name varchar(200) COMMENT 'spring bean名称', + method varchar(100) COMMENT '执行方法', + params varchar(2000) COMMENT '参数', + status tinyint unsigned NOT NULL COMMENT '任务状态 0:失败 1:成功', + error varchar(2000) COMMENT '异常信息', + times bigint NOT NULL COMMENT '耗时(单位:毫秒)', + create_time datetime COMMENT '创建时间', + PRIMARY KEY (id), + key idx_job_id (job_id) +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT='定时任务日志'; + + +INSERT INTO schedule_job (id, job_name, job_group, bean_name, method, params, cron_expression, status, concurrent, remark, version, deleted, creator, create_time, updater, update_time) VALUES (1, '测试任务', 'system', 'testTask', 'run', '123', '0 * * * * ? *', 0, 0, '', 14, 0, 10000, now(), 10000, now()); + + + + +-- ---------------------------------------------------------- +-- 以下为Quartz框架,自带的表结构 +-- ---------------------------------------------------------- + +DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; +DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; +DROP TABLE IF EXISTS QRTZ_LOCKS; +DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; +DROP TABLE IF EXISTS QRTZ_CALENDARS; + +create table QRTZ_JOB_DETAILS ( + sched_name varchar(120) not null comment '调度名称', + job_name varchar(200) not null comment '任务名称', + job_group varchar(200) not null comment '任务组名', + description varchar(250) null comment '相关介绍', + job_class_name varchar(250) not null comment '执行任务类名称', + is_durable varchar(1) not null comment '是否持久化', + is_nonconcurrent varchar(1) not null comment '是否并发', + is_update_data varchar(1) not null comment '是否更新数据', + requests_recovery varchar(1) not null comment '是否接受恢复执行', + job_data blob null comment '存放持久化job对象', + primary key (sched_name, job_name, job_group) +) ENGINE=InnoDB COMMENT = '任务详细信息表'; + +create table QRTZ_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment '触发器的名字', + trigger_group varchar(200) not null comment '触发器所属组的名字', + job_name varchar(200) not null comment 'qrtz_job_details表job_name的外键', + job_group varchar(200) not null comment 'qrtz_job_details表job_group的外键', + description varchar(250) null comment '相关介绍', + next_fire_time bigint(13) null comment '上一次触发时间(毫秒)', + prev_fire_time bigint(13) null comment '下一次触发时间(默认为-1表示不触发)', + priority integer null comment '优先级', + trigger_state varchar(16) not null comment '触发器状态', + trigger_type varchar(8) not null comment '触发器的类型', + start_time bigint(13) not null comment '开始时间', + end_time bigint(13) null comment '结束时间', + calendar_name varchar(200) null comment '日程表名称', + misfire_instr smallint(2) null comment '补偿执行的策略', + job_data blob null comment '存放持久化job对象', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, job_name, job_group) + references QRTZ_JOB_DETAILS(sched_name, job_name, job_group) +) ENGINE=InnoDB COMMENT = '触发器详细信息表'; + +create table QRTZ_SIMPLE_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + repeat_count bigint(7) not null comment '重复的次数统计', + repeat_interval bigint(12) not null comment '重复的间隔时间', + times_triggered bigint(10) not null comment '已经触发的次数', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) + references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) ENGINE=InnoDB COMMENT = '简单触发器的信息表'; + +create table QRTZ_CRON_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + cron_expression varchar(200) not null comment 'cron表达式', + time_zone_id varchar(80) comment '时区', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) + references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) ENGINE=InnoDB COMMENT = 'Cron类型的触发器表'; + +create table QRTZ_BLOB_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + blob_data blob null comment '存放持久化Trigger对象', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) + references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) ENGINE=InnoDB COMMENT = 'Blob类型的触发器表'; + +create table QRTZ_CALENDARS ( + sched_name varchar(120) not null comment '调度名称', + calendar_name varchar(200) not null comment '日历名称', + calendar blob not null comment '存放持久化calendar对象', + primary key (sched_name, calendar_name) +) ENGINE=InnoDB COMMENT = '日历信息表'; + +create table QRTZ_PAUSED_TRIGGER_GRPS ( + sched_name varchar(120) not null comment '调度名称', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + primary key (sched_name, trigger_group) +) ENGINE=InnoDB COMMENT = '暂停的触发器表'; + +create table QRTZ_FIRED_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + entry_id varchar(95) not null comment '调度器实例id', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + instance_name varchar(200) not null comment '调度器实例名', + fired_time bigint(13) not null comment '触发的时间', + sched_time bigint(13) not null comment '定时器制定的时间', + priority integer not null comment '优先级', + state varchar(16) not null comment '状态', + job_name varchar(200) null comment '任务名称', + job_group varchar(200) null comment '任务组名', + is_nonconcurrent varchar(1) null comment '是否并发', + requests_recovery varchar(1) null comment '是否接受恢复执行', + primary key (sched_name, entry_id) +) ENGINE=InnoDB COMMENT = '已触发的触发器表'; + +create table QRTZ_SCHEDULER_STATE ( + sched_name varchar(120) not null comment '调度名称', + instance_name varchar(200) not null comment '实例名称', + last_checkin_time bigint(13) not null comment '上次检查时间', + checkin_interval bigint(13) not null comment '检查间隔时间', + primary key (sched_name, instance_name) +) ENGINE=InnoDB COMMENT = '调度器状态表'; + +create table QRTZ_LOCKS ( + sched_name varchar(120) not null comment '调度名称', + lock_name varchar(40) not null comment '悲观锁名称', + primary key (sched_name, lock_name) +) ENGINE=InnoDB COMMENT = '存储的悲观锁信息表'; + +create table QRTZ_SIMPROP_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + str_prop_1 varchar(512) null comment 'String类型的trigger的第一个参数', + str_prop_2 varchar(512) null comment 'String类型的trigger的第二个参数', + str_prop_3 varchar(512) null comment 'String类型的trigger的第三个参数', + int_prop_1 int null comment 'int类型的trigger的第一个参数', + int_prop_2 int null comment 'int类型的trigger的第二个参数', + long_prop_1 bigint null comment 'long类型的trigger的第一个参数', + long_prop_2 bigint null comment 'long类型的trigger的第二个参数', + dec_prop_1 numeric(13,4) null comment 'decimal类型的trigger的第一个参数', + dec_prop_2 numeric(13,4) null comment 'decimal类型的trigger的第二个参数', + bool_prop_1 varchar(1) null comment 'Boolean类型的trigger的第一个参数', + bool_prop_2 varchar(1) null comment 'Boolean类型的trigger的第二个参数', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) + references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) ENGINE=InnoDB COMMENT = '同步机制的行锁表'; \ No newline at end of file diff --git a/db/postgresql/maku.sql b/db/postgresql/maku.sql new file mode 100644 index 0000000..eb04070 --- /dev/null +++ b/db/postgresql/maku.sql @@ -0,0 +1,826 @@ +CREATE TABLE sys_user +( + id bigserial NOT NULL, + username varchar(50) NOT NULL, + password varchar(100), + real_name varchar(50), + avatar varchar(200), + gender int, + email varchar(100), + mobile varchar(20), + org_id int8, + super_admin int, + status int, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_user IS '用户管理'; +COMMENT ON COLUMN sys_user.id IS 'id'; +COMMENT ON COLUMN sys_user.username IS '用户名'; +COMMENT ON COLUMN sys_user.password IS '密码'; +COMMENT ON COLUMN sys_user.real_name IS '姓名'; +COMMENT ON COLUMN sys_user.avatar IS '头像'; +COMMENT ON COLUMN sys_user.gender IS '性别 0:男 1:女 2:未知'; +COMMENT ON COLUMN sys_user.email IS '邮箱'; +COMMENT ON COLUMN sys_user.mobile IS '手机号'; +COMMENT ON COLUMN sys_user.org_id IS '机构ID'; +COMMENT ON COLUMN sys_user.super_admin IS '超级管理员 0:否 1:是'; +COMMENT ON COLUMN sys_user.status IS '状态 0:停用 1:正常'; +COMMENT ON COLUMN sys_user.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_user.version IS '版本号'; +COMMENT ON COLUMN sys_user.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_user.creator IS '创建者'; +COMMENT ON COLUMN sys_user.create_time IS '创建时间'; +COMMENT ON COLUMN sys_user.updater IS '更新者'; +COMMENT ON COLUMN sys_user.update_time IS '更新时间'; + + +CREATE TABLE sys_user_token +( + id bigserial NOT NULL, + user_id int8, + access_token varchar(50) NOT NULL, + access_token_expire timestamp, + refresh_token varchar(50) NOT NULL, + refresh_token_expire timestamp, + tenant_id int8, + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_user_token IS '用户管理'; +COMMENT ON COLUMN sys_user_token.id IS 'id'; +COMMENT ON COLUMN sys_user_token.user_id IS '用户ID'; +COMMENT ON COLUMN sys_user_token.access_token IS 'accessToken'; +COMMENT ON COLUMN sys_user_token.access_token_expire IS 'accessToken 过期时'; +COMMENT ON COLUMN sys_user_token.refresh_token IS 'refreshToken'; +COMMENT ON COLUMN sys_user_token.refresh_token_expire IS 'refreshToken 过期时间'; +COMMENT ON COLUMN sys_user_token.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_user_token.create_time IS '创建时间'; + + +CREATE TABLE sys_third_login +( + id bigserial NOT NULL, + open_type varchar(50), + open_id varchar(100), + username varchar(100), + user_id int8, + tenant_id int8, + version int, + deleted int, + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_third_login IS '第三方登录'; +COMMENT ON COLUMN sys_third_login.id IS 'id'; +COMMENT ON COLUMN sys_third_login.open_type IS '开放平台类型'; +COMMENT ON COLUMN sys_third_login.open_id IS '开放平台,唯一标识'; +COMMENT ON COLUMN sys_third_login.username IS '昵称'; +COMMENT ON COLUMN sys_third_login.username IS '用户ID'; +COMMENT ON COLUMN sys_third_login.user_id IS '租户ID'; +COMMENT ON COLUMN sys_third_login.version IS '版本号'; +COMMENT ON COLUMN sys_third_login.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_third_login.create_time IS '创建时间'; + + +CREATE TABLE sys_third_login_config +( + id bigserial NOT NULL, + open_type varchar(50), + client_id varchar(200), + client_secret varchar(200), + redirect_uri varchar(200), + agent_id varchar(200), + tenant_id int8, + version int, + deleted int, + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_third_login_config IS '第三方登录配置'; +COMMENT ON COLUMN sys_third_login_config.id IS 'id'; +COMMENT ON COLUMN sys_third_login_config.open_type IS '开放平台类型'; +COMMENT ON COLUMN sys_third_login_config.client_id IS 'ClientID'; +COMMENT ON COLUMN sys_third_login_config.client_secret IS 'ClientSecret'; +COMMENT ON COLUMN sys_third_login_config.redirect_uri IS 'RedirectUri'; +COMMENT ON COLUMN sys_third_login_config.agent_id IS 'AgentID'; +COMMENT ON COLUMN sys_third_login_config.version IS '版本号'; +COMMENT ON COLUMN sys_third_login_config.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_third_login_config.create_time IS '创建时间'; + + +CREATE TABLE sys_org +( + id bigserial NOT NULL, + pid int8, + name varchar(50), + sort int, + leader_id int8, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_org IS '机构管理'; +COMMENT ON COLUMN sys_org.id IS 'id'; +COMMENT ON COLUMN sys_org.pid IS '上级ID'; +COMMENT ON COLUMN sys_org.name IS '机构名称'; +COMMENT ON COLUMN sys_org.sort IS '排序'; +COMMENT ON COLUMN sys_org.leader_id IS '负责人ID'; +COMMENT ON COLUMN sys_org.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_org.version IS '版本号'; +COMMENT ON COLUMN sys_org.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_org.creator IS '创建者'; +COMMENT ON COLUMN sys_org.create_time IS '创建时间'; +COMMENT ON COLUMN sys_org.updater IS '更新者'; +COMMENT ON COLUMN sys_org.update_time IS '更新时间'; + + +create table sys_role +( + id bigserial NOT NULL, + name varchar(50), + role_code varchar(50), + remark varchar(100), + data_scope int, + org_id int8, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_role IS '角色管理'; +COMMENT ON COLUMN sys_role.id IS 'id'; +COMMENT ON COLUMN sys_role.name IS '角色名称'; +COMMENT ON COLUMN sys_role.role_code IS '角色编码'; +COMMENT ON COLUMN sys_role.remark IS '备注'; +COMMENT ON COLUMN sys_role.data_scope IS '数据范围 0:全部数据 1:本机构及子机构数据 2:本机构数据 3:本人数据 4:自定义数据'; +COMMENT ON COLUMN sys_role.org_id IS '机构ID'; +COMMENT ON COLUMN sys_role.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_role.version IS '版本号'; +COMMENT ON COLUMN sys_role.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_role.creator IS '创建者'; +COMMENT ON COLUMN sys_role.create_time IS '创建时间'; +COMMENT ON COLUMN sys_role.updater IS '更新者'; +COMMENT ON COLUMN sys_role.update_time IS '更新时间'; + + +create table sys_user_role +( + id bigserial NOT NULL, + role_id int8, + user_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_user_role IS '用户角色关系'; +COMMENT ON COLUMN sys_user_role.id IS 'id'; +COMMENT ON COLUMN sys_user_role.role_id IS '角色ID'; +COMMENT ON COLUMN sys_user_role.user_id IS '用户ID'; +COMMENT ON COLUMN sys_user_role.version IS '版本号'; +COMMENT ON COLUMN sys_user_role.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_user_role.creator IS '创建者'; +COMMENT ON COLUMN sys_user_role.create_time IS '创建时间'; +COMMENT ON COLUMN sys_user_role.updater IS '更新者'; +COMMENT ON COLUMN sys_user_role.update_time IS '更新时间'; + +CREATE TABLE sys_post +( + id bigserial NOT NULL, + post_code varchar(100), + post_name varchar(100), + sort int, + status int, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_post IS '岗位管理'; +COMMENT ON COLUMN sys_post.id IS 'id'; +COMMENT ON COLUMN sys_post.post_code IS '岗位编码'; +COMMENT ON COLUMN sys_post.post_name IS '岗位名称'; +COMMENT ON COLUMN sys_post.sort IS '排序'; +COMMENT ON COLUMN sys_post.status IS '状态 0:停用 1:正常'; +COMMENT ON COLUMN sys_post.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_post.version IS '版本号'; +COMMENT ON COLUMN sys_post.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_post.creator IS '创建者'; +COMMENT ON COLUMN sys_post.create_time IS '创建时间'; +COMMENT ON COLUMN sys_post.updater IS '更新者'; +COMMENT ON COLUMN sys_post.update_time IS '更新时间'; + + +CREATE TABLE sys_user_post +( + id bigserial NOT NULL, + user_id int8, + post_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_user_post IS '用户岗位关系'; +COMMENT ON COLUMN sys_user_post.id IS 'id'; +COMMENT ON COLUMN sys_user_post.user_id IS '用户ID'; +COMMENT ON COLUMN sys_user_post.post_id IS '岗位ID'; +COMMENT ON COLUMN sys_user_post.version IS '版本号'; +COMMENT ON COLUMN sys_user_post.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_user_post.creator IS '创建者'; +COMMENT ON COLUMN sys_user_post.create_time IS '创建时间'; +COMMENT ON COLUMN sys_user_post.updater IS '更新者'; +COMMENT ON COLUMN sys_user_post.update_time IS '更新时间'; + + +create table sys_menu +( + id bigserial NOT NULL, + pid int8, + name varchar(200), + url varchar(200), + authority varchar(500), + type int, + open_style int, + icon varchar(50), + sort int, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_menu IS '菜单管理'; +COMMENT ON COLUMN sys_menu.id IS 'id'; +COMMENT ON COLUMN sys_menu.pid IS '上级ID'; +COMMENT ON COLUMN sys_menu.name IS '菜单名称'; +COMMENT ON COLUMN sys_menu.url IS '菜单URL'; +COMMENT ON COLUMN sys_menu.authority IS '授权标识'; +COMMENT ON COLUMN sys_menu.type IS '类型 0:菜单 1:按钮 2:接口'; +COMMENT ON COLUMN sys_menu.open_style IS '打开方式 0:内部 1:外部'; +COMMENT ON COLUMN sys_menu.icon IS '菜单图标'; +COMMENT ON COLUMN sys_menu.sort IS '排序'; +COMMENT ON COLUMN sys_menu.version IS '版本号'; +COMMENT ON COLUMN sys_menu.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_menu.creator IS '创建者'; +COMMENT ON COLUMN sys_menu.create_time IS '创建时间'; +COMMENT ON COLUMN sys_menu.updater IS '更新者'; +COMMENT ON COLUMN sys_menu.update_time IS '更新时间'; + + +create table sys_role_menu +( + id bigserial NOT NULL, + role_id int8, + menu_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_role_menu IS '角色菜单关系'; +COMMENT ON COLUMN sys_role_menu.id IS 'id'; +COMMENT ON COLUMN sys_role_menu.role_id IS '角色ID'; +COMMENT ON COLUMN sys_role_menu.menu_id IS '菜单ID'; +COMMENT ON COLUMN sys_role_menu.version IS '版本号'; +COMMENT ON COLUMN sys_role_menu.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_role_menu.creator IS '创建者'; +COMMENT ON COLUMN sys_role_menu.create_time IS '创建时间'; +COMMENT ON COLUMN sys_role_menu.updater IS '更新者'; +COMMENT ON COLUMN sys_role_menu.update_time IS '更新时间'; + + +create table sys_role_data_scope +( + id bigserial NOT NULL, + role_id int8, + org_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +CREATE INDEX idx_role_id on sys_role_data_scope(role_id); + +COMMENT ON TABLE sys_role_data_scope IS '角色数据权限'; +COMMENT ON COLUMN sys_role_data_scope.id IS 'id'; +COMMENT ON COLUMN sys_role_data_scope.role_id IS '角色ID'; +COMMENT ON COLUMN sys_role_data_scope.org_id IS '机构ID'; +COMMENT ON COLUMN sys_role_data_scope.version IS '版本号'; +COMMENT ON COLUMN sys_role_data_scope.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_role_data_scope.creator IS '创建者'; +COMMENT ON COLUMN sys_role_data_scope.create_time IS '创建时间'; +COMMENT ON COLUMN sys_role_data_scope.updater IS '更新者'; +COMMENT ON COLUMN sys_role_data_scope.update_time IS '更新时间'; + +create table sys_dict_type +( + id bigserial NOT NULL, + dict_type varchar(100), + dict_name varchar(255), + dict_source int default 0, + dict_sql varchar(500), + remark varchar(255), + sort int, + pid int8, + has_child int default 0, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_dict_type IS '字典类型'; +COMMENT ON COLUMN sys_dict_type.id IS 'id'; +COMMENT ON COLUMN sys_dict_type.dict_type IS '字典类型'; +COMMENT ON COLUMN sys_dict_type.dict_name IS '字典名称'; +COMMENT ON COLUMN sys_dict_type.dict_source IS '来源 0:字典数据 1:动态SQL'; +COMMENT ON COLUMN sys_dict_type.dict_sql IS '动态SQL'; +COMMENT ON COLUMN sys_dict_type.remark IS '备注'; +COMMENT ON COLUMN sys_dict_type.sort IS '排序'; +COMMENT ON COLUMN sys_dict_type.pid IS '上级节点'; +COMMENT ON COLUMN sys_dict_type.has_child IS '是否有子节点'; +COMMENT ON COLUMN sys_dict_type.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_dict_type.version IS '版本号'; +COMMENT ON COLUMN sys_dict_type.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_dict_type.creator IS '创建者'; +COMMENT ON COLUMN sys_dict_type.create_time IS '创建时间'; +COMMENT ON COLUMN sys_dict_type.updater IS '更新者'; +COMMENT ON COLUMN sys_dict_type.update_time IS '更新时间'; + +create table sys_dict_data +( + id bigserial NOT NULL, + dict_type_id int8, + dict_label varchar(255), + dict_value varchar(255), + label_class varchar(100), + remark varchar(255), + sort int, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_dict_data IS '字典数据'; +COMMENT ON COLUMN sys_dict_data.id IS 'id'; +COMMENT ON COLUMN sys_dict_data.dict_type_id IS '字典类型ID'; +COMMENT ON COLUMN sys_dict_data.dict_label IS '字典标签'; +COMMENT ON COLUMN sys_dict_data.dict_value IS '字典值'; +COMMENT ON COLUMN sys_dict_data.label_class IS '标签样式'; +COMMENT ON COLUMN sys_dict_data.remark IS '备注'; +COMMENT ON COLUMN sys_dict_data.sort IS '排序'; +COMMENT ON COLUMN sys_dict_data.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_dict_data.version IS '版本号'; +COMMENT ON COLUMN sys_dict_data.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_dict_data.creator IS '创建者'; +COMMENT ON COLUMN sys_dict_data.create_time IS '创建时间'; +COMMENT ON COLUMN sys_dict_data.updater IS '更新者'; +COMMENT ON COLUMN sys_dict_data.update_time IS '更新时间'; + + +create table sys_attachment +( + id bigserial NOT NULL, + name varchar(255) NOT NULL, + url varchar(255) NOT NULL, + size int8, + platform varchar(50), + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_attachment IS '附件管理'; +COMMENT ON COLUMN sys_attachment.id IS 'id'; +COMMENT ON COLUMN sys_attachment.name IS '附件名称'; +COMMENT ON COLUMN sys_attachment.url IS '附件地址'; +COMMENT ON COLUMN sys_attachment.size IS '附件大小'; +COMMENT ON COLUMN sys_attachment.platform IS '存储平台'; +COMMENT ON COLUMN sys_attachment.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_attachment.version IS '版本号'; +COMMENT ON COLUMN sys_attachment.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_attachment.creator IS '创建者'; +COMMENT ON COLUMN sys_attachment.create_time IS '创建时间'; +COMMENT ON COLUMN sys_attachment.updater IS '更新者'; +COMMENT ON COLUMN sys_attachment.update_time IS '更新时间'; + + +create table sys_params +( + id bigserial NOT NULL, + param_name varchar(100), + param_type int NOT NULL, + param_key varchar(100), + param_value varchar(2000), + remark varchar(200), + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_params IS '参数管理'; +COMMENT ON COLUMN sys_params.id IS 'id'; +COMMENT ON COLUMN sys_params.param_name IS '参数名称'; +COMMENT ON COLUMN sys_params.param_type IS '系统参数 0:否 1:是'; +COMMENT ON COLUMN sys_params.param_key IS '参数键'; +COMMENT ON COLUMN sys_params.param_value IS '参数值'; +COMMENT ON COLUMN sys_params.remark IS '备注'; +COMMENT ON COLUMN sys_params.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_params.version IS '版本号'; +COMMENT ON COLUMN sys_params.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_params.creator IS '创建者'; +COMMENT ON COLUMN sys_params.create_time IS '创建时间'; +COMMENT ON COLUMN sys_params.updater IS '更新者'; +COMMENT ON COLUMN sys_params.update_time IS '更新时间'; + + +create table sys_log_login +( + id bigserial NOT NULL, + username varchar(50), + ip varchar(32), + address varchar(32), + user_agent varchar(500), + status int, + operation int, + tenant_id int8, + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_log_login IS '登录日志'; +COMMENT ON COLUMN sys_log_login.id IS 'id'; +COMMENT ON COLUMN sys_log_login.username IS '用户名'; +COMMENT ON COLUMN sys_log_login.ip IS '登录IP'; +COMMENT ON COLUMN sys_log_login.address IS '登录地点'; +COMMENT ON COLUMN sys_log_login.user_agent IS 'User Agent'; +COMMENT ON COLUMN sys_log_login.status IS '登录状态 0:失败 1:成功'; +COMMENT ON COLUMN sys_log_login.operation IS '操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误'; +COMMENT ON COLUMN sys_log_login.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_log_login.create_time IS '创建时间'; + + +create table sys_log_operate +( + id bigserial NOT NULL, + module varchar(100), + name varchar(100), + req_uri varchar(200), + req_method varchar(20), + req_params text, + ip varchar(32), + address varchar(32), + user_agent varchar(500), + operate_type int, + duration int, + status int, + user_id int, + real_name varchar(50), + result_msg varchar(500), + tenant_id int8, + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_log_operate IS '操作日志'; +COMMENT ON COLUMN sys_log_operate.id IS 'id'; +COMMENT ON COLUMN sys_log_operate.module IS '模块名'; +COMMENT ON COLUMN sys_log_operate.name IS '操作名'; +COMMENT ON COLUMN sys_log_operate.req_uri IS '请求URI'; +COMMENT ON COLUMN sys_log_operate.req_method IS '请求方法'; +COMMENT ON COLUMN sys_log_operate.req_params IS '请求参数'; +COMMENT ON COLUMN sys_log_operate.ip IS '操作IP'; +COMMENT ON COLUMN sys_log_operate.address IS '登录地点'; +COMMENT ON COLUMN sys_log_operate.user_agent IS 'User Agent'; +COMMENT ON COLUMN sys_log_operate.operate_type IS '操作类型'; +COMMENT ON COLUMN sys_log_operate.status IS '登录状态 0:失败 1:成功'; +COMMENT ON COLUMN sys_log_operate.user_id IS '用户ID'; +COMMENT ON COLUMN sys_log_operate.real_name IS '操作人'; +COMMENT ON COLUMN sys_log_operate.result_msg IS '返回消息'; +COMMENT ON COLUMN sys_log_operate.tenant_id IS '租户ID'; +COMMENT ON COLUMN sys_log_operate.create_time IS '创建时间'; + + + +CREATE TABLE sys_sms_config +( + id bigserial NOT NULL, + platform int, + group_name varchar(100), + sign_name varchar(100), + template_id varchar(100), + app_id varchar(100), + sender_id varchar(100), + url varchar(200), + access_key varchar(100), + secret_key varchar(100), + status int, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_sms_config IS '短信配置'; +COMMENT ON COLUMN sys_sms_config.id IS 'id'; +COMMENT ON COLUMN sys_sms_config.platform IS '平台类型 0:阿里云 1:腾讯云 2:七牛云 3:华为云'; +COMMENT ON COLUMN sys_sms_config.group_name IS '分组名称,发送短信时,可指定分组'; +COMMENT ON COLUMN sys_sms_config.sign_name IS '短信签名'; +COMMENT ON COLUMN sys_sms_config.template_id IS '短信模板'; +COMMENT ON COLUMN sys_sms_config.app_id IS '短信应用ID,如:腾讯云等'; +COMMENT ON COLUMN sys_sms_config.sender_id IS '腾讯云国际短信、华为云等需要'; +COMMENT ON COLUMN sys_sms_config.url IS '接入地址,如:华为云'; +COMMENT ON COLUMN sys_sms_config.access_key IS 'AccessKey'; +COMMENT ON COLUMN sys_sms_config.secret_key IS 'SecretKey'; +COMMENT ON COLUMN sys_sms_config.status IS '状态 0:禁用 1:启用'; +COMMENT ON COLUMN sys_sms_config.version IS '版本号'; +COMMENT ON COLUMN sys_sms_config.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_sms_config.creator IS '创建者'; +COMMENT ON COLUMN sys_sms_config.create_time IS '创建时间'; +COMMENT ON COLUMN sys_sms_config.updater IS '更新者'; +COMMENT ON COLUMN sys_sms_config.update_time IS '更新时间'; + + +CREATE TABLE sys_sms_log +( + id bigserial NOT NULL, + platform_id int8, + platform int, + mobile varchar(20) NOT NULL, + params varchar(200), + status int, + error varchar(2000), + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_sms_log IS '短信日志'; +COMMENT ON COLUMN sys_sms_log.id IS 'id'; +COMMENT ON COLUMN sys_sms_log.platform_id IS '平台ID'; +COMMENT ON COLUMN sys_sms_log.platform IS '平台类型'; +COMMENT ON COLUMN sys_sms_log.mobile IS '手机号'; +COMMENT ON COLUMN sys_sms_log.params IS '参数'; +COMMENT ON COLUMN sys_sms_log.status IS '状态 0:失败 1:成功'; +COMMENT ON COLUMN sys_sms_log.error IS '异常信息'; +COMMENT ON COLUMN sys_sms_log.create_time IS '创建时间'; + + +CREATE TABLE sys_mail_config +( + id bigserial NOT NULL, + platform int, + group_name varchar(100), + mail_host varchar(100), + mail_port int, + mail_from varchar(100), + mail_pass varchar(100), + region_id varchar(100), + endpoint varchar(100), + access_key varchar(100), + secret_key varchar(100), + status int, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_mail_config IS '邮件平台'; +COMMENT ON COLUMN sys_mail_config.id IS 'id'; +COMMENT ON COLUMN sys_mail_config.platform IS '平台类型 -1:本地 0:阿里云'; +COMMENT ON COLUMN sys_mail_config.group_name IS '分组名称,发送邮件时,可指定分组'; +COMMENT ON COLUMN sys_mail_config.mail_host IS 'SMTP服务器'; +COMMENT ON COLUMN sys_mail_config.mail_port IS 'SMTP端口'; +COMMENT ON COLUMN sys_mail_config.mail_from IS '发件人邮箱'; +COMMENT ON COLUMN sys_mail_config.mail_pass IS '发件人密码'; +COMMENT ON COLUMN sys_mail_config.region_id IS 'regionId'; +COMMENT ON COLUMN sys_mail_config.endpoint IS '阿里云 endpoint'; +COMMENT ON COLUMN sys_mail_config.access_key IS 'AccessKey'; +COMMENT ON COLUMN sys_mail_config.secret_key IS 'SecretKey'; +COMMENT ON COLUMN sys_mail_config.status IS '状态 0:禁用 1:启用'; +COMMENT ON COLUMN sys_mail_config.version IS '版本号'; +COMMENT ON COLUMN sys_mail_config.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN sys_mail_config.creator IS '创建者'; +COMMENT ON COLUMN sys_mail_config.create_time IS '创建时间'; +COMMENT ON COLUMN sys_mail_config.updater IS '更新者'; +COMMENT ON COLUMN sys_mail_config.update_time IS '更新时间'; + + +CREATE TABLE sys_mail_log +( + id bigserial NOT NULL, + platform_id int8, + platform int, + mail_from varchar(100), + mail_tos varchar(1000), + subject varchar(200), + content text, + status int, + error varchar(2000), + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE sys_mail_log IS '邮件日志'; +COMMENT ON COLUMN sys_mail_log.id IS 'id'; +COMMENT ON COLUMN sys_mail_log.platform_id IS '平台ID'; +COMMENT ON COLUMN sys_mail_log.platform IS '平台类型'; +COMMENT ON COLUMN sys_mail_log.mail_from IS '发件人邮箱'; +COMMENT ON COLUMN sys_mail_log.mail_tos IS '接受人邮箱'; +COMMENT ON COLUMN sys_mail_log.subject IS '邮件主题'; +COMMENT ON COLUMN sys_mail_log.content IS '邮件内容'; +COMMENT ON COLUMN sys_mail_log.status IS '状态 0:失败 1:成功'; +COMMENT ON COLUMN sys_mail_log.error IS '异常信息'; +COMMENT ON COLUMN sys_mail_log.create_time IS '创建时间'; + + +INSERT INTO sys_user (id, username, password, real_name, avatar, gender, email, mobile, status, org_id, super_admin, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (10000, 'admin', 'dc1fd00e3eeeb940ff46f457bf97d66ba7fcc36e0b20802383de142860e76ae6', 'admin', 'https://cdn.maku.net/images/avatar.png', 0, 'babamu@126.com', '13612345678', 1, null, 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1, NULL, '系统设置', NULL, NULL, 0, 0, 'icon-setting', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (2, 1, '菜单管理', 'sys/menu/index', NULL, 0, 0, 'icon-menu', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (3, 2, '查看', '', 'sys:menu:list', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (4, 2, '新增', '', 'sys:menu:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (5, 2, '修改', '', 'sys:menu:update,sys:menu:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (6, 2, '删除', '', 'sys:menu:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (7, 1, '数据字典', 'sys/dict/type', '', 0, 0, 'icon-insertrowabove', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (8, 7, '查询', '', 'sys:dict:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (9, 7, '新增', '', 'sys:dict:save', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (10, 7, '修改', '', 'sys:dict:update,sys:dict:info', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (11, 7, '删除', '', 'sys:dict:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (12, NULL, '权限管理', '', '', 0, 0, 'icon-safetycertificate', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (13, 12, '岗位管理', 'sys/post/index', '', 0, 0, 'icon-solution', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (14, 13, '查询', '', 'sys:post:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (15, 13, '新增', '', 'sys:post:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (16, 13, '修改', '', 'sys:post:update,sys:post:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (17, 13, '删除', '', 'sys:post:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (18, 12, '机构管理', 'sys/org/index', '', 0, 0, 'icon-cluster', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (19, 18, '查询', '', 'sys:org:list', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (20, 18, '新增', '', 'sys:org:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (21, 18, '修改', '', 'sys:org:update,sys:org:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (22, 18, '删除', '', 'sys:org:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (23, 12, '角色管理', 'sys/role/index', '', 0, 0, 'icon-team', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (24, 23, '查询', '', 'sys:role:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (25, 23, '新增', '', 'sys:role:save,sys:role:menu,sys:org:list', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (26, 23, '修改', '', 'sys:role:update,sys:role:info,sys:role:menu,sys:org:list,sys:user:page', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (27, 23, '删除', '', 'sys:role:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (28, 12, '用户管理', 'sys/user/index', '', 0, 0, 'icon-user', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (29, 28, '查询', '', 'sys:user:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (30, 28, '新增', '', 'sys:user:save,sys:role:list', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (31, 28, '修改', '', 'sys:user:update,sys:user:info,sys:role:list', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (32, 28, '删除', '', 'sys:user:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (33, NULL, '应用管理', '', '', 0, 0, 'icon-appstore', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (34, NULL, '日志管理', '', '', 0, 0, 'icon-filedone', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (35, 34, '登录日志', 'sys/log/login', 'sys:log:login', 0, 0, 'icon-solution', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (36, 28, '导入', '', 'sys:user:import', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (37, 28, '导出', '', 'sys:user:export', 1, 0, '', 6, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (38, 1, '参数管理', 'sys/params/index', 'sys:params:all', 0, 0, 'icon-filedone', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (39, 1, '接口文档', '{{apiUrl}}/doc.html', null, 0, 1, 'icon-file-text-fill', 10, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (40, 34, '操作日志', 'sys/log/operate', 'sys:operate:all', 0, 0, 'icon-file-text', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (41, 1, '系统配置', 'sys/config/index', null, 0, 0, 'icon-safetycertificate', 4, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (42, 41, '短信配置', '', 'sys:sms:config', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (43, 41, '邮件配置', '', 'sys:mail:config', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (44, 41, '第三方登录', '', 'sys:third:config', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (45, NULL, '基础工具', '', '', 0, 0, 'icon-wrench-fill', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (46, 45, '短信发送', 'sys/tool/sms/index', 'sys:sms:log', 0, 0, 'icon-message', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (47, 45, '邮件发送', 'sys/tool/mail/index', 'sys:mail:log', 0, 0, 'icon-mail', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (48, 45, '附件管理', 'sys/attachment/index', NULL, 0, 0, 'icon-folder-fill', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (49, 48, '查看', '', 'sys:attachment:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (50, 48, '上传', '', 'sys:attachment:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (51, 48, '删除', '', 'sys:attachment:delete', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (52, NULL, '企业版', 'https://maku.net/price', NULL, 0, 1, 'icon-safetycertificate', 10, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1, 'post_status', '状态', '岗位管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (2, 'user_gender', '性别', '用户管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (3, 'user_status', '状态', '用户管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (4, 'role_data_scope', '数据范围', '角色管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (5, 'enable_disable', '状态', '功能状态:启用 | 禁用 ', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (6, 'success_fail', '状态', '操作状态:成功 | 失败', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (7, 'login_operation', '操作信息', '登录管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (8, 'params_type', '系统参数', '参数管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (9, 'user_super_admin', '用户是否是超管','用户是否是超管', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (10, 'log_operate_type', '操作类型', '操作日志', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (11, 'sms_platform', '短信平台类型', '短信管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (12, 'mail_platform', '邮件平台类型', '邮件管理', 0, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1, 1, '停用', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (2, 1, '正常', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (3, 2, '男', '0', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (4, 2, '女', '1', 'success', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (5, 2, '未知', '2', 'warning', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (6, 3, '正常', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (7, 3, '停用', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (8, 4, '全部数据', '0', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (9, 4, '本机构及子机构数据', '1', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (10, 4, '本机构数据', '2', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (11, 4, '本人数据', '3', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (12, 4, '自定义数据', '4', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (13, 5, '禁用', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (14, 5, '启用', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (15, 6, '失败', '0', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (16, 6, '成功', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (17, 7, '登录成功', '0', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (18, 7, '退出成功', '1', 'warning', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (19, 7, '验证码错误', '2', 'danger', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (20, 7, '账号密码错误', '3', 'danger', '', 3, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (21, 8, '否', '0', 'primary', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (22, 8, '是', '1', 'danger', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (23, 9, '是', '1', 'danger', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (24, 9, '否', '0', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (25, 10, '其它', '0', 'info', '', 10, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (26, 10, '查询', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (27, 10, '新增', '2', 'success', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (28, 10, '修改', '3', 'warning', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (29, 10, '删除', '4', 'danger', '', 3, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (30, 10, '导出', '5', 'info', '', 4, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (31, 10, '导入', '6', 'info', '', 5, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (32, 11, '阿里云', '0', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (33, 11, '腾讯云', '1', '', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (34, 11, '七牛云', '2', '', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (35, 11, '华为云', '3', '', '', 3, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (36, 12, '本地', '-1', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (id, dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (37, 12, '阿里云', '0', '', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_params (param_name, param_type, param_key, param_value, remark, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES ('用户登录-验证码开关', 1, 'LOGIN_CAPTCHA', 'false', '是否开启验证码(true:开启,false:关闭)', 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_third_login_config (open_type, client_id, client_secret, redirect_uri, agent_id, tenant_id, version, deleted, create_time) VALUES ('feishu', 'cli_a541d3aa03f8500b', '5Chz39zvEhZtxSVZz3vLjfQHdkvavQaH', 'http://localhost:8090/sys/third/callback/feishu', '', 10000, 0, 0, now()); + +INSERT INTO sys_mail_config (platform, group_name, mail_host, mail_port, mail_from, mail_pass, region_id, endpoint, access_key, secret_key, status, version, deleted, creator, create_time, updater, update_time) VALUES (-1, 'test', NULL, NULL, 'baba_tv@163.com', 'TZNVURLYVBNJUNBB', '', '', NULL, NULL, 1, 1, 0, 10000, now(), 10000, now()); + +select setval('sys_user_id_seq', (select max(id) from sys_user)); +select setval('sys_menu_id_seq', (select max(id) from sys_menu)); +select setval('sys_dict_type_id_seq', (select max(id) from sys_dict_type)); +select setval('sys_dict_data_id_seq', (select max(id) from sys_dict_data)); + +commit; \ No newline at end of file diff --git a/db/postgresql/module/maku-module-generator.sql b/db/postgresql/module/maku-module-generator.sql new file mode 100644 index 0000000..e60acbb --- /dev/null +++ b/db/postgresql/module/maku-module-generator.sql @@ -0,0 +1,468 @@ +INSERT INTO sys_menu (pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (33, '代码生成器', '{{apiUrl}}/maku-generator/index.html', '', 0, 0, 'icon-rocket', 2, 0, 0, 10000, now(), 10000, now()); + +CREATE TABLE gen_datasource ( + id bigserial NOT NULL, + db_type varchar(200), + conn_name varchar(200), + conn_url varchar(500), + username varchar(200), + password varchar(200), + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE gen_datasource IS '数据源管理'; +COMMENT ON COLUMN gen_datasource.id IS 'id'; +COMMENT ON COLUMN gen_datasource.db_type IS '数据库类型'; +COMMENT ON COLUMN gen_datasource.conn_name IS '连接名'; +COMMENT ON COLUMN gen_datasource.conn_url IS 'URL'; +COMMENT ON COLUMN gen_datasource.username IS '用户名'; +COMMENT ON COLUMN gen_datasource.password IS '密码'; +COMMENT ON COLUMN gen_datasource.create_time IS '创建时间'; + +CREATE TABLE gen_config +( + id bigserial NOT NULL, + config_key varchar(200), + config_value varchar(2000), + primary key (id) +); + +CREATE TABLE gen_field_type +( + id bigserial NOT NULL, + column_type varchar(200), + attr_type varchar(200), + package_name varchar(200), + create_time timestamp, + primary key (id) +); + +CREATE UNIQUE INDEX gen_column_type on gen_field_type(column_type); + +COMMENT ON TABLE gen_field_type IS '字段类型管理'; +COMMENT ON COLUMN gen_field_type.id IS 'id'; +COMMENT ON COLUMN gen_field_type.column_type IS '字段类型'; +COMMENT ON COLUMN gen_field_type.attr_type IS '属性类型'; +COMMENT ON COLUMN gen_field_type.package_name IS '属性包名'; +COMMENT ON COLUMN gen_field_type.create_time IS '创建时间'; + + +CREATE TABLE gen_base_class +( + id bigserial NOT NULL, + package_name varchar(200), + code varchar(200), + fields varchar(500), + remark varchar(200), + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE gen_base_class IS '基类管理'; +COMMENT ON COLUMN gen_base_class.id IS 'id'; +COMMENT ON COLUMN gen_base_class.package_name IS '基类包名'; +COMMENT ON COLUMN gen_base_class.code IS '基类编码'; +COMMENT ON COLUMN gen_base_class.fields IS '基类字段,多个用英文逗号分隔'; +COMMENT ON COLUMN gen_base_class.remark IS '备注'; +COMMENT ON COLUMN gen_base_class.create_time IS '创建时间'; + +CREATE TABLE gen_table +( + id bigserial NOT NULL, + table_name varchar(200), + class_name varchar(200), + table_comment varchar(200), + author varchar(200), + email varchar(200), + package_name varchar(200), + version varchar(200), + generator_type int, + backend_path varchar(500), + frontend_path varchar(500), + module_name varchar(200), + function_name varchar(200), + form_layout int, + table_type int, + sub_table varchar(4000), + table_operation varchar(200), + auth_level int, + open_type int, + request_url varchar(200), + authority varchar(200), + tree_id varchar(200), + tree_pid varchar(200), + tree_label varchar(200), + left_title varchar(200), + left_from int, + left_table_name varchar(200), + left_url varchar(200), + left_relation_field varchar(200), + datasource_id int8, + baseclass_id int8, + create_time timestamp, + primary key (id) +); +CREATE UNIQUE INDEX gen_table_name on gen_table(table_name); + +COMMENT ON TABLE gen_table IS '代码生成表'; +COMMENT ON COLUMN gen_table.id IS 'id'; +COMMENT ON COLUMN gen_table.table_name IS '表名'; +COMMENT ON COLUMN gen_table.class_name IS '类名'; +COMMENT ON COLUMN gen_table.table_comment IS '说明'; +COMMENT ON COLUMN gen_table.author IS '作者'; +COMMENT ON COLUMN gen_table.email IS '邮箱'; +COMMENT ON COLUMN gen_table.package_name IS '项目包名'; +COMMENT ON COLUMN gen_table.version IS '项目版本号'; +COMMENT ON COLUMN gen_table.generator_type IS '生成方式 0:zip压缩包 1:自定义目录'; +COMMENT ON COLUMN gen_table.backend_path IS '后端生成路径'; +COMMENT ON COLUMN gen_table.frontend_path IS '前端生成路径'; +COMMENT ON COLUMN gen_table.module_name IS '模块名'; +COMMENT ON COLUMN gen_table.function_name IS '功能名'; +COMMENT ON COLUMN gen_table.form_layout IS '表单布局 1:一列 2:两列'; +COMMENT ON COLUMN gen_table.datasource_id IS '数据源ID'; +COMMENT ON COLUMN gen_table.baseclass_id IS '基类ID'; +COMMENT ON COLUMN gen_table.create_time IS '创建时间'; + + +CREATE TABLE gen_table_field +( + id bigserial NOT NULL, + table_id int8, + field_name varchar(200), + field_type varchar(200), + field_comment varchar(200), + attr_name varchar(200), + attr_type varchar(200), + package_name varchar(200), + sort int, + auto_fill varchar(20), + primary_pk boolean, + base_field boolean, + form_item boolean, + form_required boolean, + form_type varchar(200), + form_dict varchar(200), + form_validator varchar(200), + grid_item boolean, + grid_sort boolean, + query_item boolean, + query_type varchar(200), + query_form_type varchar(200), + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE gen_table_field IS '代码生成表字段'; +COMMENT ON COLUMN gen_table_field.id IS 'id'; +COMMENT ON COLUMN gen_table_field.table_id IS '表ID'; +COMMENT ON COLUMN gen_table_field.field_name IS '字段名称'; +COMMENT ON COLUMN gen_table_field.field_type IS '字段类型'; +COMMENT ON COLUMN gen_table_field.field_comment IS '字段说明'; +COMMENT ON COLUMN gen_table_field.attr_name IS '属性名'; +COMMENT ON COLUMN gen_table_field.attr_type IS '属性类型'; +COMMENT ON COLUMN gen_table_field.package_name IS '属性包名'; +COMMENT ON COLUMN gen_table_field.sort IS '排序'; +COMMENT ON COLUMN gen_table_field.auto_fill IS '自动填充 DEFAULT、INSERT、UPDATE、INSERT_UPDATE'; +COMMENT ON COLUMN gen_table_field.primary_pk IS '主键 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.base_field IS '基类字段 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.form_item IS '表单项 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.form_required IS '表单必填 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.form_type IS '表单类型'; +COMMENT ON COLUMN gen_table_field.form_dict IS '表单字典类型'; +COMMENT ON COLUMN gen_table_field.form_validator IS '表单效验'; +COMMENT ON COLUMN gen_table_field.grid_item IS '列表项 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.grid_sort IS '列表排序 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.query_item IS '查询项 0:否 1:是'; +COMMENT ON COLUMN gen_table_field.query_type IS '查询方式'; +COMMENT ON COLUMN gen_table_field.query_form_type IS '查询表单类型'; + + +CREATE TABLE gen_project_modify +( + id bigserial NOT NULL, + project_name varchar(100), + project_code varchar(100), + project_package varchar(100), + project_path varchar(200), + modify_project_name varchar(100), + modify_project_code varchar(100), + modify_project_package varchar(100), + exclusions varchar(200), + modify_suffix varchar(200), + modify_tmp_path varchar(100), + create_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_project_modify IS '项目名变更'; +COMMENT ON COLUMN gen_project_modify.id IS 'id'; +COMMENT ON COLUMN gen_project_modify.project_name IS '项目名'; +COMMENT ON COLUMN gen_project_modify.project_code IS '项目标识'; +COMMENT ON COLUMN gen_project_modify.project_package IS '项目包名'; +COMMENT ON COLUMN gen_project_modify.project_path IS '项目路径'; +COMMENT ON COLUMN gen_project_modify.modify_project_name IS '变更项目名'; +COMMENT ON COLUMN gen_project_modify.modify_project_code IS '变更标识'; +COMMENT ON COLUMN gen_project_modify.modify_project_package IS '变更包名'; +COMMENT ON COLUMN gen_project_modify.exclusions IS '排除文件'; +COMMENT ON COLUMN gen_project_modify.modify_suffix IS '变更文件'; +COMMENT ON COLUMN gen_project_modify.modify_tmp_path IS '变更临时路径'; +COMMENT ON COLUMN gen_project_modify.create_time IS '创建时间'; + + +-- 用于测试代码生成器的表结构 -- +CREATE TABLE gen_test_member +( + id bigserial NOT NULL, + name varchar(50), + gender int, + age int, + tenant_id int8, + create_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_member IS '单表测试'; +COMMENT ON COLUMN gen_test_member.id IS 'id'; +COMMENT ON COLUMN gen_test_member.name IS '姓名'; +COMMENT ON COLUMN gen_test_member.gender IS '性别'; + COMMENT ON COLUMN gen_test_member.age IS '年龄'; +COMMENT ON COLUMN gen_test_member.tenant_id IS '租户ID'; +COMMENT ON COLUMN gen_test_member.create_time IS '创建时间'; + + + +CREATE TABLE gen_test_tree +( + id bigserial NOT NULL, + parent_id int8, + tree_name varchar(100), + tenant_id int8, + create_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_tree IS '树表测试'; +COMMENT ON COLUMN gen_test_tree.id IS 'id'; +COMMENT ON COLUMN gen_test_tree.parent_id IS '上级ID'; +COMMENT ON COLUMN gen_test_tree.tree_name IS '名称'; +COMMENT ON COLUMN gen_test_tree.tenant_id IS '租户ID'; +COMMENT ON COLUMN gen_test_tree.create_time IS '创建时间'; + +CREATE TABLE gen_test_product +( + id bigserial NOT NULL, + name varchar(100), + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_product IS '产品测试'; +COMMENT ON COLUMN gen_test_product.id IS 'id'; +COMMENT ON COLUMN gen_test_product.name IS '名称'; + +CREATE TABLE gen_test_product_info +( + id bigserial NOT NULL, + images varchar(2000), + intro varchar(5000), + product_id int8, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_product_info IS '产品信息'; +COMMENT ON COLUMN gen_test_product_info.id IS 'id'; +COMMENT ON COLUMN gen_test_product_info.images IS '图片'; +COMMENT ON COLUMN gen_test_product_info.intro IS '介绍'; +COMMENT ON COLUMN gen_test_product_info.product_id IS '产品ID'; + + +CREATE TABLE gen_test_product_param +( + id bigserial NOT NULL, + param_name varchar(200), + param_value varchar(200), + product_id int8, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_product_param IS '产品参数'; +COMMENT ON COLUMN gen_test_product_param.id IS 'id'; +COMMENT ON COLUMN gen_test_product_param.param_name IS '参数名称'; +COMMENT ON COLUMN gen_test_product_param.param_value IS '参数值'; +COMMENT ON COLUMN gen_test_product_param.product_id IS '产品ID'; + +CREATE TABLE gen_test_goods_category +( + id bigserial NOT NULL, + name varchar(100), + pid int8, + tenant_id int8, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_goods_category IS '商品分类'; +COMMENT ON COLUMN gen_test_goods_category.id IS 'id'; +COMMENT ON COLUMN gen_test_goods_category.name IS '名称'; +COMMENT ON COLUMN gen_test_goods_category.pid IS '上级ID'; + +CREATE TABLE gen_test_goods +( + id bigserial NOT NULL, + name varchar(100), + intro varchar(5000), + category_id int8, + tenant_id int8, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE gen_test_goods IS '商品管理'; +COMMENT ON COLUMN gen_test_goods.id IS 'id'; +COMMENT ON COLUMN gen_test_goods.name IS '名称'; +COMMENT ON COLUMN gen_test_goods.intro IS '介绍'; +COMMENT ON COLUMN gen_test_goods.category_id IS '分类ID'; + + + +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('datetime', 'LocalDateTime', 'java.time.LocalDateTime', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('date', 'LocalDateTime', 'java.time.LocalDateTime', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('tinyint', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('smallint', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('mediumint', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('integer', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('bigint', 'Long', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('float', 'Float', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('double', 'Double', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('decimal', 'BigDecimal', 'java.math.BigDecimal', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('bit', 'Boolean', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('char', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('varchar', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('tinytext', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('text', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('mediumtext', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('longtext', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('timestamp', 'LocalDateTime', 'java.time.LocalDateTime', now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('NUMBER', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('BINARY_INTEGER', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('BINARY_FLOAT', 'Float', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('BINARY_DOUBLE', 'Double', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('VARCHAR2', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('NVARCHAR', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('NVARCHAR2', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('CLOB', 'String', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int8', 'Long', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int4', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('int2', 'Integer', NULL, now()); +INSERT INTO gen_field_type (column_type, attr_type, package_name, create_time) VALUES ('numeric', 'BigDecimal', 'java.math.BigDecimal', now()); + +INSERT INTO gen_base_class (package_name, code, fields, remark, create_time) VALUES ('com.bdzl.framework.mybatis.entity', 'BaseEntity', 'id,creator,create_time,updater,update_time,version,deleted', '使用该基类,则需要表里有这些字段', now()); + +INSERT INTO gen_project_modify (project_name, project_code, project_package, project_path, modify_project_name, modify_project_code, modify_project_package, exclusions, modify_suffix, create_time) VALUES ('drone-ops', 'maku', 'com.bdzl', 'D:/makunet/drone-ops', 'baba-boot', 'baba', 'com.baba', '.git,.idea,target,logs', 'java,xml,yml,txt', now()); +INSERT INTO gen_project_modify (project_name, project_code, project_package, project_path, modify_project_name, modify_project_code, modify_project_package, exclusions, modify_suffix, create_time) VALUES ('maku-cloud', 'maku', 'com.bdzl', 'D:/makunet/maku-cloud', 'baba-cloud', 'baba', 'com.baba', '.git,.idea,target,logs', 'java,xml,yml,txt', now()); + +INSERT INTO gen_config (config_key, config_value) VALUES ('gen_config', ''); + +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (20, 'gen_test_member', 'GenTestMember', '单表测试', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'member', 1, 0, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\",\"import\"]', 0, 0, '/test/member', 'test:member', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (21, 'gen_test_tree', 'GenTestTree', '树表测试', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'tree', 1, 1, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\"]', 0, 0, '/test/tree', 'test:tree', 'id', 'parent_id', 'tree_name', 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (22, 'gen_test_goods', 'GenTestGoods', '商品管理', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'goods', 1, 2, '[]', '[\"query\",\"insert\",\"update\",\"delete\"]', 0, 0, '/test/goods', 'test:goods', NULL, NULL, NULL, 0, NULL, now(), 0, 'gen_test_goods_category', '/test/category/list', 'category_id', '分类列表'); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (23, 'gen_test_goods_category', 'GenTestGoodsCategory', '商品分类', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'category', 1, 1, '[]', '[\"query\",\"insert\",\"update\",\"delete\"]', 0, 0, '/test/category', 'test:category', 'id', 'pid', 'name', 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (24, 'gen_test_product_info', 'GenTestProductInfo', '产品信息', '阿沐', 'babamu@126.com', 'com.bdzl', '', 0, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'info', 1, 0, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\"]', 0, 0, '/test/info', 'test:info', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (25, 'gen_test_product_param', 'GenTestProductParam', '产品参数', '阿沐', 'babamu@126.com', 'com.bdzl', '', 0, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'param', 1, 0, NULL, '[\"query\",\"insert\",\"update\",\"delete\",\"export\"]', 0, 0, '/test/param', 'test:param', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); +INSERT INTO gen_table (id, table_name, class_name, table_comment, author, email, package_name, version, generator_type, backend_path, frontend_path, module_name, function_name, form_layout, table_type, sub_table, table_operation, auth_level, open_type, request_url, authority, tree_id, tree_pid, tree_label, datasource_id, baseclass_id, create_time, left_from, left_table_name, left_url, left_relation_field, left_title) VALUES (26, 'gen_test_product', 'GenTestProduct', '产品测试', '阿沐', 'babamu@126.com', 'com.bdzl', '', 1, '/Users/maku/makunet/drone-ops-enterprise/drone-ops-new', '/Users/maku/makunet/maku-admin-enterprise', 'test', 'product', 1, 0, '[{\"tableName\":\"gen_test_product_info\",\"foreignKey\":\"product_id\",\"tableTitle\":\"产品信息\",\"mainRelation\":1,\"sort\":0},{\"tableName\":\"gen_test_product_param\",\"foreignKey\":\"product_id\",\"tableTitle\":\"产品参数\",\"mainRelation\":2,\"sort\":1}]', '[\"query\",\"insert\",\"update\",\"delete\"]', 0, 1, '/test/product', 'test:product', NULL, NULL, NULL, 0, NULL, now(), NULL, NULL, NULL, NULL, NULL); + +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (220, 20, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (221, 20, 'name', 'varchar', '姓名', 'name', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (222, 20, 'gender', 'tinyint', '性别', 'gender', 'Integer', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'radio', 'user_gender', NULL, 1, 0, 1, '=', 'select', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (223, 20, 'age', 'int', '年龄', 'age', 'Integer', NULL, 3, 'DEFAULT', 0, 0, 1, 1, 'number', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (224, 20, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (225, 20, 'version', 'int', '版本号', 'version', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (226, 20, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (227, 20, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (228, 21, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (229, 21, 'tree_name', 'varchar', '名称', 'treeName', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (230, 21, 'parent_id', 'bigint', '上级ID', 'parentId', 'Long', NULL, 2, 'DEFAULT', 0, 0, 1, 0, 'treeselect', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (231, 21, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (232, 21, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 4, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 1, '=', 'date', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (233, 22, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (234, 22, 'name', 'varchar', '名称', 'name', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, 'like', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (235, 22, 'intro', 'varchar', '介绍', 'intro', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (236, 22, 'category_id', 'bigint', '分类ID', 'categoryId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (237, 22, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (238, 22, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (239, 22, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (240, 22, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (241, 22, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 8, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (242, 22, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 9, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (243, 23, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (244, 23, 'name', 'varchar', '名称', 'name', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, 'like', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (245, 23, 'pid', 'bigint', '上级ID', 'pid', 'Long', NULL, 1, 'DEFAULT', 0, 0, 1, 0, 'treeselect', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (246, 23, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (247, 23, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 4, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (248, 23, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (249, 23, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 1, '=', 'datetime', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (250, 23, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 7, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (251, 23, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (252, 24, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (253, 24, 'images', 'varchar', '图片', 'images', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'image', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (254, 24, 'intro', 'varchar', '介绍', 'intro', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'editor', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (255, 24, 'product_id', 'bigint', '产品ID', 'productId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (256, 24, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (257, 24, 'version', 'int', '版本号', 'version', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (258, 24, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (259, 24, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (260, 24, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (261, 24, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 9, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (262, 24, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 10, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (263, 25, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (264, 25, 'param_name', 'varchar', '参数名称', 'paramName', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (265, 25, 'param_value', 'varchar', '参数值', 'paramValue', 'String', NULL, 2, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (266, 25, 'product_id', 'bigint', '产品ID', 'productId', 'Long', NULL, 3, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (267, 25, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 4, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (268, 25, 'version', 'int', '版本号', 'version', 'Integer', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (269, 25, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (270, 25, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 7, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (271, 25, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (272, 25, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 9, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (273, 25, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 10, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (274, 26, 'id', 'bigint', 'ID', 'id', 'Long', NULL, 0, 'DEFAULT', 1, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (275, 26, 'name', 'varchar', '名称', 'name', 'String', NULL, 1, 'DEFAULT', 0, 0, 1, 1, 'input', NULL, NULL, 1, 0, 1, 'like', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (276, 26, 'tenant_id', 'bigint', '租户ID', 'tenantId', 'Long', NULL, 2, 'DEFAULT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (277, 26, 'version', 'int', '版本号', 'version', 'Integer', NULL, 3, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (278, 26, 'deleted', 'tinyint', '删除标识', 'deleted', 'Integer', NULL, 4, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (279, 26, 'creator', 'bigint', '创建者', 'creator', 'Long', NULL, 5, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (280, 26, 'create_time', 'datetime', '创建时间', 'createTime', 'LocalDateTime', 'java.time.LocalDateTime', 6, 'INSERT', 0, 0, 0, 0, 'input', NULL, NULL, 1, 0, 1, '=', 'datetime', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (281, 26, 'updater', 'bigint', '更新者', 'updater', 'Long', NULL, 7, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); +INSERT INTO gen_table_field (id, table_id, field_name, field_type, field_comment, attr_name, attr_type, package_name, sort, auto_fill, primary_pk, base_field, form_item, form_required, form_type, form_dict, form_validator, grid_item, grid_sort, query_item, query_type, query_form_type, create_time) VALUES (282, 26, 'update_time', 'datetime', '更新时间', 'updateTime', 'LocalDateTime', 'java.time.LocalDateTime', 8, 'INSERT_UPDATE', 0, 0, 0, 0, 'input', NULL, NULL, 0, 0, 0, '=', 'input', now()); + +commit; \ No newline at end of file diff --git a/db/postgresql/module/maku-module-iot.sql b/db/postgresql/module/maku-module-iot.sql new file mode 100644 index 0000000..c747cd0 --- /dev/null +++ b/db/postgresql/module/maku-module-iot.sql @@ -0,0 +1,164 @@ +CREATE TABLE iot_device ( + id bigserial NOT NULL, + code varchar(255), + name varchar(255), + type int, + uid varchar(255), + secret varchar(255), + app_version varchar(255), + battery_percent varchar(10), + temperature varchar(10), + status int, + running_status int DEFAULT 0, + protocol_type varchar(20), + up_time timestamp, + down_time timestamp, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE iot_device IS '设备表'; +COMMENT ON COLUMN iot_device.id IS 'id'; +COMMENT ON COLUMN iot_device.code IS '编码'; +COMMENT ON COLUMN iot_device.name IS '名称'; +COMMENT ON COLUMN iot_device.type IS '设备类型,1.手持设备,2.柜体,3传感设备'; +COMMENT ON COLUMN iot_device.uid IS '唯一标识码'; +COMMENT ON COLUMN iot_device.secret IS '设备密钥'; +COMMENT ON COLUMN iot_device.app_version IS 'App版本号'; +COMMENT ON COLUMN iot_device.battery_percent IS '电池电量百分比'; +COMMENT ON COLUMN iot_device.status IS '状态,0禁用,1启用'; +COMMENT ON COLUMN iot_device.running_status IS '运行状态,0.离线状态 1.在线状态 2.正常待机 3.用户使用中 4.OTA升级中'; +COMMENT ON COLUMN iot_device.protocol_type IS '协议类型'; +COMMENT ON COLUMN iot_device.up_time IS '上线时间'; +COMMENT ON COLUMN iot_device.down_time IS '下线时间'; +COMMENT ON COLUMN iot_device.tenant_id IS '租户ID'; +COMMENT ON COLUMN iot_device.version IS '版本号'; +COMMENT ON COLUMN iot_device.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN iot_device.creator IS '创建者'; +COMMENT ON COLUMN iot_device.create_time IS '创建时间'; +COMMENT ON COLUMN iot_device.updater IS '更新者'; +COMMENT ON COLUMN iot_device.update_time IS '更新时间'; + + +CREATE TABLE iot_device_event_log ( + id bigserial NOT NULL, + device_id int8, + event_type int, + event_uid varchar(50), + event_payload varchar(1000), + event_time timestamp, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE iot_device_event_log IS '设备事件日志'; +COMMENT ON COLUMN iot_device_event_log.id IS 'id'; +COMMENT ON COLUMN iot_device_event_log.device_id IS '设备id'; +COMMENT ON COLUMN iot_device_event_log.event_type IS '事件类型'; +COMMENT ON COLUMN iot_device_event_log.event_uid IS '事件标识id'; +COMMENT ON COLUMN iot_device_event_log.event_payload IS '事件数据'; +COMMENT ON COLUMN iot_device_event_log.event_time IS '事件时间'; +COMMENT ON COLUMN iot_device_event_log.tenant_id IS '租户ID'; +COMMENT ON COLUMN iot_device_event_log.version IS '版本号'; +COMMENT ON COLUMN iot_device_event_log.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN iot_device_event_log.creator IS '创建者'; +COMMENT ON COLUMN iot_device_event_log.create_time IS '创建时间'; +COMMENT ON COLUMN iot_device_event_log.updater IS '更新者'; +COMMENT ON COLUMN iot_device_event_log.update_time IS '更新时间'; + + +CREATE TABLE iot_device_service_log ( + id bigserial NOT NULL, + device_id int8, + service_type int, + service_uid varchar(50), + service_payload varchar(1000), + service_time timestamp, + tenant_id int8, + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE iot_device_service_log IS '设备服务日志'; +COMMENT ON COLUMN iot_device_service_log.id IS 'id'; +COMMENT ON COLUMN iot_device_service_log.device_id IS '设备id'; +COMMENT ON COLUMN iot_device_service_log.service_type IS '服务类型'; +COMMENT ON COLUMN iot_device_service_log.service_uid IS '服务标识id'; +COMMENT ON COLUMN iot_device_service_log.service_payload IS '服务数据'; +COMMENT ON COLUMN iot_device_service_log.service_time IS '服务时间'; +COMMENT ON COLUMN iot_device_service_log.tenant_id IS '租户ID'; +COMMENT ON COLUMN iot_device_service_log.version IS '版本号'; +COMMENT ON COLUMN iot_device_service_log.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN iot_device_service_log.creator IS '创建者'; +COMMENT ON COLUMN iot_device_service_log.create_time IS '创建时间'; +COMMENT ON COLUMN iot_device_service_log.updater IS '更新者'; + + +INSERT INTO iot_device (id, code, name, type, uid, secret, app_version, battery_percent, temperature, status, running_status, protocol_type, up_time, down_time, tenant_id, creator, create_time, updater, update_time, version, deleted) VALUES (1, 'test-tcp', 'testTCP', 1, 'test12345678', '123456', NULL, NULL, NULL, 1, 1, 'TCP', now(), NULL, NULL, 10000, now(), 10000, now(), 0, 0); + +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1601, NULL, '物联网平台', NULL, NULL, 0, 0, 'icon-printer-fill', 6, 0, 0, 10000,now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1602, 1601, '设备列表', 'iot/device/index', NULL, 0, 0, 'icon-menu', 0, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1603, 1602, '查看', '', 'iot:device:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1604, 1602, '新增', '', 'iot:device:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1605, 1602, '修改', '', 'iot:device:update,iot:device:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1606, 1602, '删除', '', 'iot:device:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1607, 1602, '下发指令', '', 'iot:device:send', 1, 0, '', 4, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1608, 1602, '上报数据', '', 'iot:device:report', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1609, 1602, '设备事件日志', '', 'iot:device_event_log:page', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1610, 1602, '设备服务日志', '', 'iot:device_service_log:page', 1, 0, '', 5, 0, 0, 10000, now(), 10000, now()); + + +INSERT INTO sys_dict_type (id, dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUE(1601, 'device_type', '设备类型', '设备类型', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1601, '手持设备', '1', 'primary', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1601, '柜体', '2', 'primary', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1601, '传感设备', '3', 'primary', '', 2, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES(1602, 'device_running_status', '设备运行状态', '设备运行状态:离线|在线|待机|使用中|OTA升级中', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1602, '离线状态', '0', 'danger', NULL, 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1602, '在线状态', '1', 'success', NULL, 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES(1603, 'device_command', '设备指令', '设备服务具备的功能', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1603, '远程锁定', 'LOCK', NULL, NULL, 0, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1603, '远程解锁', 'UNLOCK', NULL, NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1603, '登录', 'SIGN_ON', NULL, NULL, 2, NULL, 0, 1, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1603, '登出', 'SIGN_OFF', NULL, NULL, 3, NULL, 0, 1, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1603, 'OTA升级', 'OTA_UPGRADE', NULL, NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES(1604, 'device_property', '设备属性', '设备通用属性:运行状态|APP版本|电池电量百分比|温度', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1604, '运行状态', 'RUNNING_STATUS', NULL, NULL, 0, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1604, 'APP版本', 'APP_VERSION', NULL, NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1604, '电池电量百分比', 'BATTERY_PERCENT', NULL, NULL, 2, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1604, '温度', 'TEMPERATURE', NULL, NULL, 3, NULL, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type,dict_name,remark,sort,tenant_id,version,deleted,creator,create_time,updater,update_time )VALUES(1605, 'device_event_type', '事件类型', '事件日志类型', 0, 10000, 0, 0, 10000, now(), 10000, now() ); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '下线', 'OFFLINE', 'danger', NULL, 1, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '上线', 'ONLINE', 'primary', NULL, 2, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '登录', 'SIGN_ON', 'primary', NULL, 3, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '退出登录', 'SIGN_OFF', 'danger', NULL, 4, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, 'OTA升级', 'OTA_UPGRADE', 'primary', NULL, 5, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '设备远程锁定', 'LOCK', 'primary', NULL, 6, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '设备远程解锁', 'UNLOCK', 'primary', NULL,7, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, 'APP版本信息', 'APP_VERSION_REPORT', 'primary', NULL, 8, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '电池电量', 'BATTERY_PERCENT_REPORT', 'primary', NULL, 9, NULL, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1605, '温度', 'TEMPERATURE_REPORT', 'primary', NULL, 0, NULL, 10, 0, 10000, now(), 10000, now()); + +select setval('sys_menu_id_seq', (select max(id) from sys_menu)); +select setval('sys_dict_type_id_seq', (select max(id) from sys_dict_type)); diff --git a/db/postgresql/module/maku-module-member.sql b/db/postgresql/module/maku-module-member.sql new file mode 100644 index 0000000..4da9374 --- /dev/null +++ b/db/postgresql/module/maku-module-member.sql @@ -0,0 +1,35 @@ +CREATE TABLE member_user +( + id bigserial NOT NULL, + nick_name varchar(100) NOT NULL, + mobile varchar(20) NOT NULL, + avatar varchar(200), + birthday timestamp, + gender int, + openid varchar(200), + last_login_ip varchar(100), + last_login_time timestamp, + remark varchar(500), + tenant_id int8, + status int, + version int, + deleted int, + create_time timestamp, + primary key (id) +); + +COMMENT ON TABLE member_user IS '会员管理'; +COMMENT ON COLUMN member_user.id IS 'id'; +COMMENT ON COLUMN member_user.nick_name IS '昵称'; +COMMENT ON COLUMN member_user.mobile IS '手机号'; +COMMENT ON COLUMN member_user.avatar IS '头像'; +COMMENT ON COLUMN member_user.birthday IS '出生日期'; +COMMENT ON COLUMN member_user.gender IS '性别 0:男 1:女 2:未知'; +COMMENT ON COLUMN member_user.openid IS '第三方平台,唯一标识'; +COMMENT ON COLUMN member_user.last_login_ip IS '最后登录IP'; +COMMENT ON COLUMN member_user.last_login_time IS '最后登录时间'; +COMMENT ON COLUMN member_user.remark IS '备注'; +COMMENT ON COLUMN member_user.status IS '状态 0:禁用 1:启用'; +COMMENT ON COLUMN member_user.version IS '版本号'; +COMMENT ON COLUMN member_user.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN member_user.create_time IS '创建时间'; \ No newline at end of file diff --git a/db/postgresql/module/maku-module-monitor.sql b/db/postgresql/module/maku-module-monitor.sql new file mode 100644 index 0000000..8b524a4 --- /dev/null +++ b/db/postgresql/module/maku-module-monitor.sql @@ -0,0 +1,7 @@ +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1301, 33, '系统监控', '', '', 0, 0, 'icon-Report', 10, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1302, 1301, '服务监控', 'monitor/server/index', 'monitor:server:all', 0, 0, 'icon-sever', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1304, 1301, '缓存监控', 'monitor/cache/index', 'monitor:cache:all', 0, 0, 'icon-fund-fill', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1305, 1301, '在线用户', 'monitor/user/index', 'monitor:user:all', 0, 0, 'icon-user', 3, 0, 0, 10000, now(), 10000, now()); + +commit; \ No newline at end of file diff --git a/db/postgresql/module/maku-module-quartz.sql b/db/postgresql/module/maku-module-quartz.sql new file mode 100644 index 0000000..31a7451 --- /dev/null +++ b/db/postgresql/module/maku-module-quartz.sql @@ -0,0 +1,272 @@ +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1201, 1, '定时任务', 'quartz/schedule/index', NULL, 0, 0, 'icon-reloadtime', 0, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1202, 1201, '查看', '', 'schedule:page', 1, 0, '', 0, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1203, 1201, '新增', '', 'schedule:save', 1, 0, '', 1, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1204, 1201, '修改', '', 'schedule:update,schedule:info', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1205, 1201, '删除', '', 'schedule:delete', 1, 0, '', 3, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1206, 1201, '立即运行', '', 'schedule:run', 1, 0, '', 2, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_menu (id, pid, name, url, authority, type, open_style, icon, sort, version, deleted, creator, create_time, updater, update_time) VALUES (1207, 1201, '日志', '', 'schedule:log', 1, 0, '', 4, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1201, 'schedule_group', '任务组名', '定时任务', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1201, '默认', 'default', '', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1201, '系统', 'system', '', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); + +INSERT INTO sys_dict_type (id, dict_type, dict_name, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1202, 'schedule_status', '状态', '定时任务', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1202, '暂停', '0', 'danger', '', 0, 10000, 0, 0, 10000, now(), 10000, now()); +INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value, label_class, remark, sort, tenant_id, version, deleted, creator, create_time, updater, update_time) VALUES (1202, '正常', '1', 'primary', '', 1, 10000, 0, 0, 10000, now(), 10000, now()); + +select setval('sys_menu_id_seq', (select max(id) from sys_menu)); +select setval('sys_dict_type_id_seq', (select max(id) from sys_dict_type)); +select setval('sys_dict_data_id_seq', (select max(id) from sys_dict_data)); + +DROP TABLE IF EXISTS schedule_job; +DROP TABLE IF EXISTS schedule_job_log; + +CREATE TABLE schedule_job ( + id bigserial NOT NULL, + job_name varchar(200), + job_group varchar(100), + bean_name varchar(200), + method varchar(100), + params varchar(2000), + cron_expression varchar(100), + status int, + concurrent int, + remark varchar(255), + version int, + deleted int, + creator int8, + create_time timestamp, + updater int8, + update_time timestamp, + PRIMARY KEY (id) +); + + +COMMENT ON TABLE schedule_job IS '定时任务'; +COMMENT ON COLUMN schedule_job.id IS 'id'; +COMMENT ON COLUMN schedule_job.job_name IS '名称'; +COMMENT ON COLUMN schedule_job.job_group IS '分组'; +COMMENT ON COLUMN schedule_job.bean_name IS 'spring bean名称'; +COMMENT ON COLUMN schedule_job.method IS '执行方法'; +COMMENT ON COLUMN schedule_job.params IS '参数'; +COMMENT ON COLUMN schedule_job.cron_expression IS 'cron表达式'; +COMMENT ON COLUMN schedule_job.status IS '状态 0:暂停 1:正常'; +COMMENT ON COLUMN schedule_job.concurrent IS '是否并发 0:禁止 1:允许'; +COMMENT ON COLUMN schedule_job.remark IS '备注'; +COMMENT ON COLUMN schedule_job.version IS '版本号'; +COMMENT ON COLUMN schedule_job.deleted IS '删除标识 0:正常 1:已删除'; +COMMENT ON COLUMN schedule_job.creator IS '创建者'; +COMMENT ON COLUMN schedule_job.create_time IS '创建时间'; +COMMENT ON COLUMN schedule_job.updater IS '更新者'; +COMMENT ON COLUMN schedule_job.update_time IS '更新时间'; + + +CREATE TABLE schedule_job_log ( + id bigserial NOT NULL, + job_id int8 NOT NULL, + job_name varchar(200), + job_group varchar(100), + bean_name varchar(200), + method varchar(100), + params varchar(2000), + status int, + error varchar(2000), + times int8 NOT NULL, + create_time timestamp, + PRIMARY KEY (id) +); + +COMMENT ON TABLE schedule_job_log IS '定时任务日志'; +COMMENT ON COLUMN schedule_job_log.id IS 'id'; +COMMENT ON COLUMN schedule_job_log.job_id IS '任务id'; +COMMENT ON COLUMN schedule_job_log.job_name IS '任务名称'; +COMMENT ON COLUMN schedule_job_log.job_group IS '任务组名'; +COMMENT ON COLUMN schedule_job_log.bean_name IS 'spring bean名称'; +COMMENT ON COLUMN schedule_job_log.method IS '执行方法'; +COMMENT ON COLUMN schedule_job_log.params IS '参数'; +COMMENT ON COLUMN schedule_job_log.status IS '任务状态 0:失败 1:成功'; +COMMENT ON COLUMN schedule_job_log.error IS '异常信息'; +COMMENT ON COLUMN schedule_job_log.times IS '耗时(单位:毫秒)'; +COMMENT ON COLUMN schedule_job_log.create_time IS '创建时间'; + + +INSERT INTO schedule_job (job_name, job_group, bean_name, method, params, cron_expression, status, concurrent, remark, version, deleted, creator, create_time, updater, update_time) VALUES ('测试任务', 'system', 'testTask', 'run', '123', '0 * * * * ? *', 0, 0, '', 14, 0, 10000, now(), 10000, now()); + + + + +-- ---------------------------------------------------------- +-- 以下为Quartz框架,自带的表结构 +-- ---------------------------------------------------------- + +CREATE TABLE qrtz_job_details +( + SCHED_NAME VARCHAR(120) NOT NULL, + JOB_NAME VARCHAR(200) NOT NULL, + JOB_GROUP VARCHAR(200) NOT NULL, + DESCRIPTION VARCHAR(250) NULL, + JOB_CLASS_NAME VARCHAR(250) NOT NULL, + IS_DURABLE BOOL NOT NULL, + IS_NONCONCURRENT BOOL NOT NULL, + IS_UPDATE_DATA BOOL NOT NULL, + REQUESTS_RECOVERY BOOL NOT NULL, + JOB_DATA BYTEA NULL, + PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) +); + +CREATE TABLE qrtz_triggers +( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + JOB_NAME VARCHAR(200) NOT NULL, + JOB_GROUP VARCHAR(200) NOT NULL, + DESCRIPTION VARCHAR(250) NULL, + NEXT_FIRE_TIME BIGINT NULL, + PREV_FIRE_TIME BIGINT NULL, + PRIORITY INTEGER NULL, + TRIGGER_STATE VARCHAR(16) NOT NULL, + TRIGGER_TYPE VARCHAR(8) NOT NULL, + START_TIME BIGINT NOT NULL, + END_TIME BIGINT NULL, + CALENDAR_NAME VARCHAR(200) NULL, + MISFIRE_INSTR SMALLINT NULL, + JOB_DATA BYTEA NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) + REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) +); + +CREATE TABLE qrtz_simple_triggers +( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + REPEAT_COUNT BIGINT NOT NULL, + REPEAT_INTERVAL BIGINT NOT NULL, + TIMES_TRIGGERED BIGINT NOT NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_cron_triggers +( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + CRON_EXPRESSION VARCHAR(120) NOT NULL, + TIME_ZONE_ID VARCHAR(80), + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_simprop_triggers +( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INT NULL, + INT_PROP_2 INT NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 BOOL NULL, + BOOL_PROP_2 BOOL NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_blob_triggers +( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + BLOB_DATA BYTEA NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_calendars +( + SCHED_NAME VARCHAR(120) NOT NULL, + CALENDAR_NAME VARCHAR(200) NOT NULL, + CALENDAR BYTEA NOT NULL, + PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) +); + + +CREATE TABLE qrtz_paused_trigger_grps +( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) +); + +CREATE TABLE qrtz_fired_triggers +( + SCHED_NAME VARCHAR(120) NOT NULL, + ENTRY_ID VARCHAR(95) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + INSTANCE_NAME VARCHAR(200) NOT NULL, + FIRED_TIME BIGINT NOT NULL, + SCHED_TIME BIGINT NOT NULL, + PRIORITY INTEGER NOT NULL, + STATE VARCHAR(16) NOT NULL, + JOB_NAME VARCHAR(200) NULL, + JOB_GROUP VARCHAR(200) NULL, + IS_NONCONCURRENT BOOL NULL, + REQUESTS_RECOVERY BOOL NULL, + PRIMARY KEY (SCHED_NAME,ENTRY_ID) +); + +CREATE TABLE qrtz_scheduler_state +( + SCHED_NAME VARCHAR(120) NOT NULL, + INSTANCE_NAME VARCHAR(200) NOT NULL, + LAST_CHECKIN_TIME BIGINT NOT NULL, + CHECKIN_INTERVAL BIGINT NOT NULL, + PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) +); + +CREATE TABLE qrtz_locks +( + SCHED_NAME VARCHAR(120) NOT NULL, + LOCK_NAME VARCHAR(40) NOT NULL, + PRIMARY KEY (SCHED_NAME,LOCK_NAME) +); + +create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY); +create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP); + +create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); +create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP); +create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME); +create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP); +create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE); +create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); +create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); +create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); +create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); +create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); + +create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME); +create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); +create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); +create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP); +create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); +create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP); + + +commit; \ No newline at end of file diff --git a/deploy/Dockerfile b/deploy/Dockerfile new file mode 100644 index 0000000..bf78805 --- /dev/null +++ b/deploy/Dockerfile @@ -0,0 +1,11 @@ +# 构建镜像,执行命令:【docker build -t drone-ops:1.0 .】 +FROM eclipse-temurin:17-jre +LABEL maintainer="BDZL" + +# 设置时区 +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' >/etc/timezone + +ENTRYPOINT ["java", "-server", "-Xms1024M", "-Xmx1024M", "-Djava.security.egd=file:/dev/./urandom", "-Dfile.encoding=UTF-8", "-XX:+HeapDumpOnOutOfMemoryError", "-jar", "/app/app.jar" ] + + diff --git a/deploy/docker-compose-emqx.yml b/deploy/docker-compose-emqx.yml new file mode 100644 index 0000000..6a3cf24 --- /dev/null +++ b/deploy/docker-compose-emqx.yml @@ -0,0 +1,51 @@ +version: '3.9' +# 通过 Docker Compose 构建 EMQX 集群 +services: + maku-emqx1: + image: emqx:5.7.1 + container_name: maku-emqx1 + environment: + - "EMQX_NODE_NAME=emqx@node1.emqx.io" + - "EMQX_CLUSTER__DISCOVERY_STRATEGY=static" + - "EMQX_CLUSTER__STATIC__SEEDS=[emqx@node1.emqx.io,emqx@node2.emqx.io]" + healthcheck: + test: ["CMD", "/opt/emqx/bin/emqx", "ctl", "status"] + interval: 5s + timeout: 25s + retries: 5 + networks: + emqx-bridge: + aliases: + - node1.emqx.io + ports: + - 1883:1883 + - 8083:8083 + - 8084:8084 + - 8883:8883 + - 18083:18083 + # 如果需要持久 Docker 容器 ,请将以下目录挂载到容器外部,这样即使容器被删除数据也不会丢失 + volumes: + - /work/www/emqx/data:/opt/emqx/data + - /work/www/emqx/log:/opt/emqx/log +# maku-emqx2: +# image: emqx:5.7.1 +# container_name: maku-emqx2 +# environment: +# - "EMQX_NODE_NAME=emqx@node2.emqx.io" +# - "EMQX_CLUSTER__DISCOVERY_STRATEGY=static" +# - "EMQX_CLUSTER__STATIC__SEEDS=[emqx@node1.emqx.io,emqx@node2.emqx.io]" +# healthcheck: +# test: ["CMD", "/opt/emqx/bin/emqx", "ctl", "status"] +# interval: 5s +# timeout: 25s +# retries: 5 +# networks: +# emqx-bridge: +# aliases: +# - node2.emqx.io +# volumes: +# - $PWD/emqx2_data:/opt/emqx/data + +networks: + emqx-bridge: + driver: bridge \ No newline at end of file diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000..c76d561 --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3.9' +services: + drone-ops: + image: drone-ops:1.0 + container_name: drone-ops + ports: + - 8090:8090 + environment: + - spring.profiles.active=dev + volumes: + - /usr/dj/drone-ops/drone-ops-server.jar:/app/app.jar \ No newline at end of file diff --git a/drone-ops-api/pom.xml b/drone-ops-api/pom.xml new file mode 100644 index 0000000..1b5c586 --- /dev/null +++ b/drone-ops-api/pom.xml @@ -0,0 +1,18 @@ + + + com.bdzl + drone-ops + ${revision} + + 4.0.0 + drone-ops-api + jar + + + + org.springframework.boot + spring-boot-starter-web + + + + \ No newline at end of file diff --git a/drone-ops-api/src/main/java/com/bdzl/api/module/system/SmsApi.java b/drone-ops-api/src/main/java/com/bdzl/api/module/system/SmsApi.java new file mode 100644 index 0000000..ebac1a7 --- /dev/null +++ b/drone-ops-api/src/main/java/com/bdzl/api/module/system/SmsApi.java @@ -0,0 +1,61 @@ +package com.bdzl.api.module.system; + +import java.util.Map; + +/** + * 短信服务API + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SmsApi { + + /** + * 发送短信 + * + * @param mobile 手机号 + * @param params 参数 + * @return 是否发送成功 + */ + boolean send(String mobile, Map params); + + /** + * 发送短信 + * + * @param groupName 分组名称 + * @param mobile 手机号 + * @param params 参数 + * @return 是否发送成功 + */ + boolean send(String groupName, String mobile, Map params); + + /** + * 发送短信 + * + * @param mobile 手机号 + * @param key 参数KEY + * @param value 参数Value + * @return 是否发送成功 + */ + boolean sendCode(String mobile, String key, String value); + + /** + * 发送短信 + * + * @param groupName 分组名称 + * @param mobile 手机号 + * @param key 参数KEY + * @param value 参数Value + * @return 是否发送成功 + */ + boolean sendCode(String groupName, String mobile, String key, String value); + + /** + * 效验短信验证码 + * + * @param mobile 手机号 + * @param code 验证码 + * @return 是否效验成功 + */ + boolean verifyCode(String mobile, String code); +} diff --git a/drone-ops-api/src/main/java/com/bdzl/api/module/system/StorageApi.java b/drone-ops-api/src/main/java/com/bdzl/api/module/system/StorageApi.java new file mode 100644 index 0000000..106e09c --- /dev/null +++ b/drone-ops-api/src/main/java/com/bdzl/api/module/system/StorageApi.java @@ -0,0 +1,53 @@ +package com.bdzl.api.module.system; + +import java.io.InputStream; + +/** + * 存储服务API + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface StorageApi { + + /** + * 根据文件名,生成带时间戳的新文件名 + * + * @param fileName 文件名 + * @return 返回带时间戳的文件名 + */ + String getNewFileName(String fileName); + + /** + * 生成路径,不包含文件名 + * + * @return 返回生成的路径 + */ + String getPath(); + + /** + * 根据文件名,生成路径 + * + * @param fileName 文件名 + * @return 生成文件路径 + */ + String getPath(String fileName); + + /** + * 文件上传 + * + * @param data 文件字节数组 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + String upload(byte[] data, String path); + + /** + * 文件上传 + * + * @param inputStream 字节流 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + String upload(InputStream inputStream, String path); +} diff --git a/drone-ops-framework/pom.xml b/drone-ops-framework/pom.xml new file mode 100644 index 0000000..ada2a22 --- /dev/null +++ b/drone-ops-framework/pom.xml @@ -0,0 +1,115 @@ + + + com.bdzl + drone-ops + ${revision} + + 4.0.0 + drone-ops-framework + jar + + + + org.springframework.boot + spring-boot-starter-web + + + jakarta.servlet + jakarta.servlet-api + provided + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-validation + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.7.0 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.redisson + redisson-spring-boot-starter + + + com.baomidou + lock4j-redisson-spring-boot-starter + + + org.springframework.boot + spring-boot-starter-security + + + com.mysql + mysql-connector-j + + + com.dameng + DmJdbcDriver18 + + + org.postgresql + postgresql + + + com.baomidou + mybatis-plus-spring-boot3-starter + + + com.baomidou + dynamic-datasource-spring-boot3-starter + + + cn.hutool + hutool-all + + + cn.idev.excel + fastexcel + + + okio + com.squareup.okio + + + com.fhs-opensource + easy-trans-mybatis-plus-extend + + + com.fhs-opensource + easy-trans-spring-boot-starter + + + org.jsoup + jsoup + + + com.alibaba + transmittable-thread-local + + + org.lionsoul + ip2region + + + org.bouncycastle + bcprov-jdk15to18 + + + \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/cache/RedisCache.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/cache/RedisCache.java new file mode 100644 index 0000000..0fb7a67 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/cache/RedisCache.java @@ -0,0 +1,149 @@ +package com.bdzl.framework.common.cache; + +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Redis Cache + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +public class RedisCache { + @Resource + private RedisTemplate redisTemplate; + + /** + * 默认过期时长为24小时,单位:秒 + */ + public final static long DEFAULT_EXPIRE = 60 * 60 * 24L; + /** + * 过期时长为1小时,单位:秒 + */ + public final static long HOUR_ONE_EXPIRE = 60 * 60 * 1L; + /** + * 过期时长为6小时,单位:秒 + */ + public final static long HOUR_SIX_EXPIRE = 60 * 60 * 6L; + /** + * 不设置过期时长 + */ + public final static long NOT_EXPIRE = -1L; + + public void set(String key, Object value, long expire) { + redisTemplate.opsForValue().set(key, value); + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public void set(String key, Object value) { + redisTemplate.opsForValue().set(key, value); + } + + public Object get(String key, long expire) { + Object value = redisTemplate.opsForValue().get(key); + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + return value; + } + + public Object get(String key) { + return get(key, NOT_EXPIRE); + } + + public Long increment(String key) { + return redisTemplate.opsForValue().increment(key); + } + + public Boolean hasKey(String key) { + return redisTemplate.hasKey(key); + } + + public Set keys(String pattern) { + return redisTemplate.keys(pattern); + } + + public void delete(String key) { + redisTemplate.delete(key); + } + + public void delete(Collection keys) { + redisTemplate.delete(keys); + } + + public Object hGet(String key, String field) { + return redisTemplate.opsForHash().get(key, field); + } + + public Map hGetAll(String key) { + HashOperations hashOperations = redisTemplate.opsForHash(); + return hashOperations.entries(key); + } + + public void hMSet(String key, Map map) { + hMSet(key, map, DEFAULT_EXPIRE); + } + + public void hMSet(String key, Map map, long expire) { + redisTemplate.opsForHash().putAll(key, map); + + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public void hSet(String key, String field, Object value) { + hSet(key, field, value, DEFAULT_EXPIRE); + } + + public void hSet(String key, String field, Object value, long expire) { + redisTemplate.opsForHash().put(key, field, value); + + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public void expire(String key, long expire) { + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + + public void expireAt(String key, Date expire) { + redisTemplate.expireAt(key, expire); + } + + public Long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + public void hDel(String key, Object... fields) { + redisTemplate.opsForHash().delete(key, fields); + } + + public void leftPush(String key, Object value) { + leftPush(key, value, DEFAULT_EXPIRE); + } + + public void leftPush(String key, Object value, long expire) { + redisTemplate.opsForList().leftPush(key, value); + + if (expire != NOT_EXPIRE) { + expire(key, expire); + } + } + + public Object rightPop(String key) { + return redisTemplate.opsForList().rightPop(key); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/cache/RedisKeys.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/cache/RedisKeys.java new file mode 100644 index 0000000..d15b8ed --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/cache/RedisKeys.java @@ -0,0 +1,29 @@ +package com.bdzl.framework.common.cache; + +/** + * Redis Key管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class RedisKeys { + + /** + * 验证码Key + */ + public static String getCaptchaKey(String key) { + return "sys:captcha:" + key; + } + + /** + * accessToken Key + */ + public static String getAccessTokenKey(String accessToken) { + return "sys:token:" + accessToken; + } + + public static String getLogKey() { + return "sys:log"; + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/BigNumberSerializer.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/BigNumberSerializer.java new file mode 100644 index 0000000..0a9432d --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/BigNumberSerializer.java @@ -0,0 +1,41 @@ +package com.bdzl.framework.common.config; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 解决js精度丢失问题 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + /** + * JS Number.MAX_SAFE_INTEGER Number.MIN_SAFE_INTEGER + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化位字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/CorsConfig.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/CorsConfig.java new file mode 100644 index 0000000..ac548b2 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/CorsConfig.java @@ -0,0 +1,29 @@ +package com.bdzl.framework.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +/** + * 跨域配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +public class CorsConfig { + + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.setAllowCredentials(true); + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedOriginPattern("*"); + corsConfiguration.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", corsConfiguration); + return new CorsFilter(source); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/JacksonConfig.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/JacksonConfig.java new file mode 100644 index 0000000..b3eb95b --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/JacksonConfig.java @@ -0,0 +1,49 @@ +package com.bdzl.framework.common.config; + +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +@Configuration +public class JacksonConfig { + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public Jackson2ObjectMapperBuilderCustomizer customJackson() { + return builder -> { + builder.serializerByType(LocalDateTime.class, + new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + builder.serializerByType(LocalDate.class, + new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + builder.serializerByType(LocalTime.class, + new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); + builder.deserializerByType(LocalDateTime.class, + new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + builder.deserializerByType(LocalDate.class, + new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + builder.deserializerByType(LocalTime.class, + new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); + // builder.serializationInclusion(JsonInclude.Include.NON_NULL); + + // 避免Long精度丢失,超过JS最大精度,使用String类型 + builder.serializerByType(Long.class, BigNumberSerializer.INSTANCE); + + builder.failOnUnknownProperties(false); + builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + }; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/RedisConfig.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/RedisConfig.java new file mode 100644 index 0000000..fb58cbc --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/config/RedisConfig.java @@ -0,0 +1,48 @@ +package com.bdzl.framework.common.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializer; + +/** + * Redis配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +public class RedisConfig { + + public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); + + return new GenericJackson2JsonRedisSerializer(objectMapper); + } + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + // Key HashKey使用String序列化 + template.setKeySerializer(RedisSerializer.string()); + template.setHashKeySerializer(RedisSerializer.string()); + + // Value HashValue使用Json序列化 + template.setValueSerializer(genericJackson2JsonRedisSerializer()); + template.setHashValueSerializer(genericJackson2JsonRedisSerializer()); + + template.setConnectionFactory(factory); + + template.afterPropertiesSet(); + return template; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/constant/Constant.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/constant/Constant.java new file mode 100644 index 0000000..812c188 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/constant/Constant.java @@ -0,0 +1,52 @@ +package com.bdzl.framework.common.constant; + +/** + * 常量 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface Constant { + /** + * 根节点标识 + */ + Long ROOT = 0L; + /** + * 当前页码 + */ + String PAGE = "page"; + /** + * 数据权限 + */ + String DATA_SCOPE = "dataScope"; + /** + * 超级管理员 + */ + Integer SUPER_ADMIN = 1; + /** + * 禁用 + */ + Integer DISABLE = 0; + /** + * 启用 + */ + Integer ENABLE = 1; + /** + * 失败 + */ + Integer FAIL = 0; + /** + * 成功 + */ + Integer SUCCESS = 1; + /** + * OK + */ + String OK = "OK"; + + /** + * pgsql的driver + */ + String PGSQL_DRIVER = "org.postgresql.Driver"; + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/DateConverter.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/DateConverter.java new file mode 100644 index 0000000..088f544 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/DateConverter.java @@ -0,0 +1,41 @@ +package com.bdzl.framework.common.excel; + +import cn.idev.excel.converters.Converter; +import cn.idev.excel.enums.CellDataTypeEnum; +import cn.idev.excel.metadata.GlobalConfiguration; +import cn.idev.excel.metadata.data.ReadCellData; +import cn.idev.excel.metadata.data.WriteCellData; +import cn.idev.excel.metadata.property.ExcelContentProperty; +import com.bdzl.framework.common.utils.DateUtils; + +import java.util.Date; + +/** + * 日期转换 + * + * @author eden + */ +public class DateConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Date convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + String dateString = cellData.getStringValue(); + return dateString == null ? null : DateUtils.parse(dateString, DateUtils.DATE_TIME_PATTERN); + } + + @Override + public WriteCellData convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + String dateValue = DateUtils.format(value, DateUtils.DATE_TIME_PATTERN); + return new WriteCellData<>(dateValue); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/ExcelDataListener.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/ExcelDataListener.java new file mode 100644 index 0000000..709ac29 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/ExcelDataListener.java @@ -0,0 +1,61 @@ +package com.bdzl.framework.common.excel; + +import cn.idev.excel.context.AnalysisContext; +import cn.idev.excel.event.AnalysisEventListener; + +import java.util.LinkedList; +import java.util.List; + +/** + * excel读取监听器 + * + * @author eden + */ +public class ExcelDataListener extends AnalysisEventListener { + /** + * 定义一个保存Excel所有记录的集合 + */ + private final List list = new LinkedList<>(); + /** + * 回调接口 + */ + private final ExcelFinishCallBack callBack; + + /** + * 构造 ExcelFinishCallBack + * + * @param callBack ExcelFinishCallBack + */ + public ExcelDataListener(ExcelFinishCallBack callBack) { + this.callBack = callBack; + } + + + /** + * 这个每一条数据解析都会来调用 + * 在这里可以做一些其他的操作(过滤,分批入库...) 就考自己去拓展了 + * + * @param data one row value. is same as {@link AnalysisContext#readRowHolder()} + * @param context context + */ + @Override + public void invoke(T data, AnalysisContext context) { + list.add(data); + if (list.size() == 500) { + this.callBack.doSaveBatch(list); + list.clear(); + } + } + + /** + * 所有数据解析完成了 都会来调用 + * 解析完成之后将所有数据存入回调接口中 + * + * @param context context + */ + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + this.callBack.doSaveBatch(list); + } +} + diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/ExcelFinishCallBack.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/ExcelFinishCallBack.java new file mode 100644 index 0000000..143fc52 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/ExcelFinishCallBack.java @@ -0,0 +1,21 @@ +package com.bdzl.framework.common.excel; + +import java.util.List; + +/** + * excel读取数据完成 + * + * @param the type parameter + * @author eden + */ +public interface ExcelFinishCallBack { + + /** + * Do save batch. + * + * @param result the result + */ + default void doSaveBatch(List result) { + } +} + diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/LocalDateTimeConverter.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/LocalDateTimeConverter.java new file mode 100644 index 0000000..d73162c --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/excel/LocalDateTimeConverter.java @@ -0,0 +1,43 @@ +package com.bdzl.framework.common.excel; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.idev.excel.converters.Converter; +import cn.idev.excel.enums.CellDataTypeEnum; +import cn.idev.excel.metadata.GlobalConfiguration; +import cn.idev.excel.metadata.data.ReadCellData; +import cn.idev.excel.metadata.data.WriteCellData; +import cn.idev.excel.metadata.property.ExcelContentProperty; +import com.bdzl.framework.common.utils.DateUtils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 日期转换 + * + * @author eden + */ +public class LocalDateTimeConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return LocalDateTime.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public LocalDateTime convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + String dateString = cellData.getStringValue(); + return dateString == null ? null : LocalDateTimeUtil.parse(dateString, DateTimeFormatter.ofPattern(DateUtils.DATE_TIME_PATTERN)); + } + + @Override + public WriteCellData convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + String dateValue = LocalDateTimeUtil.format(value, DateUtils.DATE_TIME_PATTERN); + return new WriteCellData<>(dateValue); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ErrorCode.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ErrorCode.java new file mode 100644 index 0000000..a4a4af9 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ErrorCode.java @@ -0,0 +1,22 @@ +package com.bdzl.framework.common.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 错误编码 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum ErrorCode { + UNAUTHORIZED(401, "还未授权,不能访问"), + FORBIDDEN(403, "没有权限,禁止访问"), + REFRESH_TOKEN_INVALID(400, "refresh_token 已失效"), + INTERNAL_SERVER_ERROR(500, "服务器异常,请稍后再试"); + + private final int code; + private final String msg; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ServerException.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ServerException.java new file mode 100644 index 0000000..d951d14 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ServerException.java @@ -0,0 +1,44 @@ +package com.bdzl.framework.common.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 自定义异常 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ServerException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private int code; + private String msg; + + public ServerException(String msg) { + super(msg); + this.code = ErrorCode.INTERNAL_SERVER_ERROR.getCode(); + this.msg = msg; + } + + public ServerException(ErrorCode errorCode) { + super(errorCode.getMsg()); + this.code = errorCode.getCode(); + this.msg = errorCode.getMsg(); + } + + public ServerException(String msg, Throwable e) { + super(msg, e); + this.code = ErrorCode.INTERNAL_SERVER_ERROR.getCode(); + this.msg = msg; + } + + public ServerException(int code, String msg) { + super(msg); + this.code = code; + this.msg = msg; + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ServerExceptionHandler.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ServerExceptionHandler.java new file mode 100644 index 0000000..7230f8f --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/exception/ServerExceptionHandler.java @@ -0,0 +1,66 @@ +package com.bdzl.framework.common.exception; + +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.Result; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; + + +/** + * 异常处理器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +@RestControllerAdvice +public class ServerExceptionHandler { + /** + * 处理自定义异常 + */ + @ExceptionHandler(ServerException.class) + public Result handleException(ServerException ex) { + + return Result.error(ex.getCode(), ex.getMsg()); + } + + /** + * SpringMVC参数绑定,Validator校验不正确 + */ + @ExceptionHandler(BindException.class) + public Result bindException(BindException ex) { + FieldError fieldError = ex.getFieldError(); + assert fieldError != null; + return Result.error(fieldError.getDefaultMessage()); + } + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity handleResourceNotFoundException(NoResourceFoundException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("404 Not Found: " + e.getResourcePath()); + } + + @ExceptionHandler(AccessDeniedException.class) + public Result handleAccessDeniedException(Exception ex) { + + return Result.error(ErrorCode.FORBIDDEN); + } + + @ExceptionHandler(IllegalArgumentException.class) + public Result handleIllegalArgumentException(Exception ex) { + + return Result.error(ex.getMessage()); + } + + @ExceptionHandler(Exception.class) + public Result handleException(Exception ex) { + log.error(ex.getMessage(), ex); + return Result.error(ErrorCode.INTERNAL_SERVER_ERROR); + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/query/Query.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/query/Query.java new file mode 100644 index 0000000..fb13b51 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/query/Query.java @@ -0,0 +1,32 @@ +package com.bdzl.framework.common.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Range; + +/** + * 查询公共参数 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class Query { + @NotNull(message = "页码不能为空") + @Min(value = 1, message = "页码最小值为 1") + @Schema(description = "当前页码", required = true) + Integer page; + + @NotNull(message = "每页条数不能为空") + @Range(min = 1, max = 1000, message = "每页条数,取值范围 1-1000") + @Schema(description = "每页条数", required = true) + Integer limit; + + @Schema(description = "排序字段") + String order; + + @Schema(description = "是否升序") + boolean asc; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/AddressUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/AddressUtils.java new file mode 100644 index 0000000..9b333a3 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/AddressUtils.java @@ -0,0 +1,59 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.http.HttpUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 获取真实地址 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +public class AddressUtils { + // 实时查询 + public static final String ADDRESS_URL = "https://whois.pconline.com.cn/ipJson.jsp"; + public static final String UNKNOWN = "未知"; + + public static String getAddressByIP(String ip) { + // 内网 + if (IpUtils.internalIp(ip)) { + return "内网IP"; + } + + try { + Map paramMap = new HashMap<>(); + paramMap.put("ip", ip); + paramMap.put("json", true); + String response = HttpUtil.get(ADDRESS_URL, paramMap); + if (StringUtils.isBlank(response)) { + log.error("根据IP获取地址异常 {}", ip); + return UNKNOWN; + } + + Address address = JsonUtils.parseObject(response, Address.class); + return String.format("%s %s", address.getPro(), address.getCity()); + } catch (Exception e) { + log.error("根据IP获取地址异常 {}", ip); + } + + return UNKNOWN; + } + + @Data + static class Address { + /** + * 省 + */ + private String pro; + /** + * 市 + */ + private String city; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/AssertUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/AssertUtils.java new file mode 100644 index 0000000..ef779fe --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/AssertUtils.java @@ -0,0 +1,33 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import com.bdzl.framework.common.exception.ServerException; + +/** + * 校验工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class AssertUtils { + + public static void isBlank(String str, String variable) { + if (StrUtil.isBlank(str)) { + throw new ServerException(variable + "不能为空"); + } + } + + public static void isNull(Object object, String variable) { + if (object == null) { + throw new ServerException(variable + "不能为空"); + } + } + + public static void isArrayEmpty(Object[] array, String variable) { + if(ArrayUtil.isEmpty(array)){ + throw new ServerException(variable + "不能为空"); + } + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/DateUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/DateUtils.java new file mode 100644 index 0000000..b01e46b --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/DateUtils.java @@ -0,0 +1,73 @@ +package com.bdzl.framework.common.utils; + + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 日期处理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class DateUtils { + /** + * 时间格式(yyyy-MM-dd) + */ + public final static String DATE_PATTERN = "yyyy-MM-dd"; + /** + * 时间格式(yyyy-MM-dd HH:mm:ss) + */ + public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + /** + * 日期格式化 日期格式为:yyyy-MM-dd + * + * @param date 日期 + * @return 返回yyyy-MM-dd格式日期 + */ + public static String format(Date date) { + return format(date, DATE_PATTERN); + } + + /** + * 日期格式化 日期格式为:yyyy-MM-dd + * + * @param date 日期 + * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN + * @return 返回yyyy-MM-dd格式日期 + */ + public static String format(Date date, String pattern) { + if (date != null) { + SimpleDateFormat df = new SimpleDateFormat(pattern); + return df.format(date); + } + return null; + } + + /** + * 日期解析 + * + * @param date 日期 + * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN + * @return 返回Date + */ + public static Date parse(String date, String pattern) { + try { + return new SimpleDateFormat(pattern).parse(date); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 日期是否过期 + */ + public static boolean isExpired(LocalDateTime time) { + LocalDateTime now = LocalDateTime.now(); + return now.isAfter(time); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/ExcelUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/ExcelUtils.java new file mode 100644 index 0000000..5376ce3 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/ExcelUtils.java @@ -0,0 +1,230 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.idev.excel.FastExcel; +import cn.idev.excel.converters.longconverter.LongStringConverter; +import cn.idev.excel.support.ExcelTypeEnum; +import com.fhs.common.utils.ConverterUtils; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.util.ReflectUtils; +import com.fhs.core.trans.vo.TransPojo; +import com.fhs.trans.service.impl.DictionaryTransService; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.excel.ExcelDataListener; +import com.bdzl.framework.common.excel.ExcelFinishCallBack; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.List; + +/** + * The type Excel utils. + * {@link } + * + * @author eden + */ +@Slf4j +public class ExcelUtils { + + /** + * 读取excel文件 + * + * @param 数据类型 + * @param file excel文件 + * @param head 列名 + * @param callBack 回调 导入时传入定义好的回调接口,excel数据解析完毕之后监听器将数据传入回调函数 + * 这样调用工具类时可以通过回调函数获取导入的数据,如果数据量过大可根据实际情况进行分配入库 + */ + public static void readAnalysis(MultipartFile file, Class head, ExcelFinishCallBack callBack) { + try { + FastExcel.read(file.getInputStream(), head, new ExcelDataListener<>(callBack)).sheet().doRead(); + } catch (IOException e) { + log.error("readAnalysis error", e); + } + } + + /** + * 读取excel文件 + * + * @param 数据类型 + * @param file excel文件 + * @param head 列名 + * @param callBack 回调 导入时传入定义好的回调接口,excel数据解析完毕之后监听器将数据传入回调函数 + * 这样调用工具类时可以通过回调函数获取导入的数据,如果数据量过大可根据实际情况进行分配入库 + */ + public static void readAnalysis(File file, Class head, ExcelFinishCallBack callBack) { + try { + FastExcel.read(new FileInputStream(file), head, new ExcelDataListener<>(callBack)).sheet().doRead(); + } catch (IOException e) { + log.error("readAnalysis error", e); + } + } + + /** + * 读取excel文件 同步 + * + * @param 数据类型 + * @param file 文件 + * @param clazz 模板类 + * @return java.util.List + */ + public static List readSync(File file, Class clazz) { + return readSync(file, clazz, 1, 0, ExcelTypeEnum.XLSX); + } + + /** + * 读取excel文件 同步 + * + * @param 数据类型 + * @param file 文件 + * @param clazz 模板类 + * @param rowNum 数据开始行 1 + * @param sheetNo 第几张表 + * @param excelType 数据表格式类型 + * @return java.util.List list + */ + public static List readSync(File file, Class clazz, Integer rowNum, Integer sheetNo, ExcelTypeEnum excelType) { + return FastExcel.read(file).headRowNumber(rowNum).excelType(excelType).head(clazz).sheet(sheetNo).doReadSync(); + } + + + /** + * 导出数据到文件 + * + * @param 数据类型 + * @param head 类名 + * @param file 导入到文件 + * @param data 数据 + */ + public static void excelExport(Class head, File file, List data) { + excelExport(head, file, "sheet1", data); + } + + /** + * 导出数据到文件 + * + * @param 写入格式 + * @param head 类名 + * @param file 写入到文件 + * @param sheetName sheet名称 + * @param data 数据列表 + */ + public static void excelExport(Class head, File file, String sheetName, List data) { + try { + FastExcel.write(file, head).sheet(sheetName).registerConverter(new LongStringConverter()).doWrite(data); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 导出数据到web + * 文件下载(失败了会返回一个有部分数据的Excel) + * + * @param head 类名 + * @param excelName excel名字 + * @param sheetName sheet名称 + * @param data 数据 + */ + public static void excelExport(Class head, String excelName, String sheetName, List data) { + try { + HttpServletResponse response = getExportResponse(excelName); + + FastExcel.write(response.getOutputStream(), head).sheet(StringUtils.isBlank(sheetName) ? "sheet1" : sheetName) + .registerConverter(new LongStringConverter()).doWrite(data); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 导出数据到web + * 文件下载(失败了会返回一个有部分数据的Excel) + * + * @param head 类名 + * @param excelName excel名字 + * @param sheetName sheet名称 + * @param data 数据 + */ + public static void excelExport(List> head, String excelName, String sheetName, List data) { + try { + HttpServletResponse response = getExportResponse(excelName); + + FastExcel.write(response.getOutputStream()).head(head).sheet(StringUtils.isBlank(sheetName) ? "sheet1" : sheetName) + .registerConverter(new LongStringConverter()).doWrite(data); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static HttpServletResponse getExportResponse(String excelName) { + HttpServletResponse response = HttpContextUtils.getHttpServletResponse(); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setCharacterEncoding("UTF-8"); + + excelName += DateUtil.format(new Date(), "yyyyMMddHHmmss"); + String fileName = URLUtil.encode(excelName, StandardCharsets.UTF_8); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + return response; + } + + /** + * 解析字典数据到字段上 + * 比如 T中有 genderLabel字段 为男 需要给 gender 字段自动设置为0 + * + * @param dataList 需要被反向解析的数据 + */ + @SneakyThrows + public static void parseDict(List dataList) { + //没有数据就不需要初始化 + if (CollectionUtil.isEmpty(dataList)) { + return; + } + Class clazz = dataList.get(0).getClass(); + //拿到所有需要反向翻译的字段 + List fields = ReflectUtils.getAnnotationField(clazz, Trans.class); + //过滤出字典翻译 + fields = fields.stream().filter(field -> TransType.DICTIONARY.equals(field.getAnnotation(Trans.class).type())).toList(); + DictionaryTransService dictionaryTransService = SpringUtil.getBean(DictionaryTransService.class); + for (T data : dataList) { + for (Field field : fields) { + Trans trans = field.getAnnotation(Trans.class); + // key不能为空并且ref不为空的才自动处理 + if (StrUtil.isAllNotBlank(trans.key(), trans.ref())) { + Field ref = ReflectUtils.getDeclaredField(clazz, trans.ref()); + ref.setAccessible(true); + // 获取字典反向值 + String value = dictionaryTransService.getDictionaryTransMap().get("un_trans:" + trans.key() + "_" + ref.get(data)); + if (StringUtils.isBlank(value)) { + continue; + } + // 一般目标字段是int或者string字段 后面有添加单独抽离方法 + if (Integer.class.equals(field.getType())) { + field.setAccessible(true); + field.set(data, ConverterUtils.toInteger(value)); + } else { + field.setAccessible(true); + field.set(data, ConverterUtils.toString(value)); + } + } + } + } + + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/ExceptionUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/ExceptionUtils.java new file mode 100644 index 0000000..e18158d --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/ExceptionUtils.java @@ -0,0 +1,32 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.core.io.IoUtil; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Exception工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class ExceptionUtils { + + /** + * 获取异常信息 + * @param e 异常 + * @return 返回异常信息 + */ + public static String getExceptionMessage(Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + e.printStackTrace(pw); + + // 关闭IO流 + IoUtil.close(pw); + IoUtil.close(sw); + + return sw.toString(); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/HttpContextUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/HttpContextUtils.java new file mode 100644 index 0000000..5b67e82 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/HttpContextUtils.java @@ -0,0 +1,77 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * Http + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class HttpContextUtils { + + public static HttpServletRequest getHttpServletRequest() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + return null; + } + + return ((ServletRequestAttributes) requestAttributes).getRequest(); + } + + + public static HttpServletResponse getHttpServletResponse() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + return null; + } + + return ((ServletRequestAttributes) requestAttributes).getResponse(); + } + + + public static Map getParameterMap(HttpServletRequest request) { + Enumeration parameters = request.getParameterNames(); + + Map params = new HashMap<>(); + while (parameters.hasMoreElements()) { + String parameter = parameters.nextElement(); + String value = request.getParameter(parameter); + if (StrUtil.isNotBlank(value)) { + params.put(parameter, value); + } + } + + return params; + } + + public static String getDomain() { + HttpServletRequest request = getHttpServletRequest(); + + return getDomain(request); + } + + public static String getDomain(HttpServletRequest request) { + String domain = request.getHeader(HttpHeaders.ORIGIN); + if (StrUtil.isBlank(domain)) { + domain = request.getHeader(HttpHeaders.REFERER); + } + return StringUtils.removeEnd(domain, "/"); + } + + public static String getOrigin() { + HttpServletRequest request = getHttpServletRequest(); + return request.getHeader(HttpHeaders.ORIGIN); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/IpUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/IpUtils.java new file mode 100644 index 0000000..383f831 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/IpUtils.java @@ -0,0 +1,238 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.exception.ServerException; +import org.lionsoul.ip2region.xdb.Searcher; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * IP地址 工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +public class IpUtils { + private final static Searcher searcher; + + static { + // ip地址库 + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + Resource resource = resolver.getResource("classpath:ip2region.xdb"); + + try { + searcher = Searcher.newWithBuffer(resource.getContentAsByteArray()); + } catch (Exception e) { + log.error("ip2region 初始化异常", e); + throw new ServerException("ip2region 初始化异常", e); + } + } + + public static String getAddressByIP(String ip) { + // 内网 + if (IpUtils.internalIp(ip)) { + return "内网IP"; + } + + try { + String address = searcher.search(ip); + return address.replace("0|", "").replace("|0", "").replace("中国|", ""); + } catch (Exception e) { + log.error("根据IP获取地址异常 {}", ip); + return "未知"; + } + } + + /** + * 获取客户端IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + if (request == null) { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Forwarded-For"); + } + if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param ip IP地址 + */ + public static boolean internalIp(String ip) { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param addr byte地址 + */ + private static boolean internalIp(byte[] addr) { + if (addr == null) return true; + + // IPv6地址处理 + if (addr.length == 16) { + return (addr[0] & 0xFE) == 0xFC; //RFC4193标准:fc00::/7 + } + + // IPv4地址长度校验 + if (addr.length != 4) return true; + + final byte b0 = addr[0]; + final byte b1 = addr[1]; + + // 10.0.0.0/8 + if (b0 == 0x0A) return true; + + // 172.16.0.0/12 + if (b0 == (byte)0xAC) { + return (b1 >= 0x10 && b1 <= 0x1F); + } + + // 192.168.0.0/16 + return (b0 == (byte)0xC0) && (b1 == (byte)0xA8); + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4(String text) { + if (StrUtil.isBlank(text)) { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try { + long l; + int i; + switch (elements.length) { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } catch (NumberFormatException e) { + return null; + } + return bytes; + } + + /** + * 获取本地IP地址 + * + * @return 本地IP地址 + */ + public static String getHostIp() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException ignored) { + + } + return "127.0.0.1"; + } + + /** + * 获取主机名 + * + * @return 本地主机名 + */ + public static String getHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException ignored) { + + } + return "未知"; + } + + /** + * 从反向代理中,获得第一个非 unknown IP地址 + */ + public static String getMultistageReverseProxyIp(String ip) { + // 反向代理检测 + if (ip.indexOf(",") > 0) { + final String[] ips = ip.trim().split(","); + for (String sub : ips) { + if (!"unknown".equalsIgnoreCase(sub)) { + ip = sub; + break; + } + } + } + return ip; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/JsonUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/JsonUtils.java new file mode 100644 index 0000000..9a695a3 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/JsonUtils.java @@ -0,0 +1,78 @@ +package com.bdzl.framework.common.utils; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class JsonUtils { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + static { + objectMapper.registerModule(new JavaTimeModule()); +// objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); +// objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + public static String toJsonString(Object object) { + try { + return objectMapper.writeValueAsString(object); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + return objectMapper.readValue(text, clazz); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return objectMapper.readValue(bytes, clazz); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + try { + return objectMapper.readValue(text, typeReference); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static List parseArray(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/PageResult.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/PageResult.java new file mode 100644 index 0000000..bf072a3 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/PageResult.java @@ -0,0 +1,35 @@ +package com.bdzl.framework.common.utils; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "分页数据") +public class PageResult implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "总记录数") + private int total; + + @Schema(description = "列表数据") + private List list; + + /** + * 分页 + * @param list 列表数据 + * @param total 总记录数 + */ + public PageResult(List list, long total) { + this.list = list; + this.total = (int)total; + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/Result.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/Result.java new file mode 100644 index 0000000..877a396 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/Result.java @@ -0,0 +1,53 @@ +package com.bdzl.framework.common.utils; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.exception.ErrorCode; + +/** + * 响应数据 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "响应") +public class Result { + @Schema(description = "编码 0表示成功,其他值表示失败") + private int code = 0; + + @Schema(description = "消息内容") + private String msg = "success"; + + @Schema(description = "响应数据") + private T data; + + public static Result ok() { + return ok(null); + } + + public static Result ok(T data) { + Result result = new Result<>(); + result.setData(data); + return result; + } + + public static Result error() { + return error(ErrorCode.INTERNAL_SERVER_ERROR); + } + + public static Result error(String msg) { + return error(ErrorCode.INTERNAL_SERVER_ERROR.getCode(), msg); + } + + public static Result error(ErrorCode errorCode) { + return error(errorCode.getCode(), errorCode.getMsg()); + } + + public static Result error(int code, String msg) { + Result result = new Result<>(); + result.setCode(code); + result.setMsg(msg); + return result; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/TreeNode.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/TreeNode.java new file mode 100644 index 0000000..cc0226a --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/TreeNode.java @@ -0,0 +1,33 @@ +package com.bdzl.framework.common.utils; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 树节点,所有需要实现树节点的,都需要继承该类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class TreeNode implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + @Schema(description = "id") + private Long id; + /** + * 上级ID + */ + @Schema(description = "上级ID") + private Long pid; + /** + * 子节点列表 + */ + private List children = new ArrayList<>(); +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/TreeUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/TreeUtils.java new file mode 100644 index 0000000..704ef23 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/utils/TreeUtils.java @@ -0,0 +1,71 @@ +package com.bdzl.framework.common.utils; + + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 树形结构工具类,如:菜单、机构等 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class TreeUtils { + + /** + * 根据pid,构建树节点 + */ + public static > List build(List treeNodes, Long pid) { + // pid不能为空 + AssertUtils.isNull(pid, "pid"); + + List treeList = new ArrayList<>(); + for (T treeNode : treeNodes) { + if (pid.equals(treeNode.getPid())) { + treeList.add(findChildren(treeNodes, treeNode)); + } + } + + return treeList; + } + + /** + * 查找子节点 + */ + private static > T findChildren(List treeNodes, T rootNode) { + for (T treeNode : treeNodes) { + if (rootNode.getId().equals(treeNode.getPid())) { + rootNode.getChildren().add(findChildren(treeNodes, treeNode)); + } + } + return rootNode; + } + + /** + * 构建树节点 + */ + public static > List build(List treeNodes) { + List result = new ArrayList<>(); + + // list转map + Map nodeMap = new LinkedHashMap<>(treeNodes.size()); + for (T treeNode : treeNodes) { + nodeMap.put(treeNode.getId(), treeNode); + } + + for (T node : nodeMap.values()) { + T parent = nodeMap.get(node.getPid()); + if (parent != null && !(node.getId().equals(parent.getId()))) { + parent.getChildren().add(node); + continue; + } + + result.add(node); + } + + return result; + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssConfiguration.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssConfiguration.java new file mode 100644 index 0000000..d1140c7 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssConfiguration.java @@ -0,0 +1,50 @@ +package com.bdzl.framework.common.xss; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; + +/** + * XSS 配置文件 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +@EnableConfigurationProperties(XssProperties.class) +@ConditionalOnProperty(prefix = "maku.xss", value = "enabled") +public class XssConfiguration { + private final static PathMatcher pathMatcher = new AntPathMatcher(); + + @Bean + public FilterRegistrationBean xssFilter(XssProperties properties) { + FilterRegistrationBean bean = new FilterRegistrationBean<>(); + bean.setFilter(new XssFilter(properties, pathMatcher)); + bean.setOrder(Integer.MAX_VALUE); + bean.setName("xssFilter"); + + return bean; + } + + /** + * xss过滤,处理json类型的请求 + */ + @Bean + public ObjectMapper xssFilterObjectMapper(Jackson2ObjectMapperBuilder builder, XssProperties properties) { + ObjectMapper objectMapper = builder.createXmlMapper(false).build(); + + // 注册xss过滤器 + SimpleModule module = new SimpleModule("XssFilterJsonDeserializer"); + module.addDeserializer(String.class, new XssFilterJsonDeserializer(properties, pathMatcher)); + objectMapper.registerModule(module); + + return objectMapper; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssFilter.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssFilter.java new file mode 100644 index 0000000..b5e9309 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssFilter.java @@ -0,0 +1,44 @@ +package com.bdzl.framework.common.xss; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.util.PathMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +/** + * Xss 过滤器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@AllArgsConstructor +public class XssFilter extends OncePerRequestFilter { + private final XssProperties properties; + private final PathMatcher pathMatcher; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + filterChain.doFilter(new XssRequestWrapper(request), response); + } + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + // 如果是json数据,则不处理 + String contentType = request.getContentType(); + if (StrUtil.isBlank(contentType) || StrUtil.startWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + + // 放行不过滤的URL + return properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, request.getServletPath())); + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssFilterJsonDeserializer.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssFilterJsonDeserializer.java new file mode 100644 index 0000000..94e931f --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssFilterJsonDeserializer.java @@ -0,0 +1,50 @@ +package com.bdzl.framework.common.xss; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import jakarta.servlet.http.HttpServletRequest; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.HttpContextUtils; +import org.springframework.util.PathMatcher; + +import java.io.IOException; + +/** + * xss json过滤 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@AllArgsConstructor +public class XssFilterJsonDeserializer extends JsonDeserializer { + private final XssProperties properties; + private final PathMatcher pathMatcher; + + @Override + public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + String value = jsonParser.getValueAsString(); + if (StrUtil.isBlank(value)) { + return value; + } + + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + if (request == null) { + return value; + } + + // 判断该URI是否放行 + boolean flag = properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, request.getServletPath())); + if (flag) { + return value; + } + + return XssUtils.filter(value); + } + + @Override + public Class handledType() { + return String.class; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssProperties.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssProperties.java new file mode 100644 index 0000000..b5c7508 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssProperties.java @@ -0,0 +1,26 @@ +package com.bdzl.framework.common.xss; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Collections; +import java.util.List; + +/** + * XSS 配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@ConfigurationProperties(prefix = "maku.xss") +public class XssProperties { + /** + * 是否开启 XSS + */ + private boolean enabled; + /** + * 排除的URL列表 + */ + private List excludeUrls = Collections.emptyList(); +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssRequestWrapper.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssRequestWrapper.java new file mode 100644 index 0000000..6829523 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssRequestWrapper.java @@ -0,0 +1,71 @@ +package com.bdzl.framework.common.xss; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; + +import java.util.LinkedHashMap; +import java.util.Map; + + +/** + * XSS Request Wrapper + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class XssRequestWrapper extends HttpServletRequestWrapper { + + public XssRequestWrapper(HttpServletRequest request) { + super(request); + } + + @Override + public String getParameter(String name) { + String value = super.getParameter(name); + + return filterXss(value); + } + + @Override + public String[] getParameterValues(String name) { + String[] parameters = super.getParameterValues(name); + if (parameters == null || parameters.length == 0) { + return null; + } + + for (int i = 0; i < parameters.length; i++) { + parameters[i] = filterXss(parameters[i]); + } + return parameters; + } + + @Override + public Map getParameterMap() { + Map map = new LinkedHashMap<>(); + Map parameters = super.getParameterMap(); + for (String key : parameters.keySet()) { + String[] values = parameters.get(key); + for (int i = 0; i < values.length; i++) { + values[i] = filterXss(values[i]); + } + map.put(key, values); + } + return map; + } + + @Override + public String getHeader(String name) { + String value = super.getHeader(name); + return filterXss(value); + } + + private String filterXss(String content) { + if (StrUtil.isBlank(content)) { + return content; + } + + return XssUtils.filter(content); + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssUtils.java new file mode 100644 index 0000000..2ab4bd7 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/common/xss/XssUtils.java @@ -0,0 +1,29 @@ +package com.bdzl.framework.common.xss; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.safety.Safelist; + +/** + * XSS 过滤工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class XssUtils { + /** + * 不格式化 + */ + private final static Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false); + + /** + * XSS过滤 + * + * @param content 需要过滤的内容 + * @return 返回过滤后的内容 + */ + public static String filter(String content) { + return Jsoup.clean(content, "", Safelist.relaxed(), outputSettings); + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/config/MybatisPlusConfig.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/config/MybatisPlusConfig.java new file mode 100644 index 0000000..b50c309 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/config/MybatisPlusConfig.java @@ -0,0 +1,40 @@ +package com.bdzl.framework.mybatis.config; + +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.bdzl.framework.mybatis.handler.FieldMetaObjectHandler; +import com.bdzl.framework.mybatis.interceptor.DataScopeInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * mybatis-plus 配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); + // 数据权限 + mybatisPlusInterceptor.addInnerInterceptor(new DataScopeInnerInterceptor()); + // 分页插件 + mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + // 乐观锁 + mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); + // 防止全表更新与删除 + mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); + + return mybatisPlusInterceptor; + } + + @Bean + public FieldMetaObjectHandler fieldMetaObjectHandler(){ + return new FieldMetaObjectHandler(); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/dao/BaseDao.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/dao/BaseDao.java new file mode 100644 index 0000000..95f5c35 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/dao/BaseDao.java @@ -0,0 +1,14 @@ +package com.bdzl.framework.mybatis.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 基础Dao + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface BaseDao extends BaseMapper { + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/entity/BaseEntity.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/entity/BaseEntity.java new file mode 100644 index 0000000..b6871c2 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/entity/BaseEntity.java @@ -0,0 +1,60 @@ +package com.bdzl.framework.mybatis.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.fhs.core.trans.vo.TransPojo; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * Entity基类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public abstract class BaseEntity implements TransPojo { + /** + * id + */ + @TableId + private Long id; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long creator; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updater; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 版本号 + */ + @Version + @TableField(fill = FieldFill.INSERT) + private Integer version; + + /** + * 删除标记 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private Integer deleted; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/handler/FieldMetaObjectHandler.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/handler/FieldMetaObjectHandler.java new file mode 100644 index 0000000..4a572ff --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/handler/FieldMetaObjectHandler.java @@ -0,0 +1,57 @@ +package com.bdzl.framework.mybatis.handler; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import org.apache.ibatis.reflection.MetaObject; + +import java.time.LocalDateTime; + +/** + * mybatis-plus 自动填充字段 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class FieldMetaObjectHandler implements MetaObjectHandler { + private final static String CREATE_TIME = "createTime"; + private final static String CREATOR = "creator"; + private final static String UPDATE_TIME = "updateTime"; + private final static String UPDATER = "updater"; + private final static String ORG_ID = "orgId"; + private final static String VERSION = "version"; + private final static String DELETED = "deleted"; + + @Override + public void insertFill(MetaObject metaObject) { + UserDetail user = SecurityUser.getUser(); + LocalDateTime now = LocalDateTime.now(); + + // 用户字段填充 + if (user != null) { + // 创建者 + setFieldValByName(CREATOR, user.getId(), metaObject); + // 更新者 + setFieldValByName(UPDATER, user.getId(), metaObject); + // 创建者所属机构 + setFieldValByName(ORG_ID, user.getOrgId(), metaObject); + } + + // 创建时间 + setFieldValByName(CREATE_TIME, now, metaObject); + // 更新时间 + setFieldValByName(UPDATE_TIME, now, metaObject); + // 版本号 + setFieldValByName(VERSION, 0, metaObject); + // 删除标识 + setFieldValByName(DELETED, 0, metaObject); + } + + @Override + public void updateFill(MetaObject metaObject) { + // 更新者 + setFieldValByName(UPDATER, SecurityUser.getUserId(), metaObject); + // 更新时间 + setFieldValByName(UPDATE_TIME, LocalDateTime.now(), metaObject); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/DataScope.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/DataScope.java new file mode 100644 index 0000000..0f2aa5b --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/DataScope.java @@ -0,0 +1,17 @@ +package com.bdzl.framework.mybatis.interceptor; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * 数据范围 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@AllArgsConstructor +public class DataScope { + private String sqlFilter; + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/DataScopeInnerInterceptor.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/DataScopeInnerInterceptor.java new file mode 100644 index 0000000..50e362a --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/DataScopeInnerInterceptor.java @@ -0,0 +1,80 @@ +package com.bdzl.framework.mybatis.interceptor; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.util.Map; + +/** + * 数据权限 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class DataScopeInnerInterceptor implements InnerInterceptor { + + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { + DataScope scope = getDataScope(parameter); + // 不进行数据过滤 + if (scope == null || StrUtil.isBlank(scope.getSqlFilter())) { + return; + } + + // 拼接新SQL + String buildSql = getSelect(boundSql.getSql(), scope); + + // 重写SQL + PluginUtils.mpBoundSql(boundSql).sql(buildSql); + } + + private DataScope getDataScope(Object parameter) { + if (parameter == null) { + return null; + } + + // 判断参数里是否有DataScope对象 + if (parameter instanceof Map parameterMap) { + for (Map.Entry entry : parameterMap.entrySet()) { + if (entry.getValue() != null && entry.getValue() instanceof DataScope) { + return (DataScope) entry.getValue(); + } + } + } else if (parameter instanceof DataScope) { + return (DataScope) parameter; + } + + return null; + } + + private String getSelect(String buildSql, DataScope scope) { + try { + Select select = (Select) CCJSqlParserUtil.parse(buildSql); + PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); + + Expression expression = plainSelect.getWhere(); + if (expression == null) { + plainSelect.setWhere(new StringValue(scope.getSqlFilter())); + } else { + AndExpression andExpression = new AndExpression(expression, new StringValue(scope.getSqlFilter())); + plainSelect.setWhere(andExpression); + } + + return select.toString(); + } catch (JSQLParserException e) { + return buildSql; + } + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/StringValue.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/StringValue.java new file mode 100644 index 0000000..b014bdf --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/interceptor/StringValue.java @@ -0,0 +1,108 @@ +package com.bdzl.framework.mybatis.interceptor; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class StringValue extends ASTNodeAccessImpl implements Expression { + + private String value = ""; + private String prefix = null; + + public static final List ALLOWED_PREFIXES = Arrays.asList("N", "U", "E", "R", "B", "RB", "_utf8"); + + public StringValue() { + // empty constructor + } + + public StringValue(String escapedValue) { + // removing "'" at the start and at the end + if (escapedValue.startsWith("'") && escapedValue.endsWith("'")) { + value = escapedValue.substring(1, escapedValue.length() - 1); + return; + } + + if (escapedValue.length() > 2) { + for (String p : ALLOWED_PREFIXES) { + if (escapedValue.length() > p.length() && escapedValue.substring(0, p.length()).equalsIgnoreCase(p) + && escapedValue.charAt(p.length()) == '\'') { + this.prefix = p; + value = escapedValue.substring(p.length() + 1, escapedValue.length() - 1); + return; + } + } + } + + value = escapedValue; + } + + public String getValue() { + return value; + } + + public String getPrefix() { + return prefix; + } + + public String getNotExcapedValue() { + StringBuilder buffer = new StringBuilder(value); + int index = 0; + int deletesNum = 0; + while ((index = value.indexOf("''", index)) != -1) { + buffer.deleteCharAt(index - deletesNum); + index += 2; + deletesNum++; + } + return buffer.toString(); + } + + public void setValue(String string) { + value = string; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + @Override + public void accept(ExpressionVisitor expressionVisitor) { +// expressionVisitor.visit(this); + } + + @Override + public String toString() { + return (prefix != null ? prefix : "") + value; + } + + public StringValue withPrefix(String prefix) { + this.setPrefix(prefix); + return this; + } + + public StringValue withValue(String value) { + this.setValue(value); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + StringValue that = (StringValue) o; + return Objects.equals(value, that.value) && Objects.equals(prefix, that.prefix); + } + + @Override + public int hashCode() { + return Objects.hash(value, prefix); + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/service/BaseService.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/service/BaseService.java new file mode 100644 index 0000000..a590319 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/service/BaseService.java @@ -0,0 +1,14 @@ +package com.bdzl.framework.mybatis.service; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 基础服务接口,所有Service接口都要继承 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface BaseService extends IService { + + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/service/impl/BaseServiceImpl.java b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/service/impl/BaseServiceImpl.java new file mode 100644 index 0000000..68ccd29 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/mybatis/service/impl/BaseServiceImpl.java @@ -0,0 +1,111 @@ +package com.bdzl.framework.mybatis.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.query.Query; +import com.bdzl.framework.mybatis.interceptor.DataScope; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; + +import java.util.List; + + +/** + * 基础服务类,所有Service都要继承 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class BaseServiceImpl, T> extends ServiceImpl implements BaseService { + + /** + * 获取分页对象 + * + * @param query 分页参数 + */ + protected IPage getPage(Query query) { + Page page = new Page<>(query.getPage(), query.getLimit()); + + // 排序 + if (StringUtils.isNotBlank(query.getOrder())) { + if (query.isAsc()) { + return page.addOrder(OrderItem.asc(query.getOrder())); + } else { + return page.addOrder(OrderItem.desc(query.getOrder())); + } + } + + return page; + } + + /** + * MyBatis-Plus 数据权限 + */ + protected void dataScopeWrapper(LambdaQueryWrapper queryWrapper) { + DataScope dataScope = getDataScope(null, null); + if (dataScope != null) { + queryWrapper.apply(dataScope.getSqlFilter()); + } + } + + /** + * 原生SQL 数据权限 + * + * @param tableAlias 表别名,多表关联时,需要填写表别名 + * @param orgIdAlias 机构ID别名,null:表示org_id + * @return 返回数据权限 + */ + protected DataScope getDataScope(String tableAlias, String orgIdAlias) { + UserDetail user = SecurityUser.getUser(); + // 如果是超级管理员,则不进行数据过滤 + if (user.getSuperAdmin().equals(Constant.SUPER_ADMIN)) { + return null; + } + + // 如果为null,则设置成空字符串 + if (tableAlias == null) { + tableAlias = ""; + } + + // 获取表的别名 + if (StringUtils.isNotBlank(tableAlias)) { + tableAlias += "."; + } + + StringBuilder sqlFilter = new StringBuilder(); + sqlFilter.append(" ("); + + // 数据权限范围 + List dataScopeList = user.getDataScopeList(); + // 全部数据权限 + if (dataScopeList == null) { + return null; + } + // 数据过滤 + if (dataScopeList.size() > 0) { + if (StringUtils.isBlank(orgIdAlias)) { + orgIdAlias = "org_id"; + } + sqlFilter.append(tableAlias).append(orgIdAlias); + + sqlFilter.append(" in(").append(StrUtil.join(",", dataScopeList)).append(")"); + + sqlFilter.append(" or "); + } + + // 查询本人数据 + sqlFilter.append(tableAlias).append("creator").append("=").append(user.getId()); + + sqlFilter.append(")"); + + return new DataScope(sqlFilter.toString()); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/annotations/OperateLog.java b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/annotations/OperateLog.java new file mode 100644 index 0000000..a1ce033 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/annotations/OperateLog.java @@ -0,0 +1,33 @@ +package com.bdzl.framework.operatelog.annotations; + +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface OperateLog { + /** + * 模块名 + */ + String module() default ""; + + /** + * 操作名 + */ + String name() default ""; + + /** + * 操作类型 + */ + OperateTypeEnum[] type() default OperateTypeEnum.OTHER; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/aspect/OperateLogAspect.java b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/aspect/OperateLogAspect.java new file mode 100644 index 0000000..40c409d --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/aspect/OperateLogAspect.java @@ -0,0 +1,172 @@ +package com.bdzl.framework.operatelog.aspect; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.utils.HttpContextUtils; +import com.bdzl.framework.common.utils.IpUtils; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.dto.OperateLogDTO; +import com.bdzl.framework.operatelog.service.OperateLogService; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.IntStream; + +/** + * 操作日志,切面处理类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Aspect +@Component +@AllArgsConstructor +public class OperateLogAspect { + private final OperateLogService operateLogService; + + @Around("@annotation(operateLog)") + public Object around(ProceedingJoinPoint joinPoint, OperateLog operateLog) throws Throwable { + // 记录开始时间 + LocalDateTime startTime = LocalDateTime.now(); + try { + //执行方法 + Object result = joinPoint.proceed(); + + //保存日志 + saveLog(joinPoint, operateLog, startTime, Constant.SUCCESS); + + return result; + } catch (Exception e) { + //保存日志 + saveLog(joinPoint, operateLog, startTime, Constant.FAIL); + throw e; + } + } + + + private void saveLog(ProceedingJoinPoint joinPoint, OperateLog operateLog, LocalDateTime startTime, Integer status) { + OperateLogDTO log = new OperateLogDTO(); + + // 执行时长 + long duration = LocalDateTimeUtil.between(startTime, LocalDateTime.now()).toMillis(); + log.setDuration((int) duration); + // 用户信息 + UserDetail user = SecurityUser.getUser(); + if (user != null) { + log.setUserId(user.getId()); + log.setRealName(user.getRealName()); + log.setTenantId(user.getTenantId()); + } + // 操作类型 + log.setOperateType(operateLog.type()[0].getValue()); + // 设置module值 + log.setModule(operateLog.module()); + // 设置name值 + log.setName(operateLog.name()); + + // 如果没有指定module值,则从tag读取 + if (StrUtil.isBlank(log.getModule())) { + Tag tag = getClassAnnotation(joinPoint, Tag.class); + if (tag != null) { + log.setModule(tag.name()); + } + } + + // 如果没有指定name值,则从operation读取 + if (StrUtil.isBlank(log.getName())) { + Operation operation = getMethodAnnotation(joinPoint, Operation.class); + if (operation != null) { + log.setName(operation.summary()); + } + } + + // 请求相关 + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + if (request != null) { + log.setIp(IpUtils.getIpAddr(request)); + log.setAddress(IpUtils.getAddressByIP(log.getIp())); + log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT)); + log.setReqUri(request.getServletPath()); + log.setReqMethod(request.getMethod()); + } + + log.setReqParams(obtainMethodArgs(joinPoint)); + log.setStatus(status); + + + // 保存操作日志 + operateLogService.saveLog(log); + } + + private String obtainMethodArgs(ProceedingJoinPoint joinPoint) { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + String[] argNames = methodSignature.getParameterNames(); + Object[] argValues = joinPoint.getArgs(); + + // 拼接参数 + Map args = MapUtil.newHashMap(argValues.length); + for (int i = 0; i < argNames.length; i++) { + String argName = argNames[i]; + Object argValue = argValues[i]; + args.put(argName, ignoreArgs(argValue) ? "[ignore]" : argValue); + } + + return JsonUtils.toJsonString(args); + } + + private static boolean ignoreArgs(Object object) { + Class clazz = object.getClass(); + + // 处理数组 + if (clazz.isArray()) { + return IntStream.range(0, Array.getLength(object)) + .anyMatch(index -> ignoreArgs(Array.get(object, index))); + } + + // 处理集合 + if (Collection.class.isAssignableFrom(clazz)) { + return ((Collection) object).stream() + .anyMatch((Predicate) OperateLogAspect::ignoreArgs); + } + + // 处理Map + if (Map.class.isAssignableFrom(clazz)) { + return ignoreArgs(((Map) object).values()); + } + + return object instanceof MultipartFile + || object instanceof HttpServletRequest + || object instanceof HttpServletResponse + || object instanceof BindingResult; + } + + private static T getMethodAnnotation(ProceedingJoinPoint joinPoint, Class annotationClass) { + return ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(annotationClass); + } + + private static T getClassAnnotation(ProceedingJoinPoint joinPoint, Class annotationClass) { + return ((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaringClass().getAnnotation(annotationClass); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/dto/OperateLogDTO.java b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/dto/OperateLogDTO.java new file mode 100644 index 0000000..aa8a3d2 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/dto/OperateLogDTO.java @@ -0,0 +1,88 @@ +package com.bdzl.framework.operatelog.dto; + + +import lombok.Data; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class OperateLogDTO { + /** + * 用户ID + */ + private Long userId; + + /** + * 操作人 + */ + private String realName; + + /** + * 模块名 + */ + private String module; + + /** + * 操作名 + */ + private String name; + + /** + * 请求URI + */ + private String reqUri; + + /** + * 请求方法 + */ + private String reqMethod; + + /** + * 请求参数 + */ + private String reqParams; + + /** + * 操作IP + */ + private String ip; + + /** + * 登录地点 + */ + private String address; + + /** + * User Agent + */ + private String userAgent; + + /** + * 操作类型 + */ + private Integer operateType; + + /** + * 执行时长 + */ + private Integer duration; + + /** + * 操作状态 + */ + private Integer status; + + /** + * 返回消息 + */ + private String resultMsg; + + /** + * 租户ID + */ + private Long tenantId; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/enums/OperateTypeEnum.java b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/enums/OperateTypeEnum.java new file mode 100644 index 0000000..e25370d --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/enums/OperateTypeEnum.java @@ -0,0 +1,45 @@ +package com.bdzl.framework.operatelog.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 操作类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum OperateTypeEnum { + /** + * 查询 + */ + GET(1), + /** + * 新增 + */ + INSERT(2), + /** + * 修改 + */ + UPDATE(3), + /** + * 删除 + */ + DELETE(4), + /** + * 导出 + */ + EXPORT(5), + /** + * 导入 + */ + IMPORT(6), + /** + * 其它 + */ + OTHER(0); + + private final int value; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/service/OperateLogService.java b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/service/OperateLogService.java new file mode 100644 index 0000000..72cf3ae --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/operatelog/service/OperateLogService.java @@ -0,0 +1,28 @@ +package com.bdzl.framework.operatelog.service; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import com.bdzl.framework.common.cache.RedisKeys; +import com.bdzl.framework.operatelog.dto.OperateLogDTO; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +/** + * 操作日志服务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class OperateLogService { + private final RedisCache redisCache; + + @Async + public void saveLog(OperateLogDTO log) { + String key = RedisKeys.getLogKey(); + + // 保存到Redis队列 + redisCache.leftPush(key, log, RedisCache.NOT_EXPIRE); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/cache/TokenStoreCache.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/cache/TokenStoreCache.java new file mode 100644 index 0000000..c782105 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/cache/TokenStoreCache.java @@ -0,0 +1,64 @@ +package com.bdzl.framework.security.cache; + +import cn.hutool.core.collection.ListUtil; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import com.bdzl.framework.common.cache.RedisKeys; +import com.bdzl.framework.security.properties.SecurityProperties; +import com.bdzl.framework.security.user.UserDetail; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +/** + * 认证 Cache + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +@AllArgsConstructor +public class TokenStoreCache { + private final RedisCache redisCache; + private final SecurityProperties securityProperties; + + public void saveUser(String accessToken, UserDetail user) { + String key = RedisKeys.getAccessTokenKey(accessToken); + redisCache.set(key, user, securityProperties.getAccessTokenExpire()); + } + + public void saveUser(String accessToken, UserDetail user, long expire) { + String key = RedisKeys.getAccessTokenKey(accessToken); + redisCache.set(key, user, expire); + } + + public void updateUser(String accessToken, UserDetail user) { + String key = RedisKeys.getAccessTokenKey(accessToken); + Long expire = redisCache.getExpire(key); + redisCache.set(key, user, expire); + } + + public Long getExpire(String accessToken) { + String key = RedisKeys.getAccessTokenKey(accessToken); + + return redisCache.getExpire(key); + } + + public UserDetail getUser(String accessToken) { + String key = RedisKeys.getAccessTokenKey(accessToken); + return (UserDetail) redisCache.get(key); + } + + public void deleteUser(String accessToken) { + String key = RedisKeys.getAccessTokenKey(accessToken); + redisCache.delete(key); + } + + public List getUserKeyList() { + String pattern = RedisKeys.getAccessTokenKey("*"); + Set sets = redisCache.keys(pattern); + + return ListUtil.toList(sets); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/PasswordConfig.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/PasswordConfig.java new file mode 100644 index 0000000..bffd5b2 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/PasswordConfig.java @@ -0,0 +1,24 @@ +package com.bdzl.framework.security.config; + +import com.bdzl.framework.security.crypto.Sm3PasswordEncoder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 加密配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +public class PasswordConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + // 使用国密SM3加密 + return new Sm3PasswordEncoder(); + + // return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/PermitResource.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/PermitResource.java new file mode 100644 index 0000000..b92f57f --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/PermitResource.java @@ -0,0 +1,60 @@ +package com.bdzl.framework.security.config; + +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * 允许访问的资源 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +public class PermitResource { + /** + * 指定被 spring security 忽略的URL + */ + @SneakyThrows + public List getPermitList() { + ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + Resource[] resources = resolver.getResources("classpath*:auth.yml"); + String key = "auth.ignore_urls"; + + return getPropertiesList(key, resources); + } + + private List getPropertiesList(String key, Resource... resources) { + List list = new ArrayList<>(); + + // 解析资源文件 + for (Resource resource : resources) { + Properties properties = loadYamlProperties(resource); + + for (Map.Entry entry : properties.entrySet()) { + String tmpKey = StringUtils.substringBefore(entry.getKey().toString(), "["); + if (tmpKey.equalsIgnoreCase(key)) { + list.add(entry.getValue().toString()); + } + } + } + return list; + } + + private Properties loadYamlProperties(Resource... resources) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resources); + factory.afterPropertiesSet(); + + return factory.getObject(); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/SecurityFilterConfig.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/SecurityFilterConfig.java new file mode 100644 index 0000000..bb5d765 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/config/SecurityFilterConfig.java @@ -0,0 +1,56 @@ +package com.bdzl.framework.security.config; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.security.exception.SecurityAuthenticationEntryPoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.util.List; + +/** + * Spring SecurityFilter 配置文件 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +@AllArgsConstructor +@EnableWebSecurity +@EnableMethodSecurity +public class SecurityFilterConfig { + private final OncePerRequestFilter authenticationTokenFilter; + private final PermitResource permitResource; + + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // 忽略授权的地址列表 + List permitList = permitResource.getPermitList(); + String[] permits = permitList.toArray(new String[0]); + + http + .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + .requestMatchers(permits).permitAll() + .requestMatchers(HttpMethod.OPTIONS).permitAll() + .anyRequest().authenticated() + ) + .exceptionHandling(exception -> exception.authenticationEntryPoint(new SecurityAuthenticationEntryPoint())) + .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) + .csrf(AbstractHttpConfigurer::disable) + ; + + return http.build(); + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/crypto/Sm2Util.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/crypto/Sm2Util.java new file mode 100644 index 0000000..e9b4d6f --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/crypto/Sm2Util.java @@ -0,0 +1,84 @@ +package com.bdzl.framework.security.crypto; + +import cn.hutool.core.util.HexUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.SM2; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.util.encoders.Hex; + +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * 国密SM2加密算法 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class Sm2Util { + /** + * 公钥 + */ + private final static String PUBLIC_KEY = "3059301306072a8648ce3d020106082a811ccf5501822d034200040a302b5e4b961afb3908a4ae191266ac5866be100fc52e3b8dba9707c8620e64ae790ceffc3bfbf262dc098d293dd3e303356cb91b54861c767997799d2f0060"; + /** + * 私钥 + */ + private final static String PRIVATE_KEY = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420d7840173df3d6cd72cad4040dfc7dbfcde539f5b490b54f3cd5c4125544b38aea00a06082a811ccf5501822da144034200040a302b5e4b961afb3908a4ae191266ac5866be100fc52e3b8dba9707c8620e64ae790ceffc3bfbf262dc098d293dd3e303356cb91b54861c767997799d2f0060"; + + private final static SM2 sm2; + + static { + sm2 = SmUtil.sm2(PRIVATE_KEY, PUBLIC_KEY); + } + + /** + * 加密 + * + * @param data 明文 + * @return 加密后的密文 + */ + public static String encrypt(String data) { + return sm2.encryptBase64(data, KeyType.PublicKey); + } + + /** + * 解密 + * + * @param data 加密后的密文 + * @return 解密后的明文 + */ + public static String decrypt(String data) { + return sm2.decryptStr(data, KeyType.PrivateKey); + } + + public static void main(String[] args) { + KeyPair keyPair = SecureUtil.generateKeyPair("SM2"); + System.out.println("privateKey:" + HexUtil.encodeHexStr(keyPair.getPrivate().getEncoded())); + System.out.println("publicKey:" + HexUtil.encodeHexStr(keyPair.getPublic().getEncoded())); + + PublicKey publicKey = keyPair.getPublic(); + if (publicKey instanceof BCECPublicKey) { + // 获取65字节非压缩缩的十六进制公钥串(0x04) + String publicKeyHex = Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false)); + System.out.println("SM2公钥:" + publicKeyHex); + } + PrivateKey privateKey = keyPair.getPrivate(); + if (privateKey instanceof BCECPrivateKey) { + // 获取32字节十六进制私钥串 + String privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16); + System.out.println("SM2私钥:" + privateKeyHex); + } + + String password = "admin"; + String sm2Password = Sm2Util.encrypt(password); + System.out.println("sm2 加密:" + sm2Password); + System.out.println("sm2 解密:" + Sm2Util.decrypt(sm2Password)); + + + System.out.println("sm3 解密:" + SmUtil.sm3("admin")); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/crypto/Sm3PasswordEncoder.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/crypto/Sm3PasswordEncoder.java new file mode 100644 index 0000000..2644bad --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/crypto/Sm3PasswordEncoder.java @@ -0,0 +1,23 @@ +package com.bdzl.framework.security.crypto; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SmUtil; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 采用国密SM3加密算法,对系统密码进行加密 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class Sm3PasswordEncoder implements PasswordEncoder { + @Override + public String encode(CharSequence rawPassword) { + return SmUtil.sm3(rawPassword.toString()); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return StrUtil.equals(SmUtil.sm3(rawPassword.toString()), encodedPassword); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/exception/SecurityAuthenticationEntryPoint.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/exception/SecurityAuthenticationEntryPoint.java new file mode 100644 index 0000000..8229827 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/exception/SecurityAuthenticationEntryPoint.java @@ -0,0 +1,30 @@ +package com.bdzl.framework.security.exception; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import com.bdzl.framework.common.exception.ErrorCode; +import com.bdzl.framework.common.utils.HttpContextUtils; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.framework.common.utils.Result; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; + +import java.io.IOException; + +/** + * 匿名用户(token不存在、错误),异常处理器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.setContentType("application/json; charset=utf-8"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); + + response.getWriter().print(JsonUtils.toJsonString(Result.error(ErrorCode.UNAUTHORIZED))); + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/filter/AuthenticationTokenFilter.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/filter/AuthenticationTokenFilter.java new file mode 100644 index 0000000..5f9f75a --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/filter/AuthenticationTokenFilter.java @@ -0,0 +1,58 @@ +package com.bdzl.framework.security.filter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import com.bdzl.framework.security.cache.TokenStoreCache; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.framework.security.utils.TokenUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +/** + * 认证过滤器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +@AllArgsConstructor +public class AuthenticationTokenFilter extends OncePerRequestFilter { + private final TokenStoreCache tokenStoreCache; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + String accessToken = TokenUtils.getAccessToken(request); + // accessToken为空,表示未登录 + if (StringUtils.isBlank(accessToken)) { + chain.doFilter(request, response); + return; + } + + // 获取登录用户信息 + UserDetail user = tokenStoreCache.getUser(accessToken); + if (user == null) { + chain.doFilter(request, response); + return; + } + + // 用户存在 + Authentication authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); + + // 新建 SecurityContext + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(authentication); + SecurityContextHolder.setContext(context); + + chain.doFilter(request, response); + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileAuthenticationProvider.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileAuthenticationProvider.java new file mode 100644 index 0000000..99a30d7 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileAuthenticationProvider.java @@ -0,0 +1,88 @@ +package com.bdzl.framework.security.mobile; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.SpringSecurityMessageSource; +import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; +import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.util.Assert; + +/** + * 手机短信登录 AuthenticationProvider + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class MobileAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware { + protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); + private final MobileUserDetailsService mobileUserDetailsService; + private final MobileVerifyCodeService mobileVerifyCodeService; + + public MobileAuthenticationProvider(MobileUserDetailsService mobileUserDetailsService, MobileVerifyCodeService mobileVerifyCodeService) { + this.mobileUserDetailsService = mobileUserDetailsService; + this.mobileVerifyCodeService = mobileVerifyCodeService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + Assert.isInstanceOf(MobileAuthenticationToken.class, authentication, + () -> messages.getMessage( + "MobileAuthenticationProvider.onlySupports", + "Only MobileAuthenticationProvider is supported")); + + MobileAuthenticationToken authenticationToken = (MobileAuthenticationToken) authentication; + String mobile = authenticationToken.getName(); + String code = (String) authenticationToken.getCredentials(); + + try { + UserDetails userDetails = mobileUserDetailsService.loadUserByMobile(mobile); + if (userDetails == null) { + throw new BadCredentialsException("Bad credentials"); + } + + // 短信验证码效验 + if (mobileVerifyCodeService.verifyCode(mobile, code)) { + return createSuccessAuthentication(authentication, userDetails); + } else { + throw new BadCredentialsException("mobile code is not matched"); + } + } catch (UsernameNotFoundException ex) { + throw new BadCredentialsException(this.messages + .getMessage("MobileAuthenticationProvider.badCredentials", "Bad credentials")); + } + + } + + protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) { + MobileAuthenticationToken result = new MobileAuthenticationToken(user, null, + authoritiesMapper.mapAuthorities(user.getAuthorities())); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return MobileAuthenticationToken.class.isAssignableFrom(authentication); + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(mobileUserDetailsService, "mobileUserDetailsService must not be null"); + Assert.notNull(mobileVerifyCodeService, "mobileVerifyCodeService must not be null"); + } + + @Override + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileAuthenticationToken.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileAuthenticationToken.java new file mode 100644 index 0000000..36d28d1 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileAuthenticationToken.java @@ -0,0 +1,57 @@ +package com.bdzl.framework.security.mobile; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.SpringSecurityCoreVersion; +import org.springframework.util.Assert; + +import java.util.Collection; + +/** + * 手机短信登录 AuthenticationToken + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class MobileAuthenticationToken extends AbstractAuthenticationToken { + private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; + private final Object principal; + private String code; + + public MobileAuthenticationToken(Object principal, String code) { + super(null); + this.principal = principal; + this.code = code; + setAuthenticated(false); + } + + public MobileAuthenticationToken(Object principal, String code, Collection authorities) { + super(authorities); + this.principal = principal; + this.code = code; + super.setAuthenticated(true); + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + Assert.isTrue(!isAuthenticated, + "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); + super.setAuthenticated(false); + } + + @Override + public Object getCredentials() { + return this.code; + } + + @Override + public Object getPrincipal() { + return this.principal; + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + this.code = null; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileUserDetailsService.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileUserDetailsService.java new file mode 100644 index 0000000..22aae53 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileUserDetailsService.java @@ -0,0 +1,22 @@ +package com.bdzl.framework.security.mobile; + +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +/** + * 手机短信登录,UserDetailsService + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface MobileUserDetailsService { + + /** + * 通过手机号加载用户信息 + * + * @param mobile 手机号 + * @return 用户信息 + * @throws UsernameNotFoundException 不存在异常 + */ + UserDetails loadUserByMobile(String mobile) throws UsernameNotFoundException; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileVerifyCodeService.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileVerifyCodeService.java new file mode 100644 index 0000000..6e6bf18 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/mobile/MobileVerifyCodeService.java @@ -0,0 +1,12 @@ +package com.bdzl.framework.security.mobile; + +/** + * 手机短信登录,验证码效验 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface MobileVerifyCodeService { + + boolean verifyCode(String mobile, String code); +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/properties/SecurityProperties.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/properties/SecurityProperties.java new file mode 100644 index 0000000..21701b0 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/properties/SecurityProperties.java @@ -0,0 +1,25 @@ +package com.bdzl.framework.security.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 安全配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "maku.security") +public class SecurityProperties { + /** + * accessToken 过期时间(单位:秒),默认2小时 + */ + private int accessTokenExpire = 60 * 60 * 2; + /** + * refreshToken 过期时间(单位:秒),默认14天 + */ + private int refreshTokenExpire = 60 * 60 * 24 * 14; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdAuthenticationProvider.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdAuthenticationProvider.java new file mode 100644 index 0000000..8f4dd01 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdAuthenticationProvider.java @@ -0,0 +1,85 @@ +package com.bdzl.framework.security.third; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.SpringSecurityMessageSource; +import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; +import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.util.Assert; + +/** + * 第三方登录 AuthenticationProvider + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class ThirdAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware { + protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); + private final ThirdUserDetailsService thirdUserDetailsService; + private final ThirdOpenIdService thirdOpenIdService; + + public ThirdAuthenticationProvider(ThirdUserDetailsService thirdUserDetailsService, ThirdOpenIdService thirdOpenIdService) { + this.thirdUserDetailsService = thirdUserDetailsService; + this.thirdOpenIdService = thirdOpenIdService; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + Assert.isInstanceOf(ThirdAuthenticationToken.class, authentication, + () -> messages.getMessage( + "ThirdAuthenticationProvider.onlySupports", + "Only ThirdAuthenticationProvider is supported")); + + ThirdAuthenticationToken authenticationToken = (ThirdAuthenticationToken) authentication; + ThirdLogin login = (ThirdLogin) authenticationToken.getPrincipal(); + + try { + // 获取用户 openId + String openId = thirdOpenIdService.getOpenId(login); + // 获取用户信息 + UserDetails userDetails = thirdUserDetailsService.loadUserByOpenTypeAndOpenId(login.getOpenType(), openId); + if (userDetails == null) { + throw new BadCredentialsException("Bad credentials"); + } + + return createSuccessAuthentication(authentication, userDetails); + } catch (UsernameNotFoundException ex) { + throw new BadCredentialsException(this.messages + .getMessage("ThirdAuthenticationProvider.badCredentials", "Bad credentials")); + } + + } + + protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) { + ThirdAuthenticationToken result = new ThirdAuthenticationToken(user, + authoritiesMapper.mapAuthorities(user.getAuthorities())); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return ThirdAuthenticationToken.class.isAssignableFrom(authentication); + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(thirdUserDetailsService, "thirdUserDetailsService must not be null"); + Assert.notNull(thirdOpenIdService, "thirdOpenIdService must not be null"); + } + + @Override + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } + +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdAuthenticationToken.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdAuthenticationToken.java new file mode 100644 index 0000000..c3396cc --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdAuthenticationToken.java @@ -0,0 +1,55 @@ +package com.bdzl.framework.security.third; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.SpringSecurityCoreVersion; +import org.springframework.util.Assert; + +import java.util.Collection; + +/** + * 第三方登录 AuthenticationToken + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class ThirdAuthenticationToken extends AbstractAuthenticationToken { + private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; + private final Object principal; + private Object credentials; + + public ThirdAuthenticationToken(Object principal) { + super(null); + this.principal = principal; + setAuthenticated(false); + } + + public ThirdAuthenticationToken(Object principal, Collection authorities) { + super(authorities); + this.principal = principal; + super.setAuthenticated(true); + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + Assert.isTrue(!isAuthenticated, + "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); + super.setAuthenticated(false); + } + + @Override + public Object getCredentials() { + return this.credentials; + } + + @Override + public Object getPrincipal() { + return this.principal; + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + this.credentials = null; + } +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdLogin.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdLogin.java new file mode 100644 index 0000000..f50aad2 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdLogin.java @@ -0,0 +1,29 @@ +package com.bdzl.framework.security.third; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 第三方登录 表单数据 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class ThirdLogin implements Serializable { + /** + * 开放平台类型 + */ + private String openType; + + /** + * 开放平台Code + */ + private String code; + + /** + * state + */ + private String state; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdOpenIdService.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdOpenIdService.java new file mode 100644 index 0000000..078641e --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdOpenIdService.java @@ -0,0 +1,18 @@ +package com.bdzl.framework.security.third; + +/** + * 第三方登录,通过code,获取开放平台用户唯一标识 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface ThirdOpenIdService { + + /** + * 通过code,获取开放平台用户唯一标识 + * + * @param login 第三方登录信息 + * @return 开放平台用户唯一标识 + */ + String getOpenId(ThirdLogin login); +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdUserDetailsService.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdUserDetailsService.java new file mode 100644 index 0000000..787e626 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/third/ThirdUserDetailsService.java @@ -0,0 +1,23 @@ +package com.bdzl.framework.security.third; + +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +/** + * 第三方登录,ThirdUserDetailsService + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface ThirdUserDetailsService { + + /** + * 通过开放平台类型和唯一标识,加载用户信息 + * + * @param openType 开放平台类型 + * @param openId 开放平台唯一标识 + * @return 用户信息 + * @throws UsernameNotFoundException 不存在异常 + */ + UserDetails loadUserByOpenTypeAndOpenId(String openType, String openId) throws UsernameNotFoundException; +} diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/user/SecurityUser.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/user/SecurityUser.java new file mode 100644 index 0000000..1639a86 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/user/SecurityUser.java @@ -0,0 +1,51 @@ +package com.bdzl.framework.security.user; + +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * 用户 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class SecurityUser { + + /** + * 获取用户信息 + */ + public static UserDetail getUser() { + UserDetail user; + try { + user = (UserDetail) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } catch (Exception e) { + return null; + } + + return user; + } + + /** + * 获取用户ID + */ + public static Long getUserId() { + UserDetail user = getUser(); + if (user == null) { + return null; + } + + return user.getId(); + } + + /** + * 获取机构ID + */ + public static Long getOrgId() { + UserDetail user = getUser(); + if (user == null) { + return null; + } + + return user.getOrgId(); + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/user/UserDetail.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/user/UserDetail.java new file mode 100644 index 0000000..809a1c6 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/user/UserDetail.java @@ -0,0 +1,91 @@ +package com.bdzl.framework.security.user; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 登录用户信息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class UserDetail implements UserDetails { + private static final long serialVersionUID = 1L; + + private Long id; + private String username; + private String password; + private String realName; + private String avatar; + private Integer gender; + private String email; + private String mobile; + private Long orgId; + private Integer status; + private Integer superAdmin; + private Long tenantId; + private LocalDateTime createTime; + + /** + * 数据权限范围 + *

+ * null:表示全部数据权限 + */ + private List dataScopeList; + /** + * 帐户是否过期 + */ + private boolean isAccountNonExpired = true; + /** + * 帐户是否被锁定 + */ + private boolean isAccountNonLocked = true; + /** + * 密码是否过期 + */ + private boolean isCredentialsNonExpired = true; + /** + * 帐户是否可用 + */ + private boolean isEnabled = true; + /** + * 拥有权限集合 + */ + private Set authoritySet; + + @Override + @JsonIgnore + public Collection getAuthorities() { + return authoritySet.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet()); + } + + @Override + public boolean isAccountNonExpired() { + return this.isAccountNonExpired; + } + + @Override + public boolean isAccountNonLocked() { + return this.isAccountNonLocked; + } + + @Override + public boolean isCredentialsNonExpired() { + return this.isCredentialsNonExpired; + } + + @Override + public boolean isEnabled() { + return this.isEnabled; + } +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/utils/PreAuthorizeUtil.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/utils/PreAuthorizeUtil.java new file mode 100644 index 0000000..7391f30 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/utils/PreAuthorizeUtil.java @@ -0,0 +1,53 @@ +package com.bdzl.framework.security.utils; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * SpringSecurity @PreAuthorize 注解 权限标识 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class PreAuthorizeUtil { + + /** + * 获取 @PreAuthorize 注解的权限标识列表 + * + * @return 权限标识列表 + */ + public static List getPreAuthorizeList() { + List authorities = new ArrayList<>(); + ApplicationContext context = SpringUtil.getApplicationContext(); + String[] beanNames = context.getBeanNamesForAnnotation(Controller.class); + for (String beanName : beanNames) { + Object bean = context.getBean(beanName); + Method[] methods = bean.getClass().getDeclaredMethods(); + for (Method method : methods) { + PreAuthorize preAuthorize = AnnotationUtils.findAnnotation(method, PreAuthorize.class); + if (preAuthorize != null) { + String value = preAuthorize.value(); + // 使用正则表达式提取权限字符串 + Pattern pattern = Pattern.compile("hasAuthority\\('([^']*)'\\)"); + Matcher matcher = pattern.matcher(value); + while (matcher.find()) { + String authority = matcher.group(1); + authorities.add(authority); + } + } + } + } + + return authorities; + } + +} \ No newline at end of file diff --git a/drone-ops-framework/src/main/java/com/bdzl/framework/security/utils/TokenUtils.java b/drone-ops-framework/src/main/java/com/bdzl/framework/security/utils/TokenUtils.java new file mode 100644 index 0000000..9d9e692 --- /dev/null +++ b/drone-ops-framework/src/main/java/com/bdzl/framework/security/utils/TokenUtils.java @@ -0,0 +1,46 @@ +package com.bdzl.framework.security.utils; + +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; +import com.bdzl.framework.common.utils.HttpContextUtils; + +/** + * Token 工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class TokenUtils { + + /** + * 生成 AccessToken + */ + public static String generator() { + return UUID.fastUUID().toString(true); + } + + /** + * 获取 AccessToken + */ + public static String getAccessToken() { + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + if (request == null) { + return null; + } + + return getAccessToken(request); + } + + /** + * 获取 AccessToken + */ + public static String getAccessToken(HttpServletRequest request) { + String accessToken = request.getHeader("Authorization"); + if (StrUtil.isBlank(accessToken)) { + accessToken = request.getParameter("access_token"); + } + + return accessToken; + } +} diff --git a/drone-ops-framework/src/main/resources/auth.yml b/drone-ops-framework/src/main/resources/auth.yml new file mode 100644 index 0000000..12dbb99 --- /dev/null +++ b/drone-ops-framework/src/main/resources/auth.yml @@ -0,0 +1,11 @@ +auth: + ignore_urls: + - /actuator/** + - /v3/api-docs/** + - /webjars/** + - /swagger/** + - /swagger-resources/** + - /swagger-ui.html + - /swagger-ui/** + - /doc.html + - / \ No newline at end of file diff --git a/drone-ops-framework/src/main/resources/ip2region.xdb b/drone-ops-framework/src/main/resources/ip2region.xdb new file mode 100644 index 0000000..31f96a1 Binary files /dev/null and b/drone-ops-framework/src/main/resources/ip2region.xdb differ diff --git a/drone-ops-module/README.md b/drone-ops-module/README.md new file mode 100644 index 0000000..15ecbd0 --- /dev/null +++ b/drone-ops-module/README.md @@ -0,0 +1,21 @@ +## 说明 +drone-ops 是采用组件模式,扩展不同的业务功能,可以很方便的实现各种业务需求,且不会导致系统臃肿,若想使用某个组件,按需引入即可,反之亦然。 + +## 引入 +如果需要使用对应的组件,如:`drone-ops-quartz`,则需要在`drone-ops/drone-ops-server/pom.xml`里面引入,如下所示: + +```xml + + com.bdzl + drone-ops-quartz + ${revision} + +``` + +## SQL语句 +引入组件时,还需要执行对应的SQL文件,初始化表结构和菜单等。 +如果使用的是MySQL数据库,则需要执行以下SQL文件: + +``` +drone-ops/db/mysql/module/maku-module-quartz.sql +``` \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-generator/pom.xml b/drone-ops-module/drone-ops-module-generator/pom.xml new file mode 100644 index 0000000..d42c30e --- /dev/null +++ b/drone-ops-module/drone-ops-module-generator/pom.xml @@ -0,0 +1,20 @@ + + + com.bdzl + drone-ops-module + ${revision} + + 4.0.0 + drone-ops-module-generator + jar + + + + net.maku + maku-generator-pro-boot-starter + 1.3.2 + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-generator/src/main/resources/auth.yml b/drone-ops-module/drone-ops-module-generator/src/main/resources/auth.yml new file mode 100644 index 0000000..a3a6ad7 --- /dev/null +++ b/drone-ops-module/drone-ops-module-generator/src/main/resources/auth.yml @@ -0,0 +1,3 @@ +auth: + ignore_urls: + - /maku-generator/** \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/pom.xml b/drone-ops-module/drone-ops-module-iot/pom.xml new file mode 100644 index 0000000..12de0f1 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/pom.xml @@ -0,0 +1,59 @@ + + + com.bdzl + drone-ops-module + ${revision} + + 4.0.0 + drone-ops-module-iot + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + org.springframework.integration + spring-integration-mqtt + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + junit + junit + 4.13.2 + test + + + + + org.mockito + mockito-core + 4.0.0 + test + + + + org.mockito + mockito-junit-jupiter + 4.0.0 + test + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/BaseCommandResponseDTO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/BaseCommandResponseDTO.java new file mode 100644 index 0000000..f38c57e --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/BaseCommandResponseDTO.java @@ -0,0 +1,18 @@ +package com.bdzl.iot.communication.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 响应消息基础类 + * + * @author eden on 2024/6/17 + */ +@Data +public class BaseCommandResponseDTO extends BaseDeviceID { + /** + * 命令ID + */ + @Schema(description = "命令ID", required = true) + protected String commandId; +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/BaseDeviceID.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/BaseDeviceID.java new file mode 100644 index 0000000..2906e7a --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/BaseDeviceID.java @@ -0,0 +1,17 @@ +package com.bdzl.iot.communication.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 设备ID + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备ID") +public class BaseDeviceID { + + @Schema(description = "设备ID") + protected String deviceId; +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/CommandResponseChan.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/CommandResponseChan.java new file mode 100644 index 0000000..31908bf --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/CommandResponseChan.java @@ -0,0 +1,96 @@ +package com.bdzl.iot.communication.dto; + +import lombok.extern.slf4j.Slf4j; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * 数据生产消费者通道 + */ +@Slf4j +public class CommandResponseChan { + + // 存储通道的 ConcurrentHashMap + private static final ConcurrentHashMap CHANNEL = new ConcurrentHashMap<>(); + + private final CompletableFuture future = new CompletableFuture<>(); + + private final Long DEFAULT_WAIT_MILLISECONDS = 5 * 1000L; + + // 私有构造函数,不允许外部直接实例化 + private CommandResponseChan() { + } + + /** + * 获取或创建通道实例 + * + * @param commandId 通道标识 + * @param isNeedCreate 是否需要创建新的通道实例 + * @return 通道实例 + */ + public static CommandResponseChan getInstance(String commandId, boolean isNeedCreate) { + if (!isNeedCreate) { + return CHANNEL.get(commandId); + } + return CHANNEL.computeIfAbsent(commandId, k -> new CommandResponseChan()); + } + + /** + * 从通道中获取数据,默认超时时间为 5 秒 + * + * @param commandId 通道标识 + * @return 获取的数据,如果超时返回 null + */ + public BaseCommandResponseDTO get(String commandId) { + return get(commandId, DEFAULT_WAIT_MILLISECONDS); + } + + /** + * 从通道中获取数据,支持超时设置 + * + * @param commandId 通道标识 + * @param timeout 超时时间(毫秒) + * @return 获取的数据,如果超时返回 null + */ + public BaseCommandResponseDTO get(String commandId, long timeout) { + CommandResponseChan channel = CHANNEL.get(commandId); + if (Objects.isNull(channel)) { + return null; + } + try { + return channel.future.get(timeout, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + // 超时异常处理 + log.error("Device response timeout. {}", commandId); + return null; + } catch (Exception e) { + // 其他异常处理 + e.printStackTrace(); + return null; + } finally { + // 确保在获取数据后移除通道 + CHANNEL.remove(commandId, channel); + } + } + + /** + * 向通道中放入数据,并唤醒可能正在等待数据的线程 + * + * @param response 要放入的数据 + */ + public void put(BaseCommandResponseDTO response) { + String commandId = response.getCommandId(); + if (commandId == null) { + return; + } + CommandResponseChan channel = CHANNEL.get(commandId); + if (Objects.isNull(channel)) { + return; + } + channel.future.complete(response); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DeviceCommandDTO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DeviceCommandDTO.java new file mode 100644 index 0000000..4ff1ccb --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DeviceCommandDTO.java @@ -0,0 +1,32 @@ +package com.bdzl.iot.communication.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.iot.enums.DeviceCommandEnum; + +/** + * 设备命令对象 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备命令对象") +public class DeviceCommandDTO extends BaseDeviceID { + /** + * 命令类型 + */ + @Schema(description = "命令类型", required = true) + private DeviceCommandEnum command; + + /** + * 命令id + */ + @Schema(description = "命令id", required = true) + private String id; + + /** + * 命令内容 + */ + @Schema(description = "命令内容") + private String payload; +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DeviceCommandResponseDTO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DeviceCommandResponseDTO.java new file mode 100644 index 0000000..e9eb9dc --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DeviceCommandResponseDTO.java @@ -0,0 +1,41 @@ +package com.bdzl.iot.communication.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.iot.enums.DeviceCommandEnum; + +/** + * 设备命令响应DTO + * + * @author LSF maku_lsf@163.com + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Schema(description = "设备命令响应DTO") +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceCommandResponseDTO extends BaseCommandResponseDTO { + /** + * 命令类型 + */ + @Schema(description = "命令类型", required = true) + private DeviceCommandEnum command; + + /** + * 命令是否完成(默认true:命令已完成;false:命令未完成,后续命令完成将再次发送响应消息,服务端将继续等待该命令完成的响应) + */ + @Schema(description = "命令是否完成(默认true:命令已完成;false:命令未完成,后续命令完成将再次发送响应消息,服务端将继续等待该命令完成的响应)") + private boolean isCompleted = true; + + /** + * 响应状态码,0成功,其它数值异常,根据业务需要自定义 + */ + @Schema(description = "响应状态码,0成功,其它数值异常,根据业务需要自定义") + private Integer statusCode = 0; + /** + * 命令响应结果 + */ + @Schema(description = "命令响应结果") + private String responsePayload; +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DevicePropertyDTO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DevicePropertyDTO.java new file mode 100644 index 0000000..ea40482 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/DevicePropertyDTO.java @@ -0,0 +1,26 @@ +package com.bdzl.iot.communication.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.iot.enums.DevicePropertyEnum; + +/** + * 设备属性对象 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备属性对象") +public class DevicePropertyDTO extends BaseDeviceID { + /** + * 设备属性类型 + */ + @Schema(description = "设备属性类型") + private DevicePropertyEnum propertyType; + + /** + * 属性数据 + */ + @Schema(description = "状态数据,不同状态类型需传入相应的状态数据", required = true) + private String payload; +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/TcpMsgDTO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/TcpMsgDTO.java new file mode 100644 index 0000000..f1be5ae --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/dto/TcpMsgDTO.java @@ -0,0 +1,16 @@ +package com.bdzl.iot.communication.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * tcp通讯数据包 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "tcp通讯数据包装类") +public class TcpMsgDTO { + private String topic; + private Object msg; +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/MqttGateway.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/MqttGateway.java new file mode 100644 index 0000000..1b2b25e --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/MqttGateway.java @@ -0,0 +1,37 @@ +package com.bdzl.iot.communication.mqtt; + +import jakarta.annotation.Resource; +import com.bdzl.iot.communication.mqtt.config.MqttConfig; +import org.springframework.integration.annotation.MessagingGateway; +import org.springframework.integration.mqtt.support.MqttHeaders; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +/** + * MQTT网关 + * + * @author LSF maku_lsf@163.com + */ +@Component +@MessagingGateway(defaultRequestChannel = MqttConfig.OUTBOUND_CHANNEL) +public class MqttGateway { + @Resource + private MqttConfig mqttConfig; + + public void sendToMqtt(String payload) { + mqttConfig.mqttOutboundHandler().handleMessage(MessageBuilder.withPayload(payload).build()); + } + + public void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload) { + mqttConfig.mqttOutboundHandler().handleMessage(MessageBuilder.withPayload(payload).setHeader(MqttHeaders.TOPIC, topic).build()); + } + + public void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload) { + mqttConfig.mqttOutboundHandler().handleMessage(MessageBuilder.withPayload(payload).setHeader(MqttHeaders.TOPIC, topic).setHeader(MqttHeaders.QOS, qos).build()); + } + + public void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.RETAINED) boolean retained, String payload) { + mqttConfig.mqttOutboundHandler().handleMessage(MessageBuilder.withPayload(payload).setHeader(MqttHeaders.TOPIC, topic).setHeader(MqttHeaders.RETAINED, retained).build()); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/config/MqttConfig.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/config/MqttConfig.java new file mode 100644 index 0000000..4bf5a13 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/config/MqttConfig.java @@ -0,0 +1,159 @@ +package com.bdzl.iot.communication.mqtt.config; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.iot.communication.mqtt.factory.MqttMessageHandlerFactory; +import com.bdzl.iot.enums.DeviceTopicEnum; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.IntegrationComponentScan; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; +import org.springframework.integration.mqtt.core.MqttPahoClientFactory; +import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; +import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; +import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHandler; + +/** + * MQTT 配置类,用于设置和管理 MQTT 连接和消息处理。 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Slf4j +@Configuration +@IntegrationComponentScan +@ConfigurationProperties(prefix = "spring.mqtt") +public class MqttConfig { + public static final String OUTBOUND_CHANNEL = "mqttOutboundChannel"; + public static final String INPUT_CHANNEL = "mqttInputChannel"; + + // MQTT 用户名 + private String username; + + // MQTT 密码 + private String password; + + // MQTT 服务器 URL + private String host; + + // 客户端 ID + private String clientId; + + // 默认主题 + private String defaultTopic; + + // 处理 MQTT 消息的工厂 + @Resource + private MqttMessageHandlerFactory mqttMessageHandlerFactory; + + @PostConstruct + public void init() { + log.info("MQTT 主机: {} 客户端ID: {} 默认主题:{}", this.host, this.clientId, this.defaultTopic); + } + + /** + * 配置并返回一个 MqttPahoClientFactory 实例,用于创建 MQTT 客户端连接。 + * + * @return MqttPahoClientFactory + */ + @Bean + public MqttPahoClientFactory mqttClientFactory() { + // 设置连接选项,包括服务器 URI、用户名和密码。 + final MqttConnectOptions options = new MqttConnectOptions(); + options.setServerURIs(new String[]{host}); + options.setUserName(username); + options.setPassword(password.toCharArray()); + final DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); + factory.setConnectionOptions(options); + return factory; + } + + /** + * 创建一个用于发送 MQTT 消息的 MessageChannel。 + * + * @return MessageChannel + */ + @Bean(OUTBOUND_CHANNEL) + public MessageChannel mqttOutboundChannel() { + return new DirectChannel(); + } + + /** + * 配置用于发送 MQTT 消息的 MessageHandler。 + * + * @return MessageHandler + */ + @Bean + @ServiceActivator(inputChannel = OUTBOUND_CHANNEL) + public MessageHandler mqttOutboundHandler() { + // 使用 MqttPahoMessageHandler 创建一个新的 MQTT 客户端连接,用于发布消息。 + final MqttPahoMessageHandler handler = new MqttPahoMessageHandler(clientId + "_pub", mqttClientFactory()); + handler.setDefaultQos(1); + handler.setDefaultRetained(false); + handler.setDefaultTopic(defaultTopic); + handler.setAsync(true); + return handler; + } + + /** + * 创建用于接收 MQTT 消息的 MessageChannel。 + * + * @return MessageChannel + */ + @Bean + public MessageChannel mqttInputChannel() { + return new DirectChannel(); + } + + /** + * 配置 客户端,订阅的主题, + * PROPERTY:设备属性上报主题, + * COMMAND_RESPONSE:下发指令执行结果主题 + * + * @return MqttPahoMessageDrivenChannelAdapter + */ + @Bean + public MqttPahoMessageDrivenChannelAdapter mqttInboundAdapter() { + final MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter( + clientId + "_sub", + mqttClientFactory(), DeviceTopicEnum.PROPERTY.getWildcard(), + DeviceTopicEnum.COMMAND_RESPONSE.getWildcard() + ); + adapter.setCompletionTimeout(15000); + adapter.setConverter(new DefaultPahoMessageConverter()); + adapter.setQos(1); + adapter.setOutputChannel(mqttInputChannel()); + return adapter; + } + + /** + * 通过通道获取数据并处理消息。 + * + * @return MessageHandler + */ + @Bean + @ServiceActivator(inputChannel = INPUT_CHANNEL) + public MessageHandler mqttMessageHandler() { + return message -> { + String topic = (String) message.getHeaders().get("mqtt_receivedTopic"); + if (topic != null) { + mqttMessageHandlerFactory.getHandlersForTopic(topic).forEach(handler -> { + if (log.isDebugEnabled()) { + log.debug("主题: {}, 消息内容: {}", topic, message.getPayload()); + } + handler.handle(topic, message.getPayload().toString()); + }); + } else { + log.warn("接收到主题为null的消息。"); + } + }; + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/DeviceCommandResponseHandlerFactory.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/DeviceCommandResponseHandlerFactory.java new file mode 100644 index 0000000..35249ca --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/DeviceCommandResponseHandlerFactory.java @@ -0,0 +1,41 @@ +package com.bdzl.iot.communication.mqtt.factory; + +import lombok.RequiredArgsConstructor; +import com.bdzl.iot.communication.mqtt.handler.DeviceCommandResponseHandler; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 设备命令响应处理器工厂,自动获取所有实现的handler实例 + * + * @author LSF maku_lsf@163.com + */ +@Component +@RequiredArgsConstructor +public class DeviceCommandResponseHandlerFactory { + private final ApplicationContext applicationContext; + + /** + * 所有设备命令响应handlers + */ + private List handlers; + + /** + * 获取设备命令响应handlers + * + * @return + */ + public List getHandlers() { + if (handlers != null) { + return handlers; + } + handlers = Collections.unmodifiableList( + new ArrayList<>(applicationContext.getBeansOfType( + DeviceCommandResponseHandler.class).values())); + return handlers; + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/DevicePropertyChangeHandlerFactory.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/DevicePropertyChangeHandlerFactory.java new file mode 100644 index 0000000..e8de043 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/DevicePropertyChangeHandlerFactory.java @@ -0,0 +1,41 @@ +package com.bdzl.iot.communication.mqtt.factory; + +import lombok.RequiredArgsConstructor; +import com.bdzl.iot.communication.mqtt.handler.DevicePropertyChangeHandler; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 设备运行状态变化处理器工厂,自动获取所有实现的handler实例 + * + * @author LSF maku_lsf@163.com + */ +@Component +@RequiredArgsConstructor +public class DevicePropertyChangeHandlerFactory { + private final ApplicationContext applicationContext; + + /** + * 所有设备运行属性变化handlers + */ + private List handlers; + + /** + * 获取设备运行状态变化handlers + * + * @return + */ + public List getHandlers() { + if (handlers != null) { + return handlers; + } + handlers = Collections.unmodifiableList( + new ArrayList<>(applicationContext.getBeansOfType( + DevicePropertyChangeHandler.class).values())); + return handlers; + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/MqttMessageHandlerFactory.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/MqttMessageHandlerFactory.java new file mode 100644 index 0000000..044462e --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/factory/MqttMessageHandlerFactory.java @@ -0,0 +1,47 @@ +package com.bdzl.iot.communication.mqtt.factory; + +import lombok.RequiredArgsConstructor; +import com.bdzl.iot.communication.mqtt.handler.MqttMessageHandler; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * MQTT消息处理器工厂,自动获取所有实现的处理器实例 + * + * @author LSF maku_lsf@163.com + */ +@Component +@RequiredArgsConstructor +public class MqttMessageHandlerFactory { + private final ApplicationContext applicationContext; + + /** + * 所有消息处理器 + */ + private List messageHandlers; + + private List loadHandlers() { + if (messageHandlers != null) { + return messageHandlers; + } + messageHandlers = new ArrayList<>(applicationContext.getBeansOfType(MqttMessageHandler.class).values()); + return messageHandlers; + } + + /** + * 获取与主题对应的处理器 + * + * @param topic 主题 + * @return 处理器列表 + */ + public List getHandlersForTopic(String topic) { + return Collections.unmodifiableList(loadHandlers().stream() + .filter(handler -> handler.supports(topic)) + .collect(Collectors.toList())); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DeviceCommandResponseHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DeviceCommandResponseHandler.java new file mode 100644 index 0000000..e6206ed --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DeviceCommandResponseHandler.java @@ -0,0 +1,19 @@ +package com.bdzl.iot.communication.mqtt.handler; + + +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; + +/** + * 设备命令响应处理器 + * + * @author LSF maku_lsf@163.com + */ +public interface DeviceCommandResponseHandler { + /** + * 设备命令响应处理 + * + * @param topic + * @param commandResponse + */ + void handle(String topic, DeviceCommandResponseDTO commandResponse); +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DeviceCommandResponseMqttMessageHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DeviceCommandResponseMqttMessageHandler.java new file mode 100644 index 0000000..c597ee0 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DeviceCommandResponseMqttMessageHandler.java @@ -0,0 +1,73 @@ +package com.bdzl.iot.communication.mqtt.handler; + +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.iot.communication.service.MQTTService; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; +import com.bdzl.iot.communication.mqtt.factory.DeviceCommandResponseHandlerFactory; +import com.bdzl.iot.enums.DeviceTopicEnum; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * 设备命令响应处理器 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class DeviceCommandResponseMqttMessageHandler implements MqttMessageHandler { + + private final DeviceCommandResponseHandlerFactory deviceCommandResponseHandlerFactory; + + private final MQTTService deviceMqttService; + + @Override + public boolean supports(String topic) { + return DeviceTopicEnum.startsWith(topic, DeviceTopicEnum.COMMAND_RESPONSE.getTopic()); + } + + @Override + public void handle(String topic, String message) { + DeviceCommandResponseDTO commandResponseDTO = parseCommandReplyMessage(topic, message); + Optional.ofNullable(commandResponseDTO.getCommand()) + .orElseThrow(() -> new IllegalArgumentException(StrUtil.format("缺失指令类型! 主题:'{}',消息:{}", topic, message))); + Optional.ofNullable(commandResponseDTO.getCommandId()) + .orElseThrow(() -> new IllegalArgumentException(StrUtil.format("缺失指令ID! 主题:'{}',消息:{}", topic, message))); + + Optional.ofNullable(commandResponseDTO) + .ifPresent(responseDTO -> { + // 调用设备命令执行器的命令响应处理逻辑 + try { + deviceMqttService.commandReplied( responseDTO); + } catch (Exception e) { + log.error(StrUtil.format("调用设备命令执行器响应处理方法出错,topic:{}, message:{}", topic, message), e); + } + // 调用自定义命令响应处理器 + try { + deviceCommandResponseHandlerFactory.getHandlers().forEach(h -> h.handle(topic, responseDTO)); + } catch (Exception e) { + log.error(StrUtil.format("调用设备命令响应响应处理器出错,topic:{}, message:{}", topic, message), e); + } + }); + } + + private DeviceCommandResponseDTO parseCommandReplyMessage(String topic, String message) { + try { + DeviceCommandResponseDTO commandResponse = JsonUtils.parseObject(message, DeviceCommandResponseDTO.class); + if (StrUtil.isBlank(commandResponse.getCommandId())) { + log.error(StrUtil.format("主题'{}'的消息,缺失指令ID", topic)); + return null; + } + return commandResponse; + + } catch (Exception e) { + log.error(StrUtil.format("将主题'{}'的消息解析为设备命令响应对象失败", topic), e); + return null; + } + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DevicePropertyChangeHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DevicePropertyChangeHandler.java new file mode 100644 index 0000000..3d1272c --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DevicePropertyChangeHandler.java @@ -0,0 +1,19 @@ +package com.bdzl.iot.communication.mqtt.handler; + + +import com.bdzl.iot.communication.dto.DevicePropertyDTO; + +/** + * 设备属性变化处理器 + * + * @author LSF maku_lsf@163.com + */ +public interface DevicePropertyChangeHandler { + /** + * 设备属性状态变化处理 + * + * @param topic + * @param deviceStatus + */ + void handle(String topic, DevicePropertyDTO deviceStatus); +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DevicePropertyMqttMessageHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DevicePropertyMqttMessageHandler.java new file mode 100644 index 0000000..2fbfce7 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/DevicePropertyMqttMessageHandler.java @@ -0,0 +1,49 @@ +package com.bdzl.iot.communication.mqtt.handler; + +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.iot.communication.dto.DevicePropertyDTO; +import com.bdzl.iot.communication.mqtt.factory.DevicePropertyChangeHandlerFactory; +import com.bdzl.iot.enums.DeviceTopicEnum; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * 设备属性上报消息处理器 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class DevicePropertyMqttMessageHandler implements MqttMessageHandler { + + private final DevicePropertyChangeHandlerFactory statusChangeHandlerFactory; + + @Override + public boolean supports(String topic) { + return DeviceTopicEnum.startsWith(topic, DeviceTopicEnum.PROPERTY.getTopic()); + } + + @Override + public void handle(String topic, String message) { + DevicePropertyDTO devicePropertyDTO = parseStatusMessage(topic, message); + Optional.ofNullable(devicePropertyDTO) + .ifPresent(deviceProperty -> statusChangeHandlerFactory.getHandlers() + .forEach(h -> h.handle(topic, deviceProperty))); + } + + private DevicePropertyDTO parseStatusMessage(String topic, String message) { + try { + return JsonUtils.parseObject(message, DevicePropertyDTO.class); + } catch (Exception e) { + log.error(StrUtil.format("将主题'{}'的消息解析为设备运行状态对象失败", topic), e); + return null; + } + } + + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/MqttMessageHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/MqttMessageHandler.java new file mode 100644 index 0000000..5d6433d --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/mqtt/handler/MqttMessageHandler.java @@ -0,0 +1,24 @@ +package com.bdzl.iot.communication.mqtt.handler; + +/** + * MQTT订阅消息处理接口 + * + * @author LSF maku_lsf@163.com + */ +public interface MqttMessageHandler { + /** + * 是否支持处理指定的topic + * + * @param topic + * @return + */ + boolean supports(String topic); + + /** + * mqtt消息处理接口 + * + * @param topic + * @param message + */ + void handle(String topic, String message); +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/BaseCommunication.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/BaseCommunication.java new file mode 100644 index 0000000..4d46a72 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/BaseCommunication.java @@ -0,0 +1,31 @@ +package com.bdzl.iot.communication.service; + +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.enums.DeviceCommandEnum; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; + + +/** + * 通信协议具备功能 + * + * @author LSF maku_lsf@163.com + */ +public interface BaseCommunication { + + // 异步发送指令,不等待设备响应 + String asyncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload); + + //同步发送指定,等待设备响应 + DeviceCommandResponseDTO syncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload); + + //同步发送指定,等待设备响应,调试实现 + DeviceCommandResponseDTO syncSendCommandDebug(IotDeviceEntity device, DeviceCommandEnum command, String payload); + + //模拟设备属性上报 + void simulateDeviceReportAttributeData(IotDeviceEntity device, String payload); + + //模拟设备服务指令响应数据 + void simulateDeviceCommandResponseAttributeData(IotDeviceEntity device, String payload); + + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/CommunicationServiceFactory.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/CommunicationServiceFactory.java new file mode 100644 index 0000000..7e65e25 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/CommunicationServiceFactory.java @@ -0,0 +1,36 @@ +package com.bdzl.iot.communication.service; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import org.springframework.stereotype.Service; + +/** + * 设备协议服务工厂 + * + * @author LSF maku_lsf@163.com + */ +@Service +@AllArgsConstructor +public class CommunicationServiceFactory { + + private final MQTTService mqttService; + private final TCPService tcpService; + + public BaseCommunication getProtocol(String protocolType) { + if (protocolType == null) { + new ServerException("协议不存在!"); + } + switch (protocolType) { + case "MQTT": + return mqttService; + case "TCP": + return tcpService; +// case "Modbus": +// return tcpService; + default: + return null; + } + } + + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/MQTTService.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/MQTTService.java new file mode 100644 index 0000000..518c2cd --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/MQTTService.java @@ -0,0 +1,195 @@ +package com.bdzl.iot.communication.service; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.iot.communication.dto.CommandResponseChan; +import com.bdzl.iot.communication.dto.DeviceCommandDTO; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; +import com.bdzl.iot.communication.mqtt.MqttGateway; +import com.bdzl.iot.dto.DeviceClientDTO; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.enums.DeviceCommandEnum; +import com.bdzl.iot.enums.DeviceTopicEnum; +import com.bdzl.iot.service.IotDeviceServiceLogService; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +/** + * MQTT协议服务类 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class MQTTService implements BaseCommunication { + + private final MqttGateway mqttGateway; + private final IotDeviceServiceLogService iotDeviceEventLogService; + + /** + * 异步发送命令,返回命令id + * + * @param device + * @param command + * @param payload + * @return + */ + @Override + public String asyncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload) { + return asyncSendCommand(device, command, payload, Boolean.FALSE); + } + + /** + * 异步发送命令,返回命令id + * + * @param device + * @param command + * @param payload + * @param retained + * @return + */ + public String asyncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload, boolean retained) { + // 构建命令对象 + String commandId = StrUtil.replaceChars(UUID.randomUUID().toString(), "-", ""); + DeviceCommandDTO commandDTO = new DeviceCommandDTO(); + commandDTO.setCommand(command); + commandDTO.setId(commandId); + commandDTO.setPayload(payload); + String commandTopic = DeviceTopicEnum.COMMAND.buildTopic(DeviceClientDTO.from(device)); + + // 发送命令到设备命令主题 + try { + mqttGateway.sendToMqtt(commandTopic, retained, JSONUtil.toJsonStr(commandDTO)); + } catch (Exception e) { + log.error(e.getMessage()); + throw new ServerException(StrUtil.format("发送'{}'命令:{} 到设备:{}-{}, Topic:{} 失败", + command.getTitle(), commandId, device.getCode(), device.getName(), commandTopic)); + } + log.info("发送'{}'命令:{} 到设备:{}-{}, Topic:{} 成功", command.getTitle(), commandId, device.getCode(), device.getName(), commandTopic); + iotDeviceEventLogService.createAndSaveDeviceServiceLog(device.getId(), device.getTenantId(), command, commandId, payload); + return commandId; + } + + /** + * 同步发送命令并返回响应结果 + * + * @param device + * @param command + * @param payload + * @return + */ + public DeviceCommandResponseDTO syncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload) { + return syncSendCommand(device, command, payload, Boolean.FALSE); + } + + /** + * 发送命令并返回响应结果 + * + * @param device + * @param command + * @param payload + * @param retained + * @return + */ + public DeviceCommandResponseDTO syncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload, boolean retained) { + // 构建并发送命令 + String commandId = asyncSendCommand(device, command, payload, retained); + // 等待返回结果 + Object receiver = CommandResponseChan.getInstance(commandId, true).get(commandId); + if (receiver == null) { + throw new ServerException(StrUtil.format("{}设备没有回复", device.getName())); + } + return (DeviceCommandResponseDTO) receiver; + } + + /** + * 发送命令并返回响应结果,模拟设备响应 + * + * @param device + * @param command + * @param payload + * @return + */ + public DeviceCommandResponseDTO syncSendCommandDebug(IotDeviceEntity device, DeviceCommandEnum command, String payload) { + // 构建并发送命令 + String commandId = asyncSendCommand(device, command, payload); + + // 2秒后模拟设备响应 + new Thread(() -> { + try { + //模拟设备正常响应 + Thread.sleep(2000); + //模拟设备超时响应 + //Thread.sleep(15000); + DeviceCommandResponseDTO simulateResponseDto = new DeviceCommandResponseDTO(); + simulateResponseDto.setCommandId(commandId); + simulateResponseDto.setResponsePayload(command.getTitle() + ",设备执行成功!"); + simulateResponseDto.setCommand(command); + simulateDeviceCommandResponseAttributeData(device, JSONUtil.toJsonStr(simulateResponseDto)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("模拟设备响应线程被中断", e); + } + }).start(); + + // 等待返回结果 + Object receiver = CommandResponseChan.getInstance(commandId, true).get(commandId); + if (receiver == null) { + throw new ServerException(StrUtil.format("{}设备没有回复", device.getName())); + } + return (DeviceCommandResponseDTO) receiver; + } + + /** + * 模拟设备属性上报 + */ + @Override + public void simulateDeviceReportAttributeData(IotDeviceEntity device, String payload) { + // 封装 设备属性上报的 topic + String commandTopic = DeviceTopicEnum.PROPERTY.buildTopic(DeviceClientDTO.from(device)); + try { + mqttGateway.sendToMqtt(commandTopic, payload); + } catch (Exception e) { + log.error(e.getMessage()); + throw new ServerException(StrUtil.format("模拟设备:{}-{},模拟属性上报失败! Topic:{} ", + device.getCode(), device.getName(), commandTopic)); + } + } + + + /** + * 模拟设备服务指令响应数据 + * + * @param device + * @param payload + */ + @Override + public void simulateDeviceCommandResponseAttributeData(IotDeviceEntity device, String payload) { + // 封装 设备命令执行结果的 topic + String commandTopic = DeviceTopicEnum.COMMAND_RESPONSE.buildTopic(DeviceClientDTO.from(device)); + try { + mqttGateway.sendToMqtt(commandTopic, payload); + } catch (Exception e) { + log.error(e.getMessage()); + throw new ServerException(StrUtil.format("模拟设备:{}-{},模拟命令执行结果上报失败! Topic:{} ", + device.getCode(), device.getName(), commandTopic)); + } + } + + /** + * 设备命令响应处理,把设备响应结果放入通道中 + * + * @param commandResponse 设备命令响应 + */ + public void commandReplied(DeviceCommandResponseDTO commandResponse) { + CommandResponseChan commandResponseChan = CommandResponseChan.getInstance(commandResponse.getCommandId(), false); + commandResponseChan.put(commandResponse); + } + + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/TCPService.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/TCPService.java new file mode 100644 index 0000000..781be1b --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/service/TCPService.java @@ -0,0 +1,139 @@ +package com.bdzl.iot.communication.service; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.iot.communication.dto.CommandResponseChan; +import com.bdzl.iot.communication.dto.DeviceCommandDTO; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; +import com.bdzl.iot.communication.dto.DevicePropertyDTO; +import com.bdzl.iot.communication.tcp.TcpGateway; +import com.bdzl.iot.dto.DeviceClientDTO; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.enums.DeviceCommandEnum; +import com.bdzl.iot.enums.DeviceTopicEnum; +import com.bdzl.iot.service.IotDeviceServiceLogService; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +/** + * TCP协议服务类 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class TCPService implements BaseCommunication { + + private final TcpGateway tcpGateway; + private final IotDeviceServiceLogService iotDeviceEventLogService; + + @Override + public String asyncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload) { + // 构建命令对象 + String commandId = StrUtil.replaceChars(UUID.randomUUID().toString(), "-", ""); + DeviceCommandDTO commandDTO = new DeviceCommandDTO(); + commandDTO.setCommand(command); + commandDTO.setId(commandId); + commandDTO.setDeviceId(String.valueOf(device.getId())); + commandDTO.setPayload(payload); + String commandTopic = DeviceTopicEnum.COMMAND.buildTopic(DeviceClientDTO.from(device)); + + // 发送命令到设备命令主题 + try { + tcpGateway.sendCommandToDevice(device.getId(),commandTopic, JSONUtil.toJsonStr(commandDTO)); + } catch (Exception e) { + log.error(e.getMessage()); + throw new ServerException(StrUtil.format("发送'{}'命令:{} 到设备:{}-{}, Topic:{} 失败,原因:{}", + command.getTitle(), commandId, device.getCode(), device.getName(), commandTopic,e.getMessage())); + } + log.info("发送'{}'命令:{} 到设备:{}-{}, Topic:{} 成功", command.getTitle(), commandId, device.getCode(), device.getName(), commandTopic); + iotDeviceEventLogService.createAndSaveDeviceServiceLog(device.getId(), device.getTenantId(), command, commandId, payload); + return commandId; + } + + @Override + public DeviceCommandResponseDTO syncSendCommand(IotDeviceEntity device, DeviceCommandEnum command, String payload) { + // 构建并发送命令 + String commandId = asyncSendCommand(device, command, payload); + // 等待返回结果 + Object receiver = CommandResponseChan.getInstance(commandId, true).get(commandId); + if (receiver == null) { + throw new ServerException(StrUtil.format("{}设备没有回复", device.getName())); + } + return (DeviceCommandResponseDTO) receiver; + } + + @Override + public DeviceCommandResponseDTO syncSendCommandDebug(IotDeviceEntity device, DeviceCommandEnum command, String payload) { + // 构建并发送命令 + String commandId = asyncSendCommand(device, command, payload); + + // 2秒后模拟设备响应 + new Thread(() -> { + try { + //模拟设备正常响应 + Thread.sleep(2000); + //模拟设备超时响应 + //Thread.sleep(15000); + DeviceCommandResponseDTO simulateResponseDto = new DeviceCommandResponseDTO(); + simulateResponseDto.setCommandId(commandId); + simulateResponseDto.setResponsePayload(command.getTitle() + ",设备执行成功!"); + simulateResponseDto.setDeviceId(String.valueOf(device.getId())); + simulateResponseDto.setCommand(command); + simulateDeviceCommandResponseAttributeData(device, JSONUtil.toJsonStr(simulateResponseDto)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("模拟设备响应线程被中断", e); + } + }).start(); + + // 等待返回结果 + Object receiver = CommandResponseChan.getInstance(commandId, true).get(commandId); + if (receiver == null) { + throw new ServerException(StrUtil.format("{}设备没有回复", device.getName())); + } + return (DeviceCommandResponseDTO) receiver; + } + + @Override + public void simulateDeviceReportAttributeData(IotDeviceEntity device, String payload) { + // 封装 设备属性上报的 topic + String commandTopic = DeviceTopicEnum.PROPERTY.buildTopic(DeviceClientDTO.from(device)); + try { + tcpGateway.simulateDeviceReport(device.getId(), commandTopic, payload, DevicePropertyDTO.class); + } catch (Exception e) { + log.error(e.getMessage()); + throw new ServerException(StrUtil.format("模拟设备:{}-{},模拟属性上报失败! Topic:{} ", + device.getCode(), device.getName(), commandTopic)); + } + } + + @Override + public void simulateDeviceCommandResponseAttributeData(IotDeviceEntity device, String payload) { + // 封装 设备命令执行结果的 topic + String commandTopic = DeviceTopicEnum.COMMAND_RESPONSE.buildTopic(DeviceClientDTO.from(device)); + try { + tcpGateway.simulateDeviceReport(device.getId(), commandTopic, payload, DeviceCommandResponseDTO.class); + } catch (Exception e) { + log.error(e.getMessage()); + throw new ServerException(StrUtil.format("模拟设备:{}-{},模拟命令执行结果上报失败! Topic:{} ", + device.getCode(), device.getName(), commandTopic)); + } + } + + + /** + * 设备命令响应处理,把设备响应结果放入通道中 + * + * @param commandResponse 设备命令响应 + */ + public void commandReplied(DeviceCommandResponseDTO commandResponse) { + CommandResponseChan commandResponseChan = CommandResponseChan.getInstance(commandResponse.getCommandId(), false); + commandResponseChan.put(commandResponse); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/TcpGateway.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/TcpGateway.java new file mode 100644 index 0000000..9143656 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/TcpGateway.java @@ -0,0 +1,74 @@ +package com.bdzl.iot.communication.tcp; + +import io.netty.channel.Channel; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.iot.communication.dto.DeviceCommandDTO; +import com.bdzl.iot.communication.dto.TcpMsgDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.ConcurrentMap; + +/** + * TCP 网关 + * + * @author LSF maku_lsf@163.com + */ +@Component +@Slf4j +public class TcpGateway { + + @Autowired + private final ConcurrentMap deviceChannels; + + @Autowired + public TcpGateway(ConcurrentMap deviceChannels) { + this.deviceChannels = deviceChannels; + } + + /** + * 发送命令到设备 + * @param deviceId 设备ID + * @param commandTopic 命令主题 + * @param payload 命令内容 + */ + public void sendCommandToDevice(Long deviceId, String commandTopic, String payload) { + Channel channel = deviceChannels.get(deviceId.toString()); + if (channel != null && channel.isActive()) { + TcpMsgDTO tcpMsgDTO = new TcpMsgDTO(); + tcpMsgDTO.setTopic(commandTopic); + DeviceCommandDTO deviceCommandDTO = JsonUtils.parseObject(payload, DeviceCommandDTO.class); + deviceCommandDTO.setDeviceId(deviceId.toString()); + tcpMsgDTO.setMsg(deviceCommandDTO); + + String commandJson = JsonUtils.toJsonString(tcpMsgDTO); +// channel.writeAndFlush(commandJson); + log.info("发送命令到设备 {}: {}", deviceId, payload); + } else { + throw new ServerException("设备"+deviceId+"不在线或通道无效"); + } + } + + public void simulateDeviceReport(Long deviceId, String commandTopic, String payload, Class reportDtoclazz) { + Channel channel = deviceChannels.get(deviceId.toString()); + if (channel != null && channel.isActive()) { + try { + TcpMsgDTO tcpMsgDTO = new TcpMsgDTO(); + tcpMsgDTO.setTopic(commandTopic); + tcpMsgDTO.setMsg(JsonUtils.parseObject(payload, reportDtoclazz)); + String devicePropertyJson = JsonUtils.toJsonString(tcpMsgDTO); + // 模拟上报,触发 channelRead 处理 + channel.pipeline().fireChannelRead(devicePropertyJson); + log.info("模拟设备 {} 上报数据: {}", deviceId, devicePropertyJson); + } catch (Exception e) { + log.error("模拟设备上报数据时出现错误", e); + } + } else { + throw new ServerException("设备 " + deviceId + " 不在线或通道无效"); + } + } + + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/DeviceClientStartupConfig.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/DeviceClientStartupConfig.java new file mode 100644 index 0000000..32c4a43 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/DeviceClientStartupConfig.java @@ -0,0 +1,41 @@ +package com.bdzl.iot.communication.tcp.config; + +import io.netty.bootstrap.Bootstrap; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; + +/** + * Netty启动顺序配置 + * + * @author LSF maku_lsf@163.com + */ +@Configuration +@Slf4j +public class DeviceClientStartupConfig implements ApplicationListener { + + private final ObjectProvider deviceClientProvider; + private final DeviceEmulatorConfig deviceEmulatorConfig; + + public DeviceClientStartupConfig(ObjectProvider deviceClientProvider, DeviceEmulatorConfig deviceEmulatorConfig) { + this.deviceClientProvider = deviceClientProvider; + this.deviceEmulatorConfig = deviceEmulatorConfig; + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + try { + Thread.sleep(5000); // 延迟5秒以确保服务器启动 + Bootstrap deviceClientBootstrap = deviceClientProvider.getIfAvailable(); + if (deviceClientBootstrap != null) { + deviceEmulatorConfig.configureBootstrap(deviceClientBootstrap); + deviceClientBootstrap.connect("127.0.0.1", 8888).sync(); + log.info("Connected to Netty server on port 8888"); + } + } catch (InterruptedException e) { + log.error("Failed to connect to Netty server", e); + } + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/DeviceEmulatorConfig.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/DeviceEmulatorConfig.java new file mode 100644 index 0000000..7503b98 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/DeviceEmulatorConfig.java @@ -0,0 +1,97 @@ +package com.bdzl.iot.communication.tcp.config; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.iot.communication.dto.DevicePropertyDTO; +import com.bdzl.iot.communication.dto.TcpMsgDTO; +import com.bdzl.iot.dto.DeviceClientDTO; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.enums.DevicePropertyEnum; +import com.bdzl.iot.enums.DeviceRunningStatusEnum; +import com.bdzl.iot.enums.DeviceTopicEnum; +import com.bdzl.iot.service.IotDeviceService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 设备模拟器配置,用于启动模拟设备,方便调试,默认启动系统所有的TCP设备 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Configuration +public class DeviceEmulatorConfig { + + @Autowired + private IotDeviceService deviceService; + + @Bean + public Bootstrap nettyClient() { + Bootstrap nettyClient = new Bootstrap(); + nettyClient.group(new NioEventLoopGroup()) + .channel(NioSocketChannel.class) + .option(ChannelOption.SO_KEEPALIVE, true) // 设置为长连接 + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60*1000); // 设置连接超时时间 + return nettyClient; + } + + public void configureBootstrap(Bootstrap bootstrap) { + List devices = deviceService.list(new LambdaQueryWrapper().eq(IotDeviceEntity::getProtocolType, "TCP")); + for (IotDeviceEntity device : devices) { + bootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new StringDecoder(), new StringEncoder(), new SimpleChannelInboundHandler() { + @Override + public void channelActive(ChannelHandlerContext ctx) { + //模拟设备认证 + Map authenticateMap = new HashMap(); + authenticateMap.put("authenticate", device.getId().toString()); + String authenticateMapJson = JsonUtils.toJsonString(authenticateMap); + log.info("------------------------> 发送认证信息到服务端: {}", authenticateMapJson); + ctx.writeAndFlush(authenticateMapJson); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, String msg) { + log.info("设备 {} 接收到服务端消息: {}", device.getId(), msg); + //模拟属性上报 + if(msg.contains("authenticate passed")){ + String commandTopic = DeviceTopicEnum.PROPERTY.buildTopic(DeviceClientDTO.from(device)); + + DevicePropertyDTO devicePropertyDTO = new DevicePropertyDTO(); + devicePropertyDTO.setDeviceId(device.getId().toString()); + devicePropertyDTO.setPropertyType(DevicePropertyEnum.RUNNING_STATUS); + devicePropertyDTO.setPayload(String.valueOf(DeviceRunningStatusEnum.ONLINE.getValue())); + + TcpMsgDTO tcpMsgDTO = new TcpMsgDTO(); + tcpMsgDTO.setTopic(commandTopic); + tcpMsgDTO.setMsg(devicePropertyDTO); + + String runningStatusjson = JsonUtils.toJsonString(tcpMsgDTO); + log.info("------------------------> 设备发送上线文本:{}",runningStatusjson); + ctx.writeAndFlush(runningStatusjson); + } + } + }); + } + }); + } + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/NettyServerConfig.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/NettyServerConfig.java new file mode 100644 index 0000000..ae8469c --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/config/NettyServerConfig.java @@ -0,0 +1,72 @@ +package com.bdzl.iot.communication.tcp.config; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.iot.communication.tcp.factory.TcpMessageHandlerFactory; +import com.bdzl.iot.communication.tcp.handler.ConnectionHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Netty服务配置 + * + * @author LSF maku_lsf@163.com + */ +@Configuration +@Slf4j +public class NettyServerConfig { + + @Bean + public ConcurrentMap deviceChannels() { + return new ConcurrentHashMap<>(); + } + + @Autowired + public TcpMessageHandlerFactory tcpMessageHandlerFactory; + + @Bean + public ServerBootstrap nettyServer(ConcurrentMap deviceChannels) { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline().addLast( + new StringDecoder(), + new StringEncoder(), + // 添加设备连接处理器 + new ConnectionHandler(deviceChannels,tcpMessageHandlerFactory) + ); + } + }) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, true); + return bootstrap; + } + + @Bean + public ChannelFuture serverChannelFuture(ServerBootstrap serverBootstrap) throws InterruptedException { + try { + ChannelFuture future = serverBootstrap.bind(8888).sync(); + log.info("------------------------ Netty 服务器在端口 8888 启动成功"); + return future; + } catch (Exception e) { + log.error("------------------------ Netty 服务器启动失败", e); + throw e; + } + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/factory/TcpMessageHandlerFactory.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/factory/TcpMessageHandlerFactory.java new file mode 100644 index 0000000..8e6ee67 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/factory/TcpMessageHandlerFactory.java @@ -0,0 +1,47 @@ +package com.bdzl.iot.communication.tcp.factory; + +import lombok.RequiredArgsConstructor; +import com.bdzl.iot.communication.tcp.handler.TCPMessageHandler; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * TCP消息处理器工厂,自动获取所有实现的处理器实例 + * + * @author LSF maku_lsf@163.com + */ +@Component +@RequiredArgsConstructor +public class TcpMessageHandlerFactory { + private final ApplicationContext applicationContext; + + /** + * 所有消息处理器 + */ + private List messageHandlers; + + private List loadHandlers() { + if (messageHandlers != null) { + return messageHandlers; + } + messageHandlers = new ArrayList<>(applicationContext.getBeansOfType(TCPMessageHandler.class).values()); + return messageHandlers; + } + + /** + * 获取与主题对应的tcp消息处理器 + * + * @param topic 主题 + * @return 处理器列表 + */ + public List getHandlersForTopic(String topic) { + return Collections.unmodifiableList(loadHandlers().stream() + .filter(handler -> handler.supports(topic)) + .collect(Collectors.toList())); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/ConnectionHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/ConnectionHandler.java new file mode 100644 index 0000000..03b3cd4 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/ConnectionHandler.java @@ -0,0 +1,129 @@ +package com.bdzl.iot.communication.tcp.handler; + +import cn.hutool.core.util.StrUtil; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.AttributeKey; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.iot.communication.dto.TcpMsgDTO; +import com.bdzl.iot.communication.tcp.factory.TcpMessageHandlerFactory; + +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * TCP服务器连接处理器 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +public class ConnectionHandler extends ChannelInboundHandlerAdapter { + + public static final AttributeKey DEVICE_ID = AttributeKey.valueOf("DEVICE_ID"); + + private ConcurrentMap deviceChannels; + private final TcpMessageHandlerFactory tcpMessageHandlerFactory; + + public ConnectionHandler(ConcurrentMap deviceChannels,TcpMessageHandlerFactory tcpMessageHandlerFactory) { + this.deviceChannels = deviceChannels; + this.tcpMessageHandlerFactory = tcpMessageHandlerFactory; + } + + + @Override + public void channelActive(ChannelHandlerContext ctx) { + System.out.printf("channelActive"); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (msg == null) { + return; + } + //鉴权认证 + if (authenticate(ctx, msg)) { + //这里可以根据业务自定义扩展消息处理 + if (StrUtil.contains(msg.toString(), "topic")) { + // 处理 TCP 消息 + handleTcpMessage( JsonUtils.parseObject(msg.toString(), TcpMsgDTO.class)); + } else { + // 处理其他类型的消息 + log.warn("接收到未知的消息类型:{}", msg); + } + } else { + ctx.close(); + } + + } + + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + String deviceId = getDeviceId(ctx.channel()); + if (deviceId != null) { + deviceChannels.remove(deviceId); + } + log.info(" 设备 {} 断开连接", deviceId == null ? "未知设备" : deviceId); + } + + private void handleTcpMessage( TcpMsgDTO message) { + String topic = message.getTopic(); + if (topic != null) { + tcpMessageHandlerFactory.getHandlersForTopic(topic).forEach(handler -> { + handler.handle(topic, message.getMsg()); + }); + } else { + log.warn("接收到主题为null的消息。"); + } + } + + + /** + * TCP连接鉴权,自行根据业务扩展 + */ + private boolean authenticate(ChannelHandlerContext ctx, Object message) { + String messageRegex = "\"(authenticate|deviceId)\"\\s*:\\s*\"\\d+\""; + Pattern messagePattern = Pattern.compile(messageRegex); + Matcher matcherPattern = messagePattern.matcher(message.toString()); + if (!matcherPattern.find()) { + ctx.writeAndFlush("设备消息无法识别!"); + return false; + } + if (StrUtil.contains(message.toString(), "authenticate")) { + Pattern pattern = Pattern.compile("\"authenticate\"\\s*:\\s*\"(\\d+)\""); + Matcher matcher = pattern.matcher(message.toString()); + if (matcher.find()) { + String deviceId = matcher.group(1); +// setDeviceId(ctx.channel(), deviceId); + ctx.channel().attr(DEVICE_ID).set(deviceId); + deviceChannels.put(deviceId, ctx.channel()); + ctx.writeAndFlush("authenticate passed"); + } + } + + if (StrUtil.contains(message.toString(), "deviceId")) { + Pattern pattern = Pattern.compile("\"deviceId\"\\s*:\\s*\"(\\d+)\""); + Matcher matcher = pattern.matcher(message.toString()); + if (matcher.find()) { + String deviceId = matcher.group(1); + Channel channel = deviceChannels.get(deviceId); + if (channel == null) { + ctx.writeAndFlush("设备连接不存在!请重新连接"); + return false; + } + } + } + return true; + } + + private String getDeviceId(Channel channel) { + return channel.attr(DEVICE_ID).get(); + } + +// private String setDeviceId(Channel channel, String deviceId) { +// return channel.attr(AttributeKey.valueOf("deviceId")).setIfAbsent(deviceId); +// } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/DeviceCommandResponseTCPMessageHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/DeviceCommandResponseTCPMessageHandler.java new file mode 100644 index 0000000..7679ccf --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/DeviceCommandResponseTCPMessageHandler.java @@ -0,0 +1,72 @@ +package com.bdzl.iot.communication.tcp.handler; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; +import com.bdzl.iot.communication.mqtt.factory.DeviceCommandResponseHandlerFactory; +import com.bdzl.iot.communication.service.TCPService; +import com.bdzl.iot.enums.DeviceTopicEnum; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * 设备命令响应处理器 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class DeviceCommandResponseTCPMessageHandler implements TCPMessageHandler { + + private final DeviceCommandResponseHandlerFactory deviceCommandResponseHandlerFactory; + + private final TCPService deviceTCPService; + @Override + public boolean supports(String topic) { + return DeviceTopicEnum.startsWith(topic, DeviceTopicEnum.COMMAND_RESPONSE.getTopic()); + } + + @Override + public void handle(String topic, Object message) { + DeviceCommandResponseDTO commandResponseDTO = parseCommandReplyMessage(topic, message); + Optional.ofNullable(commandResponseDTO.getCommand()) + .orElseThrow(() -> new IllegalArgumentException(StrUtil.format("缺失指令类型! 主题:'{}',消息:{}", topic, message))); + Optional.ofNullable(commandResponseDTO.getCommandId()) + .orElseThrow(() -> new IllegalArgumentException(StrUtil.format("缺失指令ID! 主题:'{}',消息:{}", topic, message))); + Optional.ofNullable(commandResponseDTO) + .ifPresent(responseDTO -> { + // 调用设备命令执行器的命令响应处理逻辑 + try { + deviceTCPService.commandReplied( responseDTO); + } catch (Exception e) { + log.error(StrUtil.format("调用设备命令执行器响应处理方法出错,topic:{}, message:{}", topic, message), e); + } + // 调用自定义命令响应处理器 + try { + deviceCommandResponseHandlerFactory.getHandlers().forEach(h -> h.handle(topic, responseDTO)); + } catch (Exception e) { + log.error(StrUtil.format("调用设备命令响应响应处理器出错,topic:{}, message:{}", topic, message), e); + } + }); + } + + private DeviceCommandResponseDTO parseCommandReplyMessage(String topic, Object message) { + try { + ObjectMapper mapper = new ObjectMapper(); + DeviceCommandResponseDTO commandResponse = mapper.convertValue(message, DeviceCommandResponseDTO.class); + if (StrUtil.isBlank(commandResponse.getCommandId())) { + log.error(StrUtil.format("主题'{}'的消息,缺失指令ID", topic)); + return null; + } + return commandResponse; + + } catch (Exception e) { + log.error(StrUtil.format("将主题'{}'的消息解析为设备命令响应对象失败", topic), e); + return null; + } + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/DevicePropertyTCPMessageHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/DevicePropertyTCPMessageHandler.java new file mode 100644 index 0000000..922c560 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/DevicePropertyTCPMessageHandler.java @@ -0,0 +1,48 @@ +package com.bdzl.iot.communication.tcp.handler; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.iot.communication.dto.DevicePropertyDTO; +import com.bdzl.iot.communication.mqtt.factory.DevicePropertyChangeHandlerFactory; +import com.bdzl.iot.enums.DeviceTopicEnum; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +/** + * 设备属性上报消息处理器 + * + * @author LSF maku_lsf@163.com + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class DevicePropertyTCPMessageHandler implements TCPMessageHandler { + + private final DevicePropertyChangeHandlerFactory statusChangeHandlerFactory; + + @Override + public boolean supports(String topic) { + return DeviceTopicEnum.startsWith(topic, DeviceTopicEnum.PROPERTY.getTopic()); + } + + @Override + public void handle(String topic, Object message) { + DevicePropertyDTO devicePropertyDTO = parseStatusMessage(topic, message); + Optional.ofNullable(devicePropertyDTO) + .ifPresent(deviceProperty -> statusChangeHandlerFactory.getHandlers() + .forEach(h -> h.handle(topic, deviceProperty))); + } + + private DevicePropertyDTO parseStatusMessage(String topic, Object message) { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.convertValue(message, DevicePropertyDTO.class); + } catch (Exception e) { + log.error(StrUtil.format("将主题'{}'的消息解析为设备运行状态对象失败", topic), e); + return null; + } + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/TCPMessageHandler.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/TCPMessageHandler.java new file mode 100644 index 0000000..76fdd14 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/communication/tcp/handler/TCPMessageHandler.java @@ -0,0 +1,26 @@ +package com.bdzl.iot.communication.tcp.handler; + + +/** + * TCP消息处理接口 + * + * @author LSF maku_lsf@163.com + */ +public interface TCPMessageHandler { + + /** + * 是否支持处理指定的topic + * + * @param topic + * @return + */ + boolean supports(String topic); + + /** + * TCP消息处理接口 + * + * @param topic + * @param message + */ + void handle(String topic, Object message); +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceController.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceController.java new file mode 100644 index 0000000..fe3d0d4 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceController.java @@ -0,0 +1,110 @@ +package com.bdzl.iot.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.iot.convert.IotDeviceConvert; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.query.IotDeviceQuery; +import com.bdzl.iot.service.IotDeviceService; +import com.bdzl.iot.vo.DeviceCommandVO; +import com.bdzl.iot.vo.DeviceReportAttributeDataVO; +import com.bdzl.iot.vo.IotDeviceVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设备表 + * + * @author LSF maku_lsf@163.com + */ +@RestController +@RequestMapping("iot/device") +@Tag(name = "设备表") +@AllArgsConstructor +public class IotDeviceController { + private final IotDeviceService iotDeviceService; + + @GetMapping("/page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('iot:device:page')") + public Result> page(@ParameterObject @Valid IotDeviceQuery query) { + PageResult page = iotDeviceService.page(query); + + return Result.ok(page); + } + + @GetMapping("/{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('iot:device:info')") + public Result get(@PathVariable("id") Long id) { + IotDeviceEntity entity = iotDeviceService.getById(id); + + return Result.ok(IotDeviceConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('iot:device:save')") + public Result save(@RequestBody IotDeviceVO vo) { + iotDeviceService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('iot:device:update')") + public Result update(@RequestBody @Valid IotDeviceVO vo) { + iotDeviceService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('iot:device:delete')") + public Result delete(@RequestBody List idList) { + iotDeviceService.delete(idList); + + return Result.ok(); + } + + @PostMapping("/asyncSendCommand") + @Operation(summary = "下发指令-不等待设备回复") + @PreAuthorize("hasAuthority('iot:device:send')") + public Result asyncSendCommand(@RequestBody DeviceCommandVO vo) { + iotDeviceService.asyncSendCommand(vo); + return Result.ok(); + } + + @PostMapping("/syncSendCommand") + @Operation(summary = "下发指令-等待设备回复") + @PreAuthorize("hasAuthority('iot:device:send')") + public Result syncSendCommand(@RequestBody DeviceCommandVO vo) { + iotDeviceService.syncSendCommand(vo); + return Result.ok(); + } + + @PostMapping("/syncSendCommand/debug") + @Operation(summary = "下发指令-等待设备回复-调试") + @PreAuthorize("hasAuthority('iot:device:send')") + public Result syncSendCommandDebug(@RequestBody DeviceCommandVO vo) { + return Result.ok(iotDeviceService.syncSendCommandDebug(vo).getResponsePayload()); + } + + @PostMapping("/simulateDeviceReportAttributeData") + @Operation(summary = "模拟设备属性数据上报") + @PreAuthorize("hasAuthority('iot:device:report')") + public Result simulateDeviceReportAttributeData(@RequestBody DeviceReportAttributeDataVO vo) { + iotDeviceService.simulateDeviceReportAttributeData(vo); + return Result.ok(); + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceEventLogController.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceEventLogController.java new file mode 100644 index 0000000..131a2ee --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceEventLogController.java @@ -0,0 +1,76 @@ +package com.bdzl.iot.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.iot.convert.IotDeviceEventLogConvert; +import com.bdzl.iot.entity.IotDeviceEventLogEntity; +import com.bdzl.iot.query.IotDeviceEventLogQuery; +import com.bdzl.iot.service.IotDeviceEventLogService; +import com.bdzl.iot.vo.IotDeviceEventLogVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +@RestController +@RequestMapping("iot/device_event_log") +@Tag(name = "设备事件日志") +@AllArgsConstructor +public class IotDeviceEventLogController { + private final IotDeviceEventLogService iotDeviceEventLogService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('iot:device_event_log:page')") + public Result> page(@ParameterObject @Valid IotDeviceEventLogQuery query) { + PageResult page = iotDeviceEventLogService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('iot:device_event_log:info')") + public Result get(@PathVariable("id") Long id) { + IotDeviceEventLogEntity entity = iotDeviceEventLogService.getById(id); + + return Result.ok(IotDeviceEventLogConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('iot:device_event_log:save')") + public Result save(@RequestBody IotDeviceEventLogVO vo) { + iotDeviceEventLogService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('iot:device_event_log:update')") + public Result update(@RequestBody @Valid IotDeviceEventLogVO vo) { + iotDeviceEventLogService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('iot:device_event_log:delete')") + public Result delete(@RequestBody List idList) { + iotDeviceEventLogService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceServiceLogController.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceServiceLogController.java new file mode 100644 index 0000000..298d6c0 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/controller/IotDeviceServiceLogController.java @@ -0,0 +1,76 @@ +package com.bdzl.iot.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.iot.convert.IotDeviceServiceLogConvert; +import com.bdzl.iot.entity.IotDeviceServiceLogEntity; +import com.bdzl.iot.query.IotDeviceServiceLogQuery; +import com.bdzl.iot.service.IotDeviceServiceLogService; +import com.bdzl.iot.vo.IotDeviceServiceLogVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +@RestController +@RequestMapping("iot/device_service_log") +@Tag(name = "设备服务日志") +@AllArgsConstructor +public class IotDeviceServiceLogController { + private final IotDeviceServiceLogService iotDeviceServiceLogService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('iot:device_service_log:page')") + public Result> page(@ParameterObject @Valid IotDeviceServiceLogQuery query) { + PageResult page = iotDeviceServiceLogService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('iot:device_service_log:info')") + public Result get(@PathVariable("id") Long id) { + IotDeviceServiceLogEntity entity = iotDeviceServiceLogService.getById(id); + + return Result.ok(IotDeviceServiceLogConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('iot:device_service_log:save')") + public Result save(@RequestBody IotDeviceServiceLogVO vo) { + iotDeviceServiceLogService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('iot:device_service_log:update')") + public Result update(@RequestBody @Valid IotDeviceServiceLogVO vo) { + iotDeviceServiceLogService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('iot:device_service_log:delete')") + public Result delete(@RequestBody List idList) { + iotDeviceServiceLogService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceConvert.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceConvert.java new file mode 100644 index 0000000..d302fe5 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.iot.convert; + +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.vo.IotDeviceVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 设备表 + * + * @author LSF maku_lsf@163.com + */ +@Mapper +public interface IotDeviceConvert { + IotDeviceConvert INSTANCE = Mappers.getMapper(IotDeviceConvert.class); + + IotDeviceEntity convert(IotDeviceVO vo); + + IotDeviceVO convert(IotDeviceEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceEventLogConvert.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceEventLogConvert.java new file mode 100644 index 0000000..9c7e2ca --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceEventLogConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.iot.convert; + +import com.bdzl.iot.entity.IotDeviceEventLogEntity; +import com.bdzl.iot.vo.IotDeviceEventLogVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +@Mapper +public interface IotDeviceEventLogConvert { + IotDeviceEventLogConvert INSTANCE = Mappers.getMapper(IotDeviceEventLogConvert.class); + + IotDeviceEventLogEntity convert(IotDeviceEventLogVO vo); + + IotDeviceEventLogVO convert(IotDeviceEventLogEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceServiceLogConvert.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceServiceLogConvert.java new file mode 100644 index 0000000..119b796 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/convert/IotDeviceServiceLogConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.iot.convert; + +import com.bdzl.iot.entity.IotDeviceServiceLogEntity; +import com.bdzl.iot.vo.IotDeviceServiceLogVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +@Mapper +public interface IotDeviceServiceLogConvert { + IotDeviceServiceLogConvert INSTANCE = Mappers.getMapper(IotDeviceServiceLogConvert.class); + + IotDeviceServiceLogEntity convert(IotDeviceServiceLogVO vo); + + IotDeviceServiceLogVO convert(IotDeviceServiceLogEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceDao.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceDao.java new file mode 100644 index 0000000..876088e --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceDao.java @@ -0,0 +1,15 @@ +package com.bdzl.iot.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.iot.entity.IotDeviceEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 设备表 + * + * @author LSF maku_lsf@163.com + */ +@Mapper +public interface IotDeviceDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceEventLogDao.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceEventLogDao.java new file mode 100644 index 0000000..caba93a --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceEventLogDao.java @@ -0,0 +1,15 @@ +package com.bdzl.iot.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.iot.entity.IotDeviceEventLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +@Mapper +public interface IotDeviceEventLogDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceServiceLogDao.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceServiceLogDao.java new file mode 100644 index 0000000..59efec9 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dao/IotDeviceServiceLogDao.java @@ -0,0 +1,15 @@ +package com.bdzl.iot.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.iot.entity.IotDeviceServiceLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +@Mapper +public interface IotDeviceServiceLogDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dto/DeviceClientDTO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dto/DeviceClientDTO.java new file mode 100644 index 0000000..70922da --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/dto/DeviceClientDTO.java @@ -0,0 +1,88 @@ +package com.bdzl.iot.dto; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import lombok.Builder; +import lombok.Data; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.enums.DeviceTypeEnum; + +import java.util.List; + +/** + * 设备客户端信息 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Builder +public class DeviceClientDTO { + /** + * 格式 : deviceType_tenantId_deviceId_uid + */ + private static final String CLIENT_ID_TEMPLATE = "{}_{}_{}_{}"; + private static final String INVALID_CLIENT_ID = "无效的设备clientId:{}"; + /** + * 租户id + */ + private Long tenantId; + + /** + * 设备id + */ + private Long deviceId; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 设备唯一标识 + */ + private String uid; + + /** + * 生成clientId + * + * @return + */ + public String buildClientId() { + if (StrUtil.isBlank(uid)) { + return null; + } + return StrUtil.format(CLIENT_ID_TEMPLATE, deviceType, tenantId, deviceId, uid); + } + + /** + * 从clientId解析设备client信息 + * + * @param clientId + * @return + */ + public static DeviceClientDTO parse(String clientId) { + List clientIdParts = StrUtil.split(clientId, "_"); + Assert.isTrue(clientIdParts.size() > 3, INVALID_CLIENT_ID, clientId); + return DeviceClientDTO.builder() + .deviceType(clientIdParts.get(0)) + .tenantId(Long.valueOf(clientIdParts.get(1))) + .deviceId(Long.valueOf(clientIdParts.get(2))) + .uid(clientIdParts.get(3)) + .build(); + } + + /** + * 从Device创建deviceClient + * + * @param device + * @return + */ + public static DeviceClientDTO from(IotDeviceEntity device) { + return DeviceClientDTO.builder() + .deviceType(DeviceTypeEnum.parse(device.getType().toString()).name().toLowerCase()) + .tenantId(device.getTenantId() == null ? 0 : device.getTenantId()) + .deviceId(device.getId()) + .uid(device.getUid()) + .build(); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceEntity.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceEntity.java new file mode 100644 index 0000000..02edadc --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceEntity.java @@ -0,0 +1,91 @@ +package com.bdzl.iot.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +import java.time.LocalDateTime; + +/** + * 设备表 + * + * @author LSF maku_lsf@163.com + */ +@EqualsAndHashCode(callSuper = false) +@Data +@TableName("iot_device") +public class IotDeviceEntity extends BaseEntity { + + /** + * 编码 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 设备类型,1.手持设备,2.柜体,3传感设备 + */ + private Integer type; + + /** + * 设备和服务器通信协议类型 + */ + private String protocolType; + + /** + * 唯一标识码 + */ + private String uid; + + /** + * 设备密钥 + */ + private String secret; + + /** + * App版本号 + */ + private String appVersion; + + /** + * 电池电量百分比 + */ + private String batteryPercent; + + /** + * 温度 + */ + private String temperature; + + /** + * 状态,0禁用,1正常 + */ + private Integer status; + + /** + * 运行状态,0.离线状态 1.在线状态 2.正常待机 3.用户使用中 4.OTA升级中 + */ + private Integer runningStatus; + + /** + * 上线时间 + */ + private LocalDateTime upTime; + + /** + * 下线时间 + */ + private LocalDateTime downTime; + + /** + * 租户ID + */ + private Long tenantId; + + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceEventLogEntity.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceEventLogEntity.java new file mode 100644 index 0000000..d1cd84b --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceEventLogEntity.java @@ -0,0 +1,51 @@ +package com.bdzl.iot.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +import java.time.LocalDateTime; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +@EqualsAndHashCode(callSuper = false) +@Data +@TableName("iot_device_event_log") +public class IotDeviceEventLogEntity extends BaseEntity { + + /** + * 设备id + */ + private Long deviceId; + + /** + * 事件类型 + */ + private Integer eventType; + + /** + * 事件标识id + */ + private String eventUid; + + /** + * 事件数据 + */ + private String eventPayload; + + /** + * 事件时间 + */ + private LocalDateTime eventTime; + + /** + * 租户ID + */ + private Long tenantId; + + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceServiceLogEntity.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceServiceLogEntity.java new file mode 100644 index 0000000..5bb99ad --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/entity/IotDeviceServiceLogEntity.java @@ -0,0 +1,51 @@ +package com.bdzl.iot.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +import java.time.LocalDateTime; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +@EqualsAndHashCode(callSuper = false) +@Data +@TableName("iot_device_service_log") +public class IotDeviceServiceLogEntity extends BaseEntity { + + /** + * 设备id + */ + private Long deviceId; + + /** + * 服务类型 + */ + private Integer serviceType; + + /** + * 服务标识id + */ + private String serviceUid; + + /** + * 服务数据 + */ + private String servicePayload; + + /** + * 服务时间 + */ + private LocalDateTime serviceTime; + + /** + * 租户ID + */ + private Long tenantId; + + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceCommandEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceCommandEnum.java new file mode 100644 index 0000000..de4d489 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceCommandEnum.java @@ -0,0 +1,78 @@ +package com.bdzl.iot.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 服务端下发的指令枚举类 + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum DeviceCommandEnum { + + /** + * 远程锁定 + */ + LOCK(1, "远程锁定", DeviceEventTypeEnum.LOCK), + + /** + * 远程解锁 + */ + UNLOCK(2, "远程解锁", DeviceEventTypeEnum.UNLOCK), + + /** + * OTA升级 + */ + OTA_UPGRADE(3, "OTA升级", DeviceEventTypeEnum.OTA_UPGRADE); + + /** + * 类型值 + */ + private final Integer value; + + /** + * 显示名称 + */ + private final String title; + + + /** + * 对应的设备事件日志类型 + */ + private final DeviceEventTypeEnum eventType; + + /** + * 解析指定的valueName + * + * @param valueName + * @return DeviceCommandEnum + * @throws IllegalArgumentException + */ + public static DeviceCommandEnum parse(String valueName) { + return Arrays.stream(DeviceCommandEnum.values()) + .filter(d -> d.name().equalsIgnoreCase(valueName)).findFirst() + .orElseThrow(() -> new IllegalArgumentException( + StrUtil.format("无效的DeviceCommandEnum值:{}", valueName))); + } + + /** + * 根据 value值 获取对应枚举 + * + * @param value + * @return DeviceCommandEnum + */ + public static DeviceCommandEnum getEnum(Integer value) { + for (DeviceCommandEnum commandEnum : DeviceCommandEnum.values()) { + if (commandEnum.getValue().equals(value)) { + return commandEnum; + } + } + return null; + } +} + diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceEventTypeEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceEventTypeEnum.java new file mode 100644 index 0000000..15ce66d --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceEventTypeEnum.java @@ -0,0 +1,105 @@ +package com.bdzl.iot.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 设备事件类型枚举 + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum DeviceEventTypeEnum { + /** + * 下线 + */ + OFFLINE(0, "下线事件"), + + /** + * 上线 + */ + ONLINE(1, "上线事件"), + + /** + * 登录 + */ + SIGN_ON(2, "登录事件"), + + /** + * 退出登录 + */ + SIGN_OFF(3, "退出登录事件"), + /** + * OTA升级 + */ + OTA_UPGRADE(4, "OTA升级事件"), + + /** + * 设备远程锁定 + */ + LOCK(5, "设备远程锁定"), + + /** + * 设备远程解锁 + */ + UNLOCK(6, "设备远程解锁"), + + /** + * APP版本信息上报 + */ + APP_VERSION_REPORT(7, "APP版本信息上报"), + + /** + * 电池电量上报 + */ + BATTERY_PERCENT_REPORT(8, "电池电量上报"), + + /** + * 温度上报 + */ + TEMPERATURE_REPORT(9, "温度上报"); + + /** + * 类型值 + */ + private final Integer value; + + /** + * 类型名称 + */ + private final String title; + + + /** + * 解析指定的valueName + * + * @param valueName + * @return DeviceEventTypeEnum + * @throws IllegalArgumentException + */ + public static DeviceEventTypeEnum parse(String valueName) { + return Arrays.stream(DeviceEventTypeEnum.values()) + .filter(d -> d.name().equalsIgnoreCase(valueName)).findFirst() + .orElseThrow(() -> new IllegalArgumentException( + StrUtil.format("无效的DeviceEventTypeEnum值:{}", valueName))); + } + + /** + * 根据 value值 获取对应枚举 + * + * @param value + * @return DeviceCommandEnum + */ + public static DeviceEventTypeEnum getEnum(Integer value) { + for (DeviceEventTypeEnum commandEnum : DeviceEventTypeEnum.values()) { + if (commandEnum.getValue().equals(value)) { + return commandEnum; + } + } + return null; + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DevicePropertyEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DevicePropertyEnum.java new file mode 100644 index 0000000..129c1fa --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DevicePropertyEnum.java @@ -0,0 +1,40 @@ +package com.bdzl.iot.enums; + + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 设备属性枚举 + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum DevicePropertyEnum { + /** + * 运行状态 + */ + RUNNING_STATUS(1), + + /** + * APP版本 + */ + APP_VERSION(2), + + /** + * 电池电量百分比 + */ + BATTERY_PERCENT(3), + + /** + * 温度 + */ + TEMPERATURE(4); + + /** + * 类型值 + */ + private final Integer value; + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceRunningStatusEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceRunningStatusEnum.java new file mode 100644 index 0000000..db2273f --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceRunningStatusEnum.java @@ -0,0 +1,58 @@ +package com.bdzl.iot.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 设备运行状态枚举 + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum DeviceRunningStatusEnum { + /** + * 离线状态 + */ + OFFLINE(0, "离线", DeviceEventTypeEnum.OFFLINE), + + /** + * 在线状态 + */ + ONLINE(1, "在线", DeviceEventTypeEnum.ONLINE); + + /** + * 状态值 + */ + private final Integer value; + + /** + * 状态显示名称 + */ + private final String title; + + /** + * 设备事件类型 + */ + private final DeviceEventTypeEnum eventType; + + + /** + * 解析指定的valueName + * + * @param valueName + * @return DeviceRunningStatusEnum + * @throws IllegalArgumentException + */ + public static DeviceRunningStatusEnum parse(String valueName) { + return Arrays.stream(DeviceRunningStatusEnum.values()) + .filter(d -> d.getValue().toString().equals(valueName) + || d.name().equalsIgnoreCase(valueName)).findFirst() + .orElseThrow(() -> new IllegalArgumentException( + StrUtil.format("无效的DeviceRunningStatusEnum值:{}", valueName))); + } + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceServiceEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceServiceEnum.java new file mode 100644 index 0000000..4933531 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceServiceEnum.java @@ -0,0 +1,18 @@ +package com.bdzl.iot.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum DeviceServiceEnum { + + COMMAND_ID("命令ID"); + + /** + * 类型值 + */ + private final String value; + + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceTopicEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceTopicEnum.java new file mode 100644 index 0000000..2367530 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceTopicEnum.java @@ -0,0 +1,141 @@ +package com.bdzl.iot.enums; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import com.bdzl.iot.dto.DeviceClientDTO; + +import java.util.Arrays; +import java.util.List; + + +/** + * 设备消息主题类型枚举 + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum DeviceTopicEnum { + /** + * 设备指令下发主题 + */ + COMMAND("command"), + + /** + * 设备信息上报主题(指令响应反馈) + */ + COMMAND_RESPONSE("command_response"), + + /** + * 设备信息上报主题(属性相关) + */ + PROPERTY("property"); + + /** + * 设备信息上报主题前缀 + */ + public static final String TOPIC_PREFIX = "/maku/device"; + + + /** + * MQTT 主题模板,参数:前缀/clientid(deviceType_tenantId_deviceId_uid)/设备主题 + */ + private static final String TOPIC_TEMPLATE = "{}/{}/{}"; + + /** + * 设备主题通配符模板,参数:前缀/+/设备主题 + */ + private static final String TOPIC_WILDCARD_TEMPLATE = "{}/+/{}"; + + /** + * MQTT 主题 + */ + private final String topic; + + /** + * 获取设备主题通配符 + * + * @return 主题通配符 + */ + public String getWildcard() { + return StrUtil.format(TOPIC_WILDCARD_TEMPLATE, TOPIC_PREFIX, getTopic()); + } + + /** + * 构建完整路径的设备主题 + * + * @param deviceClient 设备客户端信息 + * @return 完整路径的设备主题 + */ + public String buildTopic(DeviceClientDTO deviceClient) { + return StrUtil.format(TOPIC_TEMPLATE, TOPIC_PREFIX, deviceClient.buildClientId(), getTopic()); + } + + /** + * 解析指定的主题字符串为 DeviceTopicEnum 枚举,若无效则抛出 IllegalArgumentException 异常 + * + * @param topic 主题字符串 + * @return 对应的 DeviceTopicEnum 枚举 + * @throws IllegalArgumentException 当主题字符串无效时抛出 + */ + public static DeviceTopicEnum parse(String topic) { + String topicSuffix = StrUtil.startWith(topic, TOPIC_PREFIX) ? StrUtil.subAfter(topic, "/", true) : topic; + return Arrays.stream(DeviceTopicEnum.values()) + .filter(d -> d.name().equalsIgnoreCase(topicSuffix)).findFirst() + .orElseThrow(() -> new IllegalArgumentException(StrUtil.format("无效的 DeviceTopicEnum 值:{}", topic))); + } + + /** + * 判断指定的主题是否以给定前缀开头 + * + * @param topic 主题字符串 + * @param prefix 前缀字符串 + * @return 若主题以给定前缀开头则返回 true,否则返回 false + */ + public static boolean startsWith(String topic, String prefix) { + try { + DeviceTopicEnum deviceTopic = parse(topic); + return deviceTopic.getTopic().startsWith(prefix); + } catch (IllegalArgumentException e) { + return false; + } + } + + /** + * 解析主题并获取其完整信息(设备信息及主题) + * + * @param topic 主题字符串 + * @return 包含设备信息及主题的 DeviceTopicContext 对象 + */ + public static DeviceTopicContext parseContext(String topic) { + String topicSuffix = StrUtil.subAfter(topic, TOPIC_PREFIX, false); + List parts = StrUtil.split(topicSuffix, "/", true, true); + Assert.isTrue(parts.size() == 2, "无效的设备主题:{}", topic); + + DeviceClientDTO deviceClient = DeviceClientDTO.parse(parts.get(0)); + DeviceTopicEnum deviceTopic = DeviceTopicEnum.parse(parts.get(1)); + + return DeviceTopicContext.builder() + .client(deviceClient) + .topic(deviceTopic) + .build(); + } + + @Data + @Builder + public static class DeviceTopicContext { + /** + * 设备客户端信息 + */ + private DeviceClientDTO client; + + /** + * 设备主题 + */ + private DeviceTopicEnum topic; + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceTypeEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceTypeEnum.java new file mode 100644 index 0000000..3cec9c3 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/DeviceTypeEnum.java @@ -0,0 +1,52 @@ +package com.bdzl.iot.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * 设备类型枚举,新增的设备类型枚举命名不允许使用"_" + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum DeviceTypeEnum { + /** + * 手持设备 + */ + HANDSET(1), + + /** + * 柜体 + */ + CABINET(2), + + /** + * 传感设备 + */ + SENSOR(3); + + /** + * 类型值 + */ + private final Integer value; + + /** + * 解析指定的valueName + * + * @param valueName + * @return DeviceTypeEnum + * @throws IllegalArgumentException + */ + public static DeviceTypeEnum parse(String valueName) { + return Arrays.stream(DeviceTypeEnum.values()) + .filter(d -> d.getValue().toString().equals(valueName) + || d.name().equalsIgnoreCase(valueName)).findFirst() + .orElseThrow(() -> new IllegalArgumentException( + StrUtil.format("无效的DeviceTypeEnum值:{}", valueName))); + } + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/IOTProtocolEnum.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/IOTProtocolEnum.java new file mode 100644 index 0000000..a08f18c --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/enums/IOTProtocolEnum.java @@ -0,0 +1,28 @@ +package com.bdzl.iot.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IOT常用的通信协议 + * + * @author LSF maku_lsf@163.com + */ +@Getter +@RequiredArgsConstructor +public enum IOTProtocolEnum { + + MQTT("MQTT"), + TCP("TCP"), + UDP("UDP"), + BLE("BLE"), + CoAP("CoAP"), + LwM2M("LwM2M"), + Modbus("Modbus"); + + private final String value; +} + diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceEventLogQuery.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceEventLogQuery.java new file mode 100644 index 0000000..9bc893d --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceEventLogQuery.java @@ -0,0 +1,23 @@ +package com.bdzl.iot.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 设备事件日志查询 + * + * @author LSF maku_lsf@163.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "设备事件日志查询") +public class IotDeviceEventLogQuery extends Query { + + @Schema(description = "指令") + private String eventTypeEnum; + + @Schema(description = "设备id") + private Long deviceId; +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceQuery.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceQuery.java new file mode 100644 index 0000000..19a26ba --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceQuery.java @@ -0,0 +1,26 @@ +package com.bdzl.iot.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 设备表查询 + * + * @author LSF maku_lsf@163.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "设备表查询") +public class IotDeviceQuery extends Query { + + @Schema(description = "状态,0禁用,1正常") + private Integer status; + + @Schema(description = "运行状态,0.离线状态 1.在线状态 2.正常待机 3.用户使用中 4.OTA升级中") + private Integer runningStatus; + + @Schema(description = "设备类型,1.手持设备,2.柜体,3传感设备") + private Integer type; +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceServiceLogQuery.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceServiceLogQuery.java new file mode 100644 index 0000000..113f3f2 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/query/IotDeviceServiceLogQuery.java @@ -0,0 +1,22 @@ +package com.bdzl.iot.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 设备服务日志查询 + * + * @author LSF maku_lsf@163.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "设备服务日志查询") +public class IotDeviceServiceLogQuery extends Query { + @Schema(description = "指令") + private String deviceCommandEnum; + + @Schema(description = "设备id") + private Long deviceId; +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceEventLogService.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceEventLogService.java new file mode 100644 index 0000000..70c90f2 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceEventLogService.java @@ -0,0 +1,52 @@ +package com.bdzl.iot.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.iot.entity.IotDeviceEventLogEntity; +import com.bdzl.iot.enums.DeviceEventTypeEnum; +import com.bdzl.iot.query.IotDeviceEventLogQuery; +import com.bdzl.iot.vo.IotDeviceEventLogVO; + +import java.util.List; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +public interface IotDeviceEventLogService extends BaseService { + + PageResult page(IotDeviceEventLogQuery query); + + void save(IotDeviceEventLogVO vo); + + void update(IotDeviceEventLogVO vo); + + void delete(List idList); + + /** + * 创建设备事件 + * + * @param deviceId 设备ID + * @param tenantId 租户ID + * @param eventType 事件类型 + * @param eventUid 事件UID + * @param payload 事件数据 + * @return 设备事件 + */ + IotDeviceEventLogEntity createDeviceEvent(Long deviceId, Long tenantId, DeviceEventTypeEnum eventType, + String eventUid, Object payload); + + /** + * 创建设备事件并保存 + * + * @param deviceId 设备ID + * @param tenantId 租户ID + * @param eventType 事件类型 + * @param eventUid 事件UID + * @param payload 事件数据 + * @return 设备事件 + */ + void createAndSaveDeviceEvent(Long deviceId, Long tenantId, DeviceEventTypeEnum eventType, + String eventUid, Object payload); +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceService.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceService.java new file mode 100644 index 0000000..e5e19bc --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceService.java @@ -0,0 +1,82 @@ +package com.bdzl.iot.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; +import com.bdzl.iot.query.IotDeviceQuery; +import com.bdzl.iot.communication.service.BaseCommunication; +import com.bdzl.iot.vo.DeviceCommandResponseAttributeDataVO; +import com.bdzl.iot.vo.DeviceCommandVO; +import com.bdzl.iot.vo.DeviceReportAttributeDataVO; +import com.bdzl.iot.vo.IotDeviceVO; + +import java.util.List; + +/** + * 设备表 + * + * @author LSF maku_lsf@163.com + */ +public interface IotDeviceService extends BaseService { + + PageResult page(IotDeviceQuery query); + + void save(IotDeviceVO vo); + + void update(IotDeviceVO vo); + + void delete(List idList); + + /** + * 根据设备的协议类型获取发送服务 + * @param device 设备 + * @return + */ + BaseCommunication getSendService(IotDeviceEntity device); + + /** + * 根据协议类型获取发送服务 + * @param protocolType + * @return + */ + BaseCommunication getSendService(String protocolType); + + /** + * 根据设备ID获取发送服务 + * @param deviceId + * @return + */ + BaseCommunication getSendService(Long deviceId); + + /** + * 对设备下发指令-同步响应模式 + * + * @param vo + */ + DeviceCommandResponseDTO syncSendCommand(DeviceCommandVO vo); + + /** + * 对设备下发指令-同步响应模式-调试 + * + * @param vo + */ + DeviceCommandResponseDTO syncSendCommandDebug(DeviceCommandVO vo); + + /** + * 对设备下发指令-异步响应模式 + * + * @param vo + */ + void asyncSendCommand(DeviceCommandVO vo); + + /** + * 模拟设备属性数据上报 + */ + void simulateDeviceReportAttributeData(DeviceReportAttributeDataVO vo); + + /** + * 模拟设备服务指令响应数据 + */ + void simulateDeviceCommandResponseAttributeData(DeviceCommandResponseAttributeDataVO vo); +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceServiceLogService.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceServiceLogService.java new file mode 100644 index 0000000..1e11009 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/IotDeviceServiceLogService.java @@ -0,0 +1,52 @@ +package com.bdzl.iot.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.iot.entity.IotDeviceServiceLogEntity; +import com.bdzl.iot.enums.DeviceCommandEnum; +import com.bdzl.iot.query.IotDeviceServiceLogQuery; +import com.bdzl.iot.vo.IotDeviceServiceLogVO; + +import java.util.List; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +public interface IotDeviceServiceLogService extends BaseService { + + PageResult page(IotDeviceServiceLogQuery query); + + void save(IotDeviceServiceLogVO vo); + + void update(IotDeviceServiceLogVO vo); + + void delete(List idList); + + /** + * 创建设备服务日志 + * + * @param deviceId 设备ID + * @param tenantId 租户ID + * @param command 服务类型 + * @param eventUid 事件UID + * @param payload 事件数据 + * @return 设备事件 + */ + IotDeviceServiceLogEntity createDeviceServiceLog(Long deviceId, Long tenantId, DeviceCommandEnum command, + String eventUid, Object payload); + + /** + * 创建设备服务日志并保存 + * + * @param deviceId 设备ID + * @param tenantId 租户ID + * @param command 服务类型 + * @param eventUid 事件UID + * @param payload 事件数据 + * @return 设备事件 + */ + void createAndSaveDeviceServiceLog(Long deviceId, Long tenantId, DeviceCommandEnum command, + String eventUid, Object payload); +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceEventLogServiceImpl.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceEventLogServiceImpl.java new file mode 100644 index 0000000..1a1f6d9 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceEventLogServiceImpl.java @@ -0,0 +1,95 @@ +package com.bdzl.iot.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.iot.convert.IotDeviceEventLogConvert; +import com.bdzl.iot.dao.IotDeviceEventLogDao; +import com.bdzl.iot.entity.IotDeviceEventLogEntity; +import com.bdzl.iot.enums.DeviceEventTypeEnum; +import com.bdzl.iot.query.IotDeviceEventLogQuery; +import com.bdzl.iot.service.IotDeviceEventLogService; +import com.bdzl.iot.vo.IotDeviceEventLogVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +@Service +@AllArgsConstructor +public class IotDeviceEventLogServiceImpl extends BaseServiceImpl implements IotDeviceEventLogService { + + @Override + public PageResult page(IotDeviceEventLogQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + List vos = IotDeviceEventLogConvert.INSTANCE.convertList(page.getRecords()); + vos.forEach(vo -> { + vo.setEventTypeEnum(DeviceEventTypeEnum.getEnum(vo.getEventType())); + }); + return new PageResult<>(vos, page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(IotDeviceEventLogQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + if (StrUtil.isNotBlank(query.getEventTypeEnum())) { + wrapper.eq(IotDeviceEventLogEntity::getEventType, DeviceEventTypeEnum.parse(query.getEventTypeEnum()).getValue()); + } + wrapper.eq(query.getDeviceId() != null, IotDeviceEventLogEntity::getDeviceId, query.getDeviceId()); + wrapper.orderByDesc(IotDeviceEventLogEntity::getEventTime); + return wrapper; + } + + @Override + public void save(IotDeviceEventLogVO vo) { + IotDeviceEventLogEntity entity = IotDeviceEventLogConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(IotDeviceEventLogVO vo) { + IotDeviceEventLogEntity entity = IotDeviceEventLogConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + + @Override + public IotDeviceEventLogEntity createDeviceEvent(Long deviceId, Long tenantId, DeviceEventTypeEnum eventType, String eventUid, Object payload) { + IotDeviceEventLogEntity deviceEvent = new IotDeviceEventLogEntity(); + deviceEvent.setDeviceId(deviceId); + deviceEvent.setTenantId(tenantId); + deviceEvent.setEventType(eventType.getValue()); + deviceEvent.setEventUid(eventUid); + if (payload != null) { + deviceEvent.setEventPayload((payload instanceof String) + ? (String) payload + : JsonUtils.toJsonString(payload)); + } + deviceEvent.setEventTime(LocalDateTime.now()); + return deviceEvent; + + } + + @Override + public void createAndSaveDeviceEvent(Long deviceId, Long tenantId, DeviceEventTypeEnum eventType, String eventUid, Object payload) { + save(createDeviceEvent(deviceId, tenantId, eventType, eventUid, payload)); + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceServiceImpl.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceServiceImpl.java new file mode 100644 index 0000000..77401d6 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceServiceImpl.java @@ -0,0 +1,321 @@ +package com.bdzl.iot.service.impl; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.bdzl.iot.enums.*; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.iot.convert.IotDeviceConvert; +import com.bdzl.iot.dao.IotDeviceDao; +import com.bdzl.iot.entity.IotDeviceEntity; +import com.bdzl.iot.communication.dto.DeviceCommandResponseDTO; +import com.bdzl.iot.communication.dto.DevicePropertyDTO; +import com.bdzl.iot.communication.mqtt.handler.DeviceCommandResponseHandler; +import com.bdzl.iot.communication.mqtt.handler.DevicePropertyChangeHandler; +import com.bdzl.iot.query.IotDeviceQuery; +import com.bdzl.iot.communication.service.BaseCommunication; +import com.bdzl.iot.communication.service.CommunicationServiceFactory; +import com.bdzl.iot.service.IotDeviceEventLogService; +import com.bdzl.iot.service.IotDeviceService; +import com.bdzl.iot.vo.DeviceCommandResponseAttributeDataVO; +import com.bdzl.iot.vo.DeviceCommandVO; +import com.bdzl.iot.vo.DeviceReportAttributeDataVO; +import com.bdzl.iot.vo.IotDeviceVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 设备服务类 + * + * @author LSF maku_lsf@163.com + */ +@Service +@Slf4j +@AllArgsConstructor +public class IotDeviceServiceImpl extends BaseServiceImpl + implements IotDeviceService, DevicePropertyChangeHandler, DeviceCommandResponseHandler { + + private final CommunicationServiceFactory communicationService; + private final IotDeviceEventLogService deviceEventLogService; + + @Override + public PageResult page(IotDeviceQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(IotDeviceConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(IotDeviceQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(query.getStatus() != null, IotDeviceEntity::getStatus, query.getStatus()); + wrapper.eq(query.getType() != null, IotDeviceEntity::getType, query.getType()); + wrapper.eq(query.getRunningStatus() != null, IotDeviceEntity::getRunningStatus, query.getRunningStatus()); + return wrapper; + } + + @Override + public void save(IotDeviceVO vo) { + IotDeviceEntity entity = IotDeviceConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(IotDeviceVO vo) { + IotDeviceEntity entity = IotDeviceConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + + @Override + public BaseCommunication getSendService(IotDeviceEntity device) { + if (device != null) { + return getSendService(device.getProtocolType()); + } + return null; + } + + @Override + public BaseCommunication getSendService(String protocolType) { + return communicationService.getProtocol(protocolType); + } + + @Override + public BaseCommunication getSendService(Long deviceId) { + IotDeviceEntity device = getById(deviceId); + if (device != null) { + return getSendService(device.getProtocolType()); + } + return null; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public DeviceCommandResponseDTO syncSendCommand(DeviceCommandVO vo) { + + IotDeviceEntity device = getById(vo.getDeviceId()); + Assert.notNull(device, "未注册的设备:{}", vo.getDeviceId()); + + DeviceCommandEnum commandEnum = DeviceCommandEnum.parse(vo.getCommand()); + try { + return getSendService(device).syncSendCommand(getById(vo.getDeviceId()), commandEnum, vo.getPayload()); + } catch (ServerException e) { + if (DeviceCommandEnum.parse(vo.getCommand()).getEventType() != null + && StrUtil.contains(e.getMessage(), DeviceServiceEnum.COMMAND_ID.getValue())) { + //指令异常事件记录 + String commandId = e.getMessage().substring(e.getMessage().indexOf("<") + 1, e.getMessage().indexOf(">")); + deviceEventLogService.createAndSaveDeviceEvent( + vo.getDeviceId(), device.getTenantId(), + commandEnum.getEventType(), commandId, vo.getPayload()); + } + throw e; + } + } + + @Override + public DeviceCommandResponseDTO syncSendCommandDebug(DeviceCommandVO vo) { + IotDeviceEntity device = getById(vo.getDeviceId()); + DeviceCommandEnum commandEnum = DeviceCommandEnum.parse(vo.getCommand()); + return getSendService(device).syncSendCommandDebug(device, commandEnum, vo.getPayload()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void asyncSendCommand(DeviceCommandVO vo) { + IotDeviceEntity device = getById(vo.getDeviceId()); + getSendService(device).asyncSendCommand(device, DeviceCommandEnum.parse(vo.getCommand()), vo.getPayload()); + } + + @Override + public void simulateDeviceReportAttributeData(DeviceReportAttributeDataVO vo) { + IotDeviceEntity device = getById(vo.getDeviceId()); + vo.setDeviceId(vo.getDeviceId()); + getSendService(device).simulateDeviceReportAttributeData(device, JSONUtil.toJsonStr(vo)); + } + + @Override + public void simulateDeviceCommandResponseAttributeData(DeviceCommandResponseAttributeDataVO vo) { + IotDeviceEntity device = getById(vo.getDeviceId()); + vo.setDeviceId(vo.getDeviceId()); + getSendService(device).simulateDeviceCommandResponseAttributeData(device, JSONUtil.toJsonStr(vo)); + } + + /** + * 设备状态上报处理 + * + * @param topic + * @param deviceProperty + */ + @Override + public void handle(String topic, DevicePropertyDTO deviceProperty) { + DeviceTopicEnum.DeviceTopicContext topicContext = null; + try { + topicContext = DeviceTopicEnum.parseContext(topic); + } catch (Exception e) { + log.warn("无效设备主题:{},忽略设备状态上报消息:{}", topic, deviceProperty); + return; + } + if (log.isDebugEnabled()) { + log.warn("处理设备状态上报消息,Topic:{}, TopicContext:{}", topic, topicContext); + } + Long deviceId = topicContext.getClient().getDeviceId(); + IotDeviceEntity device = super.getById(deviceId); + if (device == null) { + log.warn("无效设备id:{},忽略设备状态上报消息:{}", deviceId, deviceProperty); + return; + } + switch (deviceProperty.getPropertyType()) { + case RUNNING_STATUS: + handleRunningStatus(device, deviceProperty, topicContext); + break; + case APP_VERSION: + handleAppVersion(device, deviceProperty, topicContext); + break; + case BATTERY_PERCENT: + handleBatteryPercent(device, deviceProperty, topicContext); + break; + case TEMPERATURE: + handleTemperature(device, deviceProperty, topicContext); + break; + default: + log.warn("未知设备属性类型:{},忽略设备状态上报消息:{}", deviceProperty.getPropertyType(), deviceProperty); + break; + } + } + + private void handleRunningStatus(IotDeviceEntity device, DevicePropertyDTO deviceProperty, DeviceTopicEnum.DeviceTopicContext topicContext) { + DeviceRunningStatusEnum oldStatus = DeviceRunningStatusEnum.parse(device.getRunningStatus().toString()); + DeviceRunningStatusEnum newStatus = DeviceRunningStatusEnum.parse(deviceProperty.getPayload()); + + device.setRunningStatus(newStatus.getValue()); + if (DeviceRunningStatusEnum.ONLINE.equals(newStatus)) { + device.setUpTime(LocalDateTime.now()); + } else if (DeviceRunningStatusEnum.OFFLINE.equals(newStatus)) { + device.setDownTime(LocalDateTime.now()); + } + device.setUpdateTime(LocalDateTime.now()); + getBaseMapper().updateById(device); + + if (newStatus.getEventType() != null) { + deviceEventLogService.createAndSaveDeviceEvent(device.getId(), topicContext.getClient().getTenantId(), + newStatus.getEventType(), null, StrUtil.format("设备上报运行状态 : {}", newStatus.getTitle())); + } + + if (log.isInfoEnabled()) { + log.info("租户:{},设备:{}-{},运行状态:{}-{} -> {}-{}", topicContext.getClient().getTenantId(), device.getId(), device.getName(), oldStatus.getValue(), oldStatus.getTitle(), newStatus.getValue(), newStatus.getTitle()); + } + } + + private void handleAppVersion(IotDeviceEntity device, DevicePropertyDTO deviceStatus, DeviceTopicEnum.DeviceTopicContext topicContext) { + if (CharSequenceUtil.equals(device.getAppVersion(), deviceStatus.getPayload())) { + return; + } + device.setAppVersion(deviceStatus.getPayload()); + device.setUpdateTime(LocalDateTime.now()); + getBaseMapper().updateById(device); + + deviceEventLogService.createAndSaveDeviceEvent(device.getId(), topicContext.getClient().getTenantId(), + DeviceEventTypeEnum.APP_VERSION_REPORT, null, + StrUtil.format(" {}:{}", DeviceEventTypeEnum.APP_VERSION_REPORT.getTitle(), deviceStatus.getPayload())); + + if (log.isInfoEnabled()) { + log.info("租户:{},设备:{}-{},App版本:{} -> {}", topicContext.getClient().getTenantId(), device.getId(), device.getName(), device.getAppVersion(), deviceStatus.getPayload()); + } + } + + private void handleBatteryPercent(IotDeviceEntity device, DevicePropertyDTO deviceStatus, DeviceTopicEnum.DeviceTopicContext topicContext) { + String batteryPercent = deviceStatus.getPayload(); + if (batteryPercent.equals(device.getBatteryPercent())) { + return; + } + device.setBatteryPercent(batteryPercent); + device.setUpdateTime(LocalDateTime.now()); + getBaseMapper().updateById(device); + + deviceEventLogService.createAndSaveDeviceEvent(device.getId(), topicContext.getClient().getTenantId(), + DeviceEventTypeEnum.BATTERY_PERCENT_REPORT, null, + StrUtil.format(" {}:{}", DeviceEventTypeEnum.BATTERY_PERCENT_REPORT.getTitle(), deviceStatus.getPayload())); + + if (log.isInfoEnabled()) { + log.info("租户:{},设备:{}-{},电池电量百分比:{} -> {}", topicContext.getClient().getTenantId(), device.getId(), device.getName(), device.getBatteryPercent(), batteryPercent); + } + } + + private void handleTemperature(IotDeviceEntity device, DevicePropertyDTO deviceStatus, DeviceTopicEnum.DeviceTopicContext topicContext) { + String temperature = deviceStatus.getPayload(); + if (temperature.equals(device.getTemperature())) { + return; + } + device.setTemperature(temperature); + device.setUpdateTime(LocalDateTime.now()); + getBaseMapper().updateById(device); + + deviceEventLogService.createAndSaveDeviceEvent(device.getId(), topicContext.getClient().getTenantId(), + DeviceEventTypeEnum.TEMPERATURE_REPORT, null, + StrUtil.format(" {}:{}", DeviceEventTypeEnum.TEMPERATURE_REPORT.getTitle(), deviceStatus.getPayload())); + + if (log.isInfoEnabled()) { + log.info("租户:{},设备:{}-{},温度:{} -> {}", topicContext.getClient().getTenantId(), device.getId(), device.getName(), device.getTemperature(), temperature); + } + } + + /** + * 设备命令响应处理 + * + * @param topic + * @param commandResponse + */ + @Override + public void handle(String topic, DeviceCommandResponseDTO commandResponse) { + DeviceTopicEnum.DeviceTopicContext topicContext = null; + try { + topicContext = DeviceTopicEnum.parseContext(topic); + } catch (Exception e) { + log.warn("无效设备主题:{},忽略设备命令响应消息:{}", topic, commandResponse); + return; + } + if (log.isDebugEnabled()) { + log.warn("处理设备设备命令响应消息,Topic:{}, TopicContext:{}", topic, topicContext); + } + + Long deviceId = topicContext.getClient().getDeviceId(); + IotDeviceEntity device = super.getById(deviceId); + if (device == null) { + log.warn("无效设备id:{},忽略设备命令响应消息:{}", deviceId, commandResponse); + return; + } + switch (commandResponse.getCommand()) { + case LOCK, UNLOCK, OTA_UPGRADE: { + //记录处理设备事件 + deviceEventLogService.createAndSaveDeviceEvent(device.getId(), + topicContext.getClient().getTenantId(), + commandResponse.getCommand().getEventType(), + commandResponse.getCommandId(), commandResponse.getResponsePayload()); + break; + } + default: + log.warn("未知设备命令类型:{},忽略设备命令响应消息:{}", commandResponse.getCommand(), commandResponse); + break; + + } + + + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceServiceLogServiceImpl.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceServiceLogServiceImpl.java new file mode 100644 index 0000000..deda0a4 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/service/impl/IotDeviceServiceLogServiceImpl.java @@ -0,0 +1,94 @@ +package com.bdzl.iot.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.iot.convert.IotDeviceServiceLogConvert; +import com.bdzl.iot.dao.IotDeviceServiceLogDao; +import com.bdzl.iot.entity.IotDeviceServiceLogEntity; +import com.bdzl.iot.enums.DeviceCommandEnum; +import com.bdzl.iot.query.IotDeviceServiceLogQuery; +import com.bdzl.iot.service.IotDeviceServiceLogService; +import com.bdzl.iot.vo.IotDeviceServiceLogVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +@Service +@AllArgsConstructor +public class IotDeviceServiceLogServiceImpl extends BaseServiceImpl implements IotDeviceServiceLogService { + + @Override + public PageResult page(IotDeviceServiceLogQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + List vos = IotDeviceServiceLogConvert.INSTANCE.convertList(page.getRecords()); + vos.forEach(vo -> { + vo.setDeviceCommandEnum(DeviceCommandEnum.getEnum(vo.getServiceType())); + }); + return new PageResult<>(vos, page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(IotDeviceServiceLogQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + if (StrUtil.isNotBlank(query.getDeviceCommandEnum())) { + wrapper.eq(IotDeviceServiceLogEntity::getServiceType, DeviceCommandEnum.parse(query.getDeviceCommandEnum()).getValue()); + } + wrapper.eq(query.getDeviceId() != null, IotDeviceServiceLogEntity::getDeviceId, query.getDeviceId()); + wrapper.orderByDesc(IotDeviceServiceLogEntity::getServiceTime); + return wrapper; + } + + @Override + public void save(IotDeviceServiceLogVO vo) { + IotDeviceServiceLogEntity entity = IotDeviceServiceLogConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(IotDeviceServiceLogVO vo) { + IotDeviceServiceLogEntity entity = IotDeviceServiceLogConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + + @Override + public IotDeviceServiceLogEntity createDeviceServiceLog(Long deviceId, Long tenantId, DeviceCommandEnum serviceCommand, String eventUid, Object payload) { + IotDeviceServiceLogEntity deviceServiceLog = new IotDeviceServiceLogEntity(); + deviceServiceLog.setDeviceId(deviceId); + deviceServiceLog.setTenantId(tenantId); + deviceServiceLog.setServiceType(serviceCommand.getValue()); + deviceServiceLog.setServiceUid(eventUid); + if (payload != null) { + deviceServiceLog.setServicePayload((payload instanceof String) + ? (String) payload + : JsonUtils.toJsonString(payload)); + } + deviceServiceLog.setServiceTime(LocalDateTime.now()); + return deviceServiceLog; + } + + @Override + public void createAndSaveDeviceServiceLog(Long deviceId, Long tenantId, DeviceCommandEnum serviceCommand, String eventUid, Object payload) { + save(createDeviceServiceLog(deviceId, tenantId, serviceCommand, eventUid, payload)); + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/utils/MqttUtils.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/utils/MqttUtils.java new file mode 100644 index 0000000..52c8805 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/utils/MqttUtils.java @@ -0,0 +1,44 @@ +package com.bdzl.iot.utils; + +import lombok.RequiredArgsConstructor; +import org.springframework.integration.mqtt.inbound.AbstractMqttMessageDrivenChannelAdapter; +import org.springframework.stereotype.Component; + +/** + * Mqtt工具类 + * + * @author LSF maku_lsf@163.com + */ +@Component +@RequiredArgsConstructor +public class MqttUtils { + private final AbstractMqttMessageDrivenChannelAdapter mqttMessageAdapter; + + /** + * 动态订阅主题,默认使用qos 1 + * + * @param topics + */ + public void addTopic(String... topics) { + mqttMessageAdapter.addTopic(topics); + } + + /** + * 动态订阅主题 + * + * @param topic + * @param qos + */ + public void addTopic(String topic, int qos) { + mqttMessageAdapter.addTopic(topic, qos); + } + + /** + * 动态取消主题订阅 + * + * @param topics + */ + public void removeTopic(String... topics) { + mqttMessageAdapter.removeTopic(topics); + } +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceCommandResponseAttributeDataVO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceCommandResponseAttributeDataVO.java new file mode 100644 index 0000000..1c8c180 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceCommandResponseAttributeDataVO.java @@ -0,0 +1,41 @@ +package com.bdzl.iot.vo; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.iot.enums.DeviceCommandEnum; + +import java.io.Serializable; + +/** + * 设备命令响应数据 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备命令响应VO") +@JsonIgnoreProperties(ignoreUnknown = true) +public class DeviceCommandResponseAttributeDataVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "设备ID") + private Long deviceId; + + @Schema(description = "命令类型", required = true) + private DeviceCommandEnum command; + + @Schema(description = "命令ID", required = true) + private String commandId; + + @Schema(description = "命令是否完成(默认true:命令已完成;false:命令未完成,后续命令完成将再次发送响应消息,服务端将继续等待该命令完成的响应)") + private boolean isCompleted = true; + + @Schema(description = "响应状态码,0成功,其它数值异常,根据业务需要自定义") + private Integer statusCode = 0; + + @Schema(description = "响应状态消息") + private String statusMessage; + + @Schema(description = "命令响应结果") + private String responsePayload; +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceCommandVO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceCommandVO.java new file mode 100644 index 0000000..d25dfc6 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceCommandVO.java @@ -0,0 +1,26 @@ +package com.bdzl.iot.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 设备指令 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备指令VO") +public class DeviceCommandVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "设备ID") + private Long deviceId; + + @Schema(description = "指令") + private String command; + + @Schema(description = "指令内容") + private String payload; +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceReportAttributeDataVO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceReportAttributeDataVO.java new file mode 100644 index 0000000..e8cae36 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/DeviceReportAttributeDataVO.java @@ -0,0 +1,27 @@ +package com.bdzl.iot.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 设备上报属性数据 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备上报属性数据VO") +public class DeviceReportAttributeDataVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "设备ID") + private Long deviceId; + + @Schema(description = "设备属性类型") + private String propertyType; + + @Schema(description = "属性数据") + private String payload; + +} diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceEventLogVO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceEventLogVO.java new file mode 100644 index 0000000..5bc9487 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceEventLogVO.java @@ -0,0 +1,38 @@ +package com.bdzl.iot.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; +import com.bdzl.iot.enums.DeviceEventTypeEnum; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 设备事件日志 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备事件日志") +public class IotDeviceEventLogVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "事件类型") + private Integer eventType; + + @Schema(description = "事件") + private DeviceEventTypeEnum eventTypeEnum; + + @Schema(description = "事件标识id") + private String eventUid; + + @Schema(description = "事件数据") + private String eventPayload; + + @Schema(description = "事件时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime eventTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceServiceLogVO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceServiceLogVO.java new file mode 100644 index 0000000..e4fa489 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceServiceLogVO.java @@ -0,0 +1,41 @@ +package com.bdzl.iot.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; +import com.bdzl.iot.enums.DeviceCommandEnum; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 设备服务日志 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备服务日志") +public class IotDeviceServiceLogVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "服务类型") + private Integer serviceType; + + @Schema(description = "指令") + private DeviceCommandEnum deviceCommandEnum; + + @Schema(description = "服务标识id") + private String serviceUid; + + @Schema(description = "服务数据") + private String servicePayload; + + @Schema(description = "服务时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime serviceTime; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceVO.java b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceVO.java new file mode 100644 index 0000000..180292c --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/java/com/bdzl/iot/vo/IotDeviceVO.java @@ -0,0 +1,82 @@ +package com.bdzl.iot.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 设备表 + * + * @author LSF maku_lsf@163.com + */ +@Data +@Schema(description = "设备表") +public class IotDeviceVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + private Long id; + + @Schema(description = "编码") + private String code; + + @Schema(description = "名称") + private String name; + + @Schema(description = "设备类型,1.手持设备,2.柜体,3传感设备") + private Integer type; + + @Schema(description = "协议类型") + private String protocolType; + + @Schema(description = "唯一标识码") + private String uid; + + @Schema(description = "设备密钥") + private String secret; + + @Schema(description = "App版本号") + private String appVersion; + + @Schema(description = "电池电量百分比") + private String batteryPercent; + + @Schema(description = "温度") + private String temperature; + + @Schema(description = "状态,0禁用,1正常") + private Integer status; + + @Schema(description = "运行状态") + private Integer runningStatus; + + @Schema(description = "上线时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime upTime; + + @Schema(description = "下线时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime downTime; + + @Schema(description = "租户ID") + private Long tenantId; + + @Schema(description = "创建者") + private Long creator; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + @Schema(description = "更新者") + private Long updater; + + @Schema(description = "更新时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceDao.xml b/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceDao.xml new file mode 100644 index 0000000..eca8d66 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceEventLogDao.xml b/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceEventLogDao.xml new file mode 100644 index 0000000..f3ba474 --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceEventLogDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceServiceLogDao.xml b/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceServiceLogDao.xml new file mode 100644 index 0000000..868df1f --- /dev/null +++ b/drone-ops-module/drone-ops-module-iot/src/main/resources/mapper/iot/IotDeviceServiceLogDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/pom.xml b/drone-ops-module/drone-ops-module-member/pom.xml new file mode 100644 index 0000000..fa4fc79 --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/pom.xml @@ -0,0 +1,20 @@ + + + com.bdzl + drone-ops-module + ${revision} + + 4.0.0 + drone-ops-module-member + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/controller/MemberUserController.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/controller/MemberUserController.java new file mode 100644 index 0000000..e3f204e --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/controller/MemberUserController.java @@ -0,0 +1,76 @@ +package com.bdzl.member.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.member.convert.MemberUserConvert; +import com.bdzl.member.entity.MemberUserEntity; +import com.bdzl.member.query.MemberUserQuery; +import com.bdzl.member.service.MemberUserService; +import com.bdzl.member.vo.MemberUserVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + */ +@RestController +@RequestMapping("member/user") +@Tag(name = "会员管理") +@AllArgsConstructor +public class MemberUserController { + private final MemberUserService memberUserService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('member:user:all')") + public Result> page(@ParameterObject @Valid MemberUserQuery query) { + PageResult page = memberUserService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('member:user:all')") + public Result get(@PathVariable("id") Long id) { + MemberUserEntity entity = memberUserService.getById(id); + + return Result.ok(MemberUserConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('member:user:all')") + public Result save(@RequestBody MemberUserVO vo) { + memberUserService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('member:user:all')") + public Result update(@RequestBody @Valid MemberUserVO vo) { + memberUserService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('member:user:all')") + public Result delete(@RequestBody List idList) { + memberUserService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/convert/MemberUserConvert.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/convert/MemberUserConvert.java new file mode 100644 index 0000000..4dc9aef --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/convert/MemberUserConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.member.convert; + +import com.bdzl.member.entity.MemberUserEntity; +import com.bdzl.member.vo.MemberUserVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface MemberUserConvert { + MemberUserConvert INSTANCE = Mappers.getMapper(MemberUserConvert.class); + + MemberUserEntity convert(MemberUserVO vo); + + MemberUserVO convert(MemberUserEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/dao/MemberUserDao.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/dao/MemberUserDao.java new file mode 100644 index 0000000..d36032d --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/dao/MemberUserDao.java @@ -0,0 +1,15 @@ +package com.bdzl.member.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.member.entity.MemberUserEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface MemberUserDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/entity/MemberUserEntity.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/entity/MemberUserEntity.java new file mode 100644 index 0000000..d9aea34 --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/entity/MemberUserEntity.java @@ -0,0 +1,94 @@ +package com.bdzl.member.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + */ + +@Data +@TableName("member_user") +public class MemberUserEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 昵称 + */ + private String nickName; + + /** + * 手机号 + */ + private String mobile; + + /** + * 头像 + */ + private String avatar; + + /** + * 出生日期 + */ + private LocalDateTime birthday; + + /** + * 性别 + */ + private Integer gender; + + /** + * 第三方平台,唯一标识 + */ + private String openid; + + /** + * 最后登录IP + */ + private String lastLoginIp; + + /** + * 最后登录时间 + */ + private LocalDateTime lastLoginTime; + + /** + * 备注 + */ + private String remark; + + /** + * 状态 + */ + private Integer status; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 版本号 + */ + private Integer version; + + /** + * 删除标识 + */ + private Integer deleted; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/query/MemberUserQuery.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/query/MemberUserQuery.java new file mode 100644 index 0000000..0024034 --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/query/MemberUserQuery.java @@ -0,0 +1,29 @@ +package com.bdzl.member.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 会员管理查询 + * + * @author 阿沐 babamu@126.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "会员管理查询") +public class MemberUserQuery extends Query { + @Schema(description = "昵称") + private String nickName; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "性别") + private Integer gender; + + @Schema(description = "状态") + private Integer status; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/service/MemberUserService.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/service/MemberUserService.java new file mode 100644 index 0000000..0c6116f --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/service/MemberUserService.java @@ -0,0 +1,25 @@ +package com.bdzl.member.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.member.entity.MemberUserEntity; +import com.bdzl.member.query.MemberUserQuery; +import com.bdzl.member.vo.MemberUserVO; + +import java.util.List; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + */ +public interface MemberUserService extends BaseService { + + PageResult page(MemberUserQuery query); + + void save(MemberUserVO vo); + + void update(MemberUserVO vo); + + void delete(List idList); +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/service/impl/MemberUserServiceImpl.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/service/impl/MemberUserServiceImpl.java new file mode 100644 index 0000000..057da0f --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/service/impl/MemberUserServiceImpl.java @@ -0,0 +1,63 @@ +package com.bdzl.member.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.member.convert.MemberUserConvert; +import com.bdzl.member.entity.MemberUserEntity; +import com.bdzl.member.query.MemberUserQuery; +import com.bdzl.member.vo.MemberUserVO; +import com.bdzl.member.dao.MemberUserDao; +import com.bdzl.member.service.MemberUserService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + * @since 1.0.0 2024-03-11 + */ +@Service +@AllArgsConstructor +public class MemberUserServiceImpl extends BaseServiceImpl implements MemberUserService { + + @Override + public PageResult page(MemberUserQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(MemberUserConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(MemberUserQuery query){ + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + + return wrapper; + } + + @Override + public void save(MemberUserVO vo) { + MemberUserEntity entity = MemberUserConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(MemberUserVO vo) { + MemberUserEntity entity = MemberUserConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/vo/MemberUserVO.java b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/vo/MemberUserVO.java new file mode 100644 index 0000000..b526f64 --- /dev/null +++ b/drone-ops-module/drone-ops-module-member/src/main/java/com/bdzl/member/vo/MemberUserVO.java @@ -0,0 +1,57 @@ +package com.bdzl.member.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 会员管理 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "会员管理") +public class MemberUserVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "昵称") + private String nickName; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "出生日期") + @JsonFormat(pattern = DateUtils.DATE_PATTERN) + private LocalDateTime birthday; + + @Schema(description = "性别") + private Integer gender; + + @Schema(description = "最后登录IP") + private String lastLoginIp; + + @Schema(description = "最后登录时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime lastLoginTime; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-monitor/pom.xml b/drone-ops-module/drone-ops-module-monitor/pom.xml new file mode 100644 index 0000000..d961de4 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/pom.xml @@ -0,0 +1,25 @@ + + + com.bdzl + drone-ops-module + ${revision} + + 4.0.0 + drone-ops-module-monitor + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + com.github.oshi + oshi-core + 6.4.0 + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/CacheController.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/CacheController.java new file mode 100644 index 0000000..6aa949a --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/CacheController.java @@ -0,0 +1,130 @@ +package com.bdzl.monitor.controller; + +import jakarta.annotation.Resource; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.monitor.vo.Cache; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.redis.connection.RedisServerCommands; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 缓存监控 + * + * @author Pure tea + */ +@RestController +@RequestMapping("monitor/cache") +public class CacheController { + @Resource + private RedisTemplate redisTemplate; + + /** + * Redis详情 + */ + @GetMapping("info") + @PreAuthorize("hasAuthority('monitor:cache:all')") + public Result> getInfo() { + Map result = new HashMap<>(); + // Step 1: 获取Redis详情 + Properties info = (Properties) redisTemplate.execute((RedisCallback) RedisServerCommands::info); + result.put("info", info); + // Step 2: 获取Key的数量 + Object dbSize = redisTemplate.execute((RedisCallback) RedisServerCommands::dbSize); + result.put("keyCount", dbSize); + // Step 3: 获取请求次数 + List> pieList = new ArrayList<>(); + Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandStats")); + if (commandStats != null && commandStats.size() != 0) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.substring(key, 8)); + data.put("value", StringUtils.substringBetween(property, "calls=", ",use")); + pieList.add(data); + }); + } + result.put("commandStats", pieList); + return Result.ok(result); + } + + /** + * 获取所有的Key + */ + @GetMapping("getCacheKeys") + @PreAuthorize("hasAuthority('monitor:cache:all')") + public Result> getCacheKeys() { + Set cacheKeys = redisTemplate.keys("*"); + return Result.ok(cacheKeys); + } + + /** + * 获取结构化键下的Key值 + * + * @param cacheKey + */ + @GetMapping("getCacheKeys/{cacheKey}") + @PreAuthorize("hasAuthority('monitor:cache:all')") + public Result> getCacheKeys(@PathVariable String cacheKey) { + Set cacheKeys = redisTemplate.keys(cacheKey + "*"); + return Result.ok(cacheKeys); + } + + /** + * 获取指定键的值 + * + * @param cacheKey + */ + @GetMapping("getCacheValue/{cacheKey}") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result getCacheValue(@PathVariable String cacheKey) { + Object cacheValue = redisTemplate.opsForValue().get(cacheKey); + Cache cache = new Cache(cacheKey, cacheValue); + return Result.ok(cache); + } + + /** + * 删除指定键的缓存 + * + * @param cacheKey > Key值 + */ + @DeleteMapping("delCacheKey/{cacheKey}") + @PreAuthorize("hasAuthority('monitor:cache:all')") + public Result delCacheKey(@PathVariable String cacheKey) { + boolean flag = redisTemplate.delete(cacheKey); + if (flag) { + return Result.ok(); + } else { + return Result.error(200, "处理失败!"); + } + } + + /** + * 删除结构化键下的缓存 + * + * @param cacheKey > Key值 + */ + @DeleteMapping("delCacheKeys/{cacheKey}") + @PreAuthorize("hasAuthority('monitor:cache:all')") + public Result delCacheKeys(@PathVariable String cacheKey) { + Collection cacheKeys = redisTemplate.keys(cacheKey + "*"); + redisTemplate.delete(cacheKeys); + return Result.ok(); + } + + /** + * 删除全部缓存 + */ + @DeleteMapping("delCacheAll") + @PreAuthorize("hasAuthority('monitor:cache:all')") + public Result delCacheAll() { + Collection cacheKeys = redisTemplate.keys("*"); + redisTemplate.delete(cacheKeys); + return Result.ok(); + } + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/ServerController.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/ServerController.java new file mode 100644 index 0000000..553ca5f --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/ServerController.java @@ -0,0 +1,82 @@ +package com.bdzl.monitor.controller; + +import com.bdzl.framework.common.utils.Result; +import com.bdzl.monitor.model.*; +import com.bdzl.monitor.vo.Server; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 服务器监控 + * + * @author Pure tea + */ +@RestController +@RequestMapping("monitor/server") +public class ServerController { + + /** + * 服务器相关信息 + */ + @GetMapping("info") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result getServerInfo() { + Server server = new Server(); + return Result.ok(server); + } + + /** + * CPU相关信息 + */ + @GetMapping("cpu") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result getCpuInfo() { + Cpu cpu = new Cpu(); + return Result.ok(cpu); + } + + /** + * 内存相关信息 + */ + @GetMapping("mem") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result getMemInfo() { + Mem mem = new Mem(); + return Result.ok(mem); + } + + /** + * JVM相关信息 + */ + @GetMapping("jvm") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result getJvmInfo() { + Jvm jvm = new Jvm(); + return Result.ok(jvm); + } + + /** + * 系统相关信息 + */ + @GetMapping("sys") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result getSysInfo() { + Sys sys = new Sys(); + return Result.ok(sys); + } + + /** + * 系统文件相关信息 + */ + @GetMapping("disk") + @PreAuthorize("hasAuthority('monitor:server:all')") + public Result> getSysFileInfo() { + Server server = new Server(new Disk()); + return Result.ok(server.getDisks()); + } + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/UserOnlineController.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/UserOnlineController.java new file mode 100644 index 0000000..e0de2ff --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/controller/UserOnlineController.java @@ -0,0 +1,76 @@ +package com.bdzl.monitor.controller; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.StrUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import com.bdzl.framework.common.cache.RedisKeys; +import com.bdzl.framework.common.query.Query; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.security.cache.TokenStoreCache; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.monitor.vo.UserOnlineVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +@RestController +@RequestMapping("monitor/user") +@AllArgsConstructor +@Tag(name = "在线用户监控") +public class UserOnlineController { + private final TokenStoreCache tokenStoreCache; + private final RedisCache redisCache; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('monitor:user:all')") + public Result> page(@ParameterObject @Valid Query query) { + // 获取登录用户的全部key + List keys = tokenStoreCache.getUserKeyList(); + + // 逻辑分页 + List keyList = ListUtil.page(query.getPage() - 1, query.getLimit(), keys); + + List userOnlineList = new ArrayList<>(); + keyList.forEach(key -> { + UserDetail user = (UserDetail) redisCache.get(key); + if (user != null) { + UserOnlineVO userOnlineVO = new UserOnlineVO(); + userOnlineVO.setId(user.getId()); + userOnlineVO.setUsername(user.getUsername()); + userOnlineVO.setRealName(user.getRealName()); + userOnlineVO.setGender(user.getGender()); + userOnlineVO.setEmail(user.getEmail()); + userOnlineVO.setAccessToken(key.replace(RedisKeys.getAccessTokenKey(""), "")); + + userOnlineList.add(userOnlineVO); + } + + }); + + return Result.ok(new PageResult<>(userOnlineList, keys.size())); + } + + @DeleteMapping("{accessToken}") + @Operation(summary = "强制退出") + @PreAuthorize("hasAuthority('monitor:user:all')") + public Result forceLogout(@PathVariable("accessToken") String accessToken) { + // token不能为空 + if (StrUtil.isBlank(accessToken)) { + Result.error("token不能为空"); + } + + // 删除用户信息 + tokenStoreCache.deleteUser(accessToken); + + return Result.ok(); + } +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Cpu.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Cpu.java new file mode 100644 index 0000000..49e8390 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Cpu.java @@ -0,0 +1,67 @@ +package com.bdzl.monitor.model; + +import cn.hutool.system.oshi.CpuInfo; +import cn.hutool.system.oshi.OshiUtil; +import lombok.Data; + +/** + * Cpu Info + * + * @author Pure tea + */ +@Data +public class Cpu { + + /** + * 设置等待时间,单位毫秒 + */ + private static final Long JOSHI_WAIT_SECOND = 360L; + + /** + * CPU型号 + */ + private String cpuModel; + + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + public Cpu() { + // 获取CPU相关信息,间隔1秒 + CpuInfo cpuInfo = OshiUtil.getCpuInfo(JOSHI_WAIT_SECOND); + this.setCpuModel(cpuInfo.getCpuModel().split("\n")[0]); + this.setCpuNum(cpuInfo.getCpuNum()); + this.setTotal(cpuInfo.getToTal()); + this.setSys(cpuInfo.getSys()); + this.setUsed(cpuInfo.getUser()); + this.setWait(cpuInfo.getWait()); + this.setFree(cpuInfo.getFree()); + } + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Disk.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Disk.java new file mode 100644 index 0000000..c6bbf41 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Disk.java @@ -0,0 +1,48 @@ +package com.bdzl.monitor.model; + +import lombok.Data; + +/** + * Disk + * + * @author Pure tea + */ +@Data +public class Disk { + + /** + * 磁盘名称 + */ + private String diskName; + + /** + * 磁盘类型 + */ + private String diskType; + + /** + * 磁盘路径 + */ + private String dirName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private double usage; + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Jvm.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Jvm.java new file mode 100644 index 0000000..6f241fe --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Jvm.java @@ -0,0 +1,101 @@ +package com.bdzl.monitor.model; + +import cn.hutool.core.date.BetweenFormatter; +import cn.hutool.core.date.DateUtil; +import cn.hutool.system.SystemUtil; +import lombok.Data; +import com.bdzl.monitor.utils.ArityUtil; + +import java.util.Date; +import java.util.List; + +/** + * Jvm Info + * + * @author Pure tea + */ +@Data +public class Jvm { + + /** + * JVM 最大可用内存总数(G) + */ + private double max; + + /** + * JVM 占用的内存总数(M) + */ + private double total; + + /** + * JVM 已用内存(M) + */ + private double used; + + /** + * JVM 空闲内存(M) + */ + private double free; + + /** + * JVM 内存使用率 + */ + private double usage; + + /** + * JVM 名称 + */ + private String name; + + /** + * Java Version + */ + private String version; + + /** + * JavaVM Vendor + */ + private String vendor; + + /** + * JDK 路径 + */ + private String home; + + /** + * JarDir + */ + private String userDir; + + /** + * JVM 启动时间 + */ + private String startTime; + + /** + * JVM 运行时间 + */ + private String runTime; + + /** + * JVM InputArguments + */ + private List inputArguments; + + public Jvm() { + this.setMax(ArityUtil.div(SystemUtil.getMaxMemory(), 1024 * 1024 * 1024, 2)); + this.setTotal(ArityUtil.div(SystemUtil.getTotalMemory(), 1024 * 1024 * 1024, 2)); + this.setFree(ArityUtil.div(SystemUtil.getFreeMemory(), 1024 * 1024 * 1024, 2)); + this.setUsed(ArityUtil.round(this.getTotal() - this.getFree(), 2)); + this.setUsage(ArityUtil.div(this.getUsed(), this.getTotal(), 4) * 100); + this.setName(SystemUtil.getRuntimeMXBean().getVmName()); + this.setVersion(SystemUtil.getJavaInfo().getVersion()); + this.setVendor(SystemUtil.getJavaInfo().getVendor()); + this.setHome(SystemUtil.getJavaRuntimeInfo().getHomeDir()); + this.setUserDir(SystemUtil.getUserInfo().getCurrentDir()); + Date startTime = new Date(SystemUtil.getRuntimeMXBean().getStartTime()); + this.setStartTime(DateUtil.formatDateTime(startTime)); + this.setRunTime(DateUtil.formatBetween(startTime, new Date(), BetweenFormatter.Level.SECOND)); + this.setInputArguments(SystemUtil.getRuntimeMXBean().getInputArguments()); + } +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Mem.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Mem.java new file mode 100644 index 0000000..f293330 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Mem.java @@ -0,0 +1,44 @@ +package com.bdzl.monitor.model; + +import cn.hutool.system.oshi.OshiUtil; +import lombok.Data; +import com.bdzl.monitor.utils.ArityUtil; +import oshi.hardware.GlobalMemory; + +/** + * Mem Info + * + * @author Pure tea + */ +@Data +public class Mem { + + /** + * 内存总数(G) + */ + private double total; + + /** + * 已用内存(G) + */ + private double used; + + /** + * 剩余内存(G) + */ + private double free; + + /** + * 内存使用率 + */ + private double usage; + + public Mem() { + GlobalMemory globalMemory = OshiUtil.getMemory(); + this.setTotal(ArityUtil.div(globalMemory.getTotal(), 1024 * 1024 * 1024, 2)); + this.setFree(ArityUtil.div(globalMemory.getAvailable(), 1024 * 1024 * 1024, 2)); + this.setUsed(ArityUtil.sub(this.getTotal(), this.getFree())); + this.setUsage(ArityUtil.round(ArityUtil.div(this.getUsed(), this.getTotal(), 4) * 100, 2)); + } + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Sys.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Sys.java new file mode 100644 index 0000000..9afdc63 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/model/Sys.java @@ -0,0 +1,49 @@ +package com.bdzl.monitor.model; + +import cn.hutool.system.SystemUtil; +import cn.hutool.system.oshi.OshiUtil; +import lombok.Data; + +/** + * System Info + * + * @author Pure tea + */ +@Data +public class Sys { + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; + + /** + * 系统版本 + */ + private String osVersion; + + + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器Ip + */ + private String computerIp; + + public Sys() { + this.setOsName(SystemUtil.getOsInfo().getName()); + this.setOsArch(SystemUtil.getOsInfo().getArch()); + this.setOsVersion(SystemUtil.getOsInfo().getVersion()); + this.setComputerName(OshiUtil.getOs().getNetworkParams().getHostName()); + this.setComputerIp(SystemUtil.getHostInfo().getAddress()); + } + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/utils/ArityUtil.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/utils/ArityUtil.java new file mode 100644 index 0000000..5b84915 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/utils/ArityUtil.java @@ -0,0 +1,114 @@ +package com.bdzl.monitor.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 精确浮点数运算 + * + * @author Pure tea + */ +public class ArityUtil { + + /** + * 默认除法运算精度 + */ + private static final int DEF_DIV_SCALE = 10; + + /** + * 这个类不能实例化 + */ + private ArityUtil() { + + } + + /** + * 提供精确的加法运算。 + * + * @param v1 被加数 + * @param v2 加数 + * @return 两个参数的和 + */ + public static double add(double v1, double v2) { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.add(b2).doubleValue(); + } + + /** + * 提供精确的减法运算。 + * + * @param v1 被减数 + * @param v2 减数 + * @return 两个参数的差 + */ + public static double sub(double v1, double v2) { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.subtract(b2).doubleValue(); + } + + /** + * 提供精确的乘法运算。 + * + * @param v1 被乘数 + * @param v2 乘数 + * @return 两个参数的积 + */ + public static double mul(double v1, double v2) { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.multiply(b2).doubleValue(); + } + + /** + * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 + * 小数点以后10位,以后的数字四舍五入。 + * + * @param v1 被除数 + * @param v2 除数 + * @return 两个参数的商 + */ + public static double div(double v1, double v2) { + return div(v1, v2, DEF_DIV_SCALE); + } + + /** + * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 + * 定精度,以后的数字四舍五入。 + * + * @param v1 被除数 + * @param v2 除数 + * @param scale 表示表示需要精确到小数点以后几位。 + * @return 两个参数的商 + */ + public static double div(double v1, double v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + if (b1.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO.doubleValue(); + } + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 提供精确的小数位四舍五入处理。 + * + * @param v 需要四舍五入的数字 + * @param scale 小数点后保留几位 + * @return 四舍五入后的结果 + */ + public static double round(double v, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b = new BigDecimal(Double.toString(v)); + BigDecimal one = BigDecimal.ONE; + return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); + } +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/Cache.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/Cache.java new file mode 100644 index 0000000..7a0dc00 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/Cache.java @@ -0,0 +1,20 @@ +package com.bdzl.monitor.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Redis Info + * + * @author Pure tea + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Cache { + + private String cacheKey; + + private Object cacheValue; +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/Server.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/Server.java new file mode 100644 index 0000000..aaa04ae --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/Server.java @@ -0,0 +1,116 @@ +package com.bdzl.monitor.vo; + +import com.bdzl.monitor.model.*; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.monitor.utils.ArityUtil; +import oshi.SystemInfo; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; + +import java.util.LinkedList; +import java.util.List; + +/** + * Server Info + * + * @author Pure tea + */ +@Tag(name = "服务器信息") +@Data +@Slf4j +public class Server { + + /** + * Cpu Info + */ + @Schema(description = "CPU信息") + private Cpu cpu; + + /** + * Mem Info + */ + @Schema(description = "内存信息") + private Mem mem; + + /** + * Jvm Info + */ + @Schema(description = "JVM信息") + private Jvm jvm; + + /** + * Sys Info + */ + @Schema(description = "系统信息") + private Sys sys; + + /** + * SysFile Info + */ + @Schema(description = "系统文件信息") + private List disks = new LinkedList<>(); + + public Server() { + this.cpu = new Cpu(); + this.mem = new Mem(); + this.jvm = new Jvm(); + this.sys = new Sys(); + this.setDiskList(); + log.debug("Server Info => {}", this); + } + + public Server(Disk disk) { + this.setDiskList(); + log.debug("Server Info => {}", this); + } + + /** + * 设置磁盘信息 + */ + private void setDiskList() { + SystemInfo systemInfo = new SystemInfo(); + FileSystem fileSystem = systemInfo.getOperatingSystem().getFileSystem(); + List fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + Disk disk = new Disk(); + disk.setDiskName(fs.getName()); + disk.setDiskType(fs.getType()); + disk.setDirName(fs.getMount()); + disk.setTotal(convertFileSize(total)); + disk.setFree(convertFileSize(free)); + disk.setUsed(convertFileSize(used)); + disk.setUsage(ArityUtil.mul(ArityUtil.div(used, total, 4), 100)); + this.disks.add(disk); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public static String convertFileSize(long size) { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) { + return String.format("%.1f GB", (float) size / gb); + } else if (size >= mb) { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } else if (size >= kb) { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } else { + return String.format("%d B", size); + } + } + +} diff --git a/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/UserOnlineVO.java b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/UserOnlineVO.java new file mode 100644 index 0000000..3d80fe0 --- /dev/null +++ b/drone-ops-module/drone-ops-module-monitor/src/main/java/com/bdzl/monitor/vo/UserOnlineVO.java @@ -0,0 +1,32 @@ +package com.bdzl.monitor.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 在线用户 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "在线用户") +public class UserOnlineVO { + @Schema(description = "id") + private Long id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "姓名") + private String realName; + + @Schema(description = "性别") + private Integer gender; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "accessToken") + private String accessToken; +} diff --git a/drone-ops-module/drone-ops-module-quartz/pom.xml b/drone-ops-module/drone-ops-module-quartz/pom.xml new file mode 100644 index 0000000..5c3ed6f --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/pom.xml @@ -0,0 +1,23 @@ + + + com.bdzl + drone-ops-module + ${revision} + + 4.0.0 + drone-ops-module-quartz + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + org.quartz-scheduler + quartz + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/config/ScheduleConfig.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/config/ScheduleConfig.java new file mode 100644 index 0000000..ef018cb --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/config/ScheduleConfig.java @@ -0,0 +1,62 @@ +package com.bdzl.quartz.config; + +import com.bdzl.framework.common.constant.Constant; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * 定时任务配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +public class ScheduleConfig { + @Value("${spring.datasource.dynamic.datasource.master.driver-class-name}") + private String driver; + + @Bean + public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) { + // quartz参数 + Properties prop = new Properties(); + prop.put("org.quartz.scheduler.instanceName", "MakuScheduler"); + prop.put("org.quartz.scheduler.instanceId", "AUTO"); + // 线程池配置 + prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); + prop.put("org.quartz.threadPool.threadCount", "20"); + prop.put("org.quartz.threadPool.threadPriority", "5"); + // jobStore配置 + prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); + // 集群配置 + prop.put("org.quartz.jobStore.isClustered", "true"); + prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); + prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); + prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); + + prop.put("org.quartz.jobStore.misfireThreshold", "12000"); + prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); + prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); + + // PostgreSQL数据库配置 + if (Constant.PGSQL_DRIVER.equals(driver)) { + prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"); + } + + SchedulerFactoryBean factory = new SchedulerFactoryBean(); + factory.setSchedulerName("MakuScheduler"); + factory.setDataSource(dataSource); + factory.setQuartzProperties(prop); + // 延时启动 + factory.setStartupDelay(10); + factory.setApplicationContextSchedulerContextKey("applicationContextKey"); + // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 + factory.setOverwriteExistingJobs(true); + + return factory; + } +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/controller/ScheduleJobController.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/controller/ScheduleJobController.java new file mode 100644 index 0000000..37698c5 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/controller/ScheduleJobController.java @@ -0,0 +1,129 @@ +package com.bdzl.quartz.controller; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.extra.spring.SpringUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.quartz.convert.ScheduleJobConvert; +import com.bdzl.quartz.entity.ScheduleJobEntity; +import com.bdzl.quartz.query.ScheduleJobQuery; +import com.bdzl.quartz.service.ScheduleJobService; +import com.bdzl.quartz.utils.CronUtils; +import com.bdzl.quartz.vo.ScheduleJobVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 定时任务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("schedule") +@Tag(name = "定时任务") +@AllArgsConstructor +public class ScheduleJobController { + private final ScheduleJobService scheduleJobService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('schedule:page')") + public Result> page(@ParameterObject @Valid ScheduleJobQuery query) { + PageResult page = scheduleJobService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('schedule:info')") + public Result get(@PathVariable("id") Long id) { + ScheduleJobEntity entity = scheduleJobService.getById(id); + + return Result.ok(ScheduleJobConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('schedule:save')") + public Result save(@RequestBody ScheduleJobVO vo) { + if (!CronUtils.isValid(vo.getCronExpression())) { + return Result.error("操作失败,Cron表达式不正确"); + } + + // 检查Bean的合法性 + checkBean(vo.getBeanName()); + + scheduleJobService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('schedule:update')") + public Result update(@RequestBody @Valid ScheduleJobVO vo) { + if (!CronUtils.isValid(vo.getCronExpression())) { + return Result.error("操作失败,Cron表达式不正确"); + } + + // 检查Bean的合法性 + checkBean(vo.getBeanName()); + + scheduleJobService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('schedule:delete')") + public Result delete(@RequestBody List idList) { + scheduleJobService.delete(idList); + + return Result.ok(); + } + + @PutMapping("run") + @Operation(summary = "立即执行") + @OperateLog(type = OperateTypeEnum.OTHER) + @PreAuthorize("hasAuthority('schedule:run')") + public Result run(@RequestBody ScheduleJobVO vo) { + scheduleJobService.run(vo); + + return Result.ok(); + } + + @PutMapping("change-status") + @Operation(summary = "修改状态") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('schedule:update')") + public Result changeStatus(@RequestBody ScheduleJobVO vo) { + scheduleJobService.changeStatus(vo); + + return Result.ok(); + } + + private void checkBean(String beanName) { + // 为避免执行jdbcTemplate等类,只允许添加有@Service注解的Bean + String[] serviceBeans = SpringUtil.getApplicationContext().getBeanNamesForAnnotation(Service.class); + if (!ArrayUtil.contains(serviceBeans, beanName)) { + throw new ServerException("只允许添加有@Service注解的Bean!"); + } + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/controller/ScheduleJobLogController.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/controller/ScheduleJobLogController.java new file mode 100644 index 0000000..b4e424c --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/controller/ScheduleJobLogController.java @@ -0,0 +1,52 @@ +package com.bdzl.quartz.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.quartz.convert.ScheduleJobLogConvert; +import com.bdzl.quartz.entity.ScheduleJobLogEntity; +import com.bdzl.quartz.query.ScheduleJobLogQuery; +import com.bdzl.quartz.service.ScheduleJobLogService; +import com.bdzl.quartz.vo.ScheduleJobLogVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 定时任务日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("schedule/log") +@Tag(name = "定时任务日志") +@AllArgsConstructor +public class ScheduleJobLogController { + private final ScheduleJobLogService scheduleJobLogService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('schedule:log')") + public Result> page(@ParameterObject @Valid ScheduleJobLogQuery query) { + PageResult page = scheduleJobLogService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('schedule:log')") + public Result get(@PathVariable("id") Long id) { + ScheduleJobLogEntity entity = scheduleJobLogService.getById(id); + + return Result.ok(ScheduleJobLogConvert.INSTANCE.convert(entity)); + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/convert/ScheduleJobConvert.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/convert/ScheduleJobConvert.java new file mode 100644 index 0000000..1b926e2 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/convert/ScheduleJobConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.quartz.convert; + +import com.bdzl.quartz.entity.ScheduleJobEntity; +import com.bdzl.quartz.vo.ScheduleJobVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** +* 定时任务 +* +* @author 阿沐 babamu@126.com +*/ +@Mapper +public interface ScheduleJobConvert { + ScheduleJobConvert INSTANCE = Mappers.getMapper(ScheduleJobConvert.class); + + ScheduleJobEntity convert(ScheduleJobVO vo); + + ScheduleJobVO convert(ScheduleJobEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/convert/ScheduleJobLogConvert.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/convert/ScheduleJobLogConvert.java new file mode 100644 index 0000000..ffeca59 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/convert/ScheduleJobLogConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.quartz.convert; + +import com.bdzl.quartz.entity.ScheduleJobLogEntity; +import com.bdzl.quartz.vo.ScheduleJobLogVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** +* 定时任务日志 +* +* @author 阿沐 babamu@126.com +*/ +@Mapper +public interface ScheduleJobLogConvert { + ScheduleJobLogConvert INSTANCE = Mappers.getMapper(ScheduleJobLogConvert.class); + + ScheduleJobLogEntity convert(ScheduleJobLogVO vo); + + ScheduleJobLogVO convert(ScheduleJobLogEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/dao/ScheduleJobDao.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/dao/ScheduleJobDao.java new file mode 100644 index 0000000..5961cf8 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/dao/ScheduleJobDao.java @@ -0,0 +1,15 @@ +package com.bdzl.quartz.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.quartz.entity.ScheduleJobEntity; +import org.apache.ibatis.annotations.Mapper; + +/** +* 定时任务 +* +* @author 阿沐 babamu@126.com +*/ +@Mapper +public interface ScheduleJobDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/dao/ScheduleJobLogDao.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/dao/ScheduleJobLogDao.java new file mode 100644 index 0000000..2c16ab5 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/dao/ScheduleJobLogDao.java @@ -0,0 +1,15 @@ +package com.bdzl.quartz.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.quartz.entity.ScheduleJobLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** +* 定时任务日志 +* +* @author 阿沐 babamu@126.com +*/ +@Mapper +public interface ScheduleJobLogDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/entity/ScheduleJobEntity.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/entity/ScheduleJobEntity.java new file mode 100644 index 0000000..587c11f --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/entity/ScheduleJobEntity.java @@ -0,0 +1,109 @@ +package com.bdzl.quartz.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 定时任务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@TableName("schedule_job") +public class ScheduleJobEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId + private Long id; + + /** + * 任务名称 + */ + private String jobName; + + /** + * 任务组名 + */ + private String jobGroup; + + /** + * bean名称 + */ + private String beanName; + + /** + * 执行方法 + */ + private String method; + + /** + * 方法参数 + */ + private String params; + + /** + * cron表达式 + */ + private String cronExpression; + + /** + * 状态 + */ + private Integer status; + + /** + * 是否并发 0:禁止 1:允许 + */ + private Integer concurrent; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long creator; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updater; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 版本号 + */ + @Version + @TableField(fill = FieldFill.INSERT) + private Integer version; + + /** + * 删除标记 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private Integer deleted; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/entity/ScheduleJobLogEntity.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/entity/ScheduleJobLogEntity.java new file mode 100644 index 0000000..0bbf536 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/entity/ScheduleJobLogEntity.java @@ -0,0 +1,77 @@ +package com.bdzl.quartz.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 定时任务日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@TableName("schedule_job_log") +public class ScheduleJobLogEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 任务id + */ + private Long jobId; + + /** + * 任务名称 + */ + private String jobName; + + /** + * 任务组名 + */ + private String jobGroup; + + /** + * spring bean名称 + */ + private String beanName; + + /** + * 执行方法 + */ + private String method; + + /** + * 参数 + */ + private String params; + + /** + * 任务状态 + */ + private Integer status; + + /** + * 异常信息 + */ + private String error; + + /** + * 耗时(单位:毫秒) + */ + private Long times; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/enums/ScheduleConcurrentEnum.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/enums/ScheduleConcurrentEnum.java new file mode 100644 index 0000000..a68f528 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/enums/ScheduleConcurrentEnum.java @@ -0,0 +1,25 @@ +package com.bdzl.quartz.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 定时任务并发枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum ScheduleConcurrentEnum { + /** + * 禁止 + */ + NO(0), + /** + * 允许 + */ + YES(1); + + private final int value; +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/enums/ScheduleStatusEnum.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/enums/ScheduleStatusEnum.java new file mode 100644 index 0000000..618e5e5 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/enums/ScheduleStatusEnum.java @@ -0,0 +1,25 @@ +package com.bdzl.quartz.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 定时任务状态枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum ScheduleStatusEnum { + /** + * 暂停 + */ + PAUSE(0), + /** + * 正常 + */ + NORMAL(1); + + private final int value; +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/query/ScheduleJobLogQuery.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/query/ScheduleJobLogQuery.java new file mode 100644 index 0000000..f552477 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/query/ScheduleJobLogQuery.java @@ -0,0 +1,26 @@ +package com.bdzl.quartz.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** +* 定时任务日志查询 +* +* @author 阿沐 babamu@126.com +*/ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "定时任务日志查询") +public class ScheduleJobLogQuery extends Query { + @Schema(description = "任务id") + private Long jobId; + + @Schema(description = "任务名称") + private String jobName; + + @Schema(description = "任务组名") + private String jobGroup; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/query/ScheduleJobQuery.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/query/ScheduleJobQuery.java new file mode 100644 index 0000000..c690713 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/query/ScheduleJobQuery.java @@ -0,0 +1,26 @@ +package com.bdzl.quartz.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** +* 定时任务查询 +* +* @author 阿沐 babamu@126.com +*/ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "定时任务查询") +public class ScheduleJobQuery extends Query { + @Schema(description = "任务名称") + private String jobName; + + @Schema(description = "任务组名") + private String jobGroup; + + @Schema(description = "状态") + private Integer status; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/ScheduleJobLogService.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/ScheduleJobLogService.java new file mode 100644 index 0000000..8691937 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/ScheduleJobLogService.java @@ -0,0 +1,19 @@ +package com.bdzl.quartz.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.quartz.entity.ScheduleJobLogEntity; +import com.bdzl.quartz.query.ScheduleJobLogQuery; +import com.bdzl.quartz.vo.ScheduleJobLogVO; + +/** + * 定时任务日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface ScheduleJobLogService extends BaseService { + + PageResult page(ScheduleJobLogQuery query); + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/ScheduleJobService.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/ScheduleJobService.java new file mode 100644 index 0000000..f305391 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/ScheduleJobService.java @@ -0,0 +1,30 @@ +package com.bdzl.quartz.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.quartz.entity.ScheduleJobEntity; +import com.bdzl.quartz.query.ScheduleJobQuery; +import com.bdzl.quartz.vo.ScheduleJobVO; + +import java.util.List; + +/** + * 定时任务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface ScheduleJobService extends BaseService { + + PageResult page(ScheduleJobQuery query); + + void save(ScheduleJobVO vo); + + void update(ScheduleJobVO vo); + + void delete(List idList); + + void run(ScheduleJobVO vo); + + void changeStatus(ScheduleJobVO vo); +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/impl/ScheduleJobLogServiceImpl.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/impl/ScheduleJobLogServiceImpl.java new file mode 100644 index 0000000..fe730ab --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/impl/ScheduleJobLogServiceImpl.java @@ -0,0 +1,44 @@ +package com.bdzl.quartz.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.quartz.convert.ScheduleJobLogConvert; +import com.bdzl.quartz.dao.ScheduleJobLogDao; +import com.bdzl.quartz.entity.ScheduleJobLogEntity; +import com.bdzl.quartz.query.ScheduleJobLogQuery; +import com.bdzl.quartz.service.ScheduleJobLogService; +import com.bdzl.quartz.vo.ScheduleJobLogVO; +import org.springframework.stereotype.Service; + +/** + * 定时任务日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class ScheduleJobLogServiceImpl extends BaseServiceImpl implements ScheduleJobLogService { + + @Override + public PageResult page(ScheduleJobLogQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(ScheduleJobLogConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(ScheduleJobLogQuery query){ + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StrUtil.isNotBlank(query.getJobName()), ScheduleJobLogEntity::getJobName, query.getJobName()); + wrapper.like(StrUtil.isNotBlank(query.getJobGroup()), ScheduleJobLogEntity::getJobGroup, query.getJobGroup()); + wrapper.eq(query.getJobId() != null, ScheduleJobLogEntity::getJobId, query.getJobId()); + wrapper.orderByDesc(ScheduleJobLogEntity::getId); + return wrapper; + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/impl/ScheduleJobServiceImpl.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/impl/ScheduleJobServiceImpl.java new file mode 100644 index 0000000..5d477c0 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/service/impl/ScheduleJobServiceImpl.java @@ -0,0 +1,127 @@ +package com.bdzl.quartz.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.annotation.PostConstruct; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.quartz.convert.ScheduleJobConvert; +import com.bdzl.quartz.dao.ScheduleJobDao; +import com.bdzl.quartz.entity.ScheduleJobEntity; +import com.bdzl.quartz.enums.ScheduleStatusEnum; +import com.bdzl.quartz.query.ScheduleJobQuery; +import com.bdzl.quartz.service.ScheduleJobService; +import com.bdzl.quartz.utils.ScheduleUtils; +import com.bdzl.quartz.vo.ScheduleJobVO; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 定时任务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class ScheduleJobServiceImpl extends BaseServiceImpl implements ScheduleJobService { + private final Scheduler scheduler; + + /** + * 启动项目时,初始化定时器 + */ + @PostConstruct + public void init() throws SchedulerException { + scheduler.clear(); + List scheduleJobList = baseMapper.selectList(null); + for (ScheduleJobEntity scheduleJob : scheduleJobList) { + ScheduleUtils.createScheduleJob(scheduler, scheduleJob); + } + } + + @Override + public PageResult page(ScheduleJobQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(ScheduleJobConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(ScheduleJobQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StrUtil.isNotBlank(query.getJobName()), ScheduleJobEntity::getJobName, query.getJobName()); + wrapper.like(StrUtil.isNotBlank(query.getJobGroup()), ScheduleJobEntity::getJobGroup, query.getJobGroup()); + wrapper.eq(query.getStatus() != null, ScheduleJobEntity::getStatus, query.getStatus()); + + return wrapper; + } + + @Override + public void save(ScheduleJobVO vo) { + ScheduleJobEntity entity = ScheduleJobConvert.INSTANCE.convert(vo); + + entity.setStatus(ScheduleStatusEnum.PAUSE.getValue()); + if (baseMapper.insert(entity) > 0) { + ScheduleUtils.createScheduleJob(scheduler, entity); + } + } + + @Override + public void update(ScheduleJobVO vo) { + ScheduleJobEntity entity = ScheduleJobConvert.INSTANCE.convert(vo); + + // 更新定时任务 + if (updateById(entity)) { + ScheduleJobEntity scheduleJob = getById(entity.getId()); + ScheduleUtils.updateSchedulerJob(scheduler, scheduleJob); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + for (Long id : idList) { + ScheduleJobEntity scheduleJob = getById(id); + + // 删除定时任务 + if (removeById(id)) { + ScheduleUtils.deleteScheduleJob(scheduler, scheduleJob); + } + } + } + + @Override + public void run(ScheduleJobVO vo) { + ScheduleJobEntity scheduleJob = getById(vo.getId()); + if (scheduleJob == null) { + return; + } + + ScheduleUtils.run(scheduler, scheduleJob); + } + + @Override + public void changeStatus(ScheduleJobVO vo) { + ScheduleJobEntity scheduleJob = getById(vo.getId()); + if (scheduleJob == null) { + return; + } + + // 更新数据 + scheduleJob.setStatus(vo.getStatus()); + updateById(scheduleJob); + + if (ScheduleStatusEnum.PAUSE.getValue() == vo.getStatus()) { + ScheduleUtils.pauseJob(scheduler, scheduleJob); + } else if (ScheduleStatusEnum.NORMAL.getValue() == vo.getStatus()) { + ScheduleUtils.resumeJob(scheduler, scheduleJob); + } + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/task/TestTask.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/task/TestTask.java new file mode 100644 index 0000000..bcad200 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/task/TestTask.java @@ -0,0 +1,20 @@ +package com.bdzl.quartz.task; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 测试定时任务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +@Service +public class TestTask { + + public void run(String params) throws InterruptedException { + log.info("我是testTask.run(),参数:{},正在被执行。", params); + Thread.sleep(1000); + } +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/AbstractScheduleJob.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/AbstractScheduleJob.java new file mode 100644 index 0000000..e9f6684 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/AbstractScheduleJob.java @@ -0,0 +1,84 @@ +package com.bdzl.quartz.utils; + +import cn.hutool.extra.spring.SpringUtil; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.ExceptionUtils; +import com.bdzl.quartz.entity.ScheduleJobEntity; +import com.bdzl.quartz.entity.ScheduleJobLogEntity; +import com.bdzl.quartz.enums.ScheduleStatusEnum; +import com.bdzl.quartz.service.ScheduleJobLogService; +import org.apache.commons.lang3.StringUtils; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.springframework.beans.BeanUtils; + +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.Date; + +@Slf4j +public abstract class AbstractScheduleJob implements Job { + private static final ThreadLocal threadLocal = new ThreadLocal<>(); + + @Override + public void execute(JobExecutionContext context) { + ScheduleJobEntity scheduleJob = new ScheduleJobEntity(); + BeanUtils.copyProperties(context.getMergedJobDataMap().get(ScheduleUtils.JOB_PARAM_KEY), scheduleJob); + + try { + threadLocal.set(new Date()); + doExecute(scheduleJob); + saveLog(scheduleJob, null); + } catch (Exception e) { + log.error("任务执行失败,任务ID:{}", scheduleJob.getId(), e); + saveLog(scheduleJob, e); + } + } + + /** + * 执行spring bean方法 + */ + protected void doExecute(ScheduleJobEntity scheduleJob) throws Exception { + log.info("准备执行任务,任务ID:{}", scheduleJob.getId()); + + Object bean = SpringUtil.getBean(scheduleJob.getBeanName()); + Method method = bean.getClass().getDeclaredMethod(scheduleJob.getMethod(), String.class); + method.invoke(bean, scheduleJob.getParams()); + + log.info("任务执行完毕,任务ID:{}", scheduleJob.getId()); + } + + /** + * 保存 log + */ + protected void saveLog(ScheduleJobEntity scheduleJob, Exception e) { + Date startTime = threadLocal.get(); + threadLocal.remove(); + + // 执行总时长 + long times = System.currentTimeMillis() - startTime.getTime(); + + // 保存执行记录 + ScheduleJobLogEntity log = new ScheduleJobLogEntity(); + log.setJobId(scheduleJob.getId()); + log.setJobName(scheduleJob.getJobName()); + log.setJobGroup(scheduleJob.getJobGroup()); + log.setBeanName(scheduleJob.getBeanName()); + log.setMethod(scheduleJob.getMethod()); + log.setParams(scheduleJob.getParams()); + log.setTimes(times); + log.setCreateTime(LocalDateTime.now()); + + if (e != null) { + log.setStatus(ScheduleStatusEnum.PAUSE.getValue()); + String error = StringUtils.substring(ExceptionUtils.getExceptionMessage(e), 0, 2000); + log.setError(error); + } else { + log.setStatus(ScheduleStatusEnum.NORMAL.getValue()); + } + + // 保存日志 + SpringUtil.getBean(ScheduleJobLogService.class).save(log); + } + +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/CronUtils.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/CronUtils.java new file mode 100644 index 0000000..5a39bfd --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/CronUtils.java @@ -0,0 +1,34 @@ +package com.bdzl.quartz.utils; + +import org.quartz.CronExpression; + +import java.text.ParseException; +import java.util.Date; + +/** + * cron 工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + * + */ +public class CronUtils { + /** + * 验证Cron表达式是否有效 + */ + public static boolean isValid(String cronExpression) { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 根据给定的Cron表达式,返回下一个执行时间 + */ + public static Date getNextExecution(String cronExpression) { + try { + CronExpression cron = new CronExpression(cronExpression); + return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); + } catch (ParseException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleConcurrentExecution.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleConcurrentExecution.java new file mode 100644 index 0000000..8eaf82e --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleConcurrentExecution.java @@ -0,0 +1,12 @@ +package com.bdzl.quartz.utils; + +/** + * 允许并发(不会等待上一次任务执行完毕,只要时间到就会执行) + * + * @author 阿沐 babamu@126.com + * MAKU + * + */ +public class ScheduleConcurrentExecution extends AbstractScheduleJob { + +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleDisallowConcurrentExecution.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleDisallowConcurrentExecution.java new file mode 100644 index 0000000..865ab61 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleDisallowConcurrentExecution.java @@ -0,0 +1,15 @@ +package com.bdzl.quartz.utils; + +import org.quartz.DisallowConcurrentExecution; + +/** + * 禁止并发 + * + * @author 阿沐 babamu@126.com + * MAKU + * + */ +@DisallowConcurrentExecution +public class ScheduleDisallowConcurrentExecution extends AbstractScheduleJob { + +} diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleUtils.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleUtils.java new file mode 100644 index 0000000..0ea7935 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/utils/ScheduleUtils.java @@ -0,0 +1,161 @@ +package com.bdzl.quartz.utils; + +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.quartz.entity.ScheduleJobEntity; +import com.bdzl.quartz.enums.ScheduleConcurrentEnum; +import com.bdzl.quartz.enums.ScheduleStatusEnum; +import org.quartz.*; + +/** + * 定时任务工具类 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class ScheduleUtils { + private final static String JOB_NAME = "TASK_NAME_"; + /** + * 任务调度参数key + */ + public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY"; + + /** + * 获取quartz任务类 + */ + public static Class getJobClass(ScheduleJobEntity scheduleJob) { + if (scheduleJob.getConcurrent().equals(ScheduleConcurrentEnum.NO.getValue())) { + return ScheduleDisallowConcurrentExecution.class; + } else { + return ScheduleConcurrentExecution.class; + } + } + + /** + * 获取触发器key + */ + public static TriggerKey getTriggerKey(ScheduleJobEntity scheduleJob) { + return TriggerKey.triggerKey(JOB_NAME + scheduleJob.getId(), scheduleJob.getJobGroup()); + } + + /** + * 获取jobKey + */ + public static JobKey getJobKey(ScheduleJobEntity scheduleJob) { + return JobKey.jobKey(JOB_NAME + scheduleJob.getId(), scheduleJob.getJobGroup()); + } + + /** + * 创建定时任务 + */ + public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + // job key + JobKey jobKey = getJobKey(scheduleJob); + // 构建job信息 + JobDetail jobDetail = JobBuilder.newJob(getJobClass(scheduleJob)).withIdentity(jobKey).build(); + + // 表达式调度构建器 + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) + .withMisfireHandlingInstructionDoNothing(); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob)) + .withSchedule(scheduleBuilder).build(); + + // 放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob); + // 把任务添加到Quartz中 + scheduler.scheduleJob(jobDetail, trigger); + + // 判断是否存在 + if (scheduler.checkExists(jobKey)) { + // 防止创建时存在数据问题,先移除,然后再执行创建操作 + scheduler.deleteJob(jobKey); + } + + // 判断任务是否过期 + if (CronUtils.getNextExecution(scheduleJob.getCronExpression()) != null) { + // 执行调度任务 + scheduler.scheduleJob(jobDetail, trigger); + } + + // 暂停任务 + if (scheduleJob.getStatus().equals(ScheduleStatusEnum.PAUSE.getValue())) { + scheduler.pauseJob(jobKey); + } + } catch (SchedulerException e) { + throw new ServerException("创建定时任务失败", e); + } + } + + + /** + * 立即执行任务 + */ + public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + // 参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(JOB_PARAM_KEY, scheduleJob); + + JobKey jobKey = getJobKey(scheduleJob); + if (scheduler.checkExists(jobKey)) { + scheduler.triggerJob(jobKey, dataMap); + } + } catch (SchedulerException e) { + throw new ServerException("执行定时任务失败", e); + } + } + + /** + * 暂停任务 + */ + public static void pauseJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + scheduler.pauseJob(getJobKey(scheduleJob)); + } catch (SchedulerException e) { + throw new ServerException("暂停定时任务失败", e); + } + } + + /** + * 恢复任务 + */ + public static void resumeJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + scheduler.resumeJob(getJobKey(scheduleJob)); + } catch (SchedulerException e) { + throw new ServerException("恢复定时任务失败", e); + } + } + + /** + * 更新定时任务 + */ + public static void updateSchedulerJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + // 判断是否存在 + JobKey jobKey = ScheduleUtils.getJobKey(scheduleJob); + + try { + // 防止创建时存在数据问题,先移除,然后再执行创建操作 + if (scheduler.checkExists(jobKey)) { + scheduler.deleteJob(jobKey); + } + } catch (SchedulerException e) { + throw new ServerException("更新定时任务失败", e); + } + + ScheduleUtils.createScheduleJob(scheduler, scheduleJob); + } + + /** + * 删除定时任务 + */ + public static void deleteScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + scheduler.deleteJob(getJobKey(scheduleJob)); + } catch (SchedulerException e) { + throw new ServerException("删除定时任务失败", e); + } + } +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/vo/ScheduleJobLogVO.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/vo/ScheduleJobLogVO.java new file mode 100644 index 0000000..235a840 --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/vo/ScheduleJobLogVO.java @@ -0,0 +1,55 @@ +package com.bdzl.quartz.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 定时任务日志 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "定时任务日志") +public class ScheduleJobLogVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "任务id") + private Long jobId; + + @Schema(description = "任务名称") + private String jobName; + + @Schema(description = "任务组名") + private String jobGroup; + + @Schema(description = "spring bean名称") + private String beanName; + + @Schema(description = "执行方法") + private String method; + + @Schema(description = "参数") + private String params; + + @Schema(description = "任务状态") + private Integer status; + + @Schema(description = "异常信息") + private String error; + + @Schema(description = "耗时(单位:毫秒)") + private Integer times; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/vo/ScheduleJobVO.java b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/vo/ScheduleJobVO.java new file mode 100644 index 0000000..466d85e --- /dev/null +++ b/drone-ops-module/drone-ops-module-quartz/src/main/java/com/bdzl/quartz/vo/ScheduleJobVO.java @@ -0,0 +1,55 @@ +package com.bdzl.quartz.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 定时任务 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "定时任务") +public class ScheduleJobVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "任务名称") + private String jobName; + + @Schema(description = "任务组名") + private String jobGroup; + + @Schema(description = "bean名称") + private String beanName; + + @Schema(description = "执行方法") + private String method; + + @Schema(description = "参数") + private String params; + + @Schema(description = "cron表达式") + private String cronExpression; + + @Schema(description = "状态 ") + private Integer status; + + @Schema(description = "是否并发") + private Integer concurrent; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-websocket/pom.xml b/drone-ops-module/drone-ops-module-websocket/pom.xml new file mode 100644 index 0000000..defab20 --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/pom.xml @@ -0,0 +1,24 @@ + + + com.bdzl + drone-ops-module + ${revision} + + 4.0.0 + drone-ops-module-websocket + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + org.springframework.boot + spring-boot-starter-websocket + + + + \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/config/WebSocketConfig.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/config/WebSocketConfig.java new file mode 100644 index 0000000..a38044a --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/config/WebSocketConfig.java @@ -0,0 +1,30 @@ +package com.bdzl.websocket.config; + +import lombok.AllArgsConstructor; +import com.bdzl.websocket.handler.MessageWebSocketHandler; +import com.bdzl.websocket.handler.UserHandshakeInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + + +/** + * WebSocket配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +@EnableWebSocket +@AllArgsConstructor +public class WebSocketConfig implements WebSocketConfigurer { + private final MessageWebSocketHandler handler; + private final UserHandshakeInterceptor interceptor; + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(handler, "/ws") + .addInterceptors(interceptor).setAllowedOriginPatterns("*"); + } +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/controller/SendMessageController.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/controller/SendMessageController.java new file mode 100644 index 0000000..23d59a5 --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/controller/SendMessageController.java @@ -0,0 +1,52 @@ +package com.bdzl.websocket.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.websocket.message.JsonDataMessage; +import com.bdzl.websocket.sender.WebSocketMessageSender; +import com.bdzl.websocket.vo.MessageVO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; + +/** + * 测试 发送消息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Tag(name = "WebSocket,发送消息") +@AllArgsConstructor +@RestController +@RequestMapping("ws/message") +public class SendMessageController { + private final WebSocketMessageSender webSocketMessageSender; + + @PostMapping("send") + @Operation(summary = "发送消息") + public Result send(Long userId, String content) { + // 获取当前用户信息 + UserDetail user = SecurityUser.getUser(); + + // 封装消息内容 + MessageVO messageVO = new MessageVO(); + messageVO.setName(user.getRealName()); + messageVO.setAvatar(user.getAvatar()); + messageVO.setContent(content); + messageVO.setSendTime(LocalDateTime.now()); + + JsonDataMessage message = new JsonDataMessage<>(); + message.setData(messageVO); + + // 发送消息 + webSocketMessageSender.send(userId, message); + + return Result.ok(); + } +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/handler/MessageWebSocketHandler.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/handler/MessageWebSocketHandler.java new file mode 100644 index 0000000..fb24fbf --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/handler/MessageWebSocketHandler.java @@ -0,0 +1,44 @@ +package com.bdzl.websocket.handler; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.websocket.session.WebSocketSessionManager; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +/** + * WebSocket 消息处理器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +@Component +@AllArgsConstructor +public class MessageWebSocketHandler extends TextWebSocketHandler { + private final WebSocketSessionManager webSocketSessionManager; + + @Override + public void afterConnectionEstablished(WebSocketSession session) { + // 新增session + webSocketSessionManager.addSession(session); + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { + // 移除session + webSocketSessionManager.removeSession(session); + } + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) { + String payload = message.getPayload(); + + log.info("Received message: {}", payload); + + // 处理接收到的消息 + } +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/handler/UserHandshakeInterceptor.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/handler/UserHandshakeInterceptor.java new file mode 100644 index 0000000..3e2e2e0 --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/handler/UserHandshakeInterceptor.java @@ -0,0 +1,35 @@ +package com.bdzl.websocket.handler; + +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.websocket.util.SessionUserUtil; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import java.util.Map; + + +/** + * webSocket 握手拦截器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +public class UserHandshakeInterceptor implements HandshakeInterceptor { + + @Override + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception { + // 当前连接的用户 + SessionUserUtil.setUser(SecurityUser.getUser(), attributes); + + return true; + } + + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { + + } +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/message/JsonDataMessage.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/message/JsonDataMessage.java new file mode 100644 index 0000000..45130b8 --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/message/JsonDataMessage.java @@ -0,0 +1,22 @@ +package com.bdzl.websocket.message; + +import lombok.Data; + +/** + * websocket json 消息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class JsonDataMessage { + /** + * 消息类型 预留 + */ + private String type = "default"; + /** + * 消息数据 + */ + private T data; + +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/sender/WebSocketMessageSender.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/sender/WebSocketMessageSender.java new file mode 100644 index 0000000..103e24f --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/sender/WebSocketMessageSender.java @@ -0,0 +1,59 @@ +package com.bdzl.websocket.sender; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.websocket.message.JsonDataMessage; +import com.bdzl.websocket.session.WebSocketSessionManager; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; + +import java.util.List; + +/** + * WebSocket 消息发送 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +@Component +@AllArgsConstructor +public class WebSocketMessageSender { + private final WebSocketSessionManager webSocketSessionManager; + + /** + * 发送信息 + * + * @param userId 用户ID + * @param message 消息内容 + */ + public void send(Long userId, JsonDataMessage message) { + webSocketSessionManager.getSessionList(userId).forEach(session -> send(session, message)); + } + + /** + * 发送信息 + * + * @param userIdList 用户ID列表 + * @param message 消息内容 + */ + public void send(List userIdList, JsonDataMessage message) { + userIdList.forEach(userId -> send(userId, message)); + } + + /** + * 发送信息 + * + * @param session WebSocketSession + * @param message 消息内容 + */ + public void send(WebSocketSession session, JsonDataMessage message) { + try { + session.sendMessage(new TextMessage(JsonUtils.toJsonString(message))); + } catch (Exception e) { + log.error("send websocket message error,{}", e.getMessage(), e); + } + } +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/session/WebSocketSessionManager.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/session/WebSocketSessionManager.java new file mode 100644 index 0000000..b66906a --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/session/WebSocketSessionManager.java @@ -0,0 +1,62 @@ +package com.bdzl.websocket.session; + +import cn.hutool.core.collection.CollUtil; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.websocket.util.SessionUserUtil; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * WebSocket 会话管理器 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +public class WebSocketSessionManager { + /** + * 用户 WebSocket 会话 + * key1:用户ID + * key2:SessionID + */ + private final ConcurrentMap> userSessions = new ConcurrentHashMap<>(); + + public void addSession(WebSocketSession session) { + // 当前连接的用户 + UserDetail user = SessionUserUtil.getUser(session); + if (user == null) { + return; + } + + userSessions.computeIfAbsent(user.getId(), k -> new ConcurrentHashMap<>()) + .putIfAbsent(session.getId(), session); + } + + public void removeSession(WebSocketSession session) { + // 当前连接的用户 + UserDetail user = SessionUserUtil.getUser(session); + if (user == null) { + return; + } + + userSessions.computeIfPresent(user.getId(), (k, sessionMap) -> { + sessionMap.remove(session.getId()); + return sessionMap.isEmpty() ? null : sessionMap; + }); + } + + public List getSessionList(Long userId) { + ConcurrentMap sessionMap = userSessions.get(userId); + if (CollUtil.isEmpty(sessionMap)) { + return new ArrayList<>(); + } + + return new ArrayList<>(sessionMap.values()); + } + +} \ No newline at end of file diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/util/SessionUserUtil.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/util/SessionUserUtil.java new file mode 100644 index 0000000..603c479 --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/util/SessionUserUtil.java @@ -0,0 +1,28 @@ +package com.bdzl.websocket.util; + +import com.bdzl.framework.security.user.UserDetail; +import org.springframework.web.socket.WebSocketSession; + +import java.util.Map; + +public class SessionUserUtil { + private static final String SESSION_USER = "SESSION_USER"; + + /** + * 设置用户 + * + * @param user 用户 + * @param attributes attributes + */ + public static void setUser(UserDetail user, Map attributes) { + attributes.put(SESSION_USER, user); + } + + /** + * 获取用户 + */ + public static UserDetail getUser(WebSocketSession session) { + return (UserDetail) session.getAttributes().get(SESSION_USER); + } + +} diff --git a/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/vo/MessageVO.java b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/vo/MessageVO.java new file mode 100644 index 0000000..b11769a --- /dev/null +++ b/drone-ops-module/drone-ops-module-websocket/src/main/java/com/bdzl/websocket/vo/MessageVO.java @@ -0,0 +1,33 @@ +package com.bdzl.websocket.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.time.LocalDateTime; + + +/** + * 发送消息的对象 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Tag(name = "发送消息的对象") +public class MessageVO { + @Schema(description = "用户名") + private String name; + + @Schema(description = "用户头像") + private String avatar; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "发送时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime sendTime; +} diff --git a/drone-ops-module/pom.xml b/drone-ops-module/pom.xml new file mode 100644 index 0000000..5df9494 --- /dev/null +++ b/drone-ops-module/pom.xml @@ -0,0 +1,20 @@ + + + com.bdzl + drone-ops + ${revision} + + 4.0.0 + drone-ops-module + pom + + + drone-ops-module-quartz + drone-ops-module-generator + drone-ops-module-monitor + drone-ops-module-member + drone-ops-module-iot + drone-ops-module-websocket + + + \ No newline at end of file diff --git a/drone-ops-new/pom.xml b/drone-ops-new/pom.xml new file mode 100644 index 0000000..33c7d0a --- /dev/null +++ b/drone-ops-new/pom.xml @@ -0,0 +1,19 @@ + + + com.bdzl + drone-ops + ${revision} + + 4.0.0 + drone-ops-new + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + + \ No newline at end of file diff --git a/drone-ops-new/src/main/java/com/bdzl/module/controller/TestController.java b/drone-ops-new/src/main/java/com/bdzl/module/controller/TestController.java new file mode 100644 index 0000000..e28b999 --- /dev/null +++ b/drone-ops-new/src/main/java/com/bdzl/module/controller/TestController.java @@ -0,0 +1,29 @@ +package com.bdzl.module.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.Result; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 新模块测试 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("new/test") +@Tag(name="新模块测试") +@AllArgsConstructor +public class TestController { + + @GetMapping() + @Operation(summary = "测试接口") + public Result test(){ + + return Result.ok("测试数据"); + } +} diff --git a/drone-ops-new/src/main/resources/auth.yml b/drone-ops-new/src/main/resources/auth.yml new file mode 100644 index 0000000..0fde962 --- /dev/null +++ b/drone-ops-new/src/main/resources/auth.yml @@ -0,0 +1,4 @@ +# 配置忽略认证的URL地址 +auth: + ignore_urls: + - /new/** \ No newline at end of file diff --git a/drone-ops-server/pom.xml b/drone-ops-server/pom.xml new file mode 100644 index 0000000..6e0baa9 --- /dev/null +++ b/drone-ops-server/pom.xml @@ -0,0 +1,69 @@ + + + com.bdzl + drone-ops + ${revision} + + 4.0.0 + drone-ops-server + jar + + + + com.bdzl + drone-ops-system + ${revision} + + + com.bdzl + drone-ops-new + ${revision} + + + com.bdzl + drone-ops-module-quartz + ${revision} + + + com.bdzl + drone-ops-module-generator + ${revision} + + + com.bdzl + drone-ops-module-member + ${revision} + + + com.bdzl + drone-ops-module-monitor + ${revision} + + + com.bdzl + drone-ops-module-websocket + ${revision} + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/drone-ops-server/src/main/java/com/bdzl/ServerApplication.java b/drone-ops-server/src/main/java/com/bdzl/ServerApplication.java new file mode 100644 index 0000000..2d98883 --- /dev/null +++ b/drone-ops-server/src/main/java/com/bdzl/ServerApplication.java @@ -0,0 +1,19 @@ +package com.bdzl; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +@SpringBootApplication +public class ServerApplication extends SpringBootServletInitializer { + + public static void main(String[] args) { + SpringApplication.run(ServerApplication.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(ServerApplication.class); + } +} \ No newline at end of file diff --git a/drone-ops-server/src/main/java/com/bdzl/SwaggerConfig.java b/drone-ops-server/src/main/java/com/bdzl/SwaggerConfig.java new file mode 100644 index 0000000..a1d3ef7 --- /dev/null +++ b/drone-ops-server/src/main/java/com/bdzl/SwaggerConfig.java @@ -0,0 +1,103 @@ +package com.bdzl; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger配置 + * + * @author 阿沐 babamu@126.com + */ +@Configuration +public class SwaggerConfig { + + @Bean + public GroupedOpenApi systemApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bdzl.system"}; + return GroupedOpenApi.builder() + .group("1") + .displayName("System API") + .pathsToMatch(paths) + .packagesToScan(packagedToMatch).build(); + } + + @Bean + public GroupedOpenApi quartzApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bdzl.quartz"}; + return GroupedOpenApi.builder() + .group("2") + .displayName("Quartz API") + .pathsToMatch(paths) + .packagesToScan(packagedToMatch).build(); + } + + @Bean + public GroupedOpenApi monitorApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bdzl.monitor"}; + return GroupedOpenApi.builder() + .group("3") + .displayName("Monitor API") + .pathsToMatch(paths) + .packagesToScan(packagedToMatch).build(); + } + + @Bean + public GroupedOpenApi memberApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bdzl.member"}; + return GroupedOpenApi.builder() + .group("4") + .displayName("Member API") + .pathsToMatch(paths) + .packagesToScan(packagedToMatch).build(); + } + + @Bean + public GroupedOpenApi iotApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bdzl.iot"}; + return GroupedOpenApi.builder() + .group("5") + .displayName("Iot API") + .pathsToMatch(paths) + .packagesToScan(packagedToMatch).build(); + } + + @Bean + public GroupedOpenApi otherApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bdzl"}; + return GroupedOpenApi.builder() + .group("99") + .displayName("Other API") + .pathsToMatch(paths) + .packagesToExclude( + "com.bdzl.system", "com.bdzl.quartz", "com.bdzl.monitor", "com.bdzl.member", "com.bdzl.iot", + "com.bdzl.generator" + ) + .packagesToScan(packagedToMatch) + .build(); + } + + @Bean + public OpenAPI openApi() { + Contact contact = new Contact(); + contact.setName("阿沐 babamu@126.com"); + + return new OpenAPI().info(new Info() + .title("Maku API") + .description("Maku API") + .contact(contact) + .version("3.x") + .termsOfService("https://maku.net") + ); + } + +} \ No newline at end of file diff --git a/drone-ops-server/src/main/resources/application-dev.yml b/drone-ops-server/src/main/resources/application-dev.yml new file mode 100644 index 0000000..956d03e --- /dev/null +++ b/drone-ops-server/src/main/resources/application-dev.yml @@ -0,0 +1,36 @@ +spring: + data: + redis: + database: 1 + host: 47.108.84.104 + port: 6379 + #password: + #timeout: 6000ms # 连接超时时长(毫秒) + datasource: + dynamic: + hikari: # Hikari 连接池全局配置 + connection-timeout: 30000 # 等待连接池分配链接的最大时长(毫秒),超过这个时长还没有可用的连接则发生 SQLException,默认:30 秒 + minimum-idle: 2 # 最小空闲连接数 + maximum-pool-size: 10 # 最大连接数 + idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10 分钟 + max-lifetime: 1800000 # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认: 30 分钟 + connection-test-query: SELECT 1 + primary: master + datasource: + master: + # MySQL8 + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://47.108.84.104:3306/maku?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true + username: root + password: RootP@ssw0rd + # PostgreSQL + # driver-class-name: org.postgresql.Driver + # url: jdbc:postgresql://192.168.3.19:5432/postgres + # username: postgres + # password: 123456 + mqtt: + host: tcp://localhost:1883 + username: maku + password: maku + clientId: maku_boot_service_dev + default-topic: topic_default \ No newline at end of file diff --git a/drone-ops-server/src/main/resources/application-prod.yml b/drone-ops-server/src/main/resources/application-prod.yml new file mode 100644 index 0000000..ba686cb --- /dev/null +++ b/drone-ops-server/src/main/resources/application-prod.yml @@ -0,0 +1,41 @@ +spring: + data: + redis: + database: 1 + host: localhost + port: 6379 + #password: + #timeout: 6000ms # 连接超时时长(毫秒) + datasource: + dynamic: + hikari: # Hikari 连接池全局配置 + connection-timeout: 30000 # 等待连接池分配链接的最大时长(毫秒),超过这个时长还没有可用的连接则发生 SQLException,默认:30 秒 + minimum-idle: 2 # 最小空闲连接数 + maximum-pool-size: 10 # 最大连接数 + idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10 分钟 + max-lifetime: 1800000 # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认: 30 分钟 + connection-test-query: SELECT 1 + primary: master + datasource: + master: + # MySQL8 + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/maku_boot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true + username: maku + password: 123456 + # 达梦 + # driver-class-name: dm.jdbc.driver.DmDriver + # url: jdbc:dm://192.168.3.19:5236/maku_boot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true + # username: maku_boot + # password: 12345678 + # PostgreSQL + # driver-class-name: org.postgresql.Driver + # url: jdbc:postgresql://192.168.3.19:5432/postgres + # username: postgres + # password: 123456 + mqtt: + host: tcp://localhost:1883 + username: maku + password: maku + clientId: maku_boot_service_dev + default-topic: topic_default \ No newline at end of file diff --git a/drone-ops-server/src/main/resources/application-test.yml b/drone-ops-server/src/main/resources/application-test.yml new file mode 100644 index 0000000..956d03e --- /dev/null +++ b/drone-ops-server/src/main/resources/application-test.yml @@ -0,0 +1,36 @@ +spring: + data: + redis: + database: 1 + host: 47.108.84.104 + port: 6379 + #password: + #timeout: 6000ms # 连接超时时长(毫秒) + datasource: + dynamic: + hikari: # Hikari 连接池全局配置 + connection-timeout: 30000 # 等待连接池分配链接的最大时长(毫秒),超过这个时长还没有可用的连接则发生 SQLException,默认:30 秒 + minimum-idle: 2 # 最小空闲连接数 + maximum-pool-size: 10 # 最大连接数 + idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10 分钟 + max-lifetime: 1800000 # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认: 30 分钟 + connection-test-query: SELECT 1 + primary: master + datasource: + master: + # MySQL8 + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://47.108.84.104:3306/maku?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true + username: root + password: RootP@ssw0rd + # PostgreSQL + # driver-class-name: org.postgresql.Driver + # url: jdbc:postgresql://192.168.3.19:5432/postgres + # username: postgres + # password: 123456 + mqtt: + host: tcp://localhost:1883 + username: maku + password: maku + clientId: maku_boot_service_dev + default-topic: topic_default \ No newline at end of file diff --git a/drone-ops-server/src/main/resources/application.yml b/drone-ops-server/src/main/resources/application.yml new file mode 100644 index 0000000..9b8d14d --- /dev/null +++ b/drone-ops-server/src/main/resources/application.yml @@ -0,0 +1,86 @@ +# Tomcat +server: + tomcat: + uri-encoding: UTF-8 + threads: + max: 1000 + min-spare: 30 + port: 8090 + servlet: + context-path: / + session: + cookie: + http-only: true + +knife4j: + enable: false + setting: + custom-code: 500 + enable-footer-custom: false + +spring: + # 环境 dev|test|prod + profiles: + active: dev + application: + name: drone-ops + jackson: + time-zone: GMT+8 + servlet: + multipart: + max-file-size: 1024MB + max-request-size: 1024MB + +storage: + enabled: true + config: + # 存储类型:local、aliyun、tencent、qiniu、huawei、minio + type: local + domain: http://localhost:8090 + local: + path: D://upload + +maku: + xss: + enabled: true + exclude-urls: + - /maku-generator/** + security: + # 8小时过期 + access-token-expire: 28800 + # 14天过期 + refresh-token-expire: 1209600 + +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.bdzl.*.entity + global-config: + # 数据库相关配置 + db-config: + # ID自增 + id-type: AUTO + # 逻辑已删除值 + logic-delete-value: 1 + # 逻辑未删除值 + logic-not-delete-value: 0 + banner: false + # 原生配置 + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + call-setters-on-nulls: true + jdbc-type-for-null: 'null' + configuration-properties: + prefix: + blobType: BLOB + boolValue: TRUE + +#easy trans 数据翻译组件 +easy-trans: + #启用redis缓存 如果不用redis请设置为false + is-enable-redis: false + #启用全局翻译(拦截所有responseBody进行自动翻译),如果对于性能要求很高可关闭此配置 + is-enable-global: true + #启用平铺模式 + is-enable-tile: true \ No newline at end of file diff --git a/drone-ops-server/src/main/resources/banner.txt b/drone-ops-server/src/main/resources/banner.txt new file mode 100644 index 0000000..b97f309 --- /dev/null +++ b/drone-ops-server/src/main/resources/banner.txt @@ -0,0 +1,6 @@ +======================================================================================================================== + ____ ____ ____ __ +( _ \( _ \(_ )( ) + ) _ < )(_) )/ /_ )(__ +(____/(____/(____)(____) +======================================================================================================================== diff --git a/drone-ops-server/src/main/resources/logback.xml b/drone-ops-server/src/main/resources/logback.xml new file mode 100644 index 0000000..0e96edd --- /dev/null +++ b/drone-ops-server/src/main/resources/logback.xml @@ -0,0 +1,113 @@ + + + logback-spring + + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + UTF-8 + + + + + + + ${logging.path}/debug.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + ${logging.path}/debug-%d{yyyy-MM-dd}.%i.log + 100MB + 60 + 20GB + + + + debug + ACCEPT + DENY + + + + + ${logging.path}/info.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + ${logging.path}/info-%d{yyyy-MM-dd}.%i.log + 100MB + 60 + 20GB + + + info + ACCEPT + DENY + + + + + ${logging.path}/warn.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + ${logging.path}/warn-%d{yyyy-MM-dd}.%i.log + 100MB + 60 + 20GB + + + warn + ACCEPT + DENY + + + + + ${logging.path}/error.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + ${logging.path}/error-%d{yyyy-MM-dd}.%i.log + 100MB + 60 + 20GB + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-server/src/test/java/com/bdzl/FileUploadTest.java b/drone-ops-server/src/test/java/com/bdzl/FileUploadTest.java new file mode 100644 index 0000000..10965ae --- /dev/null +++ b/drone-ops-server/src/test/java/com/bdzl/FileUploadTest.java @@ -0,0 +1,27 @@ +package com.bdzl; + +import cn.hutool.core.io.IoUtil; +import com.bdzl.storage.service.StorageService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.File; +import java.nio.file.Files; + +@SpringBootTest +public class FileUploadTest { + @Autowired + private StorageService storageService; + + @Test + public void uploadTest() throws Exception { + File file = new File("D://upload//1.png"); + byte[] data = IoUtil.readBytes(Files.newInputStream(file.toPath())); + + String path = storageService.getPath(file.getName()); + String url = storageService.upload(data, path); + System.out.println(url); + } + +} diff --git a/drone-ops-system/pom.xml b/drone-ops-system/pom.xml new file mode 100644 index 0000000..4e123d8 --- /dev/null +++ b/drone-ops-system/pom.xml @@ -0,0 +1,88 @@ + + + com.bdzl + drone-ops + ${revision} + + 4.0.0 + drone-ops-system + jar + + + + com.bdzl + drone-ops-framework + ${revision} + + + com.bdzl + drone-ops-api + ${revision} + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-freemarker + + + com.aliyun.oss + aliyun-sdk-oss + + + com.qcloud + cos_api + + + com.qiniu + qiniu-java-sdk + + + com.huaweicloud + esdk-obs-java-bundle + + + io.minio + minio + + + com.github.whvcse + easy-captcha + + + me.zhyd.oauth + JustAuth + + + com.aliyun + dysmsapi20170525 + + + + + + + com.tencentcloudapi + tencentcloud-sdk-java + + + + com.aliyun + dm20151123 + + + + com.tencentcloudapi + tencentcloud-sdk-java-ses + + + com.sun.mail + javax.mail + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/email/config/EmailConfig.java b/drone-ops-system/src/main/java/com/bdzl/email/config/EmailConfig.java new file mode 100644 index 0000000..abb7fd9 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/config/EmailConfig.java @@ -0,0 +1,68 @@ +package com.bdzl.email.config; + +import lombok.Data; + +/** + * 邮箱配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class EmailConfig { + /** + * 平台ID + */ + private Long id; + + /** + * 平台类型 + */ + private Integer platform; + + /** + * 分组名称,发送邮件时,可指定分组 + */ + private String groupName; + + /** + * SMTP服务器 + */ + private String mailHost; + + /** + * SMTP端口 + */ + private Integer mailPort; + + /** + * 发件人邮箱 + */ + private String mailFrom; + + /** + * 发件人密码 + */ + private String mailPass; + + /** + * regionId + */ + private String regionId; + + /** + * 阿里云 endpoint + */ + private String endpoint; + + /** + * AccessKey + */ + private String accessKey; + + /** + * SecretKey + */ + private String secretKey; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/email/param/EmailAliyunBatchSendParam.java b/drone-ops-system/src/main/java/com/bdzl/email/param/EmailAliyunBatchSendParam.java new file mode 100644 index 0000000..da262bf --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/param/EmailAliyunBatchSendParam.java @@ -0,0 +1,33 @@ +package com.bdzl.email.param; + +import lombok.Data; + +/** + * 阿里云 批量发送邮件参数 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class EmailAliyunBatchSendParam { + /** + * 分组名称,非必填 + */ + private String groupName; + /** + * 发件人邮箱 + */ + private String from; + /** + * 收件人列表名称 + */ + private String receiversName; + /** + * 邮件模板名称 + */ + private String templateName; + /** + * 邮件标签 + */ + private String tagName; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/email/param/EmailAliyunSendParam.java b/drone-ops-system/src/main/java/com/bdzl/email/param/EmailAliyunSendParam.java new file mode 100644 index 0000000..43eb091 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/param/EmailAliyunSendParam.java @@ -0,0 +1,41 @@ +package com.bdzl.email.param; + +import lombok.Data; + +/** + * 阿里云 发送邮件参数 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class EmailAliyunSendParam { + /** + * 分组名称,非必填 + */ + private String groupName; + /** + * 发件人邮箱 + */ + private String from; + /** + * 发件人昵称 + */ + private String formAlias; + /** + * 收件人邮箱列表,逗号拼接 + */ + private String tos; + /** + * 邮件主题 + */ + private String subject; + /** + * 邮件内容 + */ + private String content; + /** + * 是否为html格式 + */ + private boolean html; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/email/param/EmailLocalSendParam.java b/drone-ops-system/src/main/java/com/bdzl/email/param/EmailLocalSendParam.java new file mode 100644 index 0000000..727891a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/param/EmailLocalSendParam.java @@ -0,0 +1,41 @@ +package com.bdzl.email.param; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.Data; + +import java.io.File; +import java.util.List; + +/** + * 本地 发送邮件参数 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class EmailLocalSendParam { + /** + * 分组名称,非必填 + */ + private String groupName; + /** + * 收件人邮箱列表,逗号拼接 + */ + private String tos; + /** + * 邮件主题 + */ + private String subject; + /** + * 邮件内容 + */ + private String content; + /** + * 是否为html格式 + */ + private boolean html; + /** + * 附件列表 + */ + private List files = CollectionUtil.newArrayList(); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/email/service/EmailService.java b/drone-ops-system/src/main/java/com/bdzl/email/service/EmailService.java new file mode 100644 index 0000000..95b28a0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/service/EmailService.java @@ -0,0 +1,191 @@ +package com.bdzl.email.service; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.email.config.EmailConfig; +import com.bdzl.email.param.EmailAliyunBatchSendParam; +import com.bdzl.email.param.EmailAliyunSendParam; +import com.bdzl.email.param.EmailLocalSendParam; +import com.bdzl.email.util.EmailAliyunUtil; +import com.bdzl.email.util.EmailLocalUtil; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.ExceptionUtils; +import com.bdzl.system.cache.EmailConfigCache; +import com.bdzl.system.entity.SysMailLogEntity; +import com.bdzl.system.service.SysMailConfigService; +import com.bdzl.system.service.SysMailLogService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.util.List; + +/** + * 邮件服务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +@Service +@AllArgsConstructor +public class EmailService { + private final SysMailConfigService sysMailConfigService; + private final EmailConfigCache emailConfigCache; + private final SysMailLogService sysMailLogService; + + /** + * 本地 发送邮件 + * + * @param param 发送邮件参数 + * @return message-id + */ + public boolean sendLocal(EmailLocalSendParam param) { + EmailConfig config = roundEmailConfig(param.getGroupName()); + return sendLocal(param, config); + } + + /** + * 本地 发送邮件 + * + * @param param 发送邮件参数 + * @return message-id + */ + public boolean sendLocal(EmailLocalSendParam param, EmailConfig config) { + try { + new EmailLocalUtil(config).sendEmail(param.getTos(), param.getSubject(), param.getContent(), param.isHtml(), ArrayUtil.toArray(param.getFiles(), File.class)); + saveLog(config.getId(), config.getPlatform(), config.getMailFrom(), param.getTos(), param.getSubject(), param.getContent(), null); + + return true; + } catch (Exception e) { + log.error("本地发送邮件失败", e); + saveLog(config.getId(), config.getPlatform(), config.getMailFrom(), param.getTos(), param.getSubject(), param.getContent(), e); + return false; + } + } + + + /** + * 阿里云 发送邮件 + * + * @param param 发送邮件参数 + * @return env-id + */ + public boolean sendAliyun(EmailAliyunSendParam param) { + EmailConfig config = roundEmailConfig(param.getGroupName()); + + return sendAliyun(param, config); + } + + /** + * 阿里云 发送邮件 + * + * @param param 发送邮件参数 + * @return env-id + */ + public boolean sendAliyun(EmailAliyunSendParam param, EmailConfig config) { + try { + new EmailAliyunUtil(config).sendEmail(param.getFrom(), param.getFormAlias(), param.getTos(), param.getSubject(), param.getContent(), param.isHtml()); + saveLog(config.getId(), config.getPlatform(), param.getFrom(), param.getTos(), param.getSubject(), param.getContent(), null); + + return true; + } catch (Exception e) { + log.error("阿里云发送邮件失败", e); + saveLog(config.getId(), config.getPlatform(), param.getFrom(), param.getTos(), param.getSubject(), param.getContent(), e); + return false; + } + } + + /** + * 阿里云 批量发送邮件 + * + * @param param 发送邮件参数 + * @return message-id + */ + public boolean batchSendAliyun(EmailAliyunBatchSendParam param) { + EmailConfig config = roundEmailConfig(param.getGroupName()); + + return batchSendAliyun(param, config); + } + + /** + * 阿里云 批量发送邮件 + * + * @param param 发送邮件参数 + * @return message-id + */ + public boolean batchSendAliyun(EmailAliyunBatchSendParam param, EmailConfig config) { + try { + new EmailAliyunUtil(config).batchSendEmail(param.getFrom(), param.getReceiversName(), param.getTemplateName(), param.getTagName()); + saveLog(config.getId(), config.getPlatform(), param.getFrom(), param.getReceiversName(), null, param.getTemplateName(), null); + + return true; + } catch (Exception e) { + log.error("阿里云发送邮件失败", e); + saveLog(config.getId(), config.getPlatform(), param.getFrom(), param.getReceiversName(), null, param.getTemplateName(), e); + return false; + } + } + + /** + * 保存邮件日志 + */ + public void saveLog(Long platformId, Integer platform, String mailFrom, String mailTos, String subject, String content, Exception e) { + SysMailLogEntity logEntity = new SysMailLogEntity(); + logEntity.setPlatformId(platformId); + logEntity.setPlatform(platform); + logEntity.setMailFrom(mailFrom); + logEntity.setMailTos(mailTos); + logEntity.setSubject(subject); + logEntity.setContent(content); + + if (e != null) { + String error = StringUtils.substring(ExceptionUtils.getExceptionMessage(e), 0, 2000); + logEntity.setStatus(Constant.FAIL); + logEntity.setError(error); + } else { + logEntity.setStatus(Constant.SUCCESS); + } + + sysMailLogService.save(logEntity); + } + + /** + * 通过轮询算法,获取邮件平台的配置 + * + * @param groupName 分组名称 + * @return 邮件平台配置 + */ + private EmailConfig roundEmailConfig(String groupName) { + List platformList = sysMailConfigService.listByEnable(); + + // 是否有可用的邮件平台 + if (platformList.isEmpty()) { + throw new ServerException("没有可用的邮件平台,请先添加"); + } + + // 没有分组的情况 + if (StrUtil.isBlank(groupName)) { + // 采用轮询算法,发送邮件 + long round = emailConfigCache.getRoundValue(); + + return platformList.get((int) round % platformList.size()); + } + + + // 有分组的情况 + List newList = platformList.stream().filter(platform -> StrUtil.equals(platform.getGroupName(), groupName)).toList(); + if (newList.isEmpty()) { + throw new ServerException("邮件分组不存在"); + } + + long round = emailConfigCache.getRoundCodeValue(); + + // 指定邮件平台 + return newList.get((int) round % newList.size()); + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/email/util/EmailAliyunUtil.java b/drone-ops-system/src/main/java/com/bdzl/email/util/EmailAliyunUtil.java new file mode 100644 index 0000000..45d3be3 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/util/EmailAliyunUtil.java @@ -0,0 +1,120 @@ +package com.bdzl.email.util; + +import com.aliyun.dm20151123.Client; +import com.aliyun.dm20151123.models.BatchSendMailRequest; +import com.aliyun.dm20151123.models.SingleSendMailRequest; +import com.aliyun.teaopenapi.models.Config; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.email.config.EmailConfig; +import com.bdzl.framework.common.exception.ServerException; + +/** + * 阿里云 邮件发送 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +public class EmailAliyunUtil { + + private final Client client; + + public EmailAliyunUtil(EmailConfig emailConfig) throws Exception { + Config config = new Config(); + config.setEndpoint(emailConfig.getEndpoint()); + config.setRegionId(emailConfig.getRegionId()); + config.setAccessKeyId(emailConfig.getAccessKey()); + config.setAccessKeySecret(emailConfig.getSecretKey()); + + this.client = new Client(config); + } + + /** + * 发送邮件 + * + * @param from 发件人邮箱 + * @param formAlias 发件人昵称 + * @param tos 收件人邮箱列表,多个收件人逗号隔开 + * @param subject 邮件主题 + * @param content 邮件内容 + * @param isHtml 是否HTML格式 + * @return env-id + */ + public String sendEmail(String from, String formAlias, String tos, String subject, String content, boolean isHtml) { + SingleSendMailRequest request = new SingleSendMailRequest(); + + // 发件人邮箱 + request.setAccountName(from); + + // 发件人昵称 + request.setFromAlias(formAlias); + + // 地址类型:0-为随机账号,1-为发信地址 + request.setAddressType(1); + + // 使用管理台配置的回信地址 + request.setReplyToAddress(true); + + // 收件人邮箱 + request.setToAddress(tos); + + // 邮件主题 + request.setSubject(subject); + + // 是否HTML + if (isHtml) { + request.setHtmlBody(content); + } else { + request.setTextBody(content); + } + + // 是否开启追踪功能,开启需要备案,0关闭,1开启 + request.setClickTrace("0"); + + try { + return client.singleSendMail(request).getBody().getEnvId(); + } catch (Exception e) { + log.error("发送邮件失败", e); + throw new ServerException(e.getMessage()); + } + } + + /** + * 批量发送邮件 + * + * @param from 发件人邮箱 + * @param receiversName 收件人列表名称 + * @param templateName 邮件模板 + * @param tagName 邮件标签 + * @return env-id + */ + public String batchSendEmail(String from, String receiversName, String templateName, String tagName) { + BatchSendMailRequest request = new BatchSendMailRequest(); + + // 发件人邮箱 + request.setAccountName(from); + + // 收件人列表名称 + request.setReceiversName(receiversName); + + // 邮件模板 + request.setTemplateName(templateName); + + // 地址类型:0-为随机账号,1-为发信地址 + request.setAddressType(1); + + // 标签 + request.setTagName(tagName); + + // 是否开启追踪功能,开启需要备案,0关闭,1开启 + request.setClickTrace("0"); + + try { + return client.batchSendMail(request).getBody().getEnvId(); + } catch (Exception e) { + log.error("发送邮件失败", e); + throw new ServerException(e.getMessage()); + } + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/email/util/EmailLocalUtil.java b/drone-ops-system/src/main/java/com/bdzl/email/util/EmailLocalUtil.java new file mode 100644 index 0000000..7ce7dc4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/email/util/EmailLocalUtil.java @@ -0,0 +1,54 @@ +package com.bdzl.email.util; + +import cn.hutool.extra.mail.MailAccount; +import cn.hutool.extra.mail.MailUtil; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.email.config.EmailConfig; +import com.bdzl.framework.common.exception.ServerException; + +import java.io.File; + +/** + * 本地 邮件发送 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +public class EmailLocalUtil { + + private final MailAccount mailAccount; + + public EmailLocalUtil(EmailConfig config) { + MailAccount mailAccount = new MailAccount(); + mailAccount.setHost(config.getMailHost()); + if (config.getMailPort() != null) { + mailAccount.setPort(config.getMailPort()); + // 开启SSL加密 + if (config.getMailPort() == 465 || config.getMailPort() == 587) { + mailAccount.setSslEnable(true); + } + } + mailAccount.setFrom(config.getMailFrom()); + mailAccount.setPass(config.getMailPass()); + this.mailAccount = mailAccount; + } + + /** + * 发送邮件 + * + * @param tos 收件人邮箱列表,多个收件人逗号隔开 + * @param subject 邮件主题 + * @param content 邮件内容 + * @param files 附件列表 + * @return message-id + */ + public String sendEmail(String tos, String subject, String content, boolean isHtml, File... files) { + try { + return MailUtil.send(mailAccount, tos, subject, content, isHtml, files); + } catch (Exception e) { + log.error("发送邮件失败", e); + throw new ServerException(e.getMessage()); + } + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/security/config/SecurityConfig.java b/drone-ops-system/src/main/java/com/bdzl/security/config/SecurityConfig.java new file mode 100644 index 0000000..db1b4ef --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/config/SecurityConfig.java @@ -0,0 +1,76 @@ +package com.bdzl.security.config; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.security.mobile.MobileAuthenticationProvider; +import com.bdzl.framework.security.mobile.MobileUserDetailsService; +import com.bdzl.framework.security.mobile.MobileVerifyCodeService; +import com.bdzl.framework.security.third.ThirdAuthenticationProvider; +import com.bdzl.framework.security.third.ThirdOpenIdService; +import com.bdzl.framework.security.third.ThirdUserDetailsService; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; + +import java.util.ArrayList; +import java.util.List; + +/** + * SpringSecurity 配置文件 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +@AllArgsConstructor +@EnableWebSecurity +@EnableMethodSecurity +public class SecurityConfig { + private final UserDetailsService userDetailsService; + private final MobileUserDetailsService mobileUserDetailsService; + private final MobileVerifyCodeService mobileVerifyCodeService; + private final ThirdUserDetailsService thirdUserDetailsService; + private final ThirdOpenIdService thirdOpenIdService; + private final PasswordEncoder passwordEncoder; + private final ApplicationEventPublisher applicationEventPublisher; + + @Bean + DaoAuthenticationProvider daoAuthenticationProvider() { + DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); + daoAuthenticationProvider.setPasswordEncoder(passwordEncoder); + daoAuthenticationProvider.setUserDetailsService(userDetailsService); + + return daoAuthenticationProvider; + } + + @Bean + MobileAuthenticationProvider mobileAuthenticationProvider() { + return new MobileAuthenticationProvider(mobileUserDetailsService, mobileVerifyCodeService); + } + + @Bean + ThirdAuthenticationProvider thirdAuthenticationProvider() { + return new ThirdAuthenticationProvider(thirdUserDetailsService, thirdOpenIdService); + } + + @Bean + public AuthenticationManager authenticationManager() { + List providerList = new ArrayList<>(); + providerList.add(daoAuthenticationProvider()); + providerList.add(mobileAuthenticationProvider()); + providerList.add(thirdAuthenticationProvider()); + + ProviderManager providerManager = new ProviderManager(providerList); + providerManager.setAuthenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher)); + + return providerManager; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/security/event/AuthenticationEvents.java b/drone-ops-system/src/main/java/com/bdzl/security/event/AuthenticationEvents.java new file mode 100644 index 0000000..fcf2258 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/event/AuthenticationEvents.java @@ -0,0 +1,42 @@ +package com.bdzl.security.event; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.enums.LoginOperationEnum; +import com.bdzl.system.service.SysLogLoginService; +import org.springframework.context.event.EventListener; +import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.stereotype.Component; + +/** + * 认证事件处理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +@AllArgsConstructor +public class AuthenticationEvents { + private final SysLogLoginService sysLogLoginService; + + @EventListener + public void onSuccess(AuthenticationSuccessEvent event) { + // 用户信息 + UserDetail user = (UserDetail) event.getAuthentication().getPrincipal(); + + // 保存登录日志 + sysLogLoginService.save(user.getUsername(), Constant.SUCCESS, LoginOperationEnum.LOGIN_SUCCESS.getValue()); + } + + @EventListener + public void onFailure(AbstractAuthenticationFailureEvent event) { + // 用户名 + String username = (String) event.getAuthentication().getPrincipal(); + + // 保存登录日志 + sysLogLoginService.save(username, Constant.FAIL, LoginOperationEnum.ACCOUNT_FAIL.getValue()); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/security/service/MobileUserDetailsServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/security/service/MobileUserDetailsServiceImpl.java new file mode 100644 index 0000000..63c28d4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/service/MobileUserDetailsServiceImpl.java @@ -0,0 +1,35 @@ +package com.bdzl.security.service; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.security.mobile.MobileUserDetailsService; +import com.bdzl.system.convert.SysUserConvert; +import com.bdzl.system.dao.SysUserDao; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.service.SysUserDetailsService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * 手机验证码登录 MobileUserDetailsService + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class MobileUserDetailsServiceImpl implements MobileUserDetailsService { + private final SysUserDetailsService sysUserDetailsService; + private final SysUserDao sysUserDao; + + @Override + public UserDetails loadUserByMobile(String mobile) throws UsernameNotFoundException { + SysUserEntity userEntity = sysUserDao.getByMobile(mobile); + if (userEntity == null) { + throw new UsernameNotFoundException("手机号或验证码错误"); + } + + return sysUserDetailsService.getUserDetails(SysUserConvert.INSTANCE.convertDetail(userEntity)); + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/security/service/MobileVerifyCodeServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/security/service/MobileVerifyCodeServiceImpl.java new file mode 100644 index 0000000..401f171 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/service/MobileVerifyCodeServiceImpl.java @@ -0,0 +1,23 @@ +package com.bdzl.security.service; + +import lombok.AllArgsConstructor; +import com.bdzl.api.module.system.SmsApi; +import com.bdzl.framework.security.mobile.MobileVerifyCodeService; +import org.springframework.stereotype.Service; + +/** + * 短信验证码效验 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class MobileVerifyCodeServiceImpl implements MobileVerifyCodeService { + private final SmsApi smsApi; + + @Override + public boolean verifyCode(String mobile, String code) { + return smsApi.verifyCode(mobile, code); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/security/service/ThirdOpenIdServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/security/service/ThirdOpenIdServiceImpl.java new file mode 100644 index 0000000..ec9bfa1 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/service/ThirdOpenIdServiceImpl.java @@ -0,0 +1,40 @@ +package com.bdzl.security.service; + +import lombok.AllArgsConstructor; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.security.third.ThirdLogin; +import com.bdzl.framework.security.third.ThirdOpenIdService; +import com.bdzl.system.service.SysThirdLoginConfigService; +import org.springframework.stereotype.Service; + +/** + * 第三方登录,通过code,获取开放平台用户唯一标识 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class ThirdOpenIdServiceImpl implements ThirdOpenIdService { + private final SysThirdLoginConfigService sysThirdLoginConfigService; + + @Override + public String getOpenId(ThirdLogin login) { + AuthRequest authRequest = sysThirdLoginConfigService.getAuthRequest(login.getOpenType()); + AuthCallback callback = AuthCallback.builder().code(login.getCode()).state(login.getState()).build(); + + // 根据code,获取用户信息 + AuthResponse response = authRequest.login(callback); + + // 判断是否成功 + if (!response.ok()) { + throw new ServerException("第三方登录失败"); + } + + return response.getData().getUuid(); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/security/service/ThirdUserDetailsServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/security/service/ThirdUserDetailsServiceImpl.java new file mode 100644 index 0000000..0b6e298 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/service/ThirdUserDetailsServiceImpl.java @@ -0,0 +1,37 @@ +package com.bdzl.security.service; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.security.third.ThirdUserDetailsService; +import com.bdzl.system.convert.SysUserConvert; +import com.bdzl.system.dao.SysUserDao; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.service.SysThirdLoginService; +import com.bdzl.system.service.SysUserDetailsService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * 第三方登录,ThirdUserDetailsService + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class ThirdUserDetailsServiceImpl implements ThirdUserDetailsService { + private final SysUserDetailsService sysUserDetailsService; + private final SysThirdLoginService sysThirdLoginService; + private final SysUserDao sysUserDao; + + @Override + public UserDetails loadUserByOpenTypeAndOpenId(String openType, String openId) throws UsernameNotFoundException { + Long userId = sysThirdLoginService.getUserIdByOpenTypeAndOpenId(openType, openId); + SysUserEntity userEntity = sysUserDao.getById(userId); + if (userEntity == null) { + throw new UsernameNotFoundException("绑定的系统用户,不存在"); + } + + return sysUserDetailsService.getUserDetails(SysUserConvert.INSTANCE.convertDetail(userEntity)); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/security/service/UserDetailsServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/security/service/UserDetailsServiceImpl.java new file mode 100644 index 0000000..30e492a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/security/service/UserDetailsServiceImpl.java @@ -0,0 +1,35 @@ +package com.bdzl.security.service; + +import lombok.AllArgsConstructor; +import com.bdzl.system.convert.SysUserConvert; +import com.bdzl.system.dao.SysUserDao; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.service.SysUserDetailsService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * 账号登录 UserDetailsService + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class UserDetailsServiceImpl implements UserDetailsService { + private final SysUserDetailsService sysUserDetailsService; + private final SysUserDao sysUserDao; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + SysUserEntity userEntity = sysUserDao.getByUsername(username); + if (userEntity == null) { + throw new UsernameNotFoundException("用户名或密码错误"); + } + + return sysUserDetailsService.getUserDetails(SysUserConvert.INSTANCE.convertDetail(userEntity)); + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/AliyunSmsStrategy.java b/drone-ops-system/src/main/java/com/bdzl/sms/AliyunSmsStrategy.java new file mode 100644 index 0000000..8268365 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/AliyunSmsStrategy.java @@ -0,0 +1,65 @@ +package com.bdzl.sms; + +import cn.hutool.core.map.MapUtil; +import com.aliyun.dysmsapi20170525.Client; +import com.aliyun.dysmsapi20170525.models.SendSmsRequest; +import com.aliyun.dysmsapi20170525.models.SendSmsResponse; +import com.aliyun.teaopenapi.models.Config; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.sms.config.SmsConfig; + +import java.util.Map; + +/** + * 阿里云短信 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +public class AliyunSmsStrategy implements SmsStrategy { + private final Client client; + private final SmsConfig smsConfig; + + public AliyunSmsStrategy(SmsConfig smsConfig) { + this.smsConfig = smsConfig; + + try { + Config config = new Config(); + config.setAccessKeyId(smsConfig.getAccessKey()); + config.setAccessKeySecret(smsConfig.getSecretKey()); + config.endpoint = "dysmsapi.aliyuncs.com"; + + this.client = new Client(config); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void send(String mobile, Map params) { + SendSmsRequest request = new SendSmsRequest(); + request.setSignName(smsConfig.getSignName()); + request.setTemplateCode(smsConfig.getTemplateId()); + request.setPhoneNumbers(mobile); +// request.setTemplateParam("{\"code\":\"1234\"}"); + if (MapUtil.isNotEmpty(params)) { + request.setTemplateParam(JsonUtils.toJsonString(params)); + } + + try { + // 发送短信 + SendSmsResponse response = client.sendSms(request); + + // 发送失败 + if (!Constant.OK.equalsIgnoreCase(response.getBody().getCode())) { + throw new ServerException(response.getBody().getMessage()); + } + } catch (Exception e) { + throw new ServerException(e.getMessage()); + } + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/HuaweiSmsStrategy.java b/drone-ops-system/src/main/java/com/bdzl/sms/HuaweiSmsStrategy.java new file mode 100644 index 0000000..54ae2a1 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/HuaweiSmsStrategy.java @@ -0,0 +1,195 @@ +package com.bdzl.sms; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.CharsetUtil; +import lombok.Data; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.sms.config.SmsConfig; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; + +import javax.net.ssl.*; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 华为云短信 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class HuaweiSmsStrategy implements SmsStrategy { + // 无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 + private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; + // 无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 + private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; + private final SmsConfig smsConfig; + + public HuaweiSmsStrategy(SmsConfig smsConfig) { + this.smsConfig = smsConfig; + } + + @Override + public void send(String mobile, Map params) { + // 有参数则设置 + String templateParas = null; + if (MapUtil.isNotEmpty(params)) { + templateParas = JsonUtils.toJsonString(params.values().toArray(new String[0])); + } + + // 请求Body,不携带签名名称时,signature请填null + String body = buildRequestBody(smsConfig.getSenderId(), "+86" + mobile, smsConfig.getTemplateId(), templateParas, null, smsConfig.getSignName()); + if (StringUtils.isBlank(body)) { + throw new ServerException("body is null."); + } + + // 请求Headers中的X-WSSE参数值 + String wsseHeader = buildWsseHeader(smsConfig.getAccessKey(), smsConfig.getSecretKey()); + if (StringUtils.isBlank(wsseHeader)) { + throw new ServerException("wsse header is null."); + } + + try { + // 使用 https + trustAllHttpsCertificates(); + + // 接入地址 + String url = smsConfig.getUrl() + "/sms/batchSendSms/v1"; + URL realUrl = new URL(url); + HttpsURLConnection connection = (HttpsURLConnection) realUrl.openConnection(); + HostnameVerifier hv = (hostname, session) -> true; + connection.setHostnameVerifier(hv); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(true); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestProperty("Authorization", AUTH_HEADER_VALUE); + connection.setRequestProperty("X-WSSE", wsseHeader); + connection.connect(); + + IoUtil.writeUtf8(connection.getOutputStream(), true, body); + + int status = connection.getResponseCode(); + if (status == HttpStatus.OK.value()) { + String response = IoUtil.read(connection.getInputStream(), CharsetUtil.CHARSET_UTF_8); + HuaweiSmsResult result = JsonUtils.parseObject(response, HuaweiSmsResult.class); + + // 短信是否发送成功 + assert result != null; + if (!"000000".equals(result.code)) { + throw new ServerException(result.description); + } + } else { //400 401 + throw new ServerException(IoUtil.read(connection.getErrorStream(), CharsetUtil.CHARSET_UTF_8)); + } + } catch (Exception e) { + throw new ServerException(e.getMessage()); + } + } + + /** + * 构造请求Body体 + * + * @param signature | 签名名称,使用国内短信通用模板时填写 + */ + static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, + String statusCallBack, String signature) { + if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() + || templateId.isEmpty()) { + throw new ServerException("buildRequestBody(): sender, receiver or templateId is null."); + } + Map map = new HashMap<>(); + + map.put("from", sender); + map.put("to", receiver); + map.put("templateId", templateId); + if (null != templateParas && !templateParas.isEmpty()) { + map.put("templateParas", templateParas); + } + if (null != statusCallBack && !statusCallBack.isEmpty()) { + map.put("statusCallback", statusCallBack); + } + if (null != signature && !signature.isEmpty()) { + map.put("signature", signature); + } + + StringBuilder sb = new StringBuilder(); + String temp = ""; + + for (String s : map.keySet()) { + try { + temp = URLEncoder.encode(map.get(s), "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + sb.append(s).append("=").append(temp).append("&"); + } + + return sb.deleteCharAt(sb.length() - 1).toString(); + } + + /** + * 构造X-WSSE参数值 + */ + static String buildWsseHeader(String appKey, String appSecret) { + if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { + throw new ServerException("buildWsseHeader(): appKey or appSecret is null."); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + String time = sdf.format(new Date()); + String nonce = UUID.randomUUID().toString().replace("-", ""); + + MessageDigest md; + byte[] passwordDigest = null; + + try { + md = MessageDigest.getInstance("SHA-256"); + md.update((nonce + time + appSecret).getBytes()); + passwordDigest = md.digest(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); + + return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); + } + + static void trustAllHttpsCertificates() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) { + + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) { + + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } + }; + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + @Data + static class HuaweiSmsResult { + // code为000000,表示成功 + private String code; + private String description; + private List result; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/QiniuSmsStrategy.java b/drone-ops-system/src/main/java/com/bdzl/sms/QiniuSmsStrategy.java new file mode 100644 index 0000000..6a91fdc --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/QiniuSmsStrategy.java @@ -0,0 +1,41 @@ +package com.bdzl.sms; + +import com.qiniu.http.Response; +import com.qiniu.sms.SmsManager; +import com.qiniu.util.Auth; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.sms.config.SmsConfig; + +import java.util.Map; + +/** + * 七牛云短信 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class QiniuSmsStrategy implements SmsStrategy { + private final SmsConfig smsConfig; + private final SmsManager smsManager; + + public QiniuSmsStrategy(SmsConfig smsConfig) { + this.smsConfig = smsConfig; + + Auth auth = Auth.create(smsConfig.getAccessKey(), smsConfig.getSecretKey()); + smsManager = new SmsManager(auth); + } + + @Override + public void send(String mobile, Map params) { + try { + Response response = smsManager.sendSingleMessage(smsConfig.getTemplateId(), mobile, params); + + // 是否发送成功 + if (!response.isOK()) { + throw new ServerException(response.error); + } + } catch (Exception e) { + throw new ServerException(e.getMessage()); + } + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/SmsContext.java b/drone-ops-system/src/main/java/com/bdzl/sms/SmsContext.java new file mode 100644 index 0000000..6d029b4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/SmsContext.java @@ -0,0 +1,35 @@ +package com.bdzl.sms; + +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.sms.config.SmsConfig; +import com.bdzl.system.enums.SmsPlatformEnum; + +import java.util.Map; + +/** + * 短信 Context + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class SmsContext { + private final SmsStrategy smsStrategy; + + public SmsContext(SmsConfig config) { + if (config.getPlatform() == SmsPlatformEnum.ALIYUN.getValue()) { + this.smsStrategy = new AliyunSmsStrategy(config); + } else if (config.getPlatform() == SmsPlatformEnum.TENCENT.getValue()) { + this.smsStrategy = new TencentSmsStrategy(config); + } else if (config.getPlatform() == SmsPlatformEnum.QINIU.getValue()) { + this.smsStrategy = new QiniuSmsStrategy(config); + } else if (config.getPlatform() == SmsPlatformEnum.HUAWEI.getValue()) { + this.smsStrategy = new HuaweiSmsStrategy(config); + } else { + throw new ServerException("未知的短信平台"); + } + } + + public void send(String mobile, Map params) { + smsStrategy.send(mobile, params); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/SmsStrategy.java b/drone-ops-system/src/main/java/com/bdzl/sms/SmsStrategy.java new file mode 100644 index 0000000..6029879 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/SmsStrategy.java @@ -0,0 +1,20 @@ +package com.bdzl.sms; + +import java.util.Map; + +/** + * 短信 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SmsStrategy { + + /** + * 发送短信 + * + * @param mobile 手机号 + * @param params 参数 + */ + void send(String mobile, Map params); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/TencentSmsStrategy.java b/drone-ops-system/src/main/java/com/bdzl/sms/TencentSmsStrategy.java new file mode 100644 index 0000000..df2f562 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/TencentSmsStrategy.java @@ -0,0 +1,77 @@ +package com.bdzl.sms; + +import cn.hutool.core.map.MapUtil; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; +import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; +import com.tencentcloudapi.sms.v20210111.models.SendStatus; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.sms.config.SmsConfig; + +import java.util.Map; + +/** + * 腾讯云短信 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class TencentSmsStrategy implements SmsStrategy { + private final SmsConfig smsConfig; + private SmsClient client; + + public TencentSmsStrategy(SmsConfig smsConfig) { + this.smsConfig = smsConfig; + + try { + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setReqMethod("POST"); + httpProfile.setEndpoint("sms.tencentcloudapi.com"); + + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + + Credential cred = new Credential(smsConfig.getAccessKey(), smsConfig.getSecretKey()); + this.client = new SmsClient(cred, "ap-guangzhou", clientProfile); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void send(String mobile, Map params) { + SendSmsRequest request = new SendSmsRequest(); + request.setSmsSdkAppId(smsConfig.getAppId()); + request.setSignName(smsConfig.getSignName()); + request.setTemplateId(smsConfig.getTemplateId()); + + // 有参数则设置 + if (MapUtil.isNotEmpty(params)) { + request.setTemplateParamSet(params.values().toArray(new String[0])); + } + + // 手机号 + String[] phoneNumberSet = {"+86" + mobile}; + request.setPhoneNumberSet(phoneNumberSet); + + // 国际、港澳台短信,需要添加SenderId,国内短信填空,默认未开通 + request.setSenderId(smsConfig.getSenderId()); + + try { + // 发送短信 + SendSmsResponse response = client.SendSms(request); + SendStatus sendStatus = response.getSendStatusSet()[0]; + + // 发送失败 + if (!Constant.OK.equalsIgnoreCase(sendStatus.getCode())) { + throw new ServerException(sendStatus.getMessage()); + } + } catch (Exception e) { + throw new ServerException(e.getMessage()); + } + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/config/SmsConfig.java b/drone-ops-system/src/main/java/com/bdzl/sms/config/SmsConfig.java new file mode 100644 index 0000000..a257e89 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/config/SmsConfig.java @@ -0,0 +1,63 @@ +package com.bdzl.sms.config; + +import lombok.Data; + +/** + * 短信配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class SmsConfig { + /** + * 平台ID + */ + private Long id; + + /** + * 平台类型 + */ + private Integer platform; + + /** + * 分组名称 + */ + private String groupName; + + /** + * 短信签名 + */ + private String signName; + + /** + * 短信模板 + */ + private String templateId; + + /** + * 短信应用的ID,如:腾讯云等 + */ + private String appId; + + /** + * 腾讯云国际短信、华为云等需要 + */ + private String senderId; + + /** + * 接入地址,如:华为云 + */ + private String url; + + /** + * AccessKey + */ + private String accessKey; + + /** + * SecretKey + */ + private String secretKey; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/sms/service/SmsService.java b/drone-ops-system/src/main/java/com/bdzl/sms/service/SmsService.java new file mode 100644 index 0000000..ab010ad --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/sms/service/SmsService.java @@ -0,0 +1,151 @@ +package com.bdzl.sms.service; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.ExceptionUtils; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.sms.SmsContext; +import com.bdzl.sms.config.SmsConfig; +import com.bdzl.system.cache.SmsConfigCache; +import com.bdzl.system.entity.SysSmsLogEntity; +import com.bdzl.system.service.SysSmsConfigService; +import com.bdzl.system.service.SysSmsLogService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 短信服务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Slf4j +@Service +@AllArgsConstructor +public class SmsService { + private final SysSmsConfigService sysSmsConfigService; + private final SysSmsLogService sysSmsLogService; + private final SmsConfigCache smsConfigCache; + + /** + * 发送短信 + * + * @param mobile 手机号 + * @return 是否发送成功 + */ + public boolean send(String mobile) { + return this.send(mobile, MapUtil.newHashMap()); + } + + /** + * 发送短信 + * + * @param groupName 分组名称 + * @param mobile 手机号 + * @return 是否发送成功 + */ + public boolean send(String groupName, String mobile) { + return this.send(groupName, mobile, MapUtil.newHashMap()); + } + + /** + * 发送短信 + * + * @param mobile 手机号 + * @param params 参数 + * @return 是否发送成功 + */ + public boolean send(String mobile, Map params) { + return this.send(null, mobile, params); + } + + /** + * 发送短信 + * + * @param groupName 分组名称 + * @param mobile 手机号 + * @param params 参数 + * @return 是否发送成功 + */ + public boolean send(String groupName, String mobile, Map params) { + SmsConfig config = roundSmsConfig(groupName); + + try { + // 发送短信 + new SmsContext(config).send(mobile, params); + + saveLog(config, mobile, params, null); + return true; + } catch (Exception e) { + log.error("短信发送失败,手机号:{}", mobile, e); + + saveLog(config, mobile, params, e); + + return false; + } + } + + /** + * 保存短信日志 + */ + public void saveLog(SmsConfig config, String mobile, Map params, Exception e) { + SysSmsLogEntity logEntity = new SysSmsLogEntity(); + logEntity.setPlatform(config.getPlatform()); + logEntity.setPlatformId(config.getId()); + logEntity.setMobile(mobile); + logEntity.setParams(JsonUtils.toJsonString(params)); + + if (e != null) { + String error = StringUtils.substring(ExceptionUtils.getExceptionMessage(e), 0, 2000); + logEntity.setStatus(Constant.FAIL); + logEntity.setError(error); + } else { + logEntity.setStatus(Constant.SUCCESS); + } + + sysSmsLogService.save(logEntity); + } + + /** + * 通过轮询算法,获取短信平台的配置 + * + * @param groupName 分组名称 + * @return 短信平台配置 + */ + private SmsConfig roundSmsConfig(String groupName) { + List platformList = sysSmsConfigService.listByEnable(); + + // 是否有可用的短信平台 + if (platformList.isEmpty()) { + throw new ServerException("没有可用的短信平台,请先添加"); + } + + // 没有短信编码的情况 + if (StrUtil.isBlank(groupName)) { + // 采用轮询算法,发送短信 + long round = smsConfigCache.getRoundValue(); + + return platformList.get((int) round % platformList.size()); + } + + + // 有短信编码的情况 + List newList = platformList.stream().filter(platform -> StrUtil.equals(platform.getGroupName(), groupName)).toList(); + if (newList.isEmpty()) { + throw new ServerException("短信分组不存在"); + } + + long round = smsConfigCache.getRoundCodeValue(); + + // 指定短信平台 + return newList.get((int) round % newList.size()); + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/config/LocalResourceConfiguration.java b/drone-ops-system/src/main/java/com/bdzl/storage/config/LocalResourceConfiguration.java new file mode 100644 index 0000000..34efa5e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/config/LocalResourceConfiguration.java @@ -0,0 +1,35 @@ +package com.bdzl.storage.config; + +import jakarta.annotation.Resource; +import com.bdzl.storage.enums.StorageTypeEnum; +import com.bdzl.storage.properties.LocalStorageProperties; +import com.bdzl.storage.properties.StorageProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 本地资源映射配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Configuration +@ConditionalOnProperty(prefix = "storage", value = "enabled") +public class LocalResourceConfiguration implements WebMvcConfigurer { + @Resource + private StorageProperties properties; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // 如果不是本地存储,则返回 + if (properties.getConfig().getType() != StorageTypeEnum.LOCAL) { + return; + } + + LocalStorageProperties local = properties.getLocal(); + registry.addResourceHandler("/" + local.getUrl() + "/**") + .addResourceLocations("file:" + local.getPath() + "/"); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/config/StorageConfiguration.java b/drone-ops-system/src/main/java/com/bdzl/storage/config/StorageConfiguration.java new file mode 100644 index 0000000..d96be8e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/config/StorageConfiguration.java @@ -0,0 +1,40 @@ +package com.bdzl.storage.config; + +import com.bdzl.storage.enums.StorageTypeEnum; +import com.bdzl.storage.properties.StorageProperties; +import com.bdzl.storage.service.*; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 存储配置文件 + * + * @author 阿沐 babamu@126.com + */ +@Configuration +@EnableConfigurationProperties(StorageProperties.class) +@ConditionalOnProperty(prefix = "storage", value = "enabled") +public class StorageConfiguration { + + @Bean + public StorageService storageService(StorageProperties properties) { + if (properties.getConfig().getType() == StorageTypeEnum.LOCAL) { + return new LocalStorageService(properties); + } else if (properties.getConfig().getType() == StorageTypeEnum.ALIYUN) { + return new AliyunStorageService(properties); + } else if (properties.getConfig().getType() == StorageTypeEnum.TENCENT) { + return new TencentStorageService(properties); + } else if (properties.getConfig().getType() == StorageTypeEnum.QINIU) { + return new QiniuStorageService(properties); + } else if (properties.getConfig().getType() == StorageTypeEnum.HUAWEI) { + return new HuaweiStorageService(properties); + } else if (properties.getConfig().getType() == StorageTypeEnum.MINIO) { + return new MinioStorageService(properties); + } + + return null; + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/enums/StorageTypeEnum.java b/drone-ops-system/src/main/java/com/bdzl/storage/enums/StorageTypeEnum.java new file mode 100644 index 0000000..248aeff --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/enums/StorageTypeEnum.java @@ -0,0 +1,34 @@ +package com.bdzl.storage.enums; + +/** + * 存储类型枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public enum StorageTypeEnum { + /** + * 本地 + */ + LOCAL, + /** + * 阿里云 + */ + ALIYUN, + /** + * 腾讯云 + */ + TENCENT, + /** + * 七牛云 + */ + QINIU, + /** + * 华为云 + */ + HUAWEI, + /** + * Minio + */ + MINIO; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/AliyunStorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/AliyunStorageProperties.java new file mode 100644 index 0000000..b6a4473 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/AliyunStorageProperties.java @@ -0,0 +1,17 @@ +package com.bdzl.storage.properties; + +import lombok.Data; + +/** + * 阿里云存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class AliyunStorageProperties { + private String endPoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/HuaweiStorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/HuaweiStorageProperties.java new file mode 100644 index 0000000..ce550fd --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/HuaweiStorageProperties.java @@ -0,0 +1,17 @@ +package com.bdzl.storage.properties; + +import lombok.Data; + +/** + * 华为云存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class HuaweiStorageProperties { + private String endPoint; + private String accessKey; + private String secretKey; + private String bucketName; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/LocalStorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/LocalStorageProperties.java new file mode 100644 index 0000000..fa6a831 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/LocalStorageProperties.java @@ -0,0 +1,21 @@ +package com.bdzl.storage.properties; + +import lombok.Data; + +/** + * 本地存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class LocalStorageProperties { + /** + * 本地存储路径 + */ + private String path; + /** + * 资源起始路径 + */ + private String url = "upload"; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/MinioStorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/MinioStorageProperties.java new file mode 100644 index 0000000..db16723 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/MinioStorageProperties.java @@ -0,0 +1,17 @@ +package com.bdzl.storage.properties; + +import lombok.Data; + +/** + * Minio存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class MinioStorageProperties { + private String endPoint; + private String accessKey; + private String secretKey; + private String bucketName; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/QiniuStorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/QiniuStorageProperties.java new file mode 100644 index 0000000..d488eed --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/QiniuStorageProperties.java @@ -0,0 +1,16 @@ +package com.bdzl.storage.properties; + +import lombok.Data; + +/** + * 七牛云存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class QiniuStorageProperties { + private String accessKey; + private String secretKey; + private String bucketName; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/StorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/StorageProperties.java new file mode 100644 index 0000000..71134d5 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/StorageProperties.java @@ -0,0 +1,102 @@ +package com.bdzl.storage.properties; + +import lombok.Data; +import com.bdzl.storage.enums.StorageTypeEnum; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * 存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@ConfigurationProperties(prefix = "storage") +public class StorageProperties { + /** + * 是否开启存储 + */ + private boolean enabled; + /** + * 通用配置项 + */ + private StorageConfig config; + /** + * 本地配置项 + */ + private LocalStorageProperties local; + /** + * 阿里云配置项 + */ + private AliyunStorageProperties aliyun; + /** + * 七牛云配置项 + */ + private QiniuStorageProperties qiniu; + /** + * 华为云配置项 + */ + private HuaweiStorageProperties huawei; + /** + * Minio配置项 + */ + private MinioStorageProperties minio; + /** + * 腾讯云配置项 + */ + private TencentStorageProperties tencent; + + @Data + public static class StorageConfig { + /** + * 访问域名 + */ + private String domain; + /** + * 配置路径前缀 + */ + private String prefix; + /** + * 存储类型 + */ + private StorageTypeEnum type; + } + + @Bean + @ConfigurationProperties(prefix = "storage.local") + public LocalStorageProperties localStorageProperties() { + return new LocalStorageProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "storage.aliyun") + public AliyunStorageProperties aliyunStorageProperties() { + return new AliyunStorageProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "storage.qiniu") + public QiniuStorageProperties qiniuStorageProperties() { + return new QiniuStorageProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "storage.huawei") + public HuaweiStorageProperties huaweiStorageProperties() { + return new HuaweiStorageProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "storage.minio") + public MinioStorageProperties minioStorageProperties() { + return new MinioStorageProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "storage.tencent") + public TencentStorageProperties tencentStorageProperties() { + return new TencentStorageProperties(); + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/properties/TencentStorageProperties.java b/drone-ops-system/src/main/java/com/bdzl/storage/properties/TencentStorageProperties.java new file mode 100644 index 0000000..7f8b0d7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/properties/TencentStorageProperties.java @@ -0,0 +1,17 @@ +package com.bdzl.storage.properties; + +import lombok.Data; + +/** + * 腾讯云存储配置项 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +public class TencentStorageProperties { + private String accessKey; + private String secretKey; + private String region; + private String bucketName; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/AliyunStorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/AliyunStorageService.java new file mode 100644 index 0000000..8529000 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/AliyunStorageService.java @@ -0,0 +1,45 @@ +package com.bdzl.storage.service; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.storage.properties.StorageProperties; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 阿里云存储 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class AliyunStorageService extends StorageService { + + public AliyunStorageService(StorageProperties properties) { + this.properties = properties; + } + + @Override + public String upload(byte[] data, String path) { + return upload(new ByteArrayInputStream(data), path); + } + + @Override + public String upload(InputStream inputStream, String path) { + OSS client = new OSSClientBuilder().build(properties.getAliyun().getEndPoint(), + properties.getAliyun().getAccessKeyId(), properties.getAliyun().getAccessKeySecret()); + try { + client.putObject(properties.getAliyun().getBucketName(), path, inputStream); + } catch (Exception e) { + throw new ServerException("上传文件失败:", e); + } finally { + if (client != null) { + client.shutdown(); + } + } + + return properties.getConfig().getDomain() + "/" + path; + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/HuaweiStorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/HuaweiStorageService.java new file mode 100644 index 0000000..90f541a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/HuaweiStorageService.java @@ -0,0 +1,41 @@ +package com.bdzl.storage.service; + +import com.obs.services.ObsClient; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.storage.properties.StorageProperties; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 华为云存储 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class HuaweiStorageService extends StorageService { + + public HuaweiStorageService(StorageProperties properties) { + this.properties = properties; + } + + @Override + public String upload(byte[] data, String path) { + return upload(new ByteArrayInputStream(data), path); + } + + @Override + public String upload(InputStream inputStream, String path) { + ObsClient client = new ObsClient(properties.getHuawei().getAccessKey(), + properties.getHuawei().getSecretKey(), properties.getHuawei().getEndPoint()); + try { + client.putObject(properties.getHuawei().getBucketName(), path, inputStream); + client.close(); + } catch (Exception e) { + throw new ServerException("上传文件失败:", e); + } + + return properties.getConfig().getDomain() + "/" + path; + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/LocalStorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/LocalStorageService.java new file mode 100644 index 0000000..606de7e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/LocalStorageService.java @@ -0,0 +1,50 @@ +package com.bdzl.storage.service; + +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.storage.properties.StorageProperties; +import org.springframework.util.FileCopyUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + +/** + * 本地存储 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class LocalStorageService extends StorageService { + + public LocalStorageService(StorageProperties properties) { + this.properties = properties; + } + + @Override + public String upload(byte[] data, String path) { + return upload(new ByteArrayInputStream(data), path); + } + + + @Override + public String upload(InputStream inputStream, String path) { + + try { + File file = new File(properties.getLocal().getPath() + File.separator + path); + + // 没有目录,则自动创建目录 + File parent = file.getParentFile(); + if (parent != null && !parent.mkdirs() && !parent.isDirectory()) { + throw new IOException("目录 '" + parent + "' 创建失败"); + } + + FileCopyUtils.copy(inputStream, Files.newOutputStream(file.toPath())); + } catch (Exception e) { + throw new ServerException("上传文件失败:", e); + } + + return properties.getConfig().getDomain() + "/" + properties.getLocal().getUrl() + "/" + path; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/MinioStorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/MinioStorageService.java new file mode 100644 index 0000000..6690fd8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/MinioStorageService.java @@ -0,0 +1,67 @@ +package com.bdzl.storage.service; + +import io.minio.BucketExistsArgs; +import io.minio.MakeBucketArgs; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.storage.properties.StorageProperties; +import org.springframework.http.MediaType; +import org.springframework.http.MediaTypeFactory; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Optional; + +/** + * Minio存储 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class MinioStorageService extends StorageService { + private final MinioClient minioClient; + + public MinioStorageService(StorageProperties properties) { + this.properties = properties; + + minioClient = MinioClient.builder().endpoint(properties.getMinio().getEndPoint()) + .credentials(properties.getMinio().getAccessKey(), properties.getMinio().getSecretKey()).build(); + } + + @Override + public String upload(byte[] data, String path) { + return upload(new ByteArrayInputStream(data), path); + } + + @Override + public String upload(InputStream inputStream, String path) { + try { + //如果BucketName不存在,则创建 + boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(properties.getMinio().getBucketName()).build()); + if (!found) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(properties.getMinio().getBucketName()).build()); + } + + String contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE; + Optional mediaType = MediaTypeFactory.getMediaType(path); + if (mediaType.isPresent()) { + contentType = mediaType.get().toString(); + } + + minioClient.putObject( + PutObjectArgs.builder() + .bucket(properties.getMinio().getBucketName()) + .contentType(contentType) + .object(path) + .stream(inputStream, inputStream.available(), -1) + .build() + ); + + } catch (Exception e) { + throw new ServerException("上传文件失败:", e); + } + + return properties.getMinio().getEndPoint() + "/" + properties.getMinio().getBucketName() + "/" + path; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/QiniuStorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/QiniuStorageService.java new file mode 100644 index 0000000..2250d18 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/QiniuStorageService.java @@ -0,0 +1,58 @@ +package com.bdzl.storage.service; + +import com.qiniu.http.Response; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.Region; +import com.qiniu.storage.UploadManager; +import com.qiniu.util.Auth; +import com.qiniu.util.IOUtils; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.storage.properties.StorageProperties; + +import java.io.IOException; +import java.io.InputStream; + +/** + * 七牛云存储 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class QiniuStorageService extends StorageService { + private final UploadManager uploadManager; + + public QiniuStorageService(StorageProperties properties) { + this.properties = properties; + + uploadManager = new UploadManager(new Configuration(Region.autoRegion())); + + } + + @Override + public String upload(byte[] data, String path) { + try { + String token = Auth.create(properties.getQiniu().getAccessKey(), properties.getQiniu().getSecretKey()). + uploadToken(properties.getQiniu().getBucketName()); + + Response res = uploadManager.put(data, path, token); + if (!res.isOK()) { + throw new ServerException(res.toString()); + } + + return properties.getConfig().getDomain() + "/" + path; + } catch (Exception e) { + throw new ServerException("上传文件失败:", e); + } + } + + @Override + public String upload(InputStream inputStream, String path) { + try { + byte[] data = IOUtils.toByteArray(inputStream); + return this.upload(data, path); + } catch (IOException e) { + throw new ServerException("上传文件失败:", e); + } + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/StorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/StorageService.java new file mode 100644 index 0000000..66fbcc7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/StorageService.java @@ -0,0 +1,82 @@ +package com.bdzl.storage.service; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.file.FileNameUtil; +import com.bdzl.storage.properties.StorageProperties; +import org.springframework.util.StringUtils; + +import java.io.InputStream; +import java.util.Date; + +/** + * 存储服务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public abstract class StorageService { + public StorageProperties properties; + + /** + * 根据文件名,生成带时间戳的新文件名 + * + * @param fileName 文件名 + * @return 返回带时间戳的文件名 + */ + public String getNewFileName(String fileName) { + // 主文件名,不包含扩展名 + String prefix = FileNameUtil.getPrefix(fileName); + // 文件扩展名 + String suffix = FileNameUtil.getSuffix(fileName); + // 把当天HH:mm:ss,转换成秒 + long time = DateUtil.timeToSecond(DateUtil.formatTime(new Date())); + // 新文件名 + return prefix + "_" + time + "." + suffix; + } + + /** + * 生成路径,不包含文件名 + * + * @return 返回生成的路径 + */ + public String getPath() { + // 文件路径 + String path = DateUtil.format(new Date(), "yyyyMMdd"); + + // 如果有前缀,则也带上 + if (StringUtils.hasText(properties.getConfig().getPrefix())) { + path = properties.getConfig().getPrefix() + "/" + path; + } + + return path; + } + + /** + * 根据文件名,生成路径 + * + * @param fileName 文件名 + * @return 生成文件路径 + */ + public String getPath(String fileName) { + return getPath() + "/" + getNewFileName(fileName); + } + + /** + * 文件上传 + * + * @param data 文件字节数组 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + public abstract String upload(byte[] data, String path); + + /** + * 文件上传 + * + * @param inputStream 字节流 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + public abstract String upload(InputStream inputStream, String path); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/storage/service/TencentStorageService.java b/drone-ops-system/src/main/java/com/bdzl/storage/service/TencentStorageService.java new file mode 100644 index 0000000..def1905 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/storage/service/TencentStorageService.java @@ -0,0 +1,64 @@ +package com.bdzl.storage.service; + +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.ObjectMetadata; +import com.qcloud.cos.model.PutObjectRequest; +import com.qcloud.cos.model.PutObjectResult; +import com.qcloud.cos.region.Region; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.storage.properties.StorageProperties; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 腾讯云存储 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class TencentStorageService extends StorageService { + private final COSCredentials cred; + private final ClientConfig clientConfig; + + public TencentStorageService(StorageProperties properties) { + this.properties = properties; + + cred = new BasicCOSCredentials(properties.getTencent().getAccessKey(), properties.getTencent().getSecretKey()); + + clientConfig = new ClientConfig(new Region(properties.getTencent().getRegion())); + clientConfig.setHttpProtocol(HttpProtocol.https); + } + + @Override + public String upload(byte[] data, String path) { + return upload(new ByteArrayInputStream(data), path); + } + + @Override + public String upload(InputStream inputStream, String path) { + try { + COSClient cosClient = new COSClient(cred, clientConfig); + + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(inputStream.available()); + + PutObjectRequest request = new PutObjectRequest(properties.getTencent().getBucketName(), path, inputStream, metadata); + PutObjectResult result = cosClient.putObject(request); + + cosClient.shutdown(); + if (result.getETag() == null) { + throw new ServerException("上传文件失败,请检查配置信息"); + } + } catch (Exception e) { + throw new ServerException("上传文件失败:", e); + } + + return properties.getConfig().getDomain() + "/" + path; + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/api/SmsApiImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/api/SmsApiImpl.java new file mode 100644 index 0000000..331662f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/api/SmsApiImpl.java @@ -0,0 +1,75 @@ +package com.bdzl.system.api; + +import lombok.AllArgsConstructor; +import com.bdzl.api.module.system.SmsApi; +import com.bdzl.sms.service.SmsService; +import com.bdzl.system.cache.SmsSendCache; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 短信服务Api + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +@AllArgsConstructor +public class SmsApiImpl implements SmsApi { + private final SmsService smsService; + private final SmsSendCache smsSendCache; + + @Override + public boolean send(String mobile, Map params) { + return smsService.send(mobile, params); + } + + @Override + public boolean send(String groupName, String mobile, Map params) { + return smsService.send(groupName, mobile, params); + } + + @Override + public boolean sendCode(String mobile, String key, String value) { + // 短信参数 + Map params = new HashMap<>(); + params.put(key, value); + + // 发送短信 + boolean flag = smsService.send(mobile, params); + if (flag) { + smsSendCache.saveCode(mobile, value); + } + return flag; + } + + @Override + public boolean sendCode(String groupName, String mobile, String key, String value) { + // 短信参数 + Map params = new HashMap<>(); + params.put(key, value); + + // 发送短信 + boolean flag = smsService.send(groupName, mobile, params); + if (flag) { + smsSendCache.saveCode(mobile, value); + } + return flag; + } + + @Override + public boolean verifyCode(String mobile, String code) { + String value = smsSendCache.getCode(mobile); + if (value != null) { + // 删除短信验证码 + smsSendCache.deleteCode(mobile); + + // 效验 + return value.equalsIgnoreCase(code); + } + + return false; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/api/StorageApiImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/api/StorageApiImpl.java new file mode 100644 index 0000000..65925fd --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/api/StorageApiImpl.java @@ -0,0 +1,45 @@ +package com.bdzl.system.api; + +import lombok.AllArgsConstructor; +import com.bdzl.api.module.system.StorageApi; +import com.bdzl.storage.service.StorageService; +import org.springframework.stereotype.Component; + +import java.io.InputStream; + +/** + * 存储服务Api + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Component +@AllArgsConstructor +public class StorageApiImpl implements StorageApi { + private final StorageService storageService; + + @Override + public String getNewFileName(String fileName) { + return storageService.getNewFileName(fileName); + } + + @Override + public String getPath() { + return storageService.getPath(); + } + + @Override + public String getPath(String fileName) { + return storageService.getPath(fileName); + } + + @Override + public String upload(byte[] data, String path) { + return storageService.upload(data, path); + } + + @Override + public String upload(InputStream inputStream, String path) { + return storageService.upload(inputStream, path); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/cache/EmailConfigCache.java b/drone-ops-system/src/main/java/com/bdzl/system/cache/EmailConfigCache.java new file mode 100644 index 0000000..29eed11 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/cache/EmailConfigCache.java @@ -0,0 +1,57 @@ +package com.bdzl.system.cache; + +import lombok.AllArgsConstructor; +import com.bdzl.email.config.EmailConfig; +import com.bdzl.framework.common.cache.RedisCache; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 邮件配置 Cache + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class EmailConfigCache { + private final RedisCache redisCache; + + /** + * 邮件平台轮询KEY + */ + private final String SMS_ROUND_KEY = "sys:mail:round"; + private final String SMS_ROUND_CODE_KEY = "sys:mail:round:code"; + + /** + * 邮件平台列表KEY + */ + private final String SMS_PLATFORM_KEY = "sys:mail:platform"; + + /** + * 获取邮件轮询值 + */ + public Long getRoundValue() { + return redisCache.increment(SMS_ROUND_KEY); + } + + /** + * 获取邮件编码轮询值 + */ + public Long getRoundCodeValue() { + return redisCache.increment(SMS_ROUND_CODE_KEY); + } + + public List list() { + return (List) redisCache.get(SMS_PLATFORM_KEY); + } + + public void save(List list) { + redisCache.set(SMS_PLATFORM_KEY, list); + } + + public void delete() { + redisCache.delete(SMS_PLATFORM_KEY); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/cache/SmsConfigCache.java b/drone-ops-system/src/main/java/com/bdzl/system/cache/SmsConfigCache.java new file mode 100644 index 0000000..b1ea5eb --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/cache/SmsConfigCache.java @@ -0,0 +1,57 @@ +package com.bdzl.system.cache; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import com.bdzl.sms.config.SmsConfig; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 短信平台 Cache + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SmsConfigCache { + private final RedisCache redisCache; + + /** + * 短信平台轮询KEY + */ + private final String SMS_ROUND_KEY = "sys:sms:round"; + private final String SMS_ROUND_CODE_KEY = "sys:sms:round:code"; + + /** + * 短信平台列表KEY + */ + private final String SMS_PLATFORM_KEY = "sys:sms:platform"; + + /** + * 获取短信轮询值 + */ + public Long getRoundValue() { + return redisCache.increment(SMS_ROUND_KEY); + } + + /** + * 获取短信编码轮询值 + */ + public Long getRoundCodeValue() { + return redisCache.increment(SMS_ROUND_CODE_KEY); + } + + public List list() { + return (List) redisCache.get(SMS_PLATFORM_KEY); + } + + public void save(List list) { + redisCache.set(SMS_PLATFORM_KEY, list); + } + + public void delete() { + redisCache.delete(SMS_PLATFORM_KEY); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/cache/SmsSendCache.java b/drone-ops-system/src/main/java/com/bdzl/system/cache/SmsSendCache.java new file mode 100644 index 0000000..01087c7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/cache/SmsSendCache.java @@ -0,0 +1,44 @@ +package com.bdzl.system.cache; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import org.springframework.stereotype.Service; + +/** + * 短信发送 Cache + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SmsSendCache { + private final RedisCache redisCache; + + /** + * 获取发送手机短信验证码KEY + * + * @param mobile 手机号 + * @return KEY + */ + private String getCodeKey(String mobile) { + return "sys:sms:code" + mobile; + } + + public void saveCode(String mobile, String code) { + String key = getCodeKey(mobile); + + // 保存到Redis,有效期10分钟 + redisCache.set(key, code, 10 * 60); + } + + public String getCode(String mobile) { + String key = getCodeKey(mobile); + return (String) redisCache.get(key); + } + + public void deleteCode(String mobile) { + String key = getCodeKey(mobile); + redisCache.delete(key); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/cache/SysParamsCache.java b/drone-ops-system/src/main/java/com/bdzl/system/cache/SysParamsCache.java new file mode 100644 index 0000000..84bc5d8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/cache/SysParamsCache.java @@ -0,0 +1,50 @@ +package com.bdzl.system.cache; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import org.springframework.stereotype.Service; + +/** + * 参数管理 Cache + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysParamsCache { + private final RedisCache redisCache; + + /** + * 参数管理 KEY + */ + private final String SYSTEM_PARAMS_KEY = "system:params"; + + /** + * 根据参数键,获取参数值 + * + * @param paramKey 参数键 + */ + public String get(String paramKey) { + return (String) redisCache.hGet(SYSTEM_PARAMS_KEY, paramKey); + } + + /** + * 根据参数键,获取参数值 + * + * @param paramKey 参数键 + * @param paramValue 参数值 + */ + public void save(String paramKey, String paramValue) { + redisCache.hSet(SYSTEM_PARAMS_KEY, paramKey, paramValue, RedisCache.NOT_EXPIRE); + } + + /** + * 根据参数键,删除参数值 + * + * @param paramKey 参数键 + */ + public void del(String... paramKey) { + redisCache.hDel(SYSTEM_PARAMS_KEY, paramKey); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/IndexController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/IndexController.java new file mode 100644 index 0000000..e0283a4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/IndexController.java @@ -0,0 +1,21 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 首页 欢迎信息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Tag(name = "首页") +@RestController +public class IndexController { + + @GetMapping("/") + public String index() { + return "您好,项目已启动,祝您使用愉快!"; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysAttachmentController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysAttachmentController.java new file mode 100644 index 0000000..a99f358 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysAttachmentController.java @@ -0,0 +1,61 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.query.SysAttachmentQuery; +import com.bdzl.system.service.SysAttachmentService; +import com.bdzl.system.vo.SysAttachmentVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/attachment") +@Tag(name = "附件管理") +@AllArgsConstructor +public class SysAttachmentController { + private final SysAttachmentService sysAttachmentService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:attachment:page')") + public Result> page(@ParameterObject @Valid SysAttachmentQuery query) { + PageResult page = sysAttachmentService.page(query); + + return Result.ok(page); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:attachment:save')") + public Result save(@RequestBody SysAttachmentVO vo) { + sysAttachmentService.save(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:attachment:delete')") + public Result delete(@RequestBody List idList) { + sysAttachmentService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysAuthController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysAuthController.java new file mode 100644 index 0000000..f9d1872 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysAuthController.java @@ -0,0 +1,94 @@ +package com.bdzl.system.controller; + +import com.bdzl.system.vo.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.security.utils.TokenUtils; +import com.bdzl.system.service.SysAuthService; +import com.bdzl.system.service.SysCaptchaService; +import org.springframework.web.bind.annotation.*; + +/** + * 认证管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/auth") +@Tag(name = "认证管理") +@AllArgsConstructor +public class SysAuthController { + private final SysCaptchaService sysCaptchaService; + private final SysAuthService sysAuthService; + + @GetMapping("captcha") + @Operation(summary = "验证码") + public Result captcha() { + SysCaptchaVO captchaVO = sysCaptchaService.generate(); + + return Result.ok(captchaVO); + } + + @GetMapping("captcha/enabled") + @Operation(summary = "是否开启验证码") + public Result captchaEnabled() { + boolean enabled = sysCaptchaService.isCaptchaEnabled(); + + return Result.ok(enabled); + } + + @PostMapping("login") + @Operation(summary = "账号密码登录") + public Result login(@RequestBody SysAccountLoginVO login) { + SysUserTokenVO token = sysAuthService.loginByAccount(login); + + return Result.ok(token); + } + + @PostMapping("send/code") + @Operation(summary = "发送短信验证码") + public Result sendCode(String mobile) { + boolean flag = sysAuthService.sendCode(mobile); + if (!flag) { + return Result.error("短信发送失败!"); + } + + return Result.ok(); + } + + @PostMapping("mobile") + @Operation(summary = "手机号登录") + public Result mobile(@RequestBody SysMobileLoginVO login) { + SysUserTokenVO token = sysAuthService.loginByMobile(login); + + return Result.ok(token); + } + + @PostMapping("third") + @Operation(summary = "第三方登录") + public Result third(@RequestBody SysThirdCallbackVO login) { + SysUserTokenVO token = sysAuthService.loginByThird(login); + + return Result.ok(token); + } + + @PostMapping("token") + @Operation(summary = "获取 accessToken") + public Result token(String refreshToken) { + AccessTokenVO token = sysAuthService.getAccessToken(refreshToken); + + return Result.ok(token); + } + + @PostMapping("logout") + @Operation(summary = "退出") + public Result logout(HttpServletRequest request) { + sysAuthService.logout(TokenUtils.getAccessToken(request)); + + return Result.ok(); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysDictDataController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysDictDataController.java new file mode 100644 index 0000000..6c3ccc0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysDictDataController.java @@ -0,0 +1,83 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.convert.SysDictDataConvert; +import com.bdzl.system.entity.SysDictDataEntity; +import com.bdzl.system.query.SysDictDataQuery; +import com.bdzl.system.service.SysDictDataService; +import com.bdzl.system.vo.SysDictDataVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 字典数据 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/dict/data") +@Tag(name = "字典数据") +@AllArgsConstructor +public class SysDictDataController { + private final SysDictDataService sysDictDataService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:dict:page')") + public Result> page(@ParameterObject @Valid SysDictDataQuery query) { + PageResult page = sysDictDataService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:dict:info')") + public Result get(@PathVariable("id") Long id) { + SysDictDataEntity entity = sysDictDataService.getById(id); + + return Result.ok(SysDictDataConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:dict:save')") + public Result save(@RequestBody @Valid SysDictDataVO vo) { + sysDictDataService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:dict:update')") + public Result update(@RequestBody @Valid SysDictDataVO vo) { + sysDictDataService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:dict:delete')") + public Result delete(@RequestBody List idList) { + sysDictDataService.delete(idList); + + return Result.ok(); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysDictTypeController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysDictTypeController.java new file mode 100644 index 0000000..c9c1175 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysDictTypeController.java @@ -0,0 +1,121 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.convert.SysDictTypeConvert; +import com.bdzl.system.entity.SysDictTypeEntity; +import com.bdzl.system.query.SysDictTypeQuery; +import com.bdzl.system.service.SysDictTypeService; +import com.bdzl.system.vo.SysDictTypeVO; +import com.bdzl.system.vo.SysDictVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 字典类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/dict/type") +@Tag(name = "字典类型") +@AllArgsConstructor +public class SysDictTypeController { + private final SysDictTypeService sysDictTypeService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:dict:page')") + public Result> page(@ParameterObject @Valid SysDictTypeQuery query) { + PageResult page = sysDictTypeService.page(query); + + return Result.ok(page); + } + + @GetMapping("list") + @Operation(summary = "列表") + @PreAuthorize("hasAuthority('sys:dict:page')") + public Result> list(Long pid) { + List list = sysDictTypeService.list(pid); + + return Result.ok(list); + } + + @GetMapping("list/sql") + @Operation(summary = "动态SQL数据") + @PreAuthorize("hasAuthority('sys:dict:page')") + public Result> listSql(Long id) { + List list = sysDictTypeService.getDictSql(id); + + PageResult page = new PageResult<>(list, list.size()); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:dict:info')") + public Result get(@PathVariable("id") Long id) { + SysDictTypeEntity entity = sysDictTypeService.getById(id); + + return Result.ok(SysDictTypeConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:dict:save')") + public Result save(@RequestBody @Valid SysDictTypeVO vo) { + sysDictTypeService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:dict:update')") + public Result update(@RequestBody @Valid SysDictTypeVO vo) { + sysDictTypeService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:dict:delete')") + public Result delete(@RequestBody List idList) { + sysDictTypeService.delete(idList); + + return Result.ok(); + } + + @GetMapping("all") + @Operation(summary = "全部字典数据") + public Result> all() { + List dictList = sysDictTypeService.getDictList(); + + return Result.ok(dictList); + } + + @GetMapping("refreshTransCache") + @Operation(summary = "刷新字典翻译缓存数据") + @PreAuthorize("hasAuthority('sys:dict:refreshTransCache')") + public Result refreshTransCache() { + sysDictTypeService.refreshTransCache(); + return Result.ok(); + } + + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysFileUploadController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysFileUploadController.java new file mode 100644 index 0000000..c1e1963 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysFileUploadController.java @@ -0,0 +1,72 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.storage.service.StorageService; +import com.bdzl.system.vo.SysFileUploadVO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +/** + * 文件上传 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/file") +@Tag(name = "文件上传") +@AllArgsConstructor +public class SysFileUploadController { + private final StorageService storageService; + + @PostMapping("upload") + @Operation(summary = "上传") + @OperateLog(type = OperateTypeEnum.INSERT) + public Result upload(@RequestParam("file") MultipartFile file) throws Exception { + if (file.isEmpty()) { + return Result.error("请选择需要上传的文件"); + } + + // 上传路径 + String path = storageService.getPath(file.getOriginalFilename()); + // 上传文件 + String url = storageService.upload(file.getBytes(), path); + + SysFileUploadVO vo = new SysFileUploadVO(); + vo.setUrl(url); + vo.setSize(file.getSize()); + vo.setName(file.getOriginalFilename()); + vo.setPlatform(storageService.properties.getConfig().getType().name()); + + return Result.ok(vo); + } + + @PostMapping("uploads") + @Operation(summary = "上传") + @OperateLog(type = OperateTypeEnum.INSERT) + public SysFileUploadVO uploads(@RequestParam("file") MultipartFile file) throws Exception { + if (file.isEmpty()) { + throw new ServerException("请选择需要上传的文件"); + } + + // 上传路径 + String path = storageService.getPath(file.getOriginalFilename()); + // 上传文件 + String url = storageService.upload(file.getBytes(), path); + + SysFileUploadVO vo = new SysFileUploadVO(); + vo.setUrl(url); + vo.setName(file.getOriginalFilename()); + + return vo; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysLogLoginController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysLogLoginController.java new file mode 100644 index 0000000..015a5c7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysLogLoginController.java @@ -0,0 +1,50 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.query.SysLogLoginQuery; +import com.bdzl.system.service.SysLogLoginService; +import com.bdzl.system.vo.SysLogLoginVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/log/login") +@Tag(name = "登录日志") +@AllArgsConstructor +public class SysLogLoginController { + private final SysLogLoginService sysLogLoginService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:log:login')") + public Result> page(@ParameterObject @Valid SysLogLoginQuery query) { + PageResult page = sysLogLoginService.page(query); + + return Result.ok(page); + } + + @GetMapping("export") + @Operation(summary = "导出excel") + @OperateLog(type = OperateTypeEnum.EXPORT) + @PreAuthorize("hasAuthority('sys:log:login')") + public void export() { + sysLogLoginService.export(); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysLogOperateController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysLogOperateController.java new file mode 100644 index 0000000..69f626e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysLogOperateController.java @@ -0,0 +1,39 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.system.query.SysLogOperateQuery; +import com.bdzl.system.service.SysLogOperateService; +import com.bdzl.system.vo.SysLogOperateVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/log/operate") +@Tag(name = "操作日志") +@AllArgsConstructor +public class SysLogOperateController { + private final SysLogOperateService sysLogOperateService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:operate:all')") + public Result> page(@ParameterObject @Valid SysLogOperateQuery query) { + PageResult page = sysLogOperateService.page(query); + + return Result.ok(page); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMailConfigController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMailConfigController.java new file mode 100644 index 0000000..5269818 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMailConfigController.java @@ -0,0 +1,146 @@ +package com.bdzl.system.controller; + +import cn.hutool.core.util.StrUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.email.config.EmailConfig; +import com.bdzl.email.param.EmailAliyunBatchSendParam; +import com.bdzl.email.param.EmailAliyunSendParam; +import com.bdzl.email.param.EmailLocalSendParam; +import com.bdzl.email.service.EmailService; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.convert.SysMailConfigConvert; +import com.bdzl.system.entity.SysMailConfigEntity; +import com.bdzl.system.enums.MailFormatEnum; +import com.bdzl.system.enums.MailPlatformEnum; +import com.bdzl.system.query.SysMailConfigQuery; +import com.bdzl.system.service.SysMailConfigService; +import com.bdzl.system.vo.SysMailConfigVO; +import com.bdzl.system.vo.SysMailSendVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 邮件配置 + * + * @author 阿沐 babamu@126.com + */ +@RestController +@RequestMapping("sys/mail/config") +@Tag(name = "邮件配置") +@AllArgsConstructor +public class SysMailConfigController { + private final SysMailConfigService sysMailConfigService; + private final EmailService emailService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:mail:config')") + public Result> page(@ParameterObject @Valid SysMailConfigQuery query) { + PageResult page = sysMailConfigService.page(query); + + return Result.ok(page); + } + + @GetMapping("list") + @Operation(summary = "列表") + public Result> list(Integer platform) { + List list = sysMailConfigService.list(platform); + + return Result.ok(list); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:mail:config')") + public Result get(@PathVariable("id") Long id) { + SysMailConfigEntity entity = sysMailConfigService.getById(id); + + return Result.ok(SysMailConfigConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('sys:mail:config')") + public Result save(@RequestBody SysMailConfigVO vo) { + sysMailConfigService.save(vo); + + return Result.ok(); + } + + @PostMapping("send") + @Operation(summary = "发送邮件") + @OperateLog(type = OperateTypeEnum.OTHER) + public Result send(@RequestBody SysMailSendVO vo) { + SysMailConfigEntity entity = sysMailConfigService.getById(vo.getId()); + EmailConfig config = SysMailConfigConvert.INSTANCE.convert2(entity); + + // 发送本地邮件 + if (vo.getPlatform() == MailPlatformEnum.LOCAL.getValue()) { + EmailLocalSendParam local = new EmailLocalSendParam(); + local.setTos(vo.getMailTos()); + local.setSubject(vo.getSubject()); + local.setContent(vo.getContent()); + local.setHtml(StrUtil.equalsIgnoreCase(vo.getMailFormat(), MailFormatEnum.HTML.name())); + boolean flag = emailService.sendLocal(local, config); + + return flag ? Result.ok() : Result.error("发送失败"); + } + + + // 发送阿里云模板邮件 + if (vo.getPlatform() == MailPlatformEnum.ALIYUN.getValue() + && StrUtil.equalsIgnoreCase(vo.getMailFormat(), MailFormatEnum.TEMPLATE.name())) { + EmailAliyunBatchSendParam aliyun = new EmailAliyunBatchSendParam(); + aliyun.setFrom(vo.getMailFrom()); + aliyun.setReceiversName(vo.getReceiversName()); + aliyun.setTagName(vo.getTagName()); + aliyun.setTemplateName(vo.getTemplateName()); + boolean flag = emailService.batchSendAliyun(aliyun, config); + + return flag ? Result.ok() : Result.error("发送失败"); + } + + // 发送阿里云邮件 + if (vo.getPlatform() == MailPlatformEnum.ALIYUN.getValue()) { + EmailAliyunSendParam aliyun = new EmailAliyunSendParam(); + aliyun.setFrom(vo.getMailFrom()); + aliyun.setFormAlias(vo.getFormAlias()); + aliyun.setTos(vo.getMailTos()); + aliyun.setSubject(vo.getSubject()); + aliyun.setContent(vo.getContent()); + aliyun.setHtml(StrUtil.equalsIgnoreCase(vo.getMailFormat(), MailFormatEnum.HTML.name())); + boolean flag = emailService.sendAliyun(aliyun, config); + + return flag ? Result.ok() : Result.error("发送失败"); + } + + return Result.error("不支持的邮件平台或邮件格式"); + } + + @PutMapping + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('sys:mail:config')") + public Result update(@RequestBody @Valid SysMailConfigVO vo) { + sysMailConfigService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('sys:mail:config')") + public Result delete(@RequestBody List idList) { + sysMailConfigService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMailLogController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMailLogController.java new file mode 100644 index 0000000..120d90c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMailLogController.java @@ -0,0 +1,58 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.system.convert.SysMailLogConvert; +import com.bdzl.system.entity.SysMailLogEntity; +import com.bdzl.system.query.SysMailLogQuery; +import com.bdzl.system.service.SysMailLogService; +import com.bdzl.system.vo.SysMailLogVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +@RestController +@RequestMapping("sys/mail/log") +@Tag(name = "邮件日志") +@AllArgsConstructor +public class SysMailLogController { + private final SysMailLogService sysMailLogService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:mail:log')") + public Result> page(@ParameterObject @Valid SysMailLogQuery query) { + PageResult page = sysMailLogService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:mail:log')") + public Result get(@PathVariable("id") Long id) { + SysMailLogEntity entity = sysMailLogService.getById(id); + + return Result.ok(SysMailLogConvert.INSTANCE.convert(entity)); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('sys:mail:log')") + public Result delete(@RequestBody List idList) { + sysMailLogService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMenuController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMenuController.java new file mode 100644 index 0000000..d620bdd --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysMenuController.java @@ -0,0 +1,116 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.convert.SysMenuConvert; +import com.bdzl.system.entity.SysMenuEntity; +import com.bdzl.system.enums.MenuTypeEnum; +import com.bdzl.system.service.SysMenuService; +import com.bdzl.system.vo.SysMenuVO; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Set; + +/** + * 菜单管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/menu") +@Tag(name = "菜单管理") +@AllArgsConstructor +public class SysMenuController { + private final SysMenuService sysMenuService; + + @GetMapping("nav") + @Operation(summary = "菜单导航") + public Result> nav() { + UserDetail user = SecurityUser.getUser(); + List list = sysMenuService.getUserMenuList(user, MenuTypeEnum.MENU.getValue()); + + return Result.ok(list); + } + + @GetMapping("authority") + @Operation(summary = "用户权限标识") + public Result> authority() { + UserDetail user = SecurityUser.getUser(); + Set set = sysMenuService.getUserAuthority(user); + + return Result.ok(set); + } + + @GetMapping("list") + @Operation(summary = "菜单列表") + @Parameter(name = "type", description = "菜单类型 0:菜单 1:按钮 2:接口 null:全部") + @PreAuthorize("hasAuthority('sys:menu:list')") + public Result> list(Integer type) { + List list = sysMenuService.getMenuList(type); + + return Result.ok(list); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:menu:info')") + public Result get(@PathVariable("id") Long id) { + SysMenuEntity entity = sysMenuService.getById(id); + SysMenuVO vo = SysMenuConvert.INSTANCE.convert(entity); + + // 获取上级菜单名称 + if (entity.getPid() != null) { + SysMenuEntity parentEntity = sysMenuService.getById(entity.getPid()); + vo.setParentName(parentEntity.getName()); + } + + return Result.ok(vo); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:menu:save')") + public Result save(@RequestBody @Valid SysMenuVO vo) { + sysMenuService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:menu:update')") + public Result update(@RequestBody @Valid SysMenuVO vo) { + sysMenuService.update(vo); + + return Result.ok(); + } + + @DeleteMapping("{id}") + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:menu:delete')") + public Result delete(@PathVariable("id") Long id) { + // 判断是否有子菜单或按钮 + Long count = sysMenuService.getSubMenuCount(id); + if (count > 0) { + return Result.error("请先删除子菜单"); + } + + sysMenuService.delete(id); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysOrgController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysOrgController.java new file mode 100644 index 0000000..3af450c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysOrgController.java @@ -0,0 +1,95 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.convert.SysOrgConvert; +import com.bdzl.system.entity.SysOrgEntity; +import com.bdzl.system.service.SysOrgService; +import com.bdzl.system.vo.SysOrgVO; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 机构管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/org") +@Tag(name = "机构管理") +@AllArgsConstructor +public class SysOrgController { + private final SysOrgService sysOrgService; + + @GetMapping("list") + @Operation(summary = "列表") + @PreAuthorize("hasAuthority('sys:org:list')") + public Result> list() { + List list = sysOrgService.getList(); + + return Result.ok(list); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:org:info')") + public Result get(@PathVariable("id") Long id) { + SysOrgEntity entity = sysOrgService.getById(id); + SysOrgVO vo = SysOrgConvert.INSTANCE.convert(entity); + + // 获取上级机构名称 + if (entity.getPid() != null) { + SysOrgEntity parentEntity = sysOrgService.getById(entity.getPid()); + vo.setParentName(parentEntity.getName()); + } + + return Result.ok(vo); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:org:save')") + public Result save(@RequestBody @Valid SysOrgVO vo) { + sysOrgService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:org:update')") + public Result update(@RequestBody @Valid SysOrgVO vo) { + sysOrgService.update(vo); + + return Result.ok(); + } + + @DeleteMapping("{id}") + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:org:delete')") + public Result delete(@PathVariable("id") Long id) { + sysOrgService.delete(id); + + return Result.ok(); + } + + @PostMapping("nameList") + @Operation(summary = "名称列表") + public Result> nameList(@RequestBody List idList) { + List list = sysOrgService.getNameList(idList); + + return Result.ok(list); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysParamsController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysParamsController.java new file mode 100644 index 0000000..67179b2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysParamsController.java @@ -0,0 +1,82 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.convert.SysParamsConvert; +import com.bdzl.system.entity.SysParamsEntity; +import com.bdzl.system.query.SysParamsQuery; +import com.bdzl.system.service.SysParamsService; +import com.bdzl.system.vo.SysParamsVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/params") +@Tag(name = "参数管理") +@AllArgsConstructor +public class SysParamsController { + private final SysParamsService sysParamsService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:params:all')") + public Result> page(@ParameterObject @Valid SysParamsQuery query) { + PageResult page = sysParamsService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:params:all')") + public Result get(@PathVariable("id") Long id) { + SysParamsEntity entity = sysParamsService.getById(id); + + return Result.ok(SysParamsConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:params:all')") + public Result save(@RequestBody SysParamsVO vo) { + sysParamsService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:params:all')") + public Result update(@RequestBody @Valid SysParamsVO vo) { + sysParamsService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:params:all')") + public Result delete(@RequestBody List idList) { + sysParamsService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysPostController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysPostController.java new file mode 100644 index 0000000..76e1760 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysPostController.java @@ -0,0 +1,99 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.system.convert.SysPostConvert; +import com.bdzl.system.entity.SysPostEntity; +import com.bdzl.system.query.SysPostQuery; +import com.bdzl.system.service.SysPostService; +import com.bdzl.system.vo.SysPostVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * 岗位管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/post") +@Tag(name = "岗位管理") +@AllArgsConstructor +public class SysPostController { + private final SysPostService sysPostService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:post:page')") + public Result> page(@ParameterObject @Valid SysPostQuery query) { + PageResult page = sysPostService.page(query); + + return Result.ok(page); + } + + @GetMapping("list") + @Operation(summary = "列表") + public Result> list() { + List list = sysPostService.getList(); + + return Result.ok(list); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:post:info')") + public Result get(@PathVariable("id") Long id) { + SysPostEntity entity = sysPostService.getById(id); + + return Result.ok(SysPostConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:post:save')") + public Result save(@RequestBody SysPostVO vo) { + sysPostService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:post:update')") + public Result update(@RequestBody @Valid SysPostVO vo) { + sysPostService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:post:delete')") + public Result delete(@RequestBody List idList) { + sysPostService.delete(idList); + + return Result.ok(); + } + + @PostMapping("nameList") + @Operation(summary = "名称列表") + public Result> nameList(@RequestBody List idList) { + List list = sysPostService.getNameList(idList); + + return Result.ok(list); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysRoleController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysRoleController.java new file mode 100644 index 0000000..60cc132 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysRoleController.java @@ -0,0 +1,184 @@ +package com.bdzl.system.controller; + +import com.bdzl.system.service.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.convert.SysRoleConvert; +import com.bdzl.system.entity.SysRoleEntity; +import com.bdzl.system.query.SysRoleQuery; +import com.bdzl.system.query.SysRoleUserQuery; +import com.bdzl.system.vo.SysMenuVO; +import com.bdzl.system.vo.SysRoleDataScopeVO; +import com.bdzl.system.vo.SysRoleVO; +import com.bdzl.system.vo.SysUserVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 角色管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/role") +@Tag(name = "角色管理") +@AllArgsConstructor +public class SysRoleController { + private final SysRoleService sysRoleService; + private final SysUserService sysUserService; + private final SysRoleMenuService sysRoleMenuService; + private final SysRoleDataScopeService sysRoleDataScopeService; + private final SysMenuService sysMenuService; + private final SysUserRoleService sysUserRoleService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:role:page')") + public Result> page(@ParameterObject @Valid SysRoleQuery query) { + PageResult page = sysRoleService.page(query); + + return Result.ok(page); + } + + @GetMapping("list") + @Operation(summary = "列表") + @PreAuthorize("hasAuthority('sys:role:list')") + public Result> list() { + List list = sysRoleService.getList(new SysRoleQuery()); + + return Result.ok(list); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:role:info')") + public Result get(@PathVariable("id") Long id) { + SysRoleEntity entity = sysRoleService.getById(id); + + // 转换对象 + SysRoleVO role = SysRoleConvert.INSTANCE.convert(entity); + + // 查询角色对应的菜单 + List menuIdList = sysRoleMenuService.getMenuIdList(id); + role.setMenuIdList(menuIdList); + + // 查询角色对应的数据权限 + List orgIdList = sysRoleDataScopeService.getOrgIdList(id); + role.setOrgIdList(orgIdList); + + return Result.ok(role); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:role:save')") + public Result save(@RequestBody @Valid SysRoleVO vo) { + sysRoleService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:role:update')") + public Result update(@RequestBody @Valid SysRoleVO vo) { + sysRoleService.update(vo); + + return Result.ok(); + } + + @PutMapping("data-scope") + @Operation(summary = "数据权限") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:role:update')") + public Result dataScope(@RequestBody @Valid SysRoleDataScopeVO vo) { + sysRoleService.dataScope(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:role:delete')") + public Result delete(@RequestBody List idList) { + sysRoleService.delete(idList); + + return Result.ok(); + } + + @GetMapping("menu") + @Operation(summary = "角色菜单") + @PreAuthorize("hasAuthority('sys:role:menu')") + public Result> menu() { + UserDetail user = SecurityUser.getUser(); + List list = sysMenuService.getUserMenuList(user, null); + + return Result.ok(list); + } + + @GetMapping("user/page") + @Operation(summary = "角色用户-分页") + @PreAuthorize("hasAuthority('sys:role:update')") + public Result> userPage(@Valid SysRoleUserQuery query) { + PageResult page = sysUserService.roleUserPage(query); + + return Result.ok(page); + } + + @DeleteMapping("user/{roleId}") + @Operation(summary = "删除角色用户") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:role:update')") + public Result userDelete(@PathVariable("roleId") Long roleId, @RequestBody List userIdList) { + sysUserRoleService.deleteByUserIdList(roleId, userIdList); + + return Result.ok(); + } + + @PostMapping("user/{roleId}") + @Operation(summary = "分配角色给用户列表") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:role:update')") + public Result userSave(@PathVariable("roleId") Long roleId, @RequestBody List userIdList) { + if(userIdList.isEmpty()) { + return Result.error("UserId is empty!"); + } + //查询数据库该角色对应的用户列表 + List existsUserIdList = sysUserRoleService.getExistsUserIdList(roleId); + + //取出需要新增的用户列表 + List addUserIdList = userIdList.stream() + .filter(userId -> !existsUserIdList.contains(userId)) + .collect(Collectors.toList()); + + if(addUserIdList.isEmpty()) { + return Result.error("UserId existed!"); + } + sysUserRoleService.saveUserList(roleId, addUserIdList); + + return Result.ok(); + } + + @PostMapping("nameList") + @Operation(summary = "名称列表") + public Result> nameList(@RequestBody List idList) { + List list = sysRoleService.getNameList(idList); + + return Result.ok(list); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysSmsConfigController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysSmsConfigController.java new file mode 100644 index 0000000..dafc2d2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysSmsConfigController.java @@ -0,0 +1,129 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.ExceptionUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.sms.SmsContext; +import com.bdzl.sms.config.SmsConfig; +import com.bdzl.sms.service.SmsService; +import com.bdzl.system.convert.SysSmsConfigConvert; +import com.bdzl.system.entity.SysSmsConfigEntity; +import com.bdzl.system.query.SysSmsConfigQuery; +import com.bdzl.system.service.SysSmsConfigService; +import com.bdzl.system.vo.SysSmsConfigVO; +import com.bdzl.system.vo.SysSmsSendVO; +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 短信配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/sms/config") +@Tag(name = "短信配置") +@AllArgsConstructor +public class SysSmsConfigController { + private final SysSmsConfigService sysSmsConfigService; + private final SmsService smsService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:sms:config')") + public Result> page(@ParameterObject @Valid SysSmsConfigQuery query) { + PageResult page = sysSmsConfigService.page(query); + + return Result.ok(page); + } + + @GetMapping("list") + @Operation(summary = "列表") + public Result> list(Integer platform) { + List list = sysSmsConfigService.list(platform); + + return Result.ok(list); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:sms:config')") + public Result get(@PathVariable("id") Long id) { + SysSmsConfigEntity entity = sysSmsConfigService.getById(id); + + return Result.ok(SysSmsConfigConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:sms:config')") + public Result save(@RequestBody SysSmsConfigVO vo) { + sysSmsConfigService.save(vo); + + return Result.ok(); + } + + @PostMapping("send") + @Operation(summary = "发送短信") + @OperateLog(type = OperateTypeEnum.OTHER) + @PreAuthorize("hasAuthority('sys:sms:config')") + public Result send(@RequestBody SysSmsSendVO vo) { + SysSmsConfigEntity entity = sysSmsConfigService.getById(vo.getId()); + SmsConfig config = SysSmsConfigConvert.INSTANCE.convert2(entity); + + // 短信参数 + Map params = new LinkedHashMap<>(); + if (StringUtils.isNotBlank(vo.getParamValue())) { + params.put(vo.getParamKey(), vo.getParamValue()); + } + + try { + // 发送短信 + new SmsContext(config).send(vo.getMobile(), params); + + // 保存日志 + smsService.saveLog(config, vo.getMobile(), params, null); + + return Result.ok(); + } catch (Exception e) { + // 保存日志 + smsService.saveLog(config, vo.getMobile(), params, e); + + return Result.error(ExceptionUtils.getExceptionMessage(e)); + } + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:sms:config')") + public Result update(@RequestBody @Valid SysSmsConfigVO vo) { + sysSmsConfigService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:sms:config')") + public Result delete(@RequestBody List idList) { + sysSmsConfigService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysSmsLogController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysSmsLogController.java new file mode 100644 index 0000000..89fecb1 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysSmsLogController.java @@ -0,0 +1,52 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.system.convert.SysSmsLogConvert; +import com.bdzl.system.entity.SysSmsLogEntity; +import com.bdzl.system.query.SysSmsLogQuery; +import com.bdzl.system.service.SysSmsLogService; +import com.bdzl.system.vo.SysSmsLogVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/sms/log") +@Tag(name = "短信日志") +@AllArgsConstructor +public class SysSmsLogController { + private final SysSmsLogService sysSmsLogService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:sms:log')") + public Result> page(@ParameterObject @Valid SysSmsLogQuery query) { + PageResult page = sysSmsLogService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:sms:log')") + public Result get(@PathVariable("id") Long id) { + SysSmsLogEntity entity = sysSmsLogService.getById(id); + + return Result.ok(SysSmsLogConvert.INSTANCE.convert(entity)); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysThirdLoginConfigController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysThirdLoginConfigController.java new file mode 100644 index 0000000..789c0f0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysThirdLoginConfigController.java @@ -0,0 +1,77 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.query.Query; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.system.convert.SysThirdLoginConfigConvert; +import com.bdzl.system.entity.SysThirdLoginConfigEntity; +import com.bdzl.system.service.SysThirdLoginConfigService; +import com.bdzl.system.vo.SysThirdLoginConfigVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/third/config") +@Tag(name = "第三方登录配置") +@AllArgsConstructor +public class SysThirdLoginConfigController { + private final SysThirdLoginConfigService sysThirdLoginConfigService; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:third:config')") + public Result> page(@ParameterObject @Valid Query query) { + PageResult page = sysThirdLoginConfigService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:third:config')") + public Result get(@PathVariable("id") Long id) { + SysThirdLoginConfigEntity entity = sysThirdLoginConfigService.getById(id); + + return Result.ok(SysThirdLoginConfigConvert.INSTANCE.convert(entity)); + } + + @PostMapping + @Operation(summary = "保存") + @PreAuthorize("hasAuthority('sys:third:config')") + public Result save(@RequestBody SysThirdLoginConfigVO vo) { + sysThirdLoginConfigService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @PreAuthorize("hasAuthority('sys:third:config')") + public Result update(@RequestBody @Valid SysThirdLoginConfigVO vo) { + sysThirdLoginConfigService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @PreAuthorize("hasAuthority('sys:third:config')") + public Result delete(@RequestBody List idList) { + sysThirdLoginConfigService.delete(idList); + + return Result.ok(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysThirdLoginController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysThirdLoginController.java new file mode 100644 index 0000000..0dbf9e1 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysThirdLoginController.java @@ -0,0 +1,96 @@ +package com.bdzl.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.system.service.SysThirdLoginConfigService; +import com.bdzl.system.service.SysThirdLoginService; +import com.bdzl.system.vo.SysThirdCallbackVO; +import com.bdzl.system.vo.SysThirdLoginVO; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 第三方账号登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/third") +@Tag(name = "第三方账号") +@AllArgsConstructor +public class SysThirdLoginController { + private final SysThirdLoginService sysThirdLoginService; + private final SysThirdLoginConfigService sysThirdLoginConfigService; + + @GetMapping("list") + @Operation(summary = "列表") + public Result> list() { + List list = sysThirdLoginService.listByUserId(SecurityUser.getUserId()); + + return Result.ok(list); + } + + @RequestMapping("render/{source}") + public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException { + AuthRequest authRequest = sysThirdLoginConfigService.getAuthRequest(source); + String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); + response.sendRedirect(authorizeUrl); + } + + @RequestMapping("/callback/{source}") + public ModelAndView login(@PathVariable("source") String source, AuthCallback callback) { + Map map = new HashMap<>(); + map.put("openType", source); + map.put("state", callback.getState()); + map.put("code", callback.getCode()); + + return new ModelAndView("third_login", map); + } + + @PostMapping("bind") + @Operation(summary = "绑定") + @OperateLog(type = OperateTypeEnum.INSERT) + public Result bind(@RequestBody SysThirdCallbackVO vo) { + AuthRequest authRequest = sysThirdLoginConfigService.getAuthRequest(vo.getOpenType()); + AuthCallback callback = AuthCallback.builder().code(vo.getCode()).state(vo.getState()).build(); + + // 根据code,获取用户信息 + AuthResponse response = authRequest.login(callback); + + // 判断是否成功 + if (!response.ok()) { + throw new RuntimeException("第三方登录失败"); + } + + // 绑定用户信息 + sysThirdLoginService.bind(SecurityUser.getUserId(), vo.getOpenType(), response.getData()); + + return Result.ok(); + } + + @PutMapping("unbind/{openType}") + @Operation(summary = "解绑") + @OperateLog(type = OperateTypeEnum.UPDATE) + public Result unBind(@PathVariable("openType") String openType) { + sysThirdLoginService.unBind(SecurityUser.getUserId(), openType); + + return Result.ok(); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/controller/SysUserController.java b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysUserController.java new file mode 100644 index 0000000..5d6f51d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/controller/SysUserController.java @@ -0,0 +1,208 @@ +package com.bdzl.system.controller; + +import cn.hutool.core.util.StrUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.common.utils.Result; +import com.bdzl.framework.operatelog.annotations.OperateLog; +import com.bdzl.framework.operatelog.enums.OperateTypeEnum; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.convert.SysUserConvert; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.query.SysUserQuery; +import com.bdzl.system.service.SysPostService; +import com.bdzl.system.service.SysUserPostService; +import com.bdzl.system.service.SysUserRoleService; +import com.bdzl.system.service.SysUserService; +import com.bdzl.system.vo.SysUserAvatarVO; +import com.bdzl.system.vo.SysUserBaseVO; +import com.bdzl.system.vo.SysUserPasswordVO; +import com.bdzl.system.vo.SysUserVO; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + + +/** + * 用户管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@RestController +@RequestMapping("sys/user") +@AllArgsConstructor +@Tag(name = "用户管理") +public class SysUserController { + private final SysUserService sysUserService; + private final SysUserRoleService sysUserRoleService; + private final SysUserPostService sysUserPostService; + private final SysPostService sysPostService; + private final PasswordEncoder passwordEncoder; + + @GetMapping("page") + @Operation(summary = "分页") + @PreAuthorize("hasAuthority('sys:user:page')") + public Result> page(@ParameterObject @Valid SysUserQuery query) { + PageResult page = sysUserService.page(query); + + return Result.ok(page); + } + + @GetMapping("{id}") + @Operation(summary = "信息") + @PreAuthorize("hasAuthority('sys:user:info')") + public Result get(@PathVariable("id") Long id) { + SysUserEntity entity = sysUserService.getById(id); + + SysUserVO vo = SysUserConvert.INSTANCE.convert(entity); + + // 用户角色列表 + List roleIdList = sysUserRoleService.getRoleIdList(id); + vo.setRoleIdList(roleIdList); + + // 用户岗位列表 + List postIdList = sysUserPostService.getPostIdList(id); + vo.setPostIdList(postIdList); + + return Result.ok(vo); + } + + @GetMapping("info") + @Operation(summary = "登录用户") + public Result info() { + SysUserVO user = SysUserConvert.INSTANCE.convert(SecurityUser.getUser()); + + // 用户岗位列表 + List postIdList = sysUserPostService.getPostIdList(user.getId()); + user.setPostIdList(postIdList); + + // 用户岗位名称列表 + List postNameList = sysPostService.getNameList(postIdList); + user.setPostNameList(postNameList); + + return Result.ok(user); + } + + @PutMapping("info") + @Operation(summary = "修改登录用户信息") + @OperateLog(type = OperateTypeEnum.UPDATE) + public Result loginInfo(@RequestBody @Valid SysUserBaseVO vo) { + sysUserService.updateLoginInfo(vo); + + return Result.ok(); + } + + @PutMapping("avatar") + @Operation(summary = "修改登录用户头像") + @OperateLog(type = OperateTypeEnum.UPDATE) + public Result avatar(@RequestBody SysUserAvatarVO avatar) { + sysUserService.updateAvatar(avatar); + + return Result.ok(); + } + + @PutMapping("password") + @Operation(summary = "修改密码") + @OperateLog(type = OperateTypeEnum.UPDATE) + public Result password(@RequestBody @Valid SysUserPasswordVO vo) { + // 原密码不正确 + UserDetail user = SecurityUser.getUser(); + if (!passwordEncoder.matches(vo.getPassword(), user.getPassword())) { + return Result.error("原密码不正确"); + } + + // 修改密码 + sysUserService.updatePassword(user.getId(), passwordEncoder.encode(vo.getNewPassword())); + + return Result.ok(); + } + + @PostMapping + @Operation(summary = "保存") + @OperateLog(type = OperateTypeEnum.INSERT) + @PreAuthorize("hasAuthority('sys:user:save')") + public Result save(@RequestBody @Valid SysUserVO vo) { + // 新增密码不能为空 + if (StrUtil.isBlank(vo.getPassword())) { + return Result.error("密码不能为空"); + } + + // 密码加密 + vo.setPassword(passwordEncoder.encode(vo.getPassword())); + + // 保存 + sysUserService.save(vo); + + return Result.ok(); + } + + @PutMapping + @Operation(summary = "修改") + @OperateLog(type = OperateTypeEnum.UPDATE) + @PreAuthorize("hasAuthority('sys:user:update')") + public Result update(@RequestBody @Valid SysUserVO vo) { + // 如果密码不为空,则进行加密处理 + if (StrUtil.isBlank(vo.getPassword())) { + vo.setPassword(null); + } else { + vo.setPassword(passwordEncoder.encode(vo.getPassword())); + } + + sysUserService.update(vo); + + return Result.ok(); + } + + @DeleteMapping + @Operation(summary = "删除") + @OperateLog(type = OperateTypeEnum.DELETE) + @PreAuthorize("hasAuthority('sys:user:delete')") + public Result delete(@RequestBody List idList) { + Long userId = SecurityUser.getUserId(); + if (idList.contains(userId)) { + return Result.error("不能删除当前登录用户"); + } + + sysUserService.delete(idList); + + return Result.ok(); + } + + @PostMapping("nameList") + @Operation(summary = "用户姓名列表") + public Result> nameList(@RequestBody List idList) { + List list = sysUserService.getRealNameList(idList); + + return Result.ok(list); + } + + @PostMapping("import") + @Operation(summary = "导入用户") + @OperateLog(type = OperateTypeEnum.IMPORT) + @PreAuthorize("hasAuthority('sys:user:import')") + public Result importExcel(@RequestParam("file") MultipartFile file) { + if (file.isEmpty()) { + return Result.error("请选择需要上传的文件"); + } + sysUserService.importByExcel(file, passwordEncoder.encode("123456")); + + return Result.ok(); + } + + @GetMapping("export") + @Operation(summary = "导出用户") + @OperateLog(type = OperateTypeEnum.EXPORT) + @PreAuthorize("hasAuthority('sys:user:export')") + public void export() { + sysUserService.export(); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysAttachmentConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysAttachmentConvert.java new file mode 100644 index 0000000..748636a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysAttachmentConvert.java @@ -0,0 +1,26 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysAttachmentEntity; +import com.bdzl.system.vo.SysAttachmentVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysAttachmentConvert { + SysAttachmentConvert INSTANCE = Mappers.getMapper(SysAttachmentConvert.class); + + SysAttachmentEntity convert(SysAttachmentVO vo); + + SysAttachmentVO convert(SysAttachmentEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysDictDataConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysDictDataConvert.java new file mode 100644 index 0000000..8a3ee6c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysDictDataConvert.java @@ -0,0 +1,20 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysDictDataEntity; +import com.bdzl.system.vo.SysDictDataVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SysDictDataConvert { + SysDictDataConvert INSTANCE = Mappers.getMapper(SysDictDataConvert.class); + + SysDictDataVO convert(SysDictDataEntity entity); + + SysDictDataEntity convert(SysDictDataVO vo); + + List convertList(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysDictTypeConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysDictTypeConvert.java new file mode 100644 index 0000000..7df9595 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysDictTypeConvert.java @@ -0,0 +1,20 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysDictTypeEntity; +import com.bdzl.system.vo.SysDictTypeVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SysDictTypeConvert { + SysDictTypeConvert INSTANCE = Mappers.getMapper(SysDictTypeConvert.class); + + SysDictTypeVO convert(SysDictTypeEntity entity); + + SysDictTypeEntity convert(SysDictTypeVO vo); + + List convertList(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysLogLoginConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysLogLoginConvert.java new file mode 100644 index 0000000..c039b41 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysLogLoginConvert.java @@ -0,0 +1,26 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysLogLoginEntity; +import com.bdzl.system.vo.SysLogLoginVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysLogLoginConvert { + SysLogLoginConvert INSTANCE = Mappers.getMapper(SysLogLoginConvert.class); + + SysLogLoginEntity convert(SysLogLoginVO vo); + + SysLogLoginVO convert(SysLogLoginEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysLogOperateConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysLogOperateConvert.java new file mode 100644 index 0000000..95c9633 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysLogOperateConvert.java @@ -0,0 +1,26 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysLogOperateEntity; +import com.bdzl.system.vo.SysLogOperateVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysLogOperateConvert { + SysLogOperateConvert INSTANCE = Mappers.getMapper(SysLogOperateConvert.class); + + SysLogOperateEntity convert(SysLogOperateVO vo); + + SysLogOperateVO convert(SysLogOperateEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMailConfigConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMailConfigConvert.java new file mode 100644 index 0000000..f9451c0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMailConfigConvert.java @@ -0,0 +1,30 @@ +package com.bdzl.system.convert; + +import com.bdzl.email.config.EmailConfig; +import com.bdzl.system.entity.SysMailConfigEntity; +import com.bdzl.system.vo.SysMailConfigVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 邮件配置 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysMailConfigConvert { + SysMailConfigConvert INSTANCE = Mappers.getMapper(SysMailConfigConvert.class); + + SysMailConfigEntity convert(SysMailConfigVO vo); + + SysMailConfigVO convert(SysMailConfigEntity entity); + + List convertList(List list); + + EmailConfig convert2(SysMailConfigEntity entity); + + List convertList2(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMailLogConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMailLogConvert.java new file mode 100644 index 0000000..c775250 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMailLogConvert.java @@ -0,0 +1,25 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysMailLogEntity; +import com.bdzl.system.vo.SysMailLogVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysMailLogConvert { + SysMailLogConvert INSTANCE = Mappers.getMapper(SysMailLogConvert.class); + + SysMailLogEntity convert(SysMailLogVO vo); + + SysMailLogVO convert(SysMailLogEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMenuConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMenuConvert.java new file mode 100644 index 0000000..52fa1ca --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysMenuConvert.java @@ -0,0 +1,21 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysMenuEntity; +import com.bdzl.system.vo.SysMenuVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + + +@Mapper +public interface SysMenuConvert { + SysMenuConvert INSTANCE = Mappers.getMapper(SysMenuConvert.class); + + SysMenuEntity convert(SysMenuVO vo); + + SysMenuVO convert(SysMenuEntity entity); + + List convertList(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysOrgConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysOrgConvert.java new file mode 100644 index 0000000..e01e0e2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysOrgConvert.java @@ -0,0 +1,21 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysOrgEntity; +import com.bdzl.system.vo.SysOrgVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + + +@Mapper +public interface SysOrgConvert { + SysOrgConvert INSTANCE = Mappers.getMapper(SysOrgConvert.class); + + SysOrgEntity convert(SysOrgVO vo); + + SysOrgVO convert(SysOrgEntity entity); + + List convertList(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysParamsConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysParamsConvert.java new file mode 100644 index 0000000..c5c2439 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysParamsConvert.java @@ -0,0 +1,26 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysParamsEntity; +import com.bdzl.system.vo.SysParamsVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysParamsConvert { + SysParamsConvert INSTANCE = Mappers.getMapper(SysParamsConvert.class); + + SysParamsEntity convert(SysParamsVO vo); + + SysParamsVO convert(SysParamsEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysPostConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysPostConvert.java new file mode 100644 index 0000000..df87395 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysPostConvert.java @@ -0,0 +1,21 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysPostEntity; +import com.bdzl.system.vo.SysPostVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + + +@Mapper +public interface SysPostConvert { + SysPostConvert INSTANCE = Mappers.getMapper(SysPostConvert.class); + + SysPostVO convert(SysPostEntity entity); + + SysPostEntity convert(SysPostVO vo); + + List convertList(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysRoleConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysRoleConvert.java new file mode 100644 index 0000000..4812a17 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysRoleConvert.java @@ -0,0 +1,20 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysRoleEntity; +import com.bdzl.system.vo.SysRoleVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SysRoleConvert { + SysRoleConvert INSTANCE = Mappers.getMapper(SysRoleConvert.class); + + SysRoleVO convert(SysRoleEntity entity); + + SysRoleEntity convert(SysRoleVO vo); + + List convertList(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysSmsConfigConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysSmsConfigConvert.java new file mode 100644 index 0000000..02bf97d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysSmsConfigConvert.java @@ -0,0 +1,30 @@ +package com.bdzl.system.convert; + +import com.bdzl.sms.config.SmsConfig; +import com.bdzl.system.entity.SysSmsConfigEntity; +import com.bdzl.system.vo.SysSmsConfigVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 短信配置 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysSmsConfigConvert { + SysSmsConfigConvert INSTANCE = Mappers.getMapper(SysSmsConfigConvert.class); + + SysSmsConfigEntity convert(SysSmsConfigVO vo); + + SysSmsConfigVO convert(SysSmsConfigEntity entity); + + List convertList(List list); + + SmsConfig convert2(SysSmsConfigEntity entity); + + List convertList2(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysSmsLogConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysSmsLogConvert.java new file mode 100644 index 0000000..2d562f3 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysSmsLogConvert.java @@ -0,0 +1,23 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysSmsLogEntity; +import com.bdzl.system.vo.SysSmsLogVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysSmsLogConvert { + SysSmsLogConvert INSTANCE = Mappers.getMapper(SysSmsLogConvert.class); + + SysSmsLogVO convert(SysSmsLogEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysThirdLoginConfigConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysThirdLoginConfigConvert.java new file mode 100644 index 0000000..0ac5b31 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysThirdLoginConfigConvert.java @@ -0,0 +1,26 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysThirdLoginConfigEntity; +import com.bdzl.system.vo.SysThirdLoginConfigVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysThirdLoginConfigConvert { + SysThirdLoginConfigConvert INSTANCE = Mappers.getMapper(SysThirdLoginConfigConvert.class); + + SysThirdLoginConfigEntity convert(SysThirdLoginConfigVO vo); + + SysThirdLoginConfigVO convert(SysThirdLoginConfigEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysThirdLoginConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysThirdLoginConvert.java new file mode 100644 index 0000000..90bf40b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysThirdLoginConvert.java @@ -0,0 +1,26 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysThirdLoginEntity; +import com.bdzl.system.vo.SysThirdLoginVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysThirdLoginConvert { + SysThirdLoginConvert INSTANCE = Mappers.getMapper(SysThirdLoginConvert.class); + + SysThirdLoginEntity convert(SysThirdLoginVO vo); + + SysThirdLoginVO convert(SysThirdLoginEntity entity); + + List convertList(List list); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysUserConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysUserConvert.java new file mode 100644 index 0000000..711596d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysUserConvert.java @@ -0,0 +1,34 @@ +package com.bdzl.system.convert; + +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.vo.SysUserBaseVO; +import com.bdzl.system.vo.SysUserExcelVO; +import com.bdzl.system.vo.SysUserVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + + +@Mapper +public interface SysUserConvert { + SysUserConvert INSTANCE = Mappers.getMapper(SysUserConvert.class); + + SysUserVO convert(SysUserEntity entity); + + SysUserEntity convert(SysUserVO vo); + + SysUserEntity convert(SysUserBaseVO vo); + + SysUserVO convert(UserDetail userDetail); + + UserDetail convertDetail(SysUserEntity entity); + + List convertList(List list); + + List convert2List(List list); + + List convertListEntity(List list); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/convert/SysUserTokenConvert.java b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysUserTokenConvert.java new file mode 100644 index 0000000..41317ba --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/convert/SysUserTokenConvert.java @@ -0,0 +1,21 @@ +package com.bdzl.system.convert; + +import com.bdzl.system.entity.SysUserTokenEntity; +import com.bdzl.system.vo.SysUserTokenVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 用户Token + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysUserTokenConvert { + SysUserTokenConvert INSTANCE = Mappers.getMapper(SysUserTokenConvert.class); + + SysUserTokenEntity convert(SysUserTokenVO vo); + + SysUserTokenVO convert(SysUserTokenEntity entity); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysAttachmentDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysAttachmentDao.java new file mode 100644 index 0000000..c3bc7d3 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysAttachmentDao.java @@ -0,0 +1,16 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysAttachmentEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysAttachmentDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysDictDataDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysDictDataDao.java new file mode 100644 index 0000000..a845696 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysDictDataDao.java @@ -0,0 +1,23 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysDictDataEntity; +import com.bdzl.system.vo.SysDictVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 字典数据 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysDictDataDao extends BaseDao { + + @Select("${sql}") + List getListForSql(@Param("sql") String sql); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysDictTypeDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysDictTypeDao.java new file mode 100644 index 0000000..0001936 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysDictTypeDao.java @@ -0,0 +1,16 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysDictTypeEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 字典类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysDictTypeDao extends BaseDao { + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysLogLoginDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysLogLoginDao.java new file mode 100644 index 0000000..ea091e0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysLogLoginDao.java @@ -0,0 +1,16 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysLogLoginEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysLogLoginDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysLogOperateDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysLogOperateDao.java new file mode 100644 index 0000000..ce9111e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysLogOperateDao.java @@ -0,0 +1,16 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysLogOperateEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysLogOperateDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMailConfigDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMailConfigDao.java new file mode 100644 index 0000000..f91cbb0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMailConfigDao.java @@ -0,0 +1,15 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysMailConfigEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 邮件配置 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysMailConfigDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMailLogDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMailLogDao.java new file mode 100644 index 0000000..b099029 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMailLogDao.java @@ -0,0 +1,15 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysMailLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysMailLogDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMenuDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMenuDao.java new file mode 100644 index 0000000..f469b58 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysMenuDao.java @@ -0,0 +1,45 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysMenuEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 菜单管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysMenuDao extends BaseDao { + + /** + * 查询所有菜单列表 + * + * @param type 菜单类型 + */ + List getMenuList(@Param("type") Integer type); + + /** + * 查询用户菜单列表 + * + * @param userId 用户ID + * @param type 菜单类型 + */ + List getUserMenuList(@Param("userId") Long userId, @Param("type") Integer type); + + /** + * 查询用户权限列表 + * @param userId 用户ID + */ + List getUserAuthorityList(@Param("userId") Long userId); + + /** + * 查询所有权限列表 + */ + List getAuthorityList(); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysOrgDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysOrgDao.java new file mode 100644 index 0000000..ab3af4a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysOrgDao.java @@ -0,0 +1,26 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysOrgEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * 机构管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysOrgDao extends BaseDao { + + List getList(Map params); + + /** + * 获取所有机构的id、pid列表 + */ + List getIdAndPidList(); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysParamsDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysParamsDao.java new file mode 100644 index 0000000..4d889d8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysParamsDao.java @@ -0,0 +1,24 @@ +package com.bdzl.system.dao; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysParamsEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysParamsDao extends BaseDao { + + default boolean isExist(String paramKey) { + return this.exists(new QueryWrapper().eq("param_key", paramKey)); + } + + default SysParamsEntity get(String paramKey) { + return this.selectOne(new QueryWrapper().eq("param_key", paramKey)); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysPostDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysPostDao.java new file mode 100644 index 0000000..5573730 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysPostDao.java @@ -0,0 +1,15 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysPostEntity; +import org.apache.ibatis.annotations.Mapper; + +/** +* 岗位管理 +* +* @author 阿沐 babamu@126.com +*/ +@Mapper +public interface SysPostDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleDao.java new file mode 100644 index 0000000..620b0c9 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleDao.java @@ -0,0 +1,29 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysRoleEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysRoleDao extends BaseDao { + + /** + * 根据用户ID,获取用户最大的数据范围 + */ + Integer getDataScopeByUserId(@Param("userId") Long userId); + + /** + * 根据用户ID,获取用户角色编码 + */ + List geRoleCodeByUserId(@Param("userId") Long userId); + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleDataScopeDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleDataScopeDao.java new file mode 100644 index 0000000..225143a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleDataScopeDao.java @@ -0,0 +1,29 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysRoleDataScopeEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色数据权限 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysRoleDataScopeDao extends BaseDao { + + /** + * 根据角色ID,获取机构ID列表 + */ + List getOrgIdList(@Param("roleId") Long roleId); + + /** + * 获取用户的数据权限列表 + */ + List getDataScopeList(@Param("userId") Long userId); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleMenuDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleMenuDao.java new file mode 100644 index 0000000..fa7ce3f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysRoleMenuDao.java @@ -0,0 +1,23 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysRoleMenuEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色与菜单对应关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysRoleMenuDao extends BaseDao { + + /** + * 根据角色ID,获取菜单ID列表 + */ + List getMenuIdList(@Param("roleId") Long roleId); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysSmsConfigDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysSmsConfigDao.java new file mode 100644 index 0000000..0b2a030 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysSmsConfigDao.java @@ -0,0 +1,15 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysSmsConfigEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 短信配置 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysSmsConfigDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysSmsLogDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysSmsLogDao.java new file mode 100644 index 0000000..4c502f9 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysSmsLogDao.java @@ -0,0 +1,15 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysSmsLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysSmsLogDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysThirdLoginConfigDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysThirdLoginConfigDao.java new file mode 100644 index 0000000..c765968 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysThirdLoginConfigDao.java @@ -0,0 +1,16 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysThirdLoginConfigEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysThirdLoginConfigDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysThirdLoginDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysThirdLoginDao.java new file mode 100644 index 0000000..cb2af84 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysThirdLoginDao.java @@ -0,0 +1,16 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysThirdLoginEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysThirdLoginDao extends BaseDao { + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserDao.java new file mode 100644 index 0000000..1e9d8c4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserDao.java @@ -0,0 +1,34 @@ +package com.bdzl.system.dao; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysUserEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 系统用户 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysUserDao extends BaseDao { + + List getList(Map params); + + SysUserEntity getById(@Param("id") Long id); + + List getRoleUserList(Map params); + + default SysUserEntity getByUsername(String username) { + return this.selectOne(new QueryWrapper().eq("username", username)); + } + + default SysUserEntity getByMobile(String mobile) { + return this.selectOne(new QueryWrapper().eq("mobile", mobile)); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserPostDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserPostDao.java new file mode 100644 index 0000000..a03c468 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserPostDao.java @@ -0,0 +1,23 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysUserPostEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +* 用户岗位关系 +* +* @author 阿沐 babamu@126.com +*/ +@Mapper +public interface SysUserPostDao extends BaseDao { + + /** + * 岗位ID列表 + * @param userId 用户ID + */ + List getPostIdList(@Param("userId") Long userId); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserRoleDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserRoleDao.java new file mode 100644 index 0000000..6407e53 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserRoleDao.java @@ -0,0 +1,34 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysUserRoleEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户角色关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Mapper +public interface SysUserRoleDao extends BaseDao { + + /** + * 角色ID列表 + * @param userId 用户ID + * + * @return 返回角色ID列表 + */ + List getRoleIdList(@Param("userId") Long userId); + + /** + * 根据角色ID查询对应的用户ID列表 + * @param roleId 角色ID + * + * @return 返回用户ID列表 + */ + List getExistsUserIdList(@Param("roleId") Long roleId); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserTokenDao.java b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserTokenDao.java new file mode 100644 index 0000000..ad86990 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/dao/SysUserTokenDao.java @@ -0,0 +1,37 @@ +package com.bdzl.system.dao; + +import com.bdzl.framework.mybatis.dao.BaseDao; +import com.bdzl.system.entity.SysUserTokenEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户Token + * + * @author 阿沐 babamu@126.com + */ +@Mapper +public interface SysUserTokenDao extends BaseDao { + + /** + * 根据角色ID,查询在线用户 access_token 列表 + * + * @param roleId 角色ID + * @param time 当前时间 + * @return 返回 access_token 列表 + */ + List getOnlineAccessTokenListByRoleId(@Param("roleId") Long roleId, @Param("time") LocalDateTime time); + + /** + * 根据用户ID,查询在线用户 access_token 列表 + * + * @param userId 用户ID + * @param time 当前时间 + * @return 返回 access_token 列表 + */ + List getOnlineAccessTokenListByUserId(@Param("userId") Long userId, @Param("time") LocalDateTime time); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysAttachmentEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysAttachmentEntity.java new file mode 100644 index 0000000..c4d5641 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysAttachmentEntity.java @@ -0,0 +1,42 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_attachment") +public class SysAttachmentEntity extends BaseEntity { + /** + * 附件名称 + */ + private String name; + + /** + * 附件地址 + */ + private String url; + + /** + * 附件大小 + */ + private Long size; + + /** + * 存储平台 + */ + private String platform; + /** + * 租户ID + */ + private Long tenantId; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysDictDataEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysDictDataEntity.java new file mode 100644 index 0000000..9e7fd0b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysDictDataEntity.java @@ -0,0 +1,46 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 数据字典 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_dict_data") +public class SysDictDataEntity extends BaseEntity { + /** + * 字典类型ID + */ + private Long dictTypeId; + /** + * 字典标签 + */ + private String dictLabel; + /** + * 字典值 + */ + private String dictValue; + /** + * 标签样式 + */ + private String labelClass; + /** + * 备注 + */ + private String remark; + /** + * 排序 + */ + private Integer sort; + /** + * 租户ID + */ + private Long tenantId; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysDictTypeEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysDictTypeEntity.java new file mode 100644 index 0000000..724421f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysDictTypeEntity.java @@ -0,0 +1,57 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 字典类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_dict_type") +public class SysDictTypeEntity extends BaseEntity { + /** + * 字典类型 + */ + private String dictType; + /** + * 字典名称 + */ + private String dictName; + /** + * 备注 + */ + private String remark; + /** + * 排序 + */ + private Integer sort; + /** + * 来源 0:字典数据 1:动态SQL + */ + private Integer dictSource; + /** + * 动态sql + */ + private String dictSql; + /** + * 上级节点 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Long pid; + /** + * 是否有子节点 0:无 1:有 + */ + private Integer hasChild; + /** + * 租户ID + */ + private Long tenantId; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysLogLoginEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysLogLoginEntity.java new file mode 100644 index 0000000..5ee1d96 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysLogLoginEntity.java @@ -0,0 +1,67 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@TableName("sys_log_login") +public class SysLogLoginEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 用户名 + */ + private String username; + + /** + * 登录IP + */ + private String ip; + + /** + * 登录地点 + */ + private String address; + + /** + * User Agent + */ + private String userAgent; + + /** + * 登录状态 0:失败 1:成功 + */ + private Integer status; + + /** + * 操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误 + */ + private Integer operation; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 租户ID + */ + private Long tenantId; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysLogOperateEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysLogOperateEntity.java new file mode 100644 index 0000000..80ea476 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysLogOperateEntity.java @@ -0,0 +1,108 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ + +@Data +@TableName("sys_log_operate") +public class SysLogOperateEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 操作人 + */ + private String realName; + + /** + * 模块名 + */ + private String module; + + /** + * 操作名 + */ + private String name; + + /** + * 请求URI + */ + private String reqUri; + + /** + * 请求方法 + */ + private String reqMethod; + + /** + * 请求参数 + */ + private String reqParams; + + /** + * 操作IP + */ + private String ip; + + /** + * 登录地点 + */ + private String address; + + /** + * User Agent + */ + private String userAgent; + + /** + * 操作类型 + */ + private Integer operateType; + + /** + * 执行时长 + */ + private Integer duration; + + /** + * 操作状态 + */ + private Integer status; + + /** + * 返回消息 + */ + private String resultMsg; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 租户ID + */ + private Long tenantId; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMailConfigEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMailConfigEntity.java new file mode 100644 index 0000000..0d07078 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMailConfigEntity.java @@ -0,0 +1,72 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 邮件平台 + * + * @author 阿沐 babamu@126.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_mail_config") +public class SysMailConfigEntity extends BaseEntity { + /** + * 平台类型 -1:本地 0:阿里云 + */ + private Integer platform; + + /** + * 分组名称,发送邮件时,可指定分组 + */ + private String groupName; + + /** + * SMTP服务器 + */ + private String mailHost; + + /** + * SMTP端口 + */ + private Integer mailPort; + + /** + * 发件人邮箱 + */ + private String mailFrom; + + /** + * 发件人密码 + */ + private String mailPass; + + /** + * regionId + */ + private String regionId; + + /** + * 阿里云 endpoint + */ + private String endpoint; + + /** + * AccessKey + */ + private String accessKey; + + /** + * SecretKey + */ + private String secretKey; + + /** + * 状态 0:禁用 1:启用 + */ + private Integer status; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMailLogEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMailLogEntity.java new file mode 100644 index 0000000..dc04825 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMailLogEntity.java @@ -0,0 +1,70 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +@Data +@TableName("sys_mail_log") +public class SysMailLogEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 平台ID + */ + private Long platformId; + + /** + * 平台类型 + */ + private Integer platform; + + /** + * 发件人邮箱 + */ + private String mailFrom; + + /** + * 接受人邮箱 + */ + private String mailTos; + + /** + * 邮件主题 + */ + private String subject; + + /** + * 邮件内容 + */ + private String content; + + /** + * 状态 0:失败 1:成功 + */ + private Integer status; + + /** + * 异常信息 + */ + private String error; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMenuEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMenuEntity.java new file mode 100644 index 0000000..8796163 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysMenuEntity.java @@ -0,0 +1,55 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 菜单管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_menu") +public class SysMenuEntity extends BaseEntity { + /** + * 上级ID + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Long pid; + /** + * 菜单名称 + */ + private String name; + /** + * 菜单URL + */ + private String url; + /** + * 授权标识(多个用逗号分隔,如:sys:menu:list,sys:menu:save) + */ + private String authority; + /** + * 类型 0:菜单 1:按钮 2:接口 + */ + private Integer type; + /** + * 打开方式 0:内部 1:外部 + */ + private Integer openStyle; + /** + * 菜单图标 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private String icon; + /** + * 排序 + */ + private Integer sort; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysOrgEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysOrgEntity.java new file mode 100644 index 0000000..fc03cc9 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysOrgEntity.java @@ -0,0 +1,47 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 机构管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_org") +public class SysOrgEntity extends BaseEntity { + /** + * 上级ID + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Long pid; + /** + * 机构名称 + */ + private String name; + /** + * 排序 + */ + private Integer sort; + /** + * 负责人ID + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS) + private Long leaderId; + /** + * 上级名称 + */ + @TableField(exist = false) + private String parentName; + /** + * 租户ID + */ + private Long tenantId; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysParamsEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysParamsEntity.java new file mode 100644 index 0000000..526f0c1 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysParamsEntity.java @@ -0,0 +1,48 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_params") +public class SysParamsEntity extends BaseEntity { + + /** + * 参数名称 + */ + private String paramName; + + /** + * 系统参数 + */ + private Integer paramType; + + /** + * 参数键 + */ + private String paramKey; + + /** + * 参数值 + */ + private String paramValue; + + /** + * 备注 + */ + private String remark; + + /** + * 租户ID + */ + private Long tenantId; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysPostEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysPostEntity.java new file mode 100644 index 0000000..a729e8e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysPostEntity.java @@ -0,0 +1,38 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 岗位管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_post") +public class SysPostEntity extends BaseEntity { + /** + * 岗位编码 + */ + private String postCode; + /** + * 岗位名称 + */ + private String postName; + /** + * 排序 + */ + private Integer sort; + /** + * 状态 0:停用 1:正常 + */ + private Integer status; + /** + * 租户ID + */ + private Long tenantId; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleDataScopeEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleDataScopeEntity.java new file mode 100644 index 0000000..847f634 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleDataScopeEntity.java @@ -0,0 +1,27 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 角色数据权限 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("sys_role_data_scope") +public class SysRoleDataScopeEntity extends BaseEntity { + /** + * 角色ID + */ + private Long roleId; + /** + * 机构ID + */ + private Long orgId; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleEntity.java new file mode 100644 index 0000000..fcf70e4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleEntity.java @@ -0,0 +1,46 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; +import com.bdzl.system.enums.DataScopeEnum; + +/** + * 角色 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_role") +public class SysRoleEntity extends BaseEntity { + /** + * 角色名称 + */ + private String name; + /** + * 角色编码 + */ + private String roleCode; + /** + * 备注 + */ + private String remark; + /** + * 数据范围 {@link DataScopeEnum} + */ + private Integer dataScope; + /** + * 机构ID + */ + @TableField(fill = FieldFill.INSERT) + private Long orgId; + /** + * 租户ID + */ + private Long tenantId; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleMenuEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleMenuEntity.java new file mode 100644 index 0000000..f58923e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysRoleMenuEntity.java @@ -0,0 +1,27 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 角色菜单关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("sys_role_menu") +public class SysRoleMenuEntity extends BaseEntity { + /** + * 角色ID + */ + private Long roleId; + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysSmsConfigEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysSmsConfigEntity.java new file mode 100644 index 0000000..4ca42d3 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysSmsConfigEntity.java @@ -0,0 +1,68 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 短信平台 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_sms_config") +public class SysSmsConfigEntity extends BaseEntity { + /** + * 平台类型 0:阿里云 1:腾讯云 2:七牛云 3:华为云 + */ + private Integer platform; + + /** + * 分组名称,发送短信时,可指定分组 + */ + private String groupName; + + /** + * 短信签名 + */ + private String signName; + + /** + * 短信模板 + */ + private String templateId; + + /** + * 短信应用的ID,如:腾讯云等 + */ + private String appId; + + /** + * 腾讯云国际短信、华为云等需要 + */ + private String senderId; + + /** + * 接入地址,如:华为云 + */ + private String url; + + /** + * AccessKey + */ + private String accessKey; + + /** + * SecretKey + */ + private String secretKey; + + /** + * 状态 0:禁用 1:启用 + */ + private Integer status; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysSmsLogEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysSmsLogEntity.java new file mode 100644 index 0000000..8e2c060 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysSmsLogEntity.java @@ -0,0 +1,62 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@TableName("sys_sms_log") +public class SysSmsLogEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 平台ID + */ + private Long platformId; + + /** + * 平台类型 + */ + private Integer platform; + + /** + * 手机号 + */ + private String mobile; + + /** + * 状态 0:失败 1:成功 + */ + private Integer status; + + /** + * 参数 + */ + private String params; + + /** + * 异常信息 + */ + private String error; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysThirdLoginConfigEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysThirdLoginConfigEntity.java new file mode 100644 index 0000000..2d98669 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysThirdLoginConfigEntity.java @@ -0,0 +1,73 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@TableName("sys_third_login_config") +public class SysThirdLoginConfigEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 开放平台类型 + */ + private String openType; + + /** + * ClientID + */ + private String clientId; + + /** + * ClientSecret + */ + private String clientSecret; + + /** + * RedirectUri + */ + private String redirectUri; + + /** + * AgentID + */ + private String agentId; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 版本号 + */ + @Version + @TableField(fill = FieldFill.INSERT) + private Integer version; + + /** + * 删除标记 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private Integer deleted; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysThirdLoginEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysThirdLoginEntity.java new file mode 100644 index 0000000..4228b5a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysThirdLoginEntity.java @@ -0,0 +1,69 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ + +@Data +@TableName("sys_third_login") +public class SysThirdLoginEntity { + /** + * id + */ + @TableId + private Long id; + + /** + * 开放平台类型 + */ + private String openType; + + /** + * 开放平台,唯一标识 + */ + private String openId; + + /** + * 昵称 + */ + private String username; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 版本号 + */ + @Version + @TableField(fill = FieldFill.INSERT) + private Integer version; + + /** + * 删除标记 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private Integer deleted; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserEntity.java new file mode 100644 index 0000000..5730809 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserEntity.java @@ -0,0 +1,69 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; +import com.bdzl.system.enums.UserStatusEnum; + +/** + * 用户 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("sys_user") +public class SysUserEntity extends BaseEntity { + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 姓名 + */ + private String realName; + /** + * 头像 + */ + private String avatar; + /** + * 性别 0:男 1:女 2:未知 + */ + private Integer gender; + /** + * 邮箱 + */ + private String email; + /** + * 手机号 + */ + private String mobile; + /** + * 机构ID + */ + private Long orgId; + /** + * 超级管理员 0:否 1:是 + */ + private Integer superAdmin; + /** + * 状态 {@link UserStatusEnum} + */ + private Integer status; + /** + * 机构名称 + */ + @TableField(exist = false) + private String orgName; + /** + * 租户ID + */ + private Long tenantId; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserPostEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserPostEntity.java new file mode 100644 index 0000000..61c682d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserPostEntity.java @@ -0,0 +1,26 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 用户岗位关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("sys_user_post") +public class SysUserPostEntity extends BaseEntity { + /** + * 用户ID + */ + private Long userId; + /** + * 岗位ID + */ + private Long postId; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserRoleEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserRoleEntity.java new file mode 100644 index 0000000..5310a20 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserRoleEntity.java @@ -0,0 +1,29 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.mybatis.entity.BaseEntity; + +/** + * 用户角色关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper=false) +@TableName("sys_user_role") +public class SysUserRoleEntity extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + private Long roleId; + /** + * 用户ID + */ + private Long userId; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserTokenEntity.java b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserTokenEntity.java new file mode 100644 index 0000000..74b29b6 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/entity/SysUserTokenEntity.java @@ -0,0 +1,61 @@ +package com.bdzl.system.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户Token + * + * @author 阿沐 babamu@126.com + * MAKU + */ + +@Data +@TableName("sys_user_token") +public class SysUserTokenEntity { + + @TableId + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * accessToken + */ + private String accessToken; + + /** + * accessToken 过期时间 + */ + private LocalDateTime accessTokenExpire; + + /** + * refreshToken + */ + private String refreshToken; + + /** + * refreshToken 过期时间 + */ + private LocalDateTime refreshTokenExpire; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/DataScopeEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/DataScopeEnum.java new file mode 100644 index 0000000..5193292 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/DataScopeEnum.java @@ -0,0 +1,38 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据范围枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum DataScopeEnum { + /** + * 全部数据 + */ + ALL(0), + /** + * 本机构及子机构数据 + */ + ORG_AND_CHILD(1), + /** + * 本机构数据 + */ + ORG_ONLY(2), + /** + * 本人数据 + */ + SELF(3), + /** + * 自定义数据 + */ + CUSTOM(4); + + private final Integer value; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/DictSourceEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/DictSourceEnum.java new file mode 100644 index 0000000..c558e45 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/DictSourceEnum.java @@ -0,0 +1,25 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 字典数据来源 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum DictSourceEnum { + /** + * 字典数据 + */ + DICT(0), + /** + * 动态SQL + */ + SQL(1); + + private final int value; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/LoginOperationEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/LoginOperationEnum.java new file mode 100644 index 0000000..08c3d1b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/LoginOperationEnum.java @@ -0,0 +1,33 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录信息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum LoginOperationEnum { + /** + * 登录成功 + */ + LOGIN_SUCCESS(0), + /** + * 退出成功 + */ + LOGOUT_SUCCESS(1), + /** + * 验证码错误 + */ + CAPTCHA_FAIL(2), + /** + * 账号密码错误 + */ + ACCOUNT_FAIL(3); + + private final int value; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/MailFormatEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/MailFormatEnum.java new file mode 100644 index 0000000..d215d5a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/MailFormatEnum.java @@ -0,0 +1,27 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 邮件格式枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum MailFormatEnum { + /** + * 纯文本 + */ + TEXT, + /** + * HTML + */ + HTML, + /** + * 模板 + */ + TEMPLATE; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/MailPlatformEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/MailPlatformEnum.java new file mode 100644 index 0000000..136e6e0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/MailPlatformEnum.java @@ -0,0 +1,26 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 邮件平台枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum MailPlatformEnum { + /** + * 本地 + */ + LOCAL(-1), + /** + * 阿里云 + */ + ALIYUN(0); + + private final int value; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/MenuTypeEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/MenuTypeEnum.java new file mode 100644 index 0000000..a30ddd8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/MenuTypeEnum.java @@ -0,0 +1,30 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 菜单类型枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum MenuTypeEnum { + /** + * 菜单 + */ + MENU(0), + /** + * 按钮 + */ + BUTTON(1), + /** + * 接口 + */ + INTERFACE(2); + + private final int value; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/SmsPlatformEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/SmsPlatformEnum.java new file mode 100644 index 0000000..3cbd09b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/SmsPlatformEnum.java @@ -0,0 +1,34 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信平台枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum SmsPlatformEnum { + /** + * 阿里云 + */ + ALIYUN(0), + /** + * 腾讯云 + */ + TENCENT(1), + /** + * 七牛云 + */ + QINIU(2), + /** + * 华为云 + */ + HUAWEI(3); + + private final int value; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/SuperAdminEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/SuperAdminEnum.java new file mode 100644 index 0000000..5360dff --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/SuperAdminEnum.java @@ -0,0 +1,46 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 超级管理员枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum SuperAdminEnum { + /** + * 是 + */ + YES(1, "是"), + /** + * 否 + */ + NO(0, "否"); + + private final Integer value; + private final String name; + + public static String getNameByValue(int value) { + for (SuperAdminEnum s : SuperAdminEnum.values()) { + if (s.getValue() == value) { + return s.getName(); + } + } + return ""; + } + + public static Integer getValueByName(String name) { + for (SuperAdminEnum s : SuperAdminEnum.values()) { + if (Objects.equals(s.getName(), name)) { + return s.getValue(); + } + } + return null; + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/SysParamsEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/SysParamsEnum.java new file mode 100644 index 0000000..f400042 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/SysParamsEnum.java @@ -0,0 +1,14 @@ +package com.bdzl.system.enums; + +/** + * 系统参数 枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public enum SysParamsEnum { + /** + * 登录验证码 + */ + LOGIN_CAPTCHA +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/ThirdLoginEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/ThirdLoginEnum.java new file mode 100644 index 0000000..a292aa7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/ThirdLoginEnum.java @@ -0,0 +1,46 @@ +package com.bdzl.system.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 第三方登录枚举 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum ThirdLoginEnum { + /** + * 企业微信 + */ + WECHAT_WORK("wechat_work"), + + /** + * 钉钉 + */ + DING_TALK("dingtalk"), + /** + * 飞书 + */ + FEI_SHU("feishu"), + + /** + * 微信开放平台 + */ + WECHAT_OPEN("wechat_open"); + + private final String value; + + public static ThirdLoginEnum toEnum(String value) { + for (ThirdLoginEnum item : values()) { + if (StrUtil.equalsIgnoreCase(item.getValue(), value)) { + return item; + } + } + + throw new IllegalArgumentException("Unsupported third login type: " + value); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/UserGenderEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/UserGenderEnum.java new file mode 100644 index 0000000..f82b29e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/UserGenderEnum.java @@ -0,0 +1,50 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 用户性别状态 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum UserGenderEnum { + /** + * 男 + */ + MAN(0, "男"), + /** + * 女 + */ + WOMEN(1, "女"), + /** + * 未知 + */ + UNKNOWN(2,"未知"); + + private final int value; + private final String name; + + public static String getNameByValue(int value) { + for (UserGenderEnum s : UserGenderEnum.values()) { + if (s.getValue() == value) { + return s.getName(); + } + } + return ""; + } + + public static Integer getValueByName(String name) { + for (UserGenderEnum s : UserGenderEnum.values()) { + if (Objects.equals(s.getName(), name)) { + return s.getValue(); + } + } + return null; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/enums/UserStatusEnum.java b/drone-ops-system/src/main/java/com/bdzl/system/enums/UserStatusEnum.java new file mode 100644 index 0000000..65d418c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/enums/UserStatusEnum.java @@ -0,0 +1,46 @@ +package com.bdzl.system.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +/** + * 用户状态 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Getter +@AllArgsConstructor +public enum UserStatusEnum { + /** + * 停用 + */ + DISABLE(0, "停用"), + /** + * 正常 + */ + ENABLED(1, "正常"); + + private final int value; + private final String name; + + public static String getNameByValue(int value) { + for (UserStatusEnum s : UserStatusEnum.values()) { + if (s.getValue() == value) { + return s.getName(); + } + } + return ""; + } + + public static Integer getValueByName(String name) { + for (UserStatusEnum s : UserStatusEnum.values()) { + if (Objects.equals(s.getName(), name)) { + return s.getValue(); + } + } + return null; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysAttachmentQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysAttachmentQuery.java new file mode 100644 index 0000000..954994c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysAttachmentQuery.java @@ -0,0 +1,24 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 附件管理查询 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "附件管理查询") +public class SysAttachmentQuery extends Query { + @Schema(description = "附件名称") + private String name; + + @Schema(description = "存储平台") + private String platform; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysDictDataQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysDictDataQuery.java new file mode 100644 index 0000000..8b45368 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysDictDataQuery.java @@ -0,0 +1,23 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 字典数据 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "字典数据查询") +public class SysDictDataQuery extends Query { + @Schema(description = "字典类型ID", required = true) + @NotNull(message = "字典类型ID不能为空") + private Long dictTypeId; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysDictTypeQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysDictTypeQuery.java new file mode 100644 index 0000000..6a4501a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysDictTypeQuery.java @@ -0,0 +1,24 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 字典类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "字典类型查询") +public class SysDictTypeQuery extends Query { + @Schema(description = "字典类型") + private String dictType; + + @Schema(description = "字典名称") + private String dictName; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysLogLoginQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysLogLoginQuery.java new file mode 100644 index 0000000..a52d62b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysLogLoginQuery.java @@ -0,0 +1,27 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 登录日志查询 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "登录日志查询") +public class SysLogLoginQuery extends Query { + @Schema(description = "用户名") + private String username; + + @Schema(description = "登录地点") + private String address; + + @Schema(description = "登录状态 0:失败 1:成功") + private Integer status; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysLogOperateQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysLogOperateQuery.java new file mode 100644 index 0000000..ba385e8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysLogOperateQuery.java @@ -0,0 +1,30 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 操作日志查询 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "操作日志查询") +public class SysLogOperateQuery extends Query { + @Schema(description = "用户") + private String realName; + + @Schema(description = "模块名") + private String module; + + @Schema(description = "请求URI") + private String reqUri; + + @Schema(description = "操作状态") + private Integer status; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysMailConfigQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysMailConfigQuery.java new file mode 100644 index 0000000..344ea3b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysMailConfigQuery.java @@ -0,0 +1,20 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 邮件配置查询 + * + * @author 阿沐 babamu@126.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "邮件配置查询") +public class SysMailConfigQuery extends Query { + @Schema(description = "平台类型") + private Integer platform; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysMailLogQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysMailLogQuery.java new file mode 100644 index 0000000..3c19bd8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysMailLogQuery.java @@ -0,0 +1,22 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 邮件日志查询 + * + * @author 阿沐 babamu@126.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "邮件日志查询") +public class SysMailLogQuery extends Query { + @Schema(description = "发送人邮箱") + private String mailFrom; + + @Schema(description = "平台类型") + private Integer platform; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysParamsQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysParamsQuery.java new file mode 100644 index 0000000..bff254f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysParamsQuery.java @@ -0,0 +1,27 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 参数管理查询 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "参数管理查询") +public class SysParamsQuery extends Query { + @Schema(description = "系统参数") + private Integer paramType; + + @Schema(description = "参数键") + private String paramKey; + + @Schema(description = "参数值") + private String paramValue; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysPostQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysPostQuery.java new file mode 100644 index 0000000..2d61874 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysPostQuery.java @@ -0,0 +1,27 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 岗位管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "岗位管理查询") +public class SysPostQuery extends Query { + @Schema(description = "岗位编码") + private String postCode; + + @Schema(description = "岗位名称") + private String postName; + + @Schema(description = "状态 0:停用 1:正常") + private Integer status; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysRoleQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysRoleQuery.java new file mode 100644 index 0000000..51bc4f6 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysRoleQuery.java @@ -0,0 +1,21 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 角色管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "角色查询") +public class SysRoleQuery extends Query { + @Schema(description = "角色名称") + private String name; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysRoleUserQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysRoleUserQuery.java new file mode 100644 index 0000000..cbe29c5 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysRoleUserQuery.java @@ -0,0 +1,20 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 分配角色查询 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "分配角色查询") +public class SysRoleUserQuery extends SysUserQuery { + @Schema(description = "角色ID") + private Long roleId; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysSmsConfigQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysSmsConfigQuery.java new file mode 100644 index 0000000..75f90b2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysSmsConfigQuery.java @@ -0,0 +1,23 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 短信配置查询 + * + * @author 阿沐 babamu@126.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "短信配置查询") +public class SysSmsConfigQuery extends Query { + @Schema(description = "平台类型") + private Integer platform; + + @Schema(description = "分组名称") + private String groupName; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysSmsLogQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysSmsLogQuery.java new file mode 100644 index 0000000..b75a5ab --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysSmsLogQuery.java @@ -0,0 +1,23 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +/** + * 短信日志查询 + * + * @author 阿沐 babamu@126.com + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "短信日志查询") +public class SysSmsLogQuery extends Query { + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "平台类型") + private Integer platform; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/query/SysUserQuery.java b/drone-ops-system/src/main/java/com/bdzl/system/query/SysUserQuery.java new file mode 100644 index 0000000..8284e0d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/query/SysUserQuery.java @@ -0,0 +1,32 @@ +package com.bdzl.system.query; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.query.Query; + +import java.util.List; + +/** + * 用户查询 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(description = "用户查询") +public class SysUserQuery extends Query { + @Schema(description = "用户名") + private String username; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "性别") + private Integer gender; + + @Schema(description = "机构ID") + private List orgId; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysAttachmentService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysAttachmentService.java new file mode 100644 index 0000000..ccb7f91 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysAttachmentService.java @@ -0,0 +1,26 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysAttachmentEntity; +import com.bdzl.system.query.SysAttachmentQuery; +import com.bdzl.system.vo.SysAttachmentVO; + +import java.util.List; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysAttachmentService extends BaseService { + + PageResult page(SysAttachmentQuery query); + + void save(SysAttachmentVO vo); + + void update(SysAttachmentVO vo); + + void delete(List idList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysAuthService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysAuthService.java new file mode 100644 index 0000000..82fbf67 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysAuthService.java @@ -0,0 +1,54 @@ +package com.bdzl.system.service; + +import com.bdzl.system.vo.*; + +/** + * 权限认证服务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysAuthService { + + /** + * 账号密码登录 + * + * @param login 登录信息 + */ + SysUserTokenVO loginByAccount(SysAccountLoginVO login); + + /** + * 手机短信登录 + * + * @param login 登录信息 + */ + SysUserTokenVO loginByMobile(SysMobileLoginVO login); + + /** + * 第三方登录 + * + * @param login 登录信息 + */ + SysUserTokenVO loginByThird(SysThirdCallbackVO login); + + /** + * 发送手机验证码 + * + * @param mobile 手机号 + */ + boolean sendCode(String mobile); + + /** + * 根据刷新Token,获取AccessToken + * + * @param refreshToken refreshToken + */ + AccessTokenVO getAccessToken(String refreshToken); + + /** + * 退出登录 + * + * @param accessToken accessToken + */ + void logout(String accessToken); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysCaptchaService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysCaptchaService.java new file mode 100644 index 0000000..54426af --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysCaptchaService.java @@ -0,0 +1,32 @@ +package com.bdzl.system.service; + +import com.bdzl.system.vo.SysCaptchaVO; + +/** + * 验证码 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysCaptchaService { + /** + * 生成验证码 + */ + SysCaptchaVO generate(); + + /** + * 验证码效验 + * + * @param key key + * @param code 验证码 + * @return true:成功 false:失败 + */ + boolean validate(String key, String code); + + /** + * 是否开启登录验证码 + * + * @return true:开启 false:关闭 + */ + boolean isCaptchaEnabled(); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysDictDataService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysDictDataService.java new file mode 100644 index 0000000..07a038b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysDictDataService.java @@ -0,0 +1,27 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysDictDataEntity; +import com.bdzl.system.query.SysDictDataQuery; +import com.bdzl.system.vo.SysDictDataVO; + +import java.util.List; + +/** + * 数据字典 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysDictDataService extends BaseService { + + PageResult page(SysDictDataQuery query); + + void save(SysDictDataVO vo); + + void update(SysDictDataVO vo); + + void delete(List idList); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysDictTypeService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysDictTypeService.java new file mode 100644 index 0000000..f34e49a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysDictTypeService.java @@ -0,0 +1,45 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysDictTypeEntity; +import com.bdzl.system.query.SysDictTypeQuery; +import com.bdzl.system.vo.SysDictTypeVO; +import com.bdzl.system.vo.SysDictVO; + +import java.util.List; + +/** + * 数据字典 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysDictTypeService extends BaseService { + + PageResult page(SysDictTypeQuery query); + + List list(Long pid); + + void save(SysDictTypeVO vo); + + void update(SysDictTypeVO vo); + + void delete(List idList); + + /** + * 获取动态SQL数据 + */ + List getDictSql(Long id); + + /** + * 获取全部字典列表 + */ + List getDictList(); + + /** + * 刷新字典缓存 + */ + void refreshTransCache(); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysLogLoginService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysLogLoginService.java new file mode 100644 index 0000000..7731f61 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysLogLoginService.java @@ -0,0 +1,38 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysLogLoginEntity; +import com.bdzl.system.query.SysLogLoginQuery; +import com.bdzl.system.vo.SysLogLoginVO; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysLogLoginService extends BaseService { + + /** + * Page result. + * + * @param query the query + * @return the page result + */ + PageResult page(SysLogLoginQuery query); + + /** + * 保存登录日志 + * + * @param username 用户名 + * @param status 登录状态 + * @param operation 操作信息 + */ + void save(String username, Integer status, Integer operation); + + /** + * 导出登录日志 + */ + void export(); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysLogOperateService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysLogOperateService.java new file mode 100644 index 0000000..cdadd0a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysLogOperateService.java @@ -0,0 +1,18 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysLogOperateEntity; +import com.bdzl.system.query.SysLogOperateQuery; +import com.bdzl.system.vo.SysLogOperateVO; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysLogOperateService extends BaseService { + + PageResult page(SysLogOperateQuery query); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysMailConfigService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysMailConfigService.java new file mode 100644 index 0000000..ca0a92f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysMailConfigService.java @@ -0,0 +1,33 @@ +package com.bdzl.system.service; + +import com.bdzl.email.config.EmailConfig; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysMailConfigEntity; +import com.bdzl.system.query.SysMailConfigQuery; +import com.bdzl.system.vo.SysMailConfigVO; + +import java.util.List; + +/** + * 邮件平台 + * + * @author 阿沐 babamu@126.com + */ +public interface SysMailConfigService extends BaseService { + + PageResult page(SysMailConfigQuery query); + + List list(Integer platform); + + /** + * 启用的邮件平台列表 + */ + List listByEnable(); + + void save(SysMailConfigVO vo); + + void update(SysMailConfigVO vo); + + void delete(List idList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysMailLogService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysMailLogService.java new file mode 100644 index 0000000..504eeab --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysMailLogService.java @@ -0,0 +1,21 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysMailLogEntity; +import com.bdzl.system.query.SysMailLogQuery; +import com.bdzl.system.vo.SysMailLogVO; + +import java.util.List; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +public interface SysMailLogService extends BaseService { + + PageResult page(SysMailLogQuery query); + + void delete(List idList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysMenuService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysMenuService.java new file mode 100644 index 0000000..deb8989 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysMenuService.java @@ -0,0 +1,51 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.entity.SysMenuEntity; +import com.bdzl.system.vo.SysMenuVO; + +import java.util.List; +import java.util.Set; + + +/** + * 菜单管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysMenuService extends BaseService { + + void save(SysMenuVO vo); + + void update(SysMenuVO vo); + + void delete(Long id); + + /** + * 菜单列表 + * + * @param type 菜单类型 + */ + List getMenuList(Integer type); + + /** + * 用户菜单列表 + * + * @param user 用户 + * @param type 菜单类型 + */ + List getUserMenuList(UserDetail user, Integer type); + + /** + * 获取子菜单的数量 + * @param pid 父菜单ID + */ + Long getSubMenuCount(Long pid); + + /** + * 获取用户权限列表 + */ + Set getUserAuthority(UserDetail user); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysOrgService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysOrgService.java new file mode 100644 index 0000000..1cfcf89 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysOrgService.java @@ -0,0 +1,38 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysOrgEntity; +import com.bdzl.system.vo.SysOrgVO; + +import java.util.List; + +/** + * 机构管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysOrgService extends BaseService { + + List getList(); + + void save(SysOrgVO vo); + + void update(SysOrgVO vo); + + void delete(Long id); + + /** + * 根据机构ID,获取子机构ID列表(包含本机构ID) + * + * @param id 机构ID + */ + List getSubOrgIdList(Long id); + + /** + * 根据机构ID列表,获取机构名称列表 + * + * @param idList 机构ID列表 + */ + List getNameList(List idList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysParamsService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysParamsService.java new file mode 100644 index 0000000..4b2de8c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysParamsService.java @@ -0,0 +1,55 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysParamsEntity; +import com.bdzl.system.query.SysParamsQuery; +import com.bdzl.system.vo.SysParamsVO; + +import java.util.List; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysParamsService extends BaseService { + + PageResult page(SysParamsQuery query); + + void save(SysParamsVO vo); + + void update(SysParamsVO vo); + + void delete(List idList); + + /** + * 根据paramKey,获取字符串值 + * + * @param paramKey 参数Key + */ + String getString(String paramKey); + + /** + * 根据paramKey,获取整型值 + * + * @param paramKey 参数Key + */ + int getInt(String paramKey); + + /** + * 根据paramKey,获取布尔值 + * + * @param paramKey 参数Key + */ + boolean getBoolean(String paramKey); + + /** + * 根据paramKey,获取对象值 + * + * @param paramKey 参数Key + * @param valueType 类型 + */ + T getJSONObject(String paramKey, Class valueType); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysPostService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysPostService.java new file mode 100644 index 0000000..44892ed --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysPostService.java @@ -0,0 +1,30 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysPostEntity; +import com.bdzl.system.query.SysPostQuery; +import com.bdzl.system.vo.SysPostVO; + +import java.util.List; + +/** + * 岗位管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysPostService extends BaseService { + + PageResult page(SysPostQuery query); + + List getList(); + + List getNameList(List idList); + + void save(SysPostVO vo); + + void update(SysPostVO vo); + + void delete(List idList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleDataScopeService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleDataScopeService.java new file mode 100644 index 0000000..ebdec4e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleDataScopeService.java @@ -0,0 +1,33 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysRoleDataScopeEntity; + +import java.util.List; + +/** + * 角色数据权限 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysRoleDataScopeService extends BaseService { + + /** + * 保存或修改 + * @param roleId 角色ID + * @param orgIdList 机构ID列表 + */ + void saveOrUpdate(Long roleId, List orgIdList); + + /** + * 根据角色ID,获取机构ID列表 + */ + List getOrgIdList(Long roleId); + + /** + * 根据角色id列表,删除角色数据权限关系 + * @param roleIdList 角色id列表 + */ + void deleteByRoleIdList(List roleIdList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleMenuService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleMenuService.java new file mode 100644 index 0000000..25acbd0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleMenuService.java @@ -0,0 +1,41 @@ +package com.bdzl.system.service; + + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysRoleMenuEntity; + +import java.util.List; + + +/** + * 角色与菜单对应关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysRoleMenuService extends BaseService { + + /** + * 根据角色ID,获取菜单ID列表 + */ + List getMenuIdList(Long roleId); + + /** + * 保存或修改 + * @param roleId 角色ID + * @param menuIdList 菜单ID列表 + */ + void saveOrUpdate(Long roleId, List menuIdList); + + /** + * 根据角色id列表,删除角色菜单关系 + * @param roleIdList 角色id列表 + */ + void deleteByRoleIdList(List roleIdList); + + /** + * 根据菜单id,删除角色菜单关系 + * @param menuId 菜单id + */ + void deleteByMenuId(Long menuId); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleService.java new file mode 100644 index 0000000..a4ee213 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysRoleService.java @@ -0,0 +1,39 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysRoleEntity; +import com.bdzl.system.query.SysRoleQuery; +import com.bdzl.system.vo.SysRoleDataScopeVO; +import com.bdzl.system.vo.SysRoleVO; + +import java.util.List; + +/** + * 角色 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysRoleService extends BaseService { + + PageResult page(SysRoleQuery query); + + List getList(SysRoleQuery query); + + void save(SysRoleVO vo); + + void update(SysRoleVO vo); + + void dataScope(SysRoleDataScopeVO vo); + + void delete(List idList); + + /** + * 获取角色名称列表 + * + * @param idList 角色ID列表 + * @return 角色名称列表 + */ + List getNameList(List idList); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysSmsConfigService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysSmsConfigService.java new file mode 100644 index 0000000..fbd7978 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysSmsConfigService.java @@ -0,0 +1,35 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.sms.config.SmsConfig; +import com.bdzl.system.entity.SysSmsConfigEntity; +import com.bdzl.system.query.SysSmsConfigQuery; +import com.bdzl.system.vo.SysSmsConfigVO; + +import java.util.List; + +/** + * 短信配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysSmsConfigService extends BaseService { + + PageResult page(SysSmsConfigQuery query); + + List list(Integer platform); + + /** + * 启用的短信平台列表 + */ + List listByEnable(); + + void save(SysSmsConfigVO vo); + + void update(SysSmsConfigVO vo); + + void delete(List idList); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysSmsLogService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysSmsLogService.java new file mode 100644 index 0000000..a8636e0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysSmsLogService.java @@ -0,0 +1,22 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysSmsLogEntity; +import com.bdzl.system.query.SysSmsLogQuery; +import com.bdzl.system.vo.SysSmsLogVO; + +import java.util.List; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysSmsLogService extends BaseService { + + PageResult page(SysSmsLogQuery query); + + void delete(List idList); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysThirdLoginConfigService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysThirdLoginConfigService.java new file mode 100644 index 0000000..6f1f65e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysThirdLoginConfigService.java @@ -0,0 +1,34 @@ +package com.bdzl.system.service; + +import me.zhyd.oauth.request.AuthRequest; +import com.bdzl.framework.common.query.Query; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysThirdLoginConfigEntity; +import com.bdzl.system.vo.SysThirdLoginConfigVO; + +import java.util.List; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysThirdLoginConfigService extends BaseService { + + PageResult page(Query query); + + void save(SysThirdLoginConfigVO vo); + + void update(SysThirdLoginConfigVO vo); + + void delete(List idList); + + /** + * 根据类型,获取授权请求 + * + * @param openType 第三方登录类型 + */ + AuthRequest getAuthRequest(String openType); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysThirdLoginService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysThirdLoginService.java new file mode 100644 index 0000000..89534eb --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysThirdLoginService.java @@ -0,0 +1,33 @@ +package com.bdzl.system.service; + +import me.zhyd.oauth.model.AuthUser; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysThirdLoginEntity; +import com.bdzl.system.vo.SysThirdLoginVO; + +import java.util.List; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysThirdLoginService extends BaseService { + + List listByUserId(Long userId); + + void unBind(Long userId, String openType); + + void bind(Long userId, String openType, AuthUser authUser); + + /** + * 根据第三方登录类型和openId,查询用户Id + * + * @param openType 第三方登录类型 + * @param openId 第三方用户唯一标识 + * @return 用户Id + */ + Long getUserIdByOpenTypeAndOpenId(String openType, String openId); + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserDetailsService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserDetailsService.java new file mode 100644 index 0000000..3ecac4e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserDetailsService.java @@ -0,0 +1,12 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.security.user.UserDetail; +import org.springframework.security.core.userdetails.UserDetails; + +public interface SysUserDetailsService { + + /** + * 获取 UserDetails 对象,设置用户权限信息 + */ + UserDetails getUserDetails(UserDetail userDetail); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserPostService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserPostService.java new file mode 100644 index 0000000..b9abb2d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserPostService.java @@ -0,0 +1,40 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysUserPostEntity; + +import java.util.List; + +/** + * 用户岗位关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysUserPostService extends BaseService { + + /** + * 保存或修改 + * @param userId 用户ID + * @param postIdList 岗位ID列表 + */ + void saveOrUpdate(Long userId, List postIdList); + + /** + * 根据岗位id列表,删除用户岗位关系 + * @param postIdList 岗位id列表 + */ + void deleteByPostIdList(List postIdList); + + /** + * 根据用户id列表,删除用户岗位关系 + * @param userIdList 用户id列表 + */ + void deleteByUserIdList(List userIdList); + + /** + * 岗位ID列表 + * @param userId 用户ID + */ + List getPostIdList(Long userId); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserRoleService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserRoleService.java new file mode 100644 index 0000000..0b87f12 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserRoleService.java @@ -0,0 +1,60 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysUserRoleEntity; + +import java.util.List; + +/** + * 用户角色关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysUserRoleService extends BaseService { + + /** + * 保存或修改 + * @param userId 用户ID + * @param roleIdList 角色ID列表 + */ + void saveOrUpdate(Long userId, List roleIdList); + + /** + * 分配角色给用户列表 + * @param roleId 角色ID + * @param userIdList 用户ID列表 + */ + void saveUserList(Long roleId, List userIdList); + + /** + * 根据角色id列表,删除用户角色关系 + * @param roleIdList 角色id + */ + void deleteByRoleIdList(List roleIdList); + + /** + * 根据用户id列表,删除用户角色关系 + * @param userIdList 用户id列表 + */ + void deleteByUserIdList(List userIdList); + + /** + * 根据角色id、用户id列表,删除用户角色关系 + * @param roleId 角色id + * @param userIdList 用户id列表 + */ + void deleteByUserIdList(Long roleId, List userIdList); + + /** + * 角色ID列表 + * @param userId 用户ID + */ + List getRoleIdList(Long userId); + + /** + * 根据角色ID查询对应的用户ID列表 + * @param roleId 角色ID + */ + List getExistsUserIdList(Long roleId); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserService.java new file mode 100644 index 0000000..6bd5b26 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserService.java @@ -0,0 +1,70 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.query.SysRoleUserQuery; +import com.bdzl.system.query.SysUserQuery; +import com.bdzl.system.vo.SysUserAvatarVO; +import com.bdzl.system.vo.SysUserBaseVO; +import com.bdzl.system.vo.SysUserVO; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 用户管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public interface SysUserService extends BaseService { + + PageResult page(SysUserQuery query); + + void save(SysUserVO vo); + + void update(SysUserVO vo); + + void updateLoginInfo(SysUserBaseVO vo); + + void updateAvatar(SysUserAvatarVO avatar); + + void delete(List idList); + + /** + * 获取用户姓名列表 + * + * @param idList 用户ID列表 + * @return 用户姓名列表 + */ + List getRealNameList(List idList); + + SysUserVO getByMobile(String mobile); + + /** + * 修改密码 + * + * @param id 用户ID + * @param newPassword 新密码 + */ + void updatePassword(Long id, String newPassword); + + /** + * 分配角色,用户列表 + */ + PageResult roleUserPage(SysRoleUserQuery query); + + /** + * 批量导入用户 + * + * @param file excel文件 + * @param password 密码 + */ + void importByExcel(MultipartFile file, String password); + + /** + * 导出用户信息表格 + */ + void export(); +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserTokenService.java b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserTokenService.java new file mode 100644 index 0000000..ecb0ffd --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/SysUserTokenService.java @@ -0,0 +1,51 @@ +package com.bdzl.system.service; + +import com.bdzl.framework.mybatis.service.BaseService; +import com.bdzl.system.entity.SysUserTokenEntity; +import com.bdzl.system.vo.SysUserTokenVO; + + +/** + * 用户Token + * + * @author 阿沐 babamu@126.com + */ +public interface SysUserTokenService extends BaseService { + + /** + * 根据用户ID,生成用户Token + * + * @param userId 用户ID + * @return 用户Token + */ + SysUserTokenVO createToken(Long userId); + + /** + * 根据refreshToken,生成新Token + * + * @param refreshToken refreshToken + * @return 用户Token + */ + SysUserTokenVO refreshToken(String refreshToken); + + /** + * Token过期 + * + * @param userId 用户ID + */ + void expireToken(Long userId); + + /** + * 根据角色ID,更新用户缓存权限 + * + * @param roleId 角色ID + */ + void updateCacheAuthByRoleId(Long roleId); + + /** + * 根据用户ID,更新用户缓存权限 + * + * @param userId 用户ID + */ + void updateCacheAuthByUserId(Long userId); +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysAttachmentServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysAttachmentServiceImpl.java new file mode 100644 index 0000000..167c57d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysAttachmentServiceImpl.java @@ -0,0 +1,66 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysAttachmentConvert; +import com.bdzl.system.dao.SysAttachmentDao; +import com.bdzl.system.entity.SysAttachmentEntity; +import com.bdzl.system.query.SysAttachmentQuery; +import com.bdzl.system.service.SysAttachmentService; +import com.bdzl.system.vo.SysAttachmentVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysAttachmentServiceImpl extends BaseServiceImpl implements SysAttachmentService { + + @Override + public PageResult page(SysAttachmentQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysAttachmentConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(SysAttachmentQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(StrUtil.isNotBlank(query.getPlatform()), SysAttachmentEntity::getPlatform, query.getPlatform()); + wrapper.like(StrUtil.isNotBlank(query.getName()), SysAttachmentEntity::getName, query.getName()); + wrapper.orderByDesc(SysAttachmentEntity::getId); + return wrapper; + } + + @Override + public void save(SysAttachmentVO vo) { + SysAttachmentEntity entity = SysAttachmentConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(SysAttachmentVO vo) { + SysAttachmentEntity entity = SysAttachmentConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysAuthServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysAuthServiceImpl.java new file mode 100644 index 0000000..767a12f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysAuthServiceImpl.java @@ -0,0 +1,161 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.RandomUtil; +import com.bdzl.system.service.*; +import com.bdzl.system.vo.*; +import lombok.AllArgsConstructor; +import com.bdzl.api.module.system.SmsApi; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.security.cache.TokenStoreCache; +import com.bdzl.framework.security.crypto.Sm2Util; +import com.bdzl.framework.security.mobile.MobileAuthenticationToken; +import com.bdzl.framework.security.third.ThirdAuthenticationToken; +import com.bdzl.framework.security.third.ThirdLogin; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.enums.LoginOperationEnum; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +/** + * 权限认证服务 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysAuthServiceImpl implements SysAuthService { + private final SysCaptchaService sysCaptchaService; + private final TokenStoreCache tokenStoreCache; + private final AuthenticationManager authenticationManager; + private final SysLogLoginService sysLogLoginService; + private final SysUserService sysUserService; + private final SysUserTokenService sysUserTokenService; + private final SmsApi smsApi; + + @Override + public SysUserTokenVO loginByAccount(SysAccountLoginVO login) { + // 验证码效验 + boolean flag = sysCaptchaService.validate(login.getKey(), login.getCaptcha()); + if (!flag) { + // 保存登录日志 + sysLogLoginService.save(login.getUsername(), Constant.FAIL, LoginOperationEnum.CAPTCHA_FAIL.getValue()); + + throw new ServerException("验证码错误"); + } + + Authentication authentication; + try { + // 用户认证 + authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(login.getUsername(), Sm2Util.decrypt(login.getPassword()))); + } catch (BadCredentialsException e) { + throw new ServerException("用户名或密码错误"); + } + + // 用户信息 + UserDetail user = (UserDetail) authentication.getPrincipal(); + + // 生成 accessToken + SysUserTokenVO userTokenVO = sysUserTokenService.createToken(user.getId()); + + // 保存用户信息到缓存 + tokenStoreCache.saveUser(userTokenVO.getAccessToken(), user); + + return userTokenVO; + } + + @Override + public SysUserTokenVO loginByMobile(SysMobileLoginVO login) { + Authentication authentication; + try { + // 用户认证 + authentication = authenticationManager.authenticate( + new MobileAuthenticationToken(login.getMobile(), login.getCode())); + } catch (BadCredentialsException e) { + throw new ServerException("手机号或验证码错误"); + } + + // 用户信息 + UserDetail user = (UserDetail) authentication.getPrincipal(); + + // 生成 accessToken + SysUserTokenVO userTokenVO = sysUserTokenService.createToken(user.getId()); + + // 保存用户信息到缓存 + tokenStoreCache.saveUser(userTokenVO.getAccessToken(), user); + + return userTokenVO; + } + + @Override + public SysUserTokenVO loginByThird(SysThirdCallbackVO login) { + Authentication authentication; + try { + // 转换对象 + ThirdLogin thirdLogin = BeanUtil.copyProperties(login, ThirdLogin.class); + + // 用户认证 + authentication = authenticationManager.authenticate(new ThirdAuthenticationToken(thirdLogin)); + } catch (BadCredentialsException e) { + throw new ServerException("第三方登录失败"); + } + + // 用户信息 + UserDetail user = (UserDetail) authentication.getPrincipal(); + + // 生成 accessToken + SysUserTokenVO userTokenVO = sysUserTokenService.createToken(user.getId()); + + // 保存用户信息到缓存 + tokenStoreCache.saveUser(userTokenVO.getAccessToken(), user); + + return userTokenVO; + } + + @Override + public boolean sendCode(String mobile) { + // 生成6位验证码 + String code = RandomUtil.randomNumbers(6); + + SysUserVO user = sysUserService.getByMobile(mobile); + if (user == null) { + throw new ServerException("手机号未注册"); + } + + // 发送短信 + return smsApi.sendCode(mobile, "code", code); + } + + @Override + public AccessTokenVO getAccessToken(String refreshToken) { + SysUserTokenVO token = sysUserTokenService.refreshToken(refreshToken); + + // 封装 AccessToken + AccessTokenVO accessToken = new AccessTokenVO(); + accessToken.setAccessToken(token.getAccessToken()); + accessToken.setAccessTokenExpire(token.getAccessTokenExpire()); + + return accessToken; + } + + @Override + public void logout(String accessToken) { + // 用户信息 + UserDetail user = tokenStoreCache.getUser(accessToken); + + // 删除用户信息 + tokenStoreCache.deleteUser(accessToken); + + // Token过期 + sysUserTokenService.expireToken(user.getId()); + + // 保存登录日志 + sysLogLoginService.save(user.getUsername(), Constant.SUCCESS, LoginOperationEnum.LOGOUT_SUCCESS.getValue()); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysCaptchaServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysCaptchaServiceImpl.java new file mode 100644 index 0000000..e753592 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysCaptchaServiceImpl.java @@ -0,0 +1,85 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.StrUtil; +import com.wf.captcha.SpecCaptcha; +import com.wf.captcha.base.Captcha; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import com.bdzl.framework.common.cache.RedisKeys; +import com.bdzl.system.enums.SysParamsEnum; +import com.bdzl.system.service.SysCaptchaService; +import com.bdzl.system.service.SysParamsService; +import com.bdzl.system.vo.SysCaptchaVO; +import org.springframework.stereotype.Service; + +/** + * 验证码 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysCaptchaServiceImpl implements SysCaptchaService { + private final RedisCache redisCache; + private final SysParamsService sysParamsService; + + @Override + public SysCaptchaVO generate() { + // 生成验证码key + String key = UUID.randomUUID().toString(); + + // 生成验证码 + SpecCaptcha captcha = new SpecCaptcha(150, 40); + captcha.setLen(5); + captcha.setCharType(Captcha.TYPE_DEFAULT); + String image = captcha.toBase64(); + + // 保存到缓存 + String redisKey = RedisKeys.getCaptchaKey(key); + redisCache.set(redisKey, captcha.text(), 300); + + // 封装返回数据 + SysCaptchaVO captchaVO = new SysCaptchaVO(); + captchaVO.setKey(key); + captchaVO.setImage(image); + + return captchaVO; + } + + @Override + public boolean validate(String key, String code) { + // 如果关闭了验证码,则直接效验通过 + if (!isCaptchaEnabled()) { + return true; + } + + if (StrUtil.isBlank(key) || StrUtil.isBlank(code)) { + return false; + } + + // 获取验证码 + String captcha = getCache(key); + + // 效验成功 + return code.equalsIgnoreCase(captcha); + } + + @Override + public boolean isCaptchaEnabled() { + return sysParamsService.getBoolean(SysParamsEnum.LOGIN_CAPTCHA.name()); + } + + private String getCache(String key) { + key = RedisKeys.getCaptchaKey(key); + String captcha = (String) redisCache.get(key); + // 删除验证码 + if (captcha != null) { + redisCache.delete(key); + } + + return captcha; + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysDictDataServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000..c17438a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,85 @@ +package com.bdzl.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysDictDataConvert; +import com.bdzl.system.dao.SysDictDataDao; +import com.bdzl.system.entity.SysDictDataEntity; +import com.bdzl.system.query.SysDictDataQuery; +import com.bdzl.system.service.SysDictDataService; +import com.bdzl.system.vo.SysDictDataVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 数据字典 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysDictDataServiceImpl extends BaseServiceImpl implements SysDictDataService { + + @Override + public PageResult page(SysDictDataQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysDictDataConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private Wrapper getWrapper(SysDictDataQuery query){ + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysDictDataEntity::getDictTypeId, query.getDictTypeId()); + wrapper.orderByAsc(SysDictDataEntity::getSort); + + return wrapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(SysDictDataVO vo) { + SysDictDataEntity sysDictData = getOne(Wrappers.lambdaQuery() + .eq(SysDictDataEntity::getDictTypeId, vo.getDictTypeId()) + .eq(SysDictDataEntity::getDictValue, vo.getDictValue())); + if (sysDictData != null) { + throw new ServerException("字典值重复!"); + } + + SysDictDataEntity entity = SysDictDataConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysDictDataVO vo) { + SysDictDataEntity sysDictData = getOne(Wrappers.lambdaQuery() + .eq(SysDictDataEntity::getDictTypeId, vo.getDictTypeId()) + .eq(SysDictDataEntity::getDictValue, vo.getDictValue()) + .ne(SysDictDataEntity::getId, vo.getId())); + if (sysDictData != null) { + throw new ServerException("字典值重复!"); + } + + SysDictDataEntity entity = SysDictDataConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysDictTypeServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..192b29c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,213 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fhs.trans.service.impl.DictionaryTransService; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysDictTypeConvert; +import com.bdzl.system.dao.SysDictDataDao; +import com.bdzl.system.dao.SysDictTypeDao; +import com.bdzl.system.entity.SysDictDataEntity; +import com.bdzl.system.entity.SysDictTypeEntity; +import com.bdzl.system.enums.DictSourceEnum; +import com.bdzl.system.query.SysDictTypeQuery; +import com.bdzl.system.service.SysDictTypeService; +import com.bdzl.system.vo.SysDictTypeVO; +import com.bdzl.system.vo.SysDictVO; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +/** + * 字典类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysDictTypeServiceImpl extends BaseServiceImpl implements SysDictTypeService, InitializingBean { + private final SysDictDataDao sysDictDataDao; + private final DictionaryTransService dictionaryTransService; + + @Override + public PageResult page(SysDictTypeQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + return new PageResult<>(SysDictTypeConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + @Override + public List list(Long pid) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(pid != null, SysDictTypeEntity::getPid, pid); + + List list = baseMapper.selectList(wrapper); + return SysDictTypeConvert.INSTANCE.convertList(list); + } + + private Wrapper getWrapper(SysDictTypeQuery query) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StrUtil.isNotBlank(query.getDictType()), SysDictTypeEntity::getDictType, query.getDictType()); + wrapper.like(StrUtil.isNotBlank(query.getDictName()), SysDictTypeEntity::getDictName, query.getDictName()); + wrapper.isNull(SysDictTypeEntity::getPid); + wrapper.orderByAsc(SysDictTypeEntity::getSort); + + return wrapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(SysDictTypeVO vo) { + SysDictTypeEntity entity = SysDictTypeConvert.INSTANCE.convert(vo); + + // 更新上级,有子节点 + if (vo.getPid() != null) { + this.updateHasChild(vo.getPid(), 1); + } + + baseMapper.insert(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysDictTypeVO vo) { + SysDictTypeEntity entity = SysDictTypeConvert.INSTANCE.convert(vo); + + // 更新上级,有子节点 + if (vo.getPid() != null) { + this.updateHasChild(vo.getPid(), 1); + } + + // 获取原先的上级ID + Long oldPid = baseMapper.selectById(vo.getId()).getPid(); + + // 更新 + updateById(entity); + + // 上级已修改 + if (!ObjectUtil.equals(oldPid, vo.getPid())) { + long count = baseMapper.selectCount(new LambdaQueryWrapper().eq(SysDictTypeEntity::getPid, oldPid)); + if (count == 0) { + // 更新原先的上级,没有子节点 + this.updateHasChild(oldPid, 0); + } + } + + } + + /** + * 更新上级,有子节点 + * + * @param pid 上级ID + * @param hasChild 是否有子节点 + */ + private void updateHasChild(Long pid, Integer hasChild) { + SysDictTypeEntity entity = new SysDictTypeEntity(); + entity.setId(pid); + entity.setHasChild(hasChild); + baseMapper.updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + + @Override + public List getDictSql(Long id) { + SysDictTypeEntity entity = this.getById(id); + try { + return sysDictDataDao.getListForSql(entity.getDictSql()); + } catch (Exception e) { + throw new ServerException("动态SQL执行失败,请检查SQL是否正确!"); + } + } + + @Override + public List getDictList() { + // 全部字典类型列表 + List typeList = this.list(Wrappers.emptyWrapper()); + + // 全部字典数据列表 + QueryWrapper query = new QueryWrapper().orderByAsc("sort"); + List dataList = sysDictDataDao.selectList(query); + + // 全部字典列表 + List dictList = new ArrayList<>(typeList.size()); + for (SysDictTypeEntity type : typeList) { + SysDictVO dict = new SysDictVO(); + dict.setDictType(type.getDictType()); + + for (SysDictDataEntity data : dataList) { + if (type.getId().equals(data.getDictTypeId())) { + dict.getDataList().add(new SysDictVO.DictData(data.getDictLabel(), data.getDictValue(), data.getLabelClass(), null)); + } + } + + // 数据来源动态SQL + if (type.getDictSource() == DictSourceEnum.SQL.getValue()) { + // 增加动态列表 + String sql = type.getDictSql(); + try { + dict.setDataList(sysDictDataDao.getListForSql(sql)); + } catch (Exception e) { + log.error("增加动态字典异常: type=" + type, e); + } + } + + dictList.add(dict); + } + + return dictList; + } + + @Override + public void afterPropertiesSet() { + refreshTransCache(); + } + + public void refreshTransCache() { + // 异步不阻塞主线程,不会 增加启动用时 + CompletableFuture.supplyAsync(() -> { + // 获取所有的字典项数据 + List dataList = sysDictDataDao.selectList(new LambdaQueryWrapper<>()); + // 根据类型分组 + Map> dictTypeDataMap = dataList.stream().collect(Collectors + .groupingBy(SysDictDataEntity::getDictTypeId)); + List dictTypeEntities = super.list(); + for (SysDictTypeEntity dictTypeEntity : dictTypeEntities) { + if (dictTypeDataMap.containsKey(dictTypeEntity.getId())) { + try { + dictionaryTransService.refreshCache(dictTypeEntity.getDictType(), dictTypeDataMap.get(dictTypeEntity.getId()) + .stream().collect(Collectors.toMap(SysDictDataEntity::getDictValue, SysDictDataEntity::getDictLabel))); + } catch (Exception e) { + log.error("刷新字典缓存异常: type=" + dictTypeEntity, e); + } + } else { + try { + dictionaryTransService.refreshCache(dictTypeEntity.getDictType(), sysDictDataDao.getListForSql(dictTypeEntity.getDictSql()) + .stream().collect(Collectors.toMap(SysDictVO.DictData::getDictValue, SysDictVO.DictData::getDictLabel))); + } catch (Exception e) { + log.error("刷新动态SQL字典缓存异常: type=" + dictTypeEntity, e); + } + } + } + return null; + }); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysLogLoginServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysLogLoginServiceImpl.java new file mode 100644 index 0000000..ee556bd --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysLogLoginServiceImpl.java @@ -0,0 +1,84 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fhs.trans.service.impl.TransService; +import jakarta.servlet.http.HttpServletRequest; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import com.bdzl.framework.common.utils.ExcelUtils; +import com.bdzl.framework.common.utils.HttpContextUtils; +import com.bdzl.framework.common.utils.IpUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysLogLoginConvert; +import com.bdzl.system.dao.SysLogLoginDao; +import com.bdzl.system.entity.SysLogLoginEntity; +import com.bdzl.system.query.SysLogLoginQuery; +import com.bdzl.system.service.SysLogLoginService; +import com.bdzl.system.vo.SysLogLoginVO; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysLogLoginServiceImpl extends BaseServiceImpl implements SysLogLoginService { + private final TransService transService; + + @Override + public PageResult page(SysLogLoginQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysLogLoginConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(SysLogLoginQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StrUtil.isNotBlank(query.getUsername()), SysLogLoginEntity::getUsername, query.getUsername()); + wrapper.like(StrUtil.isNotBlank(query.getAddress()), SysLogLoginEntity::getAddress, query.getAddress()); + wrapper.like(query.getStatus() != null, SysLogLoginEntity::getStatus, query.getStatus()); + wrapper.orderByDesc(SysLogLoginEntity::getId); + + return wrapper; + } + + @Override + public void save(String username, Integer status, Integer operation) { + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + assert request != null; + String userAgent = request.getHeader(HttpHeaders.USER_AGENT); + String ip = IpUtils.getIpAddr(request); + String address = IpUtils.getAddressByIP(ip); + + SysLogLoginEntity entity = new SysLogLoginEntity(); + entity.setUsername(username); + entity.setStatus(status); + entity.setOperation(operation); + entity.setIp(ip); + entity.setAddress(address); + entity.setUserAgent(userAgent); + + baseMapper.insert(entity); + } + + @Override + @SneakyThrows + public void export() { + List list = list(); + List sysLogLoginVOS = SysLogLoginConvert.INSTANCE.convertList(list); + transService.transBatch(sysLogLoginVOS); + // 写到浏览器打开 + ExcelUtils.excelExport(SysLogLoginVO.class, "登录日志", null, sysLogLoginVOS); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysLogOperateServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysLogOperateServiceImpl.java new file mode 100644 index 0000000..03d405d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysLogOperateServiceImpl.java @@ -0,0 +1,83 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import jakarta.annotation.PostConstruct; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.cache.RedisCache; +import com.bdzl.framework.common.cache.RedisKeys; +import com.bdzl.framework.common.utils.ExceptionUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.framework.operatelog.dto.OperateLogDTO; +import com.bdzl.system.convert.SysLogOperateConvert; +import com.bdzl.system.dao.SysLogOperateDao; +import com.bdzl.system.entity.SysLogOperateEntity; +import com.bdzl.system.query.SysLogOperateQuery; +import com.bdzl.system.service.SysLogOperateService; +import com.bdzl.system.vo.SysLogOperateVO; +import org.springframework.stereotype.Service; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysLogOperateServiceImpl extends BaseServiceImpl implements SysLogOperateService { + private final RedisCache redisCache; + + @Override + public PageResult page(SysLogOperateQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysLogOperateConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(SysLogOperateQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(query.getStatus() != null, SysLogOperateEntity::getStatus, query.getStatus()); + wrapper.like(StrUtil.isNotBlank(query.getRealName()), SysLogOperateEntity::getRealName, query.getRealName()); + wrapper.like(StrUtil.isNotBlank(query.getModule()), SysLogOperateEntity::getModule, query.getModule()); + wrapper.like(StrUtil.isNotBlank(query.getReqUri()), SysLogOperateEntity::getReqUri, query.getReqUri()); + wrapper.orderByDesc(SysLogOperateEntity::getId); + return wrapper; + } + + /** + * 启动项目时,从Redis队列获取操作日志并保存 + */ + @PostConstruct + public void saveLog() { + ScheduledExecutorService scheduledService = ThreadUtil.createScheduledExecutor(1); + + // 每隔10秒钟,执行一次 + scheduledService.scheduleWithFixedDelay(() -> { + try { + String key = RedisKeys.getLogKey(); + // 每次插入10条 + int count = 10; + for (int i = 0; i < count; i++) { + OperateLogDTO log = (OperateLogDTO) redisCache.rightPop(key); + if (log == null) { + return; + } + + SysLogOperateEntity entity = BeanUtil.copyProperties(log, SysLogOperateEntity.class); + baseMapper.insert(entity); + } + } catch (Exception e) { + log.error("SysLogOperateServiceImpl.saveLog Error:" + ExceptionUtils.getExceptionMessage(e)); + } + }, 1, 10, TimeUnit.SECONDS); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMailConfigServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMailConfigServiceImpl.java new file mode 100644 index 0000000..fc00800 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMailConfigServiceImpl.java @@ -0,0 +1,91 @@ +package com.bdzl.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.email.config.EmailConfig; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.cache.EmailConfigCache; +import com.bdzl.system.convert.SysMailConfigConvert; +import com.bdzl.system.dao.SysMailConfigDao; +import com.bdzl.system.entity.SysMailConfigEntity; +import com.bdzl.system.query.SysMailConfigQuery; +import com.bdzl.system.service.SysMailConfigService; +import com.bdzl.system.vo.SysMailConfigVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 邮件配置 + * + * @author 阿沐 babamu@126.com + */ +@Service +@AllArgsConstructor +public class SysMailConfigServiceImpl extends BaseServiceImpl implements SysMailConfigService { + private final EmailConfigCache emailConfigCache; + + @Override + public PageResult page(SysMailConfigQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysMailConfigConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + @Override + public List list(Integer platform) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(platform != null, SysMailConfigEntity::getPlatform, platform); + + List list = baseMapper.selectList(wrapper); + return SysMailConfigConvert.INSTANCE.convertList(list); + } + + @Override + public List listByEnable() { + // 从缓存读取 + List cacheList = emailConfigCache.list(); + + // 如果缓存没有,则从DB读取,然后保存到缓存里 + if (cacheList == null) { + List list = this.list(new LambdaQueryWrapper().in(SysMailConfigEntity::getStatus, Constant.ENABLE)); + + cacheList = SysMailConfigConvert.INSTANCE.convertList2(list); + emailConfigCache.save(cacheList); + } + + return cacheList; + } + + private LambdaQueryWrapper getWrapper(SysMailConfigQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(query.getPlatform() != null, SysMailConfigEntity::getPlatform, query.getPlatform()); + return wrapper; + } + + @Override + public void save(SysMailConfigVO vo) { + SysMailConfigEntity entity = SysMailConfigConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(SysMailConfigVO vo) { + SysMailConfigEntity entity = SysMailConfigConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMailLogServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMailLogServiceImpl.java new file mode 100644 index 0000000..e3c3fe9 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMailLogServiceImpl.java @@ -0,0 +1,52 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysMailLogConvert; +import com.bdzl.system.dao.SysMailLogDao; +import com.bdzl.system.entity.SysMailLogEntity; +import com.bdzl.system.query.SysMailLogQuery; +import com.bdzl.system.service.SysMailLogService; +import com.bdzl.system.vo.SysMailLogVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +@Service +@AllArgsConstructor +public class SysMailLogServiceImpl extends BaseServiceImpl implements SysMailLogService { + + @Override + public PageResult page(SysMailLogQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysMailLogConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(SysMailLogQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(query.getPlatform() != null, SysMailLogEntity::getPlatform, query.getPlatform()); + wrapper.like(StrUtil.isNotBlank(query.getMailFrom()), SysMailLogEntity::getMailFrom, query.getMailFrom()); + wrapper.orderByDesc(SysMailLogEntity::getId); + + return wrapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMenuServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..87720be --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,119 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.TreeUtils; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.framework.security.utils.PreAuthorizeUtil; +import com.bdzl.system.convert.SysMenuConvert; +import com.bdzl.system.dao.SysMenuDao; +import com.bdzl.system.entity.SysMenuEntity; +import com.bdzl.system.enums.SuperAdminEnum; +import com.bdzl.system.service.SysMenuService; +import com.bdzl.system.service.SysRoleMenuService; +import com.bdzl.system.vo.SysMenuVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 菜单管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysMenuServiceImpl extends BaseServiceImpl implements SysMenuService { + private final SysRoleMenuService sysRoleMenuService; + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(SysMenuVO vo) { + SysMenuEntity entity = SysMenuConvert.INSTANCE.convert(vo); + + // 保存菜单 + baseMapper.insert(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysMenuVO vo) { + SysMenuEntity entity = SysMenuConvert.INSTANCE.convert(vo); + + // 上级菜单不能为自己 + if (entity.getId().equals(entity.getPid())) { + throw new ServerException("上级菜单不能为自己"); + } + + // 更新菜单 + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + // 删除菜单 + removeById(id); + + // 删除角色菜单关系 + sysRoleMenuService.deleteByMenuId(id); + } + + @Override + public List getMenuList(Integer type) { + List menuList = baseMapper.getMenuList(type); + + return TreeUtils.build(SysMenuConvert.INSTANCE.convertList(menuList)); + } + + @Override + public List getUserMenuList(UserDetail user, Integer type) { + List menuList; + + // 系统管理员,拥有最高权限 + if (user.getSuperAdmin().equals(SuperAdminEnum.YES.getValue())) { + menuList = baseMapper.getMenuList(type); + } else { + menuList = baseMapper.getUserMenuList(user.getId(), type); + } + + return TreeUtils.build(SysMenuConvert.INSTANCE.convertList(menuList)); + } + + @Override + public Long getSubMenuCount(Long pid) { + return count(new LambdaQueryWrapper().eq(SysMenuEntity::getPid, pid)); + } + + @Override + public Set getUserAuthority(UserDetail user) { + // 系统管理员,拥有最高权限 + List authorityList; + if (user.getSuperAdmin().equals(SuperAdminEnum.YES.getValue())) { + // authorityList = baseMapper.getAuthorityList(); + authorityList = PreAuthorizeUtil.getPreAuthorizeList(); + } else { + authorityList = baseMapper.getUserAuthorityList(user.getId()); + } + + // 用户权限列表 + Set permsSet = new HashSet<>(); + for (String authority : authorityList) { + if (StrUtil.isBlank(authority)) { + continue; + } + permsSet.addAll(Arrays.asList(authority.trim().split(","))); + } + + return permsSet; + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysOrgServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysOrgServiceImpl.java new file mode 100644 index 0000000..2c37085 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysOrgServiceImpl.java @@ -0,0 +1,128 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.TreeUtils; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysOrgConvert; +import com.bdzl.system.dao.SysOrgDao; +import com.bdzl.system.dao.SysUserDao; +import com.bdzl.system.entity.SysOrgEntity; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.service.SysOrgService; +import com.bdzl.system.vo.SysOrgVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 机构管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysOrgServiceImpl extends BaseServiceImpl implements SysOrgService { + private final SysUserDao sysUserDao; + + @Override + public List getList() { + Map params = new HashMap<>(); + + // 数据权限 + params.put(Constant.DATA_SCOPE, getDataScope("t1", "id")); + + // 机构列表 + List entityList = baseMapper.getList(params); + + return TreeUtils.build(SysOrgConvert.INSTANCE.convertList(entityList)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(SysOrgVO vo) { + SysOrgEntity entity = SysOrgConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysOrgVO vo) { + SysOrgEntity entity = SysOrgConvert.INSTANCE.convert(vo); + + // 上级机构不能为自身 + if (entity.getId().equals(entity.getPid())) { + throw new ServerException("上级机构不能为自身"); + } + + // 上级机构不能为下级 + List subOrgList = getSubOrgIdList(entity.getId()); + if (subOrgList.contains(entity.getPid())) { + throw new ServerException("上级机构不能为下级"); + } + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + // 判断是否有子机构 + long orgCount = count(new QueryWrapper().eq("pid", id)); + if (orgCount > 0) { + throw new ServerException("请先删除子机构"); + } + + // 判断机构下面是否有用户 + long userCount = sysUserDao.selectCount(new QueryWrapper().eq("org_id", id)); + if (userCount > 0) { + throw new ServerException("机构下面有用户,不能删除"); + } + + // 删除 + removeById(id); + } + + @Override + public List getSubOrgIdList(Long id) { + // 所有机构的id、pid列表 + List orgList = baseMapper.getIdAndPidList(); + + // 递归查询所有子机构ID列表 + List subIdList = new ArrayList<>(); + getTree(id, orgList, subIdList); + + // 本机构也添加进去 + subIdList.add(id); + + return subIdList; + } + + @Override + public List getNameList(List idList) { + if (idList.isEmpty()) { + return null; + } + + return baseMapper.selectBatchIds(idList).stream().map(SysOrgEntity::getName).toList(); + } + + private void getTree(Long id, List orgList, List subIdList) { + for (SysOrgEntity org : orgList) { + if (ObjectUtil.equals(org.getPid(), id)) { + getTree(org.getId(), orgList, subIdList); + + subIdList.add(org.getId()); + } + } + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysParamsServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysParamsServiceImpl.java new file mode 100644 index 0000000..adbc84c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysParamsServiceImpl.java @@ -0,0 +1,146 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.JsonUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.cache.SysParamsCache; +import com.bdzl.system.convert.SysParamsConvert; +import com.bdzl.system.dao.SysParamsDao; +import com.bdzl.system.entity.SysParamsEntity; +import com.bdzl.system.query.SysParamsQuery; +import com.bdzl.system.service.SysParamsService; +import com.bdzl.system.vo.SysParamsVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysParamsServiceImpl extends BaseServiceImpl implements SysParamsService { + private final SysParamsCache sysParamsCache; + + @Override + public PageResult page(SysParamsQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysParamsConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + private LambdaQueryWrapper getWrapper(SysParamsQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + + wrapper.like(StrUtil.isNotBlank(query.getParamKey()), SysParamsEntity::getParamKey, query.getParamKey()); + wrapper.eq(StrUtil.isNotBlank(query.getParamValue()), SysParamsEntity::getParamValue, query.getParamValue()); + wrapper.eq(query.getParamType() != null, SysParamsEntity::getParamType, query.getParamType()); + wrapper.orderByDesc(SysParamsEntity::getId); + + return wrapper; + } + + @Override + public void save(SysParamsVO vo) { + // 判断 参数键 是否存在 + boolean exist = baseMapper.isExist(vo.getParamKey()); + if (exist) { + throw new ServerException("参数键已存在"); + } + + SysParamsEntity entity = SysParamsConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + + // 保存到缓存 + sysParamsCache.save(entity.getParamKey(), entity.getParamValue()); + } + + @Override + public void update(SysParamsVO vo) { + SysParamsEntity entity = baseMapper.selectById(vo.getId()); + + // 如果 参数键 修改过 + if (!StrUtil.equalsIgnoreCase(entity.getParamKey(), vo.getParamKey())) { + // 判断 新参数键 是否存在 + boolean exist = baseMapper.isExist(vo.getParamKey()); + if (exist) { + throw new ServerException("参数键已存在"); + } + + // 删除修改前的缓存 + sysParamsCache.del(entity.getParamKey()); + } + + // 修改数据 + updateById(SysParamsConvert.INSTANCE.convert(vo)); + + // 保存到缓存 + sysParamsCache.save(vo.getParamKey(), vo.getParamValue()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + // 查询列表 + List list = baseMapper.selectBatchIds(idList); + + // 删除数据 + removeByIds(idList); + + // 删除缓存 + String[] keys = list.stream().map(SysParamsEntity::getParamKey).toArray(String[]::new); + sysParamsCache.del(keys); + } + + @Override + public String getString(String paramKey) { + String value = sysParamsCache.get(paramKey); + if (StrUtil.isNotBlank(value)) { + return value; + } + + // 如果缓存没有,则查询数据库 + SysParamsEntity entity = baseMapper.get(paramKey); + if (entity == null) { + throw new ServerException("参数值不存在,paramKey:" + paramKey); + } + + // 保存到缓存 + sysParamsCache.save(entity.getParamKey(), entity.getParamValue()); + + return entity.getParamValue(); + } + + @Override + public int getInt(String paramKey) { + String value = getString(paramKey); + + return Integer.parseInt(value); + } + + @Override + public boolean getBoolean(String paramKey) { + String value = getString(paramKey); + + return Boolean.parseBoolean(value); + } + + @Override + public T getJSONObject(String paramKey, Class valueType) { + String value = getString(paramKey); + + return JsonUtils.parseObject(value, valueType); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysPostServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000..f0396d5 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,93 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysPostConvert; +import com.bdzl.system.dao.SysPostDao; +import com.bdzl.system.entity.SysPostEntity; +import com.bdzl.system.query.SysPostQuery; +import com.bdzl.system.service.SysPostService; +import com.bdzl.system.service.SysUserPostService; +import com.bdzl.system.vo.SysPostVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 岗位管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysPostServiceImpl extends BaseServiceImpl implements SysPostService { + private final SysUserPostService sysUserPostService; + + @Override + public PageResult page(SysPostQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysPostConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + @Override + public List getList() { + SysPostQuery query = new SysPostQuery(); + //正常岗位列表 + query.setStatus(1); + List entityList = baseMapper.selectList(getWrapper(query)); + + return SysPostConvert.INSTANCE.convertList(entityList); + } + + @Override + public List getNameList(List idList) { + if (idList.isEmpty()) { + return null; + } + + return baseMapper.selectBatchIds(idList).stream().map(SysPostEntity::getPostName).toList(); + } + + private Wrapper getWrapper(SysPostQuery query) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StrUtil.isNotBlank(query.getPostCode()), SysPostEntity::getPostCode, query.getPostCode()); + wrapper.like(StrUtil.isNotBlank(query.getPostName()), SysPostEntity::getPostName, query.getPostName()); + wrapper.eq(query.getStatus() != null, SysPostEntity::getStatus, query.getStatus()); + wrapper.orderByAsc(SysPostEntity::getSort); + + return wrapper; + } + + @Override + public void save(SysPostVO vo) { + SysPostEntity entity = SysPostConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(SysPostVO vo) { + SysPostEntity entity = SysPostConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + // 删除岗位 + removeByIds(idList); + + // 删除岗位用户关系 + sysUserPostService.deleteByPostIdList(idList); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleDataScopeServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleDataScopeServiceImpl.java new file mode 100644 index 0000000..0f5305a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleDataScopeServiceImpl.java @@ -0,0 +1,66 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.dao.SysRoleDataScopeDao; +import com.bdzl.system.entity.SysRoleDataScopeEntity; +import com.bdzl.system.service.SysRoleDataScopeService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 角色数据权限 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +public class SysRoleDataScopeServiceImpl extends BaseServiceImpl + implements SysRoleDataScopeService { + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrUpdate(Long roleId, List orgIdList) { + // 数据库机构ID列表 + List dbOrgIdList = getOrgIdList(roleId); + + // 需要新增的机构ID + Collection insertOrgIdList = CollUtil.subtract(orgIdList, dbOrgIdList); + if (CollUtil.isNotEmpty(insertOrgIdList)){ + List orgList = insertOrgIdList.stream().map(orgId -> { + SysRoleDataScopeEntity entity = new SysRoleDataScopeEntity(); + entity.setOrgId(orgId); + entity.setRoleId(roleId); + return entity; + }).collect(Collectors.toList()); + + // 批量新增 + saveBatch(orgList); + } + + // 需要删除的机构ID + Collection deleteOrgIdList = CollUtil.subtract(dbOrgIdList, orgIdList); + if (CollUtil.isNotEmpty(deleteOrgIdList)){ + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysRoleDataScopeEntity::getRoleId, roleId); + queryWrapper.in(SysRoleDataScopeEntity::getOrgId, deleteOrgIdList); + + remove(queryWrapper); + } + } + + @Override + public List getOrgIdList(Long roleId) { + return baseMapper.getOrgIdList(roleId); + } + + @Override + public void deleteByRoleIdList(List roleIdList) { + remove(new LambdaQueryWrapper().in(SysRoleDataScopeEntity::getRoleId, roleIdList)); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleMenuServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleMenuServiceImpl.java new file mode 100644 index 0000000..de97b98 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleMenuServiceImpl.java @@ -0,0 +1,71 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.dao.SysRoleMenuDao; +import com.bdzl.system.entity.SysRoleMenuEntity; +import com.bdzl.system.service.SysRoleMenuService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + + +/** + * 角色与菜单对应关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +public class SysRoleMenuServiceImpl extends BaseServiceImpl implements SysRoleMenuService { + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrUpdate(Long roleId, List menuIdList) { + // 数据库菜单ID列表 + List dbMenuIdList = getMenuIdList(roleId); + + // 需要新增的菜单ID + Collection insertMenuIdList = CollUtil.subtract(menuIdList, dbMenuIdList); + if (CollUtil.isNotEmpty(insertMenuIdList)){ + List menuList = insertMenuIdList.stream().map(menuId -> { + SysRoleMenuEntity entity = new SysRoleMenuEntity(); + entity.setMenuId(menuId); + entity.setRoleId(roleId); + return entity; + }).collect(Collectors.toList()); + + // 批量新增 + saveBatch(menuList); + } + + // 需要删除的菜单ID + Collection deleteMenuIdList = CollUtil.subtract(dbMenuIdList, menuIdList); + if (CollUtil.isNotEmpty(deleteMenuIdList)){ + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + remove(queryWrapper.eq(SysRoleMenuEntity::getRoleId, roleId).in(SysRoleMenuEntity::getMenuId, deleteMenuIdList)); + } + } + + @Override + public List getMenuIdList(Long roleId){ + return baseMapper.getMenuIdList(roleId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteByRoleIdList(List roleIdList) { + remove(new LambdaQueryWrapper().in(SysRoleMenuEntity::getRoleId, roleIdList)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteByMenuId(Long menuId) { + remove(new LambdaQueryWrapper().eq(SysRoleMenuEntity::getMenuId, menuId)); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..84d8962 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,137 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.bdzl.system.service.*; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysRoleConvert; +import com.bdzl.system.dao.SysRoleDao; +import com.bdzl.system.entity.SysRoleEntity; +import com.bdzl.system.enums.DataScopeEnum; +import com.bdzl.system.query.SysRoleQuery; +import com.bdzl.system.vo.SysRoleDataScopeVO; +import com.bdzl.system.vo.SysRoleVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.List; + +/** + * 角色 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysRoleServiceImpl extends BaseServiceImpl implements SysRoleService { + private final SysRoleMenuService sysRoleMenuService; + private final SysRoleDataScopeService sysRoleDataScopeService; + private final SysUserRoleService sysUserRoleService; + private final SysUserTokenService sysUserTokenService; + + @Override + public PageResult page(SysRoleQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysRoleConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + @Override + public List getList(SysRoleQuery query) { + List entityList = baseMapper.selectList(getWrapper(query)); + + return SysRoleConvert.INSTANCE.convertList(entityList); + } + + private Wrapper getWrapper(SysRoleQuery query) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StrUtil.isNotBlank(query.getName()), SysRoleEntity::getName, query.getName()); + + // 数据权限 + dataScopeWrapper(wrapper); + + return wrapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(SysRoleVO vo) { + SysRoleEntity entity = SysRoleConvert.INSTANCE.convert(vo); + + // 保存角色 + entity.setDataScope(DataScopeEnum.SELF.getValue()); + baseMapper.insert(entity); + + // 保存角色菜单关系 + sysRoleMenuService.saveOrUpdate(entity.getId(), vo.getMenuIdList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysRoleVO vo) { + SysRoleEntity entity = SysRoleConvert.INSTANCE.convert(vo); + + // 更新角色 + updateById(entity); + + // 更新角色菜单关系 + sysRoleMenuService.saveOrUpdate(entity.getId(), vo.getMenuIdList()); + + // 更新角色对应用户的缓存权限 + sysUserTokenService.updateCacheAuthByRoleId(entity.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void dataScope(SysRoleDataScopeVO vo) { + SysRoleEntity entity = getById(vo.getId()); + entity.setDataScope(vo.getDataScope()); + // 更新角色 + updateById(entity); + + // 更新角色数据权限关系 + if (vo.getDataScope().equals(DataScopeEnum.CUSTOM.getValue())) { + sysRoleDataScopeService.saveOrUpdate(entity.getId(), vo.getOrgIdList()); + } else { + sysRoleDataScopeService.deleteByRoleIdList(Collections.singletonList(vo.getId())); + } + + // 更新角色对应用户的缓存权限 + sysUserTokenService.updateCacheAuthByRoleId(entity.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + // 删除角色 + removeByIds(idList); + + // 删除用户角色关系 + sysUserRoleService.deleteByRoleIdList(idList); + + // 删除角色菜单关系 + sysRoleMenuService.deleteByRoleIdList(idList); + + // 删除角色数据权限关系 + sysRoleDataScopeService.deleteByRoleIdList(idList); + + // 更新角色对应用户的缓存权限 + idList.forEach(sysUserTokenService::updateCacheAuthByRoleId); + } + + @Override + public List getNameList(List idList) { + if (idList.isEmpty()) { + return null; + } + + return baseMapper.selectBatchIds(idList).stream().map(SysRoleEntity::getName).toList(); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysSmsConfigServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysSmsConfigServiceImpl.java new file mode 100644 index 0000000..d5cf13f --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysSmsConfigServiceImpl.java @@ -0,0 +1,100 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.sms.config.SmsConfig; +import com.bdzl.system.cache.SmsConfigCache; +import com.bdzl.system.convert.SysSmsConfigConvert; +import com.bdzl.system.dao.SysSmsConfigDao; +import com.bdzl.system.entity.SysSmsConfigEntity; +import com.bdzl.system.query.SysSmsConfigQuery; +import com.bdzl.system.service.SysSmsConfigService; +import com.bdzl.system.vo.SysSmsConfigVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 短信配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysSmsConfigServiceImpl extends BaseServiceImpl implements SysSmsConfigService { + private final SmsConfigCache smsConfigCache; + + @Override + public PageResult page(SysSmsConfigQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysSmsConfigConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + @Override + public List list(Integer platform) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(platform != null, SysSmsConfigEntity::getPlatform, platform); + + List list = baseMapper.selectList(wrapper); + return SysSmsConfigConvert.INSTANCE.convertList(list); + } + + private LambdaQueryWrapper getWrapper(SysSmsConfigQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(query.getPlatform() != null, SysSmsConfigEntity::getPlatform, query.getPlatform()); + wrapper.like(StrUtil.isNotBlank(query.getGroupName()), SysSmsConfigEntity::getGroupName, query.getGroupName()); + return wrapper; + } + + @Override + public List listByEnable() { + // 从缓存读取 + List cacheList = smsConfigCache.list(); + + // 如果缓存没有,则从DB读取,然后保存到缓存里 + if (cacheList == null) { + List list = this.list(new LambdaQueryWrapper().in(SysSmsConfigEntity::getStatus, Constant.ENABLE)); + + cacheList = SysSmsConfigConvert.INSTANCE.convertList2(list); + smsConfigCache.save(cacheList); + } + + return cacheList; + } + + @Override + public void save(SysSmsConfigVO vo) { + SysSmsConfigEntity entity = SysSmsConfigConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + + smsConfigCache.delete(); + } + + @Override + public void update(SysSmsConfigVO vo) { + SysSmsConfigEntity entity = SysSmsConfigConvert.INSTANCE.convert(vo); + + updateById(entity); + + smsConfigCache.delete(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + + smsConfigCache.delete(); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysSmsLogServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysSmsLogServiceImpl.java new file mode 100644 index 0000000..ffa03ed --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysSmsLogServiceImpl.java @@ -0,0 +1,53 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysSmsLogConvert; +import com.bdzl.system.dao.SysSmsLogDao; +import com.bdzl.system.entity.SysSmsLogEntity; +import com.bdzl.system.query.SysSmsLogQuery; +import com.bdzl.system.service.SysSmsLogService; +import com.bdzl.system.vo.SysSmsLogVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysSmsLogServiceImpl extends BaseServiceImpl implements SysSmsLogService { + + @Override + public PageResult page(SysSmsLogQuery query) { + IPage page = baseMapper.selectPage(getPage(query), getWrapper(query)); + + return new PageResult<>(SysSmsLogConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + + private LambdaQueryWrapper getWrapper(SysSmsLogQuery query) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(query.getPlatform() != null, SysSmsLogEntity::getPlatform, query.getPlatform()); + wrapper.like(StrUtil.isNotBlank(query.getMobile()), SysSmsLogEntity::getMobile, query.getMobile()); + wrapper.orderByDesc(SysSmsLogEntity::getId); + return wrapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysThirdLoginConfigServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysThirdLoginConfigServiceImpl.java new file mode 100644 index 0000000..a38051c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysThirdLoginConfigServiceImpl.java @@ -0,0 +1,97 @@ +package com.bdzl.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.request.*; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.query.Query; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysThirdLoginConfigConvert; +import com.bdzl.system.dao.SysThirdLoginConfigDao; +import com.bdzl.system.entity.SysThirdLoginConfigEntity; +import com.bdzl.system.enums.ThirdLoginEnum; +import com.bdzl.system.service.SysThirdLoginConfigService; +import com.bdzl.system.vo.SysThirdLoginConfigVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysThirdLoginConfigServiceImpl extends BaseServiceImpl implements SysThirdLoginConfigService { + + @Override + public PageResult page(Query query) { + IPage page = baseMapper.selectPage(getPage(query), Wrappers.lambdaQuery()); + + return new PageResult<>(SysThirdLoginConfigConvert.INSTANCE.convertList(page.getRecords()), page.getTotal()); + } + + @Override + public void save(SysThirdLoginConfigVO vo) { + SysThirdLoginConfigEntity entity = SysThirdLoginConfigConvert.INSTANCE.convert(vo); + + baseMapper.insert(entity); + } + + @Override + public void update(SysThirdLoginConfigVO vo) { + SysThirdLoginConfigEntity entity = SysThirdLoginConfigConvert.INSTANCE.convert(vo); + + updateById(entity); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(List idList) { + removeByIds(idList); + } + + @Override + public AuthRequest getAuthRequest(String openType) { + SysThirdLoginConfigEntity config = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysThirdLoginConfigEntity::getOpenType, openType)); + + if (config == null) { + throw new ServerException("未配置第三方登录,请配置后再尝试"); + } + + AuthRequest authRequest = switch (ThirdLoginEnum.toEnum(openType)) { + case WECHAT_WORK -> new AuthWeChatEnterpriseQrcodeRequest(AuthConfig.builder() + .clientId(config.getClientId()) + .clientSecret(config.getClientSecret()) + .redirectUri(config.getRedirectUri()) + .agentId(config.getAgentId()) + .build()); + case DING_TALK -> new AuthDingTalkRequest(AuthConfig.builder() + .clientId(config.getClientId()) + .clientSecret(config.getClientSecret()) + .redirectUri(config.getRedirectUri()) + .build()); + case FEI_SHU -> new AuthFeishuRequest(AuthConfig.builder() + .clientId(config.getClientId()) + .clientSecret(config.getClientSecret()) + .redirectUri(config.getRedirectUri()) + .build()); + case WECHAT_OPEN -> new AuthWeChatOpenRequest(AuthConfig.builder() + .clientId(config.getClientId()) + .clientSecret(config.getClientSecret()) + .redirectUri(config.getRedirectUri()) + .build()); + }; + + return authRequest; + } + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysThirdLoginServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysThirdLoginServiceImpl.java new file mode 100644 index 0000000..d3f3c59 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysThirdLoginServiceImpl.java @@ -0,0 +1,62 @@ +package com.bdzl.system.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import me.zhyd.oauth.model.AuthUser; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.convert.SysThirdLoginConvert; +import com.bdzl.system.dao.SysThirdLoginDao; +import com.bdzl.system.entity.SysThirdLoginEntity; +import com.bdzl.system.service.SysThirdLoginService; +import com.bdzl.system.vo.SysThirdLoginVO; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysThirdLoginServiceImpl extends BaseServiceImpl implements SysThirdLoginService { + + @Override + public List listByUserId(Long userId) { + List list = baseMapper.selectList( + Wrappers.lambdaQuery().eq(SysThirdLoginEntity::getUserId, userId)); + + return SysThirdLoginConvert.INSTANCE.convertList(list); + } + + @Override + public void unBind(Long userId, String openType) { + baseMapper.delete(Wrappers.lambdaQuery(). + eq(SysThirdLoginEntity::getUserId, userId).eq(SysThirdLoginEntity::getOpenType, openType)); + } + + @Override + public void bind(Long userId, String openType, AuthUser authUser) { + SysThirdLoginEntity entity = new SysThirdLoginEntity(); + entity.setUserId(userId); + entity.setOpenType(openType); + entity.setOpenId(authUser.getUuid()); + entity.setUsername(authUser.getUsername()); + + baseMapper.insert(entity); + } + + @Override + public Long getUserIdByOpenTypeAndOpenId(String openType, String openId) { + SysThirdLoginEntity entity = baseMapper.selectOne(Wrappers.lambdaQuery() + .eq(SysThirdLoginEntity::getOpenType, openType).eq(SysThirdLoginEntity::getOpenId, openId)); + if (entity == null) { + throw new ServerException("还未绑定用户,请先绑定用户"); + } + + return entity.getUserId(); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserDetailsServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserDetailsServiceImpl.java new file mode 100644 index 0000000..e98b4c2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserDetailsServiceImpl.java @@ -0,0 +1,87 @@ +package com.bdzl.system.service.impl; + +import lombok.AllArgsConstructor; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.system.dao.SysRoleDao; +import com.bdzl.system.dao.SysRoleDataScopeDao; +import com.bdzl.system.enums.DataScopeEnum; +import com.bdzl.system.enums.UserStatusEnum; +import com.bdzl.system.service.SysMenuService; +import com.bdzl.system.service.SysOrgService; +import com.bdzl.system.service.SysUserDetailsService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * 用户 UserDetails 信息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysUserDetailsServiceImpl implements SysUserDetailsService { + private final SysMenuService sysMenuService; + private final SysOrgService sysOrgService; + private final SysRoleDao sysRoleDao; + private final SysRoleDataScopeDao sysRoleDataScopeDao; + + @Override + public UserDetails getUserDetails(UserDetail userDetail) { + // 账号不可用 + if (userDetail.getStatus() == UserStatusEnum.DISABLE.getValue()) { + userDetail.setEnabled(false); + } + + // 数据权限范围 + List dataScopeList = getDataScope(userDetail); + userDetail.setDataScopeList(dataScopeList); + + // 用户权限列表 + Set authoritySet = sysMenuService.getUserAuthority(userDetail); + + // 用户角色编码列表 + List roleCodeList = sysRoleDao.geRoleCodeByUserId(userDetail.getId()); + roleCodeList.forEach(roleCode -> authoritySet.add("ROLE_" + roleCode)); + + userDetail.setAuthoritySet(authoritySet); + + return userDetail; + } + + private List getDataScope(UserDetail userDetail) { + Integer dataScope = sysRoleDao.getDataScopeByUserId(userDetail.getId()); + if (dataScope == null) { + return new ArrayList<>(); + } + + if (dataScope.equals(DataScopeEnum.ALL.getValue())) { + // 全部数据权限,则返回null + return null; + } else if (dataScope.equals(DataScopeEnum.ORG_AND_CHILD.getValue())) { + // 本机构及子机构数据 + List dataScopeList = sysOrgService.getSubOrgIdList(userDetail.getOrgId()); + // 自定义数据权限范围 + dataScopeList.addAll(sysRoleDataScopeDao.getDataScopeList(userDetail.getId())); + + return dataScopeList; + } else if (dataScope.equals(DataScopeEnum.ORG_ONLY.getValue())) { + // 本机构数据 + List dataScopeList = new ArrayList<>(); + dataScopeList.add(userDetail.getOrgId()); + // 自定义数据权限范围 + dataScopeList.addAll(sysRoleDataScopeDao.getDataScopeList(userDetail.getId())); + + return dataScopeList; + } else if (dataScope.equals(DataScopeEnum.CUSTOM.getValue())) { + // 自定义数据权限范围 + return sysRoleDataScopeDao.getDataScopeList(userDetail.getId()); + } + + return new ArrayList<>(); + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserPostServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserPostServiceImpl.java new file mode 100644 index 0000000..66956fe --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserPostServiceImpl.java @@ -0,0 +1,65 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.dao.SysUserPostDao; +import com.bdzl.system.entity.SysUserPostEntity; +import com.bdzl.system.service.SysUserPostService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 用户岗位关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +public class SysUserPostServiceImpl extends BaseServiceImpl implements SysUserPostService { + + @Override + public void saveOrUpdate(Long userId, List postIdList) { + // 数据库岗位ID列表 + List dbPostIdList = getPostIdList(userId); + + // 需要新增的岗位ID + Collection insertPostIdList = CollUtil.subtract(postIdList, dbPostIdList); + if (CollUtil.isNotEmpty(insertPostIdList)){ + List postList = insertPostIdList.stream().map(postId -> { + SysUserPostEntity entity = new SysUserPostEntity(); + entity.setUserId(userId); + entity.setPostId(postId); + return entity; + }).collect(Collectors.toList()); + + // 批量新增 + saveBatch(postList); + } + + // 需要删除的岗位ID + Collection deletePostIdList = CollUtil.subtract(dbPostIdList, postIdList); + if (CollUtil.isNotEmpty(deletePostIdList)){ + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + remove(queryWrapper.eq(SysUserPostEntity::getUserId, userId).in(SysUserPostEntity::getPostId, deletePostIdList)); + } + } + + @Override + public void deleteByPostIdList(List postIdList) { + remove(new LambdaQueryWrapper().in(SysUserPostEntity::getPostId, postIdList)); + } + + @Override + public void deleteByUserIdList(List userIdList) { + remove(new LambdaQueryWrapper().in(SysUserPostEntity::getUserId, userIdList)); + } + + @Override + public List getPostIdList(Long userId) { + return baseMapper.getPostIdList(userId); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserRoleServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 0000000..b3116a2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,99 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.AllArgsConstructor; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.system.dao.SysUserRoleDao; +import com.bdzl.system.entity.SysUserRoleEntity; +import com.bdzl.system.service.SysUserRoleService; +import com.bdzl.system.service.SysUserTokenService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 用户角色关系 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysUserRoleServiceImpl extends BaseServiceImpl implements SysUserRoleService { + private final SysUserTokenService sysUserTokenService; + + @Override + public void saveOrUpdate(Long userId, List roleIdList) { + // 数据库角色ID列表 + List dbRoleIdList = getRoleIdList(userId); + + // 需要新增的角色ID + Collection insertRoleIdList = CollUtil.subtract(roleIdList, dbRoleIdList); + if (CollUtil.isNotEmpty(insertRoleIdList)) { + List roleList = insertRoleIdList.stream().map(roleId -> { + SysUserRoleEntity entity = new SysUserRoleEntity(); + entity.setUserId(userId); + entity.setRoleId(roleId); + return entity; + }).collect(Collectors.toList()); + + // 批量新增 + saveBatch(roleList); + } + + // 需要删除的角色ID + Collection deleteRoleIdList = CollUtil.subtract(dbRoleIdList, roleIdList); + if (CollUtil.isNotEmpty(deleteRoleIdList)) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + remove(queryWrapper.eq(SysUserRoleEntity::getUserId, userId).in(SysUserRoleEntity::getRoleId, deleteRoleIdList)); + } + } + + @Override + public void saveUserList(Long roleId, List userIdList) { + List list = userIdList.stream().map(userId -> { + SysUserRoleEntity entity = new SysUserRoleEntity(); + entity.setUserId(userId); + entity.setRoleId(roleId); + return entity; + }).collect(Collectors.toList()); + + // 批量新增 + saveBatch(list); + + // 更新用户的缓存权限 + userIdList.forEach(sysUserTokenService::updateCacheAuthByUserId); + } + + @Override + public void deleteByRoleIdList(List roleIdList) { + remove(new LambdaQueryWrapper().in(SysUserRoleEntity::getRoleId, roleIdList)); + } + + @Override + public void deleteByUserIdList(List userIdList) { + remove(new LambdaQueryWrapper().in(SysUserRoleEntity::getUserId, userIdList)); + } + + @Override + public void deleteByUserIdList(Long roleId, List userIdList) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + remove(queryWrapper.eq(SysUserRoleEntity::getRoleId, roleId).in(SysUserRoleEntity::getUserId, userIdList)); + + // 更新用户的缓存权限 + userIdList.forEach(sysUserTokenService::updateCacheAuthByUserId); + } + + @Override + public List getRoleIdList(Long userId) { + return baseMapper.getRoleIdList(userId); + } + + @Override + public List getExistsUserIdList(Long roleId) { + return baseMapper.getExistsUserIdList(roleId); + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..d6e47ad --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,263 @@ +package com.bdzl.system.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fhs.trans.service.impl.TransService; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import com.bdzl.framework.common.constant.Constant; +import com.bdzl.framework.common.excel.ExcelFinishCallBack; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.common.utils.ExcelUtils; +import com.bdzl.framework.common.utils.PageResult; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.framework.security.cache.TokenStoreCache; +import com.bdzl.framework.security.user.SecurityUser; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.framework.security.utils.TokenUtils; +import com.bdzl.system.convert.SysUserConvert; +import com.bdzl.system.dao.SysUserDao; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.enums.SuperAdminEnum; +import com.bdzl.system.query.SysRoleUserQuery; +import com.bdzl.system.query.SysUserQuery; +import com.bdzl.system.service.SysUserPostService; +import com.bdzl.system.service.SysUserRoleService; +import com.bdzl.system.service.SysUserService; +import com.bdzl.system.service.SysUserTokenService; +import com.bdzl.system.vo.SysUserAvatarVO; +import com.bdzl.system.vo.SysUserBaseVO; +import com.bdzl.system.vo.SysUserExcelVO; +import com.bdzl.system.vo.SysUserVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 用户管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Service +@AllArgsConstructor +public class SysUserServiceImpl extends BaseServiceImpl implements SysUserService { + private final SysUserRoleService sysUserRoleService; + private final SysUserPostService sysUserPostService; + private final SysUserTokenService sysUserTokenService; + private final TokenStoreCache tokenStoreCache; + private final TransService transService; + + @Override + public PageResult page(SysUserQuery query) { + // 查询参数 + Map params = getParams(query); + + // 分页查询 + IPage page = getPage(query); + params.put(Constant.PAGE, page); + + // 数据列表 + List list = baseMapper.getList(params); + + return new PageResult<>(SysUserConvert.INSTANCE.convertList(list), page.getTotal()); + } + + private Map getParams(SysUserQuery query) { + Map params = new HashMap<>(); + params.put("username", query.getUsername()); + params.put("mobile", query.getMobile()); + params.put("gender", query.getGender()); + + // 数据权限 + params.put(Constant.DATA_SCOPE, getDataScope("t1", null)); + + // 机构过滤 + if (query.getOrgId() != null) { + params.put("orgList", query.getOrgId()); + } + + return params; + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(SysUserVO vo) { + SysUserEntity entity = SysUserConvert.INSTANCE.convert(vo); + entity.setSuperAdmin(SuperAdminEnum.NO.getValue()); + + // 判断用户名是否存在 + SysUserEntity user = baseMapper.getByUsername(entity.getUsername()); + if (user != null) { + throw new ServerException("用户名已经存在"); + } + + // 判断手机号是否存在 + user = baseMapper.getByMobile(entity.getMobile()); + if (user != null) { + throw new ServerException("手机号已经存在"); + } + + // 保存用户 + baseMapper.insert(entity); + + // 保存用户角色关系 + sysUserRoleService.saveOrUpdate(entity.getId(), vo.getRoleIdList()); + + // 更新用户岗位关系 + sysUserPostService.saveOrUpdate(entity.getId(), vo.getPostIdList()); + } + + @Override + public void update(SysUserVO vo) { + SysUserEntity entity = SysUserConvert.INSTANCE.convert(vo); + + // 判断用户名是否存在 + SysUserEntity user = baseMapper.getByUsername(entity.getUsername()); + if (user != null && !user.getId().equals(entity.getId())) { + throw new ServerException("用户名已经存在"); + } + + // 判断手机号是否存在 + user = baseMapper.getByMobile(entity.getMobile()); + if (user != null && !user.getId().equals(entity.getId())) { + throw new ServerException("手机号已经存在"); + } + + // 更新用户 + updateById(entity); + + // 更新用户角色关系 + sysUserRoleService.saveOrUpdate(entity.getId(), vo.getRoleIdList()); + + // 更新用户岗位关系 + sysUserPostService.saveOrUpdate(entity.getId(), vo.getPostIdList()); + + // 更新用户缓存权限 + sysUserTokenService.updateCacheAuthByUserId(entity.getId()); + } + + @Override + public void updateLoginInfo(SysUserBaseVO vo) { + SysUserEntity entity = SysUserConvert.INSTANCE.convert(vo); + // 设置登录用户ID + entity.setId(SecurityUser.getUserId()); + + // 判断手机号是否存在 + SysUserEntity user = baseMapper.getByMobile(entity.getMobile()); + if (user != null && !user.getId().equals(entity.getId())) { + throw new ServerException("手机号已经存在"); + } + + // 更新用户 + updateById(entity); + + // 更新缓存逻辑 + String accessToken = TokenUtils.getAccessToken(); + UserDetail cacheUser = tokenStoreCache.getUser(accessToken); + cacheUser.setRealName(vo.getRealName()); + cacheUser.setMobile(vo.getMobile()); + cacheUser.setEmail(vo.getEmail()); + cacheUser.setGender(vo.getGender()); + // 更新操作 + tokenStoreCache.updateUser(accessToken, cacheUser); + } + + @Override + public void updateAvatar(SysUserAvatarVO avatar) { + SysUserEntity entity = new SysUserEntity(); + entity.setId(SecurityUser.getUserId()); + entity.setAvatar(avatar.getAvatar()); + updateById(entity); + + // 更新缓存逻辑 + String accessToken = TokenUtils.getAccessToken(); + UserDetail cacheUser = tokenStoreCache.getUser(accessToken); + cacheUser.setAvatar(avatar.getAvatar()); + // 更新操作 + tokenStoreCache.updateUser(accessToken, cacheUser); + } + + @Override + public void delete(List idList) { + // 删除用户 + removeByIds(idList); + + // 删除用户角色关系 + sysUserRoleService.deleteByUserIdList(idList); + + // 删除用户岗位关系 + sysUserPostService.deleteByUserIdList(idList); + } + + @Override + public List getRealNameList(List idList) { + if (idList.isEmpty()) { + return null; + } + + return baseMapper.selectBatchIds(idList).stream().map(SysUserEntity::getRealName).toList(); + } + + @Override + public SysUserVO getByMobile(String mobile) { + SysUserEntity user = baseMapper.getByMobile(mobile); + + return SysUserConvert.INSTANCE.convert(user); + } + + @Override + public void updatePassword(Long id, String newPassword) { + // 修改密码 + SysUserEntity user = getById(id); + user.setPassword(newPassword); + + updateById(user); + } + + @Override + public PageResult roleUserPage(SysRoleUserQuery query) { + // 查询参数 + Map params = getParams(query); + params.put("roleId", query.getRoleId()); + + // 分页查询 + IPage page = getPage(query); + params.put(Constant.PAGE, page); + + // 数据列表 + List list = baseMapper.getRoleUserList(params); + + return new PageResult<>(SysUserConvert.INSTANCE.convertList(list), page.getTotal()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void importByExcel(MultipartFile file, String password) { + ExcelUtils.readAnalysis(file, SysUserExcelVO.class, new ExcelFinishCallBack<>() { + @Override + public void doSaveBatch(List result) { + ExcelUtils.parseDict(result); + List userList = SysUserConvert.INSTANCE.convertListEntity(result); + userList.forEach(user -> user.setPassword(password)); + saveBatch(userList); + } + }); + } + + @Override + @SneakyThrows + public void export() { + List list = list(Wrappers.lambdaQuery(SysUserEntity.class).eq(SysUserEntity::getSuperAdmin, SuperAdminEnum.NO.getValue())); + List userExcelVOS = SysUserConvert.INSTANCE.convert2List(list); + transService.transBatch(userExcelVOS); + // 写到浏览器打开 + ExcelUtils.excelExport(SysUserExcelVO.class, "用户管理", null, userExcelVOS); + } + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserTokenServiceImpl.java b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserTokenServiceImpl.java new file mode 100644 index 0000000..9f3bb73 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/service/impl/SysUserTokenServiceImpl.java @@ -0,0 +1,157 @@ +package com.bdzl.system.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.AllArgsConstructor; +import com.bdzl.framework.common.exception.ErrorCode; +import com.bdzl.framework.common.exception.ServerException; +import com.bdzl.framework.mybatis.service.impl.BaseServiceImpl; +import com.bdzl.framework.security.cache.TokenStoreCache; +import com.bdzl.framework.security.properties.SecurityProperties; +import com.bdzl.framework.security.user.UserDetail; +import com.bdzl.framework.security.utils.TokenUtils; +import com.bdzl.system.convert.SysUserConvert; +import com.bdzl.system.convert.SysUserTokenConvert; +import com.bdzl.system.dao.SysUserDao; +import com.bdzl.system.dao.SysUserTokenDao; +import com.bdzl.system.entity.SysUserEntity; +import com.bdzl.system.entity.SysUserTokenEntity; +import com.bdzl.system.service.SysUserDetailsService; +import com.bdzl.system.service.SysUserTokenService; +import com.bdzl.system.vo.SysUserTokenVO; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; + +/** + * 用户Token + * + * @author 阿沐 babamu@126.com + */ +@Service +@AllArgsConstructor +public class SysUserTokenServiceImpl extends BaseServiceImpl implements SysUserTokenService { + private final TokenStoreCache tokenStoreCache; + private final SysUserDetailsService sysUserDetailsService; + private final SecurityProperties securityProperties; + private final SysUserDao sysUserDao; + + @Override + public SysUserTokenVO createToken(Long userId) { + // 生成token + String accessToken = TokenUtils.generator(); + String refreshToken = TokenUtils.generator(); + + SysUserTokenEntity entity = new SysUserTokenEntity(); + entity.setUserId(userId); + entity.setAccessToken(accessToken); + entity.setRefreshToken(refreshToken); + + // 过期时间 + Date now = new Date(); + entity.setAccessTokenExpire(DateUtil.toLocalDateTime(DateUtil.offsetSecond(now, securityProperties.getAccessTokenExpire()))); + entity.setRefreshTokenExpire(DateUtil.toLocalDateTime(DateUtil.offsetSecond(now, securityProperties.getRefreshTokenExpire()))); + + // 是否存在Token + SysUserTokenEntity tokenEntity = baseMapper.selectOne(new LambdaQueryWrapper().eq(SysUserTokenEntity::getUserId, userId)); + if (tokenEntity == null) { + baseMapper.insert(entity); + } else { + entity.setId(tokenEntity.getId()); + baseMapper.updateById(entity); + } + + return SysUserTokenConvert.INSTANCE.convert(entity); + } + + @Override + public SysUserTokenVO refreshToken(String refreshToken) { + LambdaQueryWrapper query = Wrappers.lambdaQuery(); + query.eq(SysUserTokenEntity::getRefreshToken, refreshToken); + query.ge(SysUserTokenEntity::getRefreshTokenExpire, new Date()); + + // 不存在,则表示refreshToken错误,或者已过期 + SysUserTokenEntity entity = baseMapper.selectOne(query); + if (entity == null) { + throw new ServerException(ErrorCode.REFRESH_TOKEN_INVALID); + } + + // 删除缓存信息 + tokenStoreCache.deleteUser(entity.getAccessToken()); + + // 生成新 accessToken + String accessToken = TokenUtils.generator(); + entity.setAccessToken(accessToken); + entity.setAccessTokenExpire(DateUtil.toLocalDateTime(DateUtil.offsetSecond(new Date(), securityProperties.getAccessTokenExpire()))); + + // 更新 + baseMapper.updateById(entity); + + // 设置用户权限信息 + SysUserEntity user = sysUserDao.selectById(entity.getUserId()); + UserDetail userDetail = SysUserConvert.INSTANCE.convertDetail(user); + sysUserDetailsService.getUserDetails(userDetail); + + // 保存用户信息到缓存 + tokenStoreCache.saveUser(accessToken, userDetail); + + return SysUserTokenConvert.INSTANCE.convert(entity); + } + + @Override + public void expireToken(Long userId) { + SysUserTokenEntity entity = new SysUserTokenEntity(); + LocalDateTime now = LocalDateTime.now(); + entity.setAccessTokenExpire(now); + entity.setRefreshTokenExpire(now); + + baseMapper.update(entity, new LambdaQueryWrapper().eq(SysUserTokenEntity::getUserId, userId)); + } + + @Async + @Override + public void updateCacheAuthByRoleId(Long roleId) { + // 根据角色ID,查询用户 access_token 列表 + List accessTokenList = baseMapper.getOnlineAccessTokenListByRoleId(roleId, LocalDateTime.now()); + + accessTokenList.forEach(this::updateCacheAuth); + } + + @Async + @Override + public void updateCacheAuthByUserId(Long userId) { + // 根据用户ID,查询用户 access_token 列表 + List accessTokenList = baseMapper.getOnlineAccessTokenListByUserId(userId, LocalDateTime.now()); + + accessTokenList.forEach(this::updateCacheAuth); + } + + /** + * 根据accessToken,更新Cache里面的用户权限 + * + * @param accessToken access_token + */ + private void updateCacheAuth(String accessToken) { + UserDetail user = tokenStoreCache.getUser(accessToken); + // 用户不存在 + if (user == null) { + return; + } + + // 查询过期时间 + Long expire = tokenStoreCache.getExpire(accessToken); + if (expire == null) { + return; + } + + // 设置用户权限信息 + sysUserDetailsService.getUserDetails(user); + // 更新缓存 + tokenStoreCache.saveUser(accessToken, user, expire); + + } +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/AccessTokenVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/AccessTokenVO.java new file mode 100644 index 0000000..65e53d7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/AccessTokenVO.java @@ -0,0 +1,33 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * AccessToken + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "AccessToken") +public class AccessTokenVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "access_token") + @JsonProperty(value = "access_token") + private String accessToken; + + @Schema(description = "access_token 过期时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime accessTokenExpire; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysAccountLoginVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysAccountLoginVO.java new file mode 100644 index 0000000..e524408 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysAccountLoginVO.java @@ -0,0 +1,30 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 账号登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "账号登录") +public class SysAccountLoginVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "密码") + private String password; + + @Schema(description = "唯一key") + private String key; + + @Schema(description = "验证码") + private String captcha; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysAttachmentVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysAttachmentVO.java new file mode 100644 index 0000000..4ebdf11 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysAttachmentVO.java @@ -0,0 +1,41 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 附件管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "附件管理") +public class SysAttachmentVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "附件名称") + private String name; + + @Schema(description = "附件地址") + private String url; + + @Schema(description = "附件大小") + private Long size; + + @Schema(description = "存储平台") + private String platform; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysCaptchaVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysCaptchaVO.java new file mode 100644 index 0000000..0eccd21 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysCaptchaVO.java @@ -0,0 +1,24 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 图片验证码 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "图片验证码") +public class SysCaptchaVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "key") + private String key; + + @Schema(description = "image base64") + private String image; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictDataVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictDataVO.java new file mode 100644 index 0000000..6b4ec8c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictDataVO.java @@ -0,0 +1,56 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 字典数据 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "字典数据") +public class SysDictDataVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "字典类型ID", required = true) + @NotNull(message = "字典类型ID不能为空") + private Long dictTypeId; + + @Schema(description = "字典标签", required = true) + @NotBlank(message = "字典标签不能为空") + private String dictLabel; + + @Schema(description = "标签样式") + private String labelClass; + + @Schema(description = "字典值") + private String dictValue; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "排序", required = true) + @Min(value = 0, message = "排序值不能小于0") + private Integer sort; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime updateTime; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictTypeVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictTypeVO.java new file mode 100644 index 0000000..b0b57c4 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictTypeVO.java @@ -0,0 +1,61 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 字典类型 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "字典类型") +public class SysDictTypeVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "字典类型", required = true) + @NotBlank(message = "字典类型不能为空") + private String dictType; + + @Schema(description = "字典名称", required = true) + @NotBlank(message = "字典名称不能为空") + private String dictName; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "排序", required = true) + @Min(value = 0, message = "排序值不能小于0") + private Integer sort; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime updateTime; + + @Schema(description = "来源 0:字典数据 1:动态SQL") + private Integer dictSource; + + @Schema(description = "动态sql") + private String dictSql; + + @Schema(description = "上级节点") + private Long pid; + + @Schema(description = "是否有子节点 0:无 1:有") + private Integer hasChild; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictVO.java new file mode 100644 index 0000000..b83d572 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysDictVO.java @@ -0,0 +1,43 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * 全部字典 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "全部字典") +public class SysDictVO { + @Schema(description = "字典类型") + private String dictType; + + @Schema(description = "字典数据列表") + private List dataList = new ArrayList<>(); + + @Data + @AllArgsConstructor + @NoArgsConstructor + @Schema(description = "字典数据") + public static class DictData { + @Schema(description = "字典标签") + private String dictLabel; + + @Schema(description = "字典值") + private String dictValue; + + @Schema(description = "标签样式") + private String labelClass; + + @Schema(description = "上级节点") + private String pid; + } +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysFileUploadVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysFileUploadVO.java new file mode 100644 index 0000000..c68498d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysFileUploadVO.java @@ -0,0 +1,30 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 文件上传 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "文件上传") +public class SysFileUploadVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "文件名称") + private String name; + + @Schema(description = "文件地址") + private String url; + + @Schema(description = "文件大小") + private Long size; + + @Schema(description = "存储平台") + private String platform; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysLogLoginVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysLogLoginVO.java new file mode 100644 index 0000000..3431b1c --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysLogLoginVO.java @@ -0,0 +1,71 @@ +package com.bdzl.system.vo; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import cn.idev.excel.annotation.write.style.ColumnWidth; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.TransPojo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.excel.LocalDateTimeConverter; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 登录日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@ColumnWidth(20) +@Schema(description = "登录日志") +public class SysLogLoginVO implements Serializable, TransPojo { + private static final long serialVersionUID = 1L; + + @ExcelIgnore + @Schema(description = "id") + private Long id; + + @ExcelProperty("用户名") + @Schema(description = "用户名") + private String username; + + @ExcelProperty("登录IP") + @Schema(description = "登录IP") + private String ip; + + @ExcelProperty("登录地点") + @Schema(description = "登录地点") + private String address; + + @ExcelProperty("User Agent") + @Schema(description = "User Agent") + private String userAgent; + + @ExcelIgnore + @Trans(type = TransType.DICTIONARY, key = "success_fail", ref = "statusLabel") + @Schema(description = "登录状态 0:失败 1:成功") + private Integer status; + + @ExcelProperty(value = "登录状态") + private String statusLabel; + + @ExcelIgnore + @Trans(type = TransType.DICTIONARY, key = "login_operation", ref = "operationLabel") + @Schema(description = "操作信息 0:登录成功 1:退出成功 2:验证码错误 3:账号密码错误") + private Integer operation; + + @ExcelProperty(value = "操作信息") + private String operationLabel; + + @ExcelProperty(value = "创建时间", converter = LocalDateTimeConverter.class) + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysLogOperateVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysLogOperateVO.java new file mode 100644 index 0000000..e326bf2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysLogOperateVO.java @@ -0,0 +1,71 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 操作日志 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "操作日志") +public class SysLogOperateVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "操作人") + private String realName; + + @Schema(description = "模块名") + private String module; + + @Schema(description = "操作名") + private String name; + + @Schema(description = "请求URI") + private String reqUri; + + @Schema(description = "请求方法") + private String reqMethod; + + @Schema(description = "请求参数") + private String reqParams; + + @Schema(description = "操作IP") + private String ip; + + @Schema(description = "登录地点") + private String address; + + @Schema(description = "User Agent") + private String userAgent; + + @Schema(description = "操作类型") + private Integer operateType; + + @Schema(description = "执行时长") + private Integer duration; + + @Schema(description = "操作状态") + private Integer status; + + @Schema(description = "返回消息") + private String resultMsg; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailConfigVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailConfigVO.java new file mode 100644 index 0000000..68e8a80 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailConfigVO.java @@ -0,0 +1,78 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.util.Date; + +/** + * 邮件配置 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "邮件配置") +public class SysMailConfigVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "平台类型") + private Integer platform; + + @Schema(description = "分组名称,发送邮件时,可指定分组") + private String groupName; + + @Schema(description = "SMTP服务器") + private String mailHost; + + @Schema(description = "SMTP端口") + private Integer mailPort; + + @Schema(description = "发件人邮箱") + private String mailFrom; + + @Schema(description = "发件人密码") + private String mailPass; + + @Schema(description = "regionId") + private String regionId; + + @Schema(description = "阿里云 endpoint") + private String endpoint; + + @Schema(description = "AccessKey") + private String accessKey; + + @Schema(description = "SecretKey") + private String secretKey; + + @Schema(description = "状态 0:禁用 1:启用") + private Integer status; + + @Schema(description = "版本号") + private Integer version; + + @Schema(description = "删除标识") + private Integer deleted; + + @Schema(description = "创建者") + private Long creator; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private Date createTime; + + @Schema(description = "更新者") + private Long updater; + + @Schema(description = "更新时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private Date updateTime; + + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailLogVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailLogVO.java new file mode 100644 index 0000000..65d728e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailLogVO.java @@ -0,0 +1,52 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 邮件日志 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "邮件日志") +public class SysMailLogVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "平台ID") + private Long platformId; + + @Schema(description = "平台类型") + private Integer platform; + + @Schema(description = "发件人邮箱") + private String mailFrom; + + @Schema(description = "接受人邮箱") + private String mailTos; + + @Schema(description = "邮件主题") + private String subject; + + @Schema(description = "邮件内容") + private String content; + + @Schema(description = "状态 0:失败 1:成功") + private Integer status; + + @Schema(description = "异常信息") + private String error; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailSendVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailSendVO.java new file mode 100644 index 0000000..854989b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMailSendVO.java @@ -0,0 +1,51 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 邮件发送 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "邮件发送") +public class SysMailSendVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "平台") + private Integer platform; + + @Schema(description = "邮件格式") + private String mailFormat; + + @Schema(description = "发件人邮箱") + private String mailFrom; + + @Schema(description = "发件人昵称") + private String formAlias; + + @Schema(description = "接收人邮箱") + private String mailTos; + + @Schema(description = "收件人列表") + private String receiversName; + + @Schema(description = "模板名") + private String templateName; + + @Schema(description = "标签名") + private String tagName; + + @Schema(description = "邮件主题") + private String subject; + + @Schema(description = "邮件正文") + private String content; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMenuVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMenuVO.java new file mode 100644 index 0000000..3668576 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMenuVO.java @@ -0,0 +1,57 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.utils.DateUtils; +import com.bdzl.framework.common.utils.TreeNode; +import org.hibernate.validator.constraints.Range; + +import java.time.LocalDateTime; + +/** + * 菜单管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "菜单") +public class SysMenuVO extends TreeNode { + + @Schema(description = "菜单名称") + @NotBlank(message = "菜单名称不能为空") + private String name; + + @Schema(description = "菜单URL") + private String url; + + @Schema(description = "类型 0:菜单 1:按钮 2:接口") + @Range(min = 0, max = 2, message = "类型不正确") + private Integer type; + + @Schema(description = "打开方式 0:内部 1:外部") + @Range(min = 0, max = 1, message = "打开方式不正确") + private Integer openStyle; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "授权标识(多个用逗号分隔,如:sys:menu:list,sys:menu:save)") + private String authority; + + @Schema(description = "排序") + @Min(value = 0, message = "排序值不能小于0") + private Integer sort; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + @Schema(description = "上级菜单名称") + private String parentName; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMobileLoginVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMobileLoginVO.java new file mode 100644 index 0000000..5efa9a8 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysMobileLoginVO.java @@ -0,0 +1,24 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 手机号登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "手机号登录") +public class SysMobileLoginVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "验证码") + private String code; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysOrgVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysOrgVO.java new file mode 100644 index 0000000..48718f7 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysOrgVO.java @@ -0,0 +1,43 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.bdzl.framework.common.utils.DateUtils; +import com.bdzl.framework.common.utils.TreeNode; + +import java.time.LocalDateTime; + +/** + * 机构列表 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "机构") +public class SysOrgVO extends TreeNode { + + @Schema(description = "机构名称", required = true) + @NotBlank(message = "机构名称不能为空") + private String name; + + @Schema(description = "排序", required = true) + @Min(value = 0, message = "排序值不能小于0") + private Integer sort; + + @Schema(description = "负责人ID") + private Long leaderId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + @Schema(description = "上级名称") + private String parentName; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysParamsVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysParamsVO.java new file mode 100644 index 0000000..6517edc --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysParamsVO.java @@ -0,0 +1,61 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 参数管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "参数管理") +public class SysParamsVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "参数名称") + private String paramName; + + @Schema(description = "系统参数") + private Integer paramType; + + @Schema(description = "参数键") + private String paramKey; + + @Schema(description = "参数值") + private String paramValue; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "版本号") + private Integer version; + + @Schema(description = "删除标识") + private Integer deleted; + + @Schema(description = "创建者") + private Long creator; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + @Schema(description = "更新者") + private Long updater; + + @Schema(description = "更新时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime updateTime; + + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysPostVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysPostVO.java new file mode 100644 index 0000000..51e3186 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysPostVO.java @@ -0,0 +1,48 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; +import org.hibernate.validator.constraints.Range; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 岗位管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "岗位管理") +public class SysPostVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "岗位编码", required = true) + @NotBlank(message = "岗位编码不能为空") + private String postCode; + + @Schema(description = "岗位名称", required = true) + @NotBlank(message = "岗位名称不能为空") + private String postName; + + @Schema(description = "排序", required = true) + @Min(value = 0, message = "排序值不能小于0") + private Integer sort; + + @Schema(description = "状态 0:停用 1:正常", required = true) + @Range(min = 0, max = 1, message = "状态不正确") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysRoleDataScopeVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysRoleDataScopeVO.java new file mode 100644 index 0000000..3a130e2 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysRoleDataScopeVO.java @@ -0,0 +1,32 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 角色数据权限 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "角色数据权限") +public class SysRoleDataScopeVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + @NotNull(message = "角色ID不能为空") + private Long id; + + @Schema(description = "数据范围 0:全部数据 1:本机构及子机构数据 2:本机构数据 3:本人数据 4:自定义数据") + @NotNull(message = "数据范围不能为空") + private Integer dataScope; + + @Schema(description = "机构ID列表") + private List orgIdList; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysRoleVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysRoleVO.java new file mode 100644 index 0000000..294c6fa --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysRoleVO.java @@ -0,0 +1,51 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 角色管理 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "角色") +public class SysRoleVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "角色名称") + @NotBlank(message = "角色名称不能为空") + private String name; + + @Schema(description = "角色编码") + @NotBlank(message = "角色编码不能为空") + private String roleCode; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "数据范围 0:全部数据 1:本机构及子机构数据 2:本机构数据 3:本人数据 4:自定义数据") + private Integer dataScope; + + @Schema(description = "菜单ID列表") + private List menuIdList; + + @Schema(description = "机构ID列表") + private List orgIdList; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsConfigVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsConfigVO.java new file mode 100644 index 0000000..d33f42d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsConfigVO.java @@ -0,0 +1,59 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 短信配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "短信配置") +public class SysSmsConfigVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "平台类型") + private Integer platform; + + @Schema(description = "分组名称,发送短信时,可指定分组") + private String groupName; + + @Schema(description = "短信签名") + private String signName; + + @Schema(description = "短信模板") + private String templateId; + + @Schema(description = "短信应用的ID,如:腾讯云等") + private String appId; + + @Schema(description = "腾讯云国际短信、华为云等需要") + private String senderId; + + @Schema(description = "接入地址,如:华为云") + private String url; + + @Schema(description = "AccessKey") + private String accessKey; + + @Schema(description = "SecretKey") + private String secretKey; + + @Schema(description = "状态 0:禁用 1:启用") + private Integer status; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsLogVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsLogVO.java new file mode 100644 index 0000000..b5bd443 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsLogVO.java @@ -0,0 +1,46 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 短信日志 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "短信日志") +public class SysSmsLogVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "平台ID") + private Long platformId; + + @Schema(description = "平台类型") + private Integer platform; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "状态 0:失败 1:成功") + private Integer status; + + @Schema(description = "参数") + private String params; + + @Schema(description = "异常信息") + private String error; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsSendVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsSendVO.java new file mode 100644 index 0000000..292ffcf --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysSmsSendVO.java @@ -0,0 +1,30 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 短信发送 + * + * @author 阿沐 babamu@126.com + */ +@Data +@Schema(description = "短信发送") +public class SysSmsSendVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "参数Key") + private String paramKey; + + @Schema(description = "参数Value") + private String paramValue; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdCallbackVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdCallbackVO.java new file mode 100644 index 0000000..4636dd0 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdCallbackVO.java @@ -0,0 +1,27 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 第三方登录 回调参数 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "第三方登录 回调参数") +public class SysThirdCallbackVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "开放平台类型") + private String openType; + + @Schema(description = "开放平台Code") + private String code; + + @Schema(description = "state") + private String state; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdLoginConfigVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdLoginConfigVO.java new file mode 100644 index 0000000..514e19b --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdLoginConfigVO.java @@ -0,0 +1,45 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 第三方登录配置 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "第三方登录配置") +public class SysThirdLoginConfigVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "开放平台类型") + private String openType; + + @Schema(description = "ClientID") + private String clientId; + + @Schema(description = "ClientSecret") + private String clientSecret; + + @Schema(description = "RedirectUri") + private String redirectUri; + + @Schema(description = "AgentID") + private String agentId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; + + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdLoginVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdLoginVO.java new file mode 100644 index 0000000..c60176a --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysThirdLoginVO.java @@ -0,0 +1,43 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 第三方登录 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "第三方登录") +public class SysThirdLoginVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "开放平台类型") + private String openType; + + @Schema(description = "开放平台,唯一标识") + private String openId; + + @Schema(description = "昵称") + private String username; + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "租户ID") + private Long tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserAvatarVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserAvatarVO.java new file mode 100644 index 0000000..e2a1b53 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserAvatarVO.java @@ -0,0 +1,24 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户头像 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "用户头像") +public class SysUserAvatarVO implements Serializable { + private static final long serialVersionUID = 1L; + + @NotBlank(message = "头像不能为空") + @Schema(description = "头像") + private String avatar; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserBaseVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserBaseVO.java new file mode 100644 index 0000000..7687c9e --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserBaseVO.java @@ -0,0 +1,41 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.hibernate.validator.constraints.Range; + +import java.io.Serializable; + +/** + * 用户基本信息 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "用户基本信息") +public class SysUserBaseVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "姓名", required = true) + @NotBlank(message = "姓名不能为空") + private String realName; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "性别 0:男 1:女 2:未知", required = true) + @Range(min = 0, max = 2, message = "性别不正确") + private Integer gender; + + @Schema(description = "邮箱") + @Email(message = "邮箱格式不正确") + private String email; + + @Schema(description = "手机号", required = true) + @NotBlank(message = "手机号不能为空") + private String mobile; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserExcelVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserExcelVO.java new file mode 100644 index 0000000..229f71d --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserExcelVO.java @@ -0,0 +1,71 @@ +package com.bdzl.system.vo; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import cn.idev.excel.annotation.write.style.ColumnWidth; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.TransPojo; +import lombok.Data; +import com.bdzl.framework.common.excel.LocalDateTimeConverter; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * excel用户表 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@ColumnWidth(20) +public class SysUserExcelVO implements Serializable, TransPojo { + private static final long serialVersionUID = 1L; + + /** + * 本属性对于导出无用,只是用于翻译 + */ + @ExcelIgnore + private Long id; + + @ExcelProperty("用户名") + private String username; + + @ExcelProperty("姓名") + private String realName; + + @ExcelIgnore + @Trans(type = TransType.DICTIONARY, key = "user_gender", ref = "genderLabel") + private Integer gender; + + @ExcelProperty(value = "性别") + private String genderLabel; + + @ExcelProperty("邮箱") + private String email; + + @ExcelProperty("手机号") + private String mobile; + + @ExcelProperty("机构ID") + private Long orgId; + + @ExcelIgnore + @Trans(type = TransType.DICTIONARY, key = "user_status", ref = "statusLabel") + private Integer status; + + @ExcelProperty(value = "状态") + private String statusLabel; + + @ExcelIgnore + @Trans(type = TransType.DICTIONARY, key = "user_super_admin", ref = "superAdminLabel") + private Integer superAdmin; + + @ExcelProperty(value = "超级管理员") + private String superAdminLabel; + + @ExcelProperty(value = "创建时间", converter = LocalDateTimeConverter.class) + private LocalDateTime createTime; + +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserPasswordVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserPasswordVO.java new file mode 100644 index 0000000..da5b211 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserPasswordVO.java @@ -0,0 +1,29 @@ +package com.bdzl.system.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import java.io.Serializable; + +/** + * 用户修改密码 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "用户修改密码") +public class SysUserPasswordVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "原密码", required = true) + @NotBlank(message = "原密码不能为空") + private String password; + + @Schema(description = "新密码,密码长度为 4-20 位", required = true) + @Length(min = 4, max = 20, message = "新密码长度为 4-20 位") + private String newPassword; + +} \ No newline at end of file diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserTokenVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserTokenVO.java new file mode 100644 index 0000000..2f77760 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserTokenVO.java @@ -0,0 +1,40 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 用户Token + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@AllArgsConstructor +@Schema(description = "用户Token") +public class SysUserTokenVO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "access_token") + @JsonProperty(value = "access_token") + private String accessToken; + + @Schema(description = "refresh_token") + @JsonProperty(value = "refresh_token") + private String refreshToken; + + @Schema(description = "access_token 过期时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime accessTokenExpire; + + @Schema(description = "refresh_token 过期时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime refreshTokenExpire; +} diff --git a/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserVO.java b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserVO.java new file mode 100644 index 0000000..47e2fe9 --- /dev/null +++ b/drone-ops-system/src/main/java/com/bdzl/system/vo/SysUserVO.java @@ -0,0 +1,89 @@ +package com.bdzl.system.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.TransPojo; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import com.bdzl.framework.common.utils.DateUtils; +import com.bdzl.system.entity.SysOrgEntity; +import org.hibernate.validator.constraints.Range; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +@Data +@Schema(description = "用户") +public class SysUserVO implements Serializable, TransPojo { + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "用户名", required = true) + @NotBlank(message = "用户名不能为空") + private String username; + + @Schema(description = "密码") + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String password; + + @Schema(description = "姓名", required = true) + @NotBlank(message = "姓名不能为空") + private String realName; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "性别 0:男 1:女 2:未知", required = true) + @Range(min = 0, max = 2, message = "性别不正确") + private Integer gender; + + @Schema(description = "邮箱") + @Email(message = "邮箱格式不正确") + private String email; + + @Schema(description = "手机号", required = true) + @NotBlank(message = "手机号不能为空") + private String mobile; + + @Schema(description = "机构ID", required = true) + @NotNull(message = "机构ID不能为空") + @Trans(type = TransType.SIMPLE, target = SysOrgEntity.class, fields = "name", ref = "orgName") + private Long orgId; + + @Schema(description = "状态 0:停用 1:正常", required = true) + @Range(min = 0, max = 1, message = "用户状态不正确") + private Integer status; + + @Schema(description = "角色ID列表") + private List roleIdList; + + @Schema(description = "岗位ID列表") + private List postIdList; + + @Schema(description = "岗位名称列表") + private List postNameList; + + @Schema(description = "超级管理员 0:否 1:是") + private Integer superAdmin; + + @Schema(description = "机构名称") + private String orgName; + + @Schema(description = "创建时间") + @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN) + private LocalDateTime createTime; +} diff --git a/drone-ops-system/src/main/resources/auth.yml b/drone-ops-system/src/main/resources/auth.yml new file mode 100644 index 0000000..a16e12e --- /dev/null +++ b/drone-ops-system/src/main/resources/auth.yml @@ -0,0 +1,13 @@ +auth: + ignore_urls: + - /sys/auth/captcha + - /sys/auth/captcha/enabled + - /sys/auth/login + - /sys/auth/token + - /sys/auth/send/code + - /sys/auth/mobile + - /sys/auth/third + - /sys/third/callback/** + - /sys/third/render/** + - /upload/** + - / \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysAttachmentDao.xml b/drone-ops-system/src/main/resources/mapper/SysAttachmentDao.xml new file mode 100644 index 0000000..074b31b --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysAttachmentDao.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysDictDataDao.xml b/drone-ops-system/src/main/resources/mapper/SysDictDataDao.xml new file mode 100644 index 0000000..568421b --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysDictDataDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysDictTypeDao.xml b/drone-ops-system/src/main/resources/mapper/SysDictTypeDao.xml new file mode 100644 index 0000000..82cc30e --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysDictTypeDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysLogLoginDao.xml b/drone-ops-system/src/main/resources/mapper/SysLogLoginDao.xml new file mode 100644 index 0000000..1fae757 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysLogLoginDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysLogOperateDao.xml b/drone-ops-system/src/main/resources/mapper/SysLogOperateDao.xml new file mode 100644 index 0000000..f8152b4 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysLogOperateDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysMenuDao.xml b/drone-ops-system/src/main/resources/mapper/SysMenuDao.xml new file mode 100644 index 0000000..5cb235d --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysMenuDao.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysOrgDao.xml b/drone-ops-system/src/main/resources/mapper/SysOrgDao.xml new file mode 100644 index 0000000..4c88be4 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysOrgDao.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysParamsDao.xml b/drone-ops-system/src/main/resources/mapper/SysParamsDao.xml new file mode 100644 index 0000000..4326525 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysParamsDao.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysPostDao.xml b/drone-ops-system/src/main/resources/mapper/SysPostDao.xml new file mode 100644 index 0000000..e684743 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysPostDao.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysRoleDao.xml b/drone-ops-system/src/main/resources/mapper/SysRoleDao.xml new file mode 100644 index 0000000..f54b8c9 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysRoleDao.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysRoleDataScopeDao.xml b/drone-ops-system/src/main/resources/mapper/SysRoleDataScopeDao.xml new file mode 100644 index 0000000..0f895b4 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysRoleDataScopeDao.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysRoleMenuDao.xml b/drone-ops-system/src/main/resources/mapper/SysRoleMenuDao.xml new file mode 100644 index 0000000..50fbb77 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysRoleMenuDao.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysUseTokenDao.xml b/drone-ops-system/src/main/resources/mapper/SysUseTokenDao.xml new file mode 100644 index 0000000..c14f416 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysUseTokenDao.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysUserDao.xml b/drone-ops-system/src/main/resources/mapper/SysUserDao.xml new file mode 100644 index 0000000..9ac96ad --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysUserDao.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysUserPostDao.xml b/drone-ops-system/src/main/resources/mapper/SysUserPostDao.xml new file mode 100644 index 0000000..d5f8d2c --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysUserPostDao.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/mapper/SysUserRoleDao.xml b/drone-ops-system/src/main/resources/mapper/SysUserRoleDao.xml new file mode 100644 index 0000000..6bbdc56 --- /dev/null +++ b/drone-ops-system/src/main/resources/mapper/SysUserRoleDao.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/drone-ops-system/src/main/resources/templates/third_login.ftlh b/drone-ops-system/src/main/resources/templates/third_login.ftlh new file mode 100644 index 0000000..5ddf0bd --- /dev/null +++ b/drone-ops-system/src/main/resources/templates/third_login.ftlh @@ -0,0 +1,24 @@ + + + + + + + 第三方登录 + + +登陆中... + + + \ No newline at end of file diff --git a/images/0.png b/images/0.png new file mode 100644 index 0000000..3d3cc01 Binary files /dev/null and b/images/0.png differ diff --git a/images/1.png b/images/1.png new file mode 100644 index 0000000..60abdb3 Binary files /dev/null and b/images/1.png differ diff --git a/images/10.png b/images/10.png new file mode 100644 index 0000000..20b98de Binary files /dev/null and b/images/10.png differ diff --git a/images/11.png b/images/11.png new file mode 100644 index 0000000..3f81e41 Binary files /dev/null and b/images/11.png differ diff --git a/images/12.png b/images/12.png new file mode 100644 index 0000000..a65b771 Binary files /dev/null and b/images/12.png differ diff --git a/images/13.png b/images/13.png new file mode 100644 index 0000000..7af6e0a Binary files /dev/null and b/images/13.png differ diff --git a/images/14.png b/images/14.png new file mode 100644 index 0000000..d4021ab Binary files /dev/null and b/images/14.png differ diff --git a/images/15.png b/images/15.png new file mode 100644 index 0000000..3f37af2 Binary files /dev/null and b/images/15.png differ diff --git a/images/16.png b/images/16.png new file mode 100644 index 0000000..1f24022 Binary files /dev/null and b/images/16.png differ diff --git a/images/17.png b/images/17.png new file mode 100644 index 0000000..6de91df Binary files /dev/null and b/images/17.png differ diff --git a/images/18.png b/images/18.png new file mode 100644 index 0000000..67440d1 Binary files /dev/null and b/images/18.png differ diff --git a/images/19.png b/images/19.png new file mode 100644 index 0000000..78cc1a5 Binary files /dev/null and b/images/19.png differ diff --git a/images/2.png b/images/2.png new file mode 100644 index 0000000..2e69e0e Binary files /dev/null and b/images/2.png differ diff --git a/images/20.png b/images/20.png new file mode 100644 index 0000000..7bd44e7 Binary files /dev/null and b/images/20.png differ diff --git a/images/21.png b/images/21.png new file mode 100644 index 0000000..51248f3 Binary files /dev/null and b/images/21.png differ diff --git a/images/22.png b/images/22.png new file mode 100644 index 0000000..9672138 Binary files /dev/null and b/images/22.png differ diff --git a/images/3.png b/images/3.png new file mode 100644 index 0000000..578bc74 Binary files /dev/null and b/images/3.png differ diff --git a/images/4.png b/images/4.png new file mode 100644 index 0000000..90a269c Binary files /dev/null and b/images/4.png differ diff --git a/images/5.png b/images/5.png new file mode 100644 index 0000000..cdd0faf Binary files /dev/null and b/images/5.png differ diff --git a/images/6.png b/images/6.png new file mode 100644 index 0000000..56acf09 Binary files /dev/null and b/images/6.png differ diff --git a/images/7.png b/images/7.png new file mode 100644 index 0000000..9dee82c Binary files /dev/null and b/images/7.png differ diff --git a/images/8.png b/images/8.png new file mode 100644 index 0000000..63d71e5 Binary files /dev/null and b/images/8.png differ diff --git a/images/9.png b/images/9.png new file mode 100644 index 0000000..62943cc Binary files /dev/null and b/images/9.png differ diff --git a/images/qrcode.png b/images/qrcode.png new file mode 100644 index 0000000..e545926 Binary files /dev/null and b/images/qrcode.png differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f2e286b --- /dev/null +++ b/pom.xml @@ -0,0 +1,257 @@ + + 4.0.0 + com.bdzl + drone-ops + ${revision} + pom + + drone-ops + drone-ops + + + org.springframework.boot + spring-boot-starter-parent + 3.4.5 + + + + drone-ops-new + drone-ops-system + drone-ops-module + drone-ops-api + drone-ops-framework + drone-ops-server + + + + 4.8.0 + true + UTF-8 + UTF-8 + 17 + 3.5.7 + 4.3.1 + 3.21.3 + 2.2.7 + 8.1.2.79 + 4.5.0 + 5.8.28 + 1.6.2 + 1.5.5.Final + 3.15.2 + 2.0.23 + 3.1.574 + 7.12.1 + 8.5.17 + 5.6.97 + 3.22.3 + 1.1.0 + 3.3.0 + 3.0.5 + 1.16.1 + 1.16.6 + 2.7.0 + 1.69 + 2.14.2 + 1.0.6 + 3.1.944 + 1.6.2 + 5.5.6 + + + + + org.projectlombok + lombok + true + + + org.mapstruct + mapstruct + + + org.mapstruct + mapstruct-processor + + + + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatisplus.version} + + + com.baomidou + dynamic-datasource-spring-boot3-starter + ${dynamic-datasource.version} + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + com.dameng + DmJdbcDriver18 + ${dameng.version} + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + ${knife4j.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + com.github.whvcse + easy-captcha + ${captcha.version} + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + com.aliyun.oss + aliyun-sdk-oss + ${aliyun.oss.version} + + + com.aliyun + dysmsapi20170525 + ${aliyun.dysmsapi.version} + + + com.tencentcloudapi + tencentcloud-sdk-java + ${tencentcloud.sdk.version} + + + com.qiniu + qiniu-java-sdk + ${qiniu.version} + + + io.minio + minio + ${minio.version} + + + com.qcloud + cos_api + ${qcloud.cos.version} + + + com.huaweicloud + esdk-obs-java-bundle + ${huaweicloud.obs.version} + + + cn.idev.excel + fastexcel + ${fastexcel.version} + + + okio + com.squareup.okio + ${okio.version} + + + com.fhs-opensource + easy-trans-spring-boot-starter + ${easytrans.version} + + + com.fhs-opensource + easy-trans-mybatis-plus-extend + ${easytrans.version} + + + org.jsoup + jsoup + ${jsoup.version} + + + com.alibaba + transmittable-thread-local + ${transmittable.thread.local.version} + + + me.zhyd.oauth + JustAuth + ${justauth.version} + + + org.lionsoul + ip2region + ${ip2region.version} + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + + com.aliyun + dm20151123 + ${aliyun.dm.version} + + + com.tencentcloudapi + tencentcloud-sdk-java-ses + ${tencentcloud.sdk.ses.version} + + + com.sun.mail + javax.mail + ${mail.version} + + + org.springframework.integration + spring-integration-mqtt + ${spring-integration-mqtt.version} + + + + + + + public + 阿里云公共仓库 + https://maven.aliyun.com/repository/public/ + + true + + + + + + public + 阿里云公共仓库 + https://maven.aliyun.com/repository/public/ + + true + + + false + + + + \ No newline at end of file