Merge remote-tracking branch 'upstream/master'

This commit is contained in:
leoxxx 2022-06-16 17:12:39 +08:00
commit 9309ef2fdc
87 changed files with 976 additions and 1569 deletions

View File

@ -11,7 +11,7 @@
Target Server Version : 80026
File Encoding : 65001
Date: 25/05/2022 23:28:25
Date: 15/06/2022 08:11:25
*/
SET NAMES utf8mb4;
@ -300,7 +300,7 @@ CREATE TABLE `bpm_form` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的表单定义';
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的表单定义';
-- ----------------------------
-- Records of bpm_form
@ -359,7 +359,7 @@ CREATE TABLE `bpm_process_definition_ext` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 104 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 流程定义的拓展表\n';
) ENGINE = InnoDB AUTO_INCREMENT = 119 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 流程定义的拓展表\n';
-- ----------------------------
-- Records of bpm_process_definition_ext
@ -389,7 +389,7 @@ CREATE TABLE `bpm_process_instance_ext` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 204 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程实例的拓展';
) ENGINE = InnoDB AUTO_INCREMENT = 256 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程实例的拓展';
-- ----------------------------
-- Records of bpm_process_instance_ext
@ -415,7 +415,7 @@ CREATE TABLE `bpm_task_assign_rule` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 201 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 任务规则表';
) ENGINE = InnoDB AUTO_INCREMENT = 225 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Bpm 任务规则表';
-- ----------------------------
-- Records of bpm_task_assign_rule
@ -431,6 +431,7 @@ CREATE TABLE `bpm_task_ext` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`assignee_user_id` bigint NULL DEFAULT NULL COMMENT '任务的审批人',
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '任务的名字',
`task_def_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '流程任务key',
`task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务的编号',
`result` tinyint NOT NULL COMMENT '任务的结果',
`reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '审批建议',
@ -444,7 +445,7 @@ CREATE TABLE `bpm_task_ext` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 217 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程任务的拓展表';
) ENGINE = InnoDB AUTO_INCREMENT = 295 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '工作流的流程任务的拓展表';
-- ----------------------------
-- Records of bpm_task_ext
@ -504,7 +505,7 @@ CREATE TABLE `infra_api_access_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 33232 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表';
) ENGINE = InnoDB AUTO_INCREMENT = 35150 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表';
-- ----------------------------
-- Records of infra_api_access_log
@ -546,7 +547,7 @@ CREATE TABLE `infra_api_error_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 454 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
) ENGINE = InnoDB AUTO_INCREMENT = 627 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
-- ----------------------------
-- Records of infra_api_error_log
@ -688,6 +689,7 @@ DROP TABLE IF EXISTS `infra_file`;
CREATE TABLE `infra_file` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件编号',
`config_id` bigint NULL DEFAULT NULL COMMENT '配置编号',
`name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件名',
`path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件路径',
`url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '文件 URL',
`type` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件类型',
@ -698,7 +700,7 @@ CREATE TABLE `infra_file` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 83 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
) ENGINE = InnoDB AUTO_INCREMENT = 85 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
-- ----------------------------
-- Records of infra_file
@ -723,7 +725,7 @@ CREATE TABLE `infra_file_config` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表';
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表';
-- ----------------------------
-- Records of infra_file_config
@ -732,6 +734,9 @@ BEGIN;
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2022-03-26 21:39:26', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '本地磁盘', 10, '测试下本地存储', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/file_test\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:57:00', '1', '2022-03-26 21:39:26', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (11, 'S3 - 七牛云', 20, NULL, b'1', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-03-19 18:00:03', '1', '2022-03-26 21:39:26', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, 'S3 - 七牛云', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-06-10 20:50:41', '1', '2022-06-10 20:50:41', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (16, 'S3 - 七牛云', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-06-11 20:32:08', '1', '2022-06-11 20:32:08', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, 'S3 - 七牛云', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3-cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8\",\"accessSecret\":\"kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP\"}', '1', '2022-06-11 20:32:47', '1', '2022-06-11 20:32:47', b'0');
COMMIT;
-- ----------------------------
@ -862,7 +867,7 @@ CREATE TABLE `member_user` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
) ENGINE = InnoDB AUTO_INCREMENT = 247 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户';
) ENGINE = InnoDB AUTO_INCREMENT = 248 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户';
-- ----------------------------
-- Records of member_user
@ -1258,7 +1263,6 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (79, 2, '手动编辑', '2', 'system_error_code_type', 0, 'primary', '', NULL, '1', '2021-04-21 00:07:14', '1', '2022-02-16 13:57:24', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (82, 102, 'Mock 登录', '102', 'system_login_type', 0, 'danger', '', 'Mock 登录', '1', '2021-10-06 00:52:32', '1', '2022-02-16 13:11:44', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (85, 202, '强制登出', '202', 'system_login_type', 0, 'danger', '', '强制退出', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', b'0');
@ -1411,7 +1415,7 @@ CREATE TABLE `system_error_code` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5829 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表';
) ENGINE = InnoDB AUTO_INCREMENT = 5832 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表';
-- ----------------------------
-- Records of system_error_code
@ -1440,7 +1444,7 @@ CREATE TABLE `system_login_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1416 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
) ENGINE = InnoDB AUTO_INCREMENT = 1489 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
-- ----------------------------
-- Records of system_login_log
@ -1757,7 +1761,7 @@ CREATE TABLE `system_oauth2_access_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 172 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
) ENGINE = InnoDB AUTO_INCREMENT = 231 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
-- ----------------------------
-- Records of system_oauth2_access_token
@ -1877,7 +1881,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 106 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '刷新令牌';
) ENGINE = InnoDB AUTO_INCREMENT = 165 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '刷新令牌';
-- ----------------------------
-- Records of system_oauth2_refresh_token
@ -1917,7 +1921,7 @@ CREATE TABLE `system_operate_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2214 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
) ENGINE = InnoDB AUTO_INCREMENT = 2432 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
-- ----------------------------
-- Records of system_operate_log
@ -1983,7 +1987,7 @@ CREATE TABLE `system_role` (
BEGIN;
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '132', '', '2021-01-06 13:49:35', '1', '2022-04-01 21:37:13', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '132', '', '2021-01-06 13:49:35', '1', '2022-05-28 16:11:05', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (110, '测试角色', 'test', 0, 1, '[]', 0, 2, '嘿嘿', '110', '2022-02-23 00:14:34', '110', '2022-02-23 13:14:58', b'0', 121);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122);
@ -2253,7 +2257,7 @@ COMMIT;
DROP TABLE IF EXISTS `system_sms_channel`;
CREATE TABLE `system_sms_channel` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`signature` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信签名',
`signature` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '短信签名',
`code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '渠道编码',
`status` tinyint NOT NULL COMMENT '开启状态',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
@ -2300,7 +2304,7 @@ CREATE TABLE `system_sms_code` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
) ENGINE = InnoDB AUTO_INCREMENT = 468 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
) ENGINE = InnoDB AUTO_INCREMENT = 469 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
-- ----------------------------
-- Records of system_sms_code
@ -2343,7 +2347,7 @@ CREATE TABLE `system_sms_log` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 144 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
) ENGINE = InnoDB AUTO_INCREMENT = 242 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
-- ----------------------------
-- Records of system_sms_log
@ -2413,7 +2417,7 @@ CREATE TABLE `system_social_user` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
-- ----------------------------
-- Records of system_social_user
@ -2438,7 +2442,7 @@ CREATE TABLE `system_social_user_bind` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
-- ----------------------------
-- Records of system_social_user_bind
@ -2545,7 +2549,7 @@ CREATE TABLE `system_user_role` (
`deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
-- ----------------------------
-- Records of system_user_role
@ -2556,7 +2560,6 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 104, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 107, 106, '1', '2022-02-20 22:59:33', '1', '2022-02-20 22:59:33', b'0', 118);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 108, 107, '1', '2022-02-20 23:00:50', '1', '2022-02-20 23:00:50', b'0', 119);
@ -2567,6 +2570,7 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (17, 114, 101, '1', '2022-03-19 21:51:13', '1', '2022-03-19 21:51:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (19, 116, 113, '1', '2022-05-17 10:07:10', '1', '2022-05-17 10:07:10', b'0', 124);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (20, 104, 101, '1', '2022-05-28 15:43:57', '1', '2022-05-28 15:43:57', b'0', 1);
COMMIT;
-- ----------------------------
@ -2630,10 +2634,10 @@ CREATE TABLE `system_users` (
-- Records of system_users
-- ----------------------------
BEGIN;
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://test.yudao.iocoder.cn/48934f2f-92d4-4250-b917-d10d2b262c6a', 0, '127.0.0.1', '2022-05-23 20:27:29', 'admin', '2021-01-05 17:03:47', NULL, '2022-05-23 20:27:29', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://test.yudao.iocoder.cn/48934f2f-92d4-4250-b917-d10d2b262c6a', 0, '127.0.0.1', '2022-06-15 08:03:23', 'admin', '2021-01-05 17:03:47', NULL, '2022-06-15 08:03:23', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-05-22 19:35:33', '', '2021-01-07 09:07:17', NULL, '2022-05-22 19:35:33', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$wWoPT7sqriM2O1YXRL.je.GiL538OR6ZTN8aQZr9JAGdnpCH2tpYe', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '127.0.0.1', '2022-01-18 00:33:40', '', '2021-01-13 23:50:35', NULL, '2022-01-18 00:33:40', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$e5RpuDCC0GYSt0Hvd2.CjujIXwgGct4SnXi6dVGxdgFsnqgEryk5a', '测试号', NULL, 107, '[1]', '111@qq.com', '15601691200', 1, '', 0, '127.0.0.1', '2022-03-19 21:46:19', '', '2021-01-21 02:13:53', '1', '2022-05-16 19:36:28', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$GP8zvqHB//TekuzYZSBYAuBQJiNq1.fxQVDYJ.uBCOnWCtDVKE4H6', '测试号', NULL, 107, '[1]', '111@qq.com', '15601691200', 1, '', 0, '127.0.0.1', '2022-05-28 15:43:17', '', '2021-01-21 02:13:53', NULL, '2022-05-28 15:43:17', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120);

View File

@ -11,7 +11,7 @@
Target Server Version : 110200
File Encoding : 65001
Date: 26/05/2022 00:38:28
Date: 15/06/2022 08:20:08
*/
@ -884,7 +884,8 @@ CREATE TABLE "INFRA_FILE" (
"CREATE_TIME" DATE NOT NULL,
"UPDATER" NVARCHAR2(64),
"UPDATE_TIME" DATE NOT NULL,
"DELETED" NUMBER(1,0) DEFAULT 0
"DELETED" NUMBER(1,0) DEFAULT 0,
"NAME" NVARCHAR2(512)
)
LOGGING
NOCOMPRESS
@ -913,6 +914,7 @@ COMMENT ON COLUMN "INFRA_FILE"."CREATOR" IS '创建者';
COMMENT ON COLUMN "INFRA_FILE"."CREATE_TIME" IS '创建时间';
COMMENT ON COLUMN "INFRA_FILE"."UPDATER" IS '更新者';
COMMENT ON COLUMN "INFRA_FILE"."UPDATE_TIME" IS '更新时间';
COMMENT ON COLUMN "INFRA_FILE"."NAME" IS '文件名';
COMMENT ON TABLE "INFRA_FILE" IS '文件表';
-- ----------------------------
@ -3196,7 +3198,7 @@ COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."STATUS" IS '状态';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."ACCESS_TOKEN_VALIDITY_SECONDS" IS '访问令牌的有效期';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."REFRESH_TOKEN_VALIDITY_SECONDS" IS '刷新令牌的有效期';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."REDIRECT_URIS" IS '可重定向的 URI 地址';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."AUTO_APPROVE_SCOPES" IS '是否自动授权';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."AUTO_APPROVE_SCOPES" IS '自动通过的授权范围';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."AUTHORIZED_GRANT_TYPES" IS '授权类型';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."SCOPES" IS '授权范围';
COMMENT ON COLUMN "SYSTEM_OAUTH2_CLIENT"."AUTHORITIES" IS '权限';
@ -3795,7 +3797,7 @@ COMMIT;
DROP TABLE "SYSTEM_SMS_CHANNEL";
CREATE TABLE "SYSTEM_SMS_CHANNEL" (
"ID" NUMBER(20,0) NOT NULL,
"SIGNATURE" NVARCHAR2(10),
"SIGNATURE" NVARCHAR2(12),
"CODE" NVARCHAR2(63),
"STATUS" NUMBER(4,0) NOT NULL,
"REMARK" NVARCHAR2(255),
@ -5393,10 +5395,8 @@ ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT "SYS_C008671" CHECK ("STATE" IS
-- Indexes structure for table QRTZ_FIRED_TRIGGERS
-- ----------------------------
CREATE INDEX "IDX_QRTZ_FT_INST_JOB_REQ_RCVRY"
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "INSTANCE_NAME" ASC, "REQUESTS_RECOVERY" ASC) LOCAL
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "INSTANCE_NAME" ASC, "REQUESTS_RECOVERY" ASC)
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2
@ -5410,7 +5410,7 @@ STORAGE (
BUFFER_POOL DEFAULT
);
CREATE INDEX "IDX_QRTZ_FT_JG"
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC) LOCAL
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC)
LOGGING
ONLINE
NOSORT
@ -5427,10 +5427,8 @@ STORAGE (
BUFFER_POOL DEFAULT
);
CREATE INDEX "IDX_QRTZ_FT_J_G"
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC) LOCAL
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC)
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2
@ -5446,7 +5444,6 @@ STORAGE (
CREATE INDEX "IDX_QRTZ_FT_TG"
ON "QRTZ_FIRED_TRIGGERS" ("SCHED_NAME" ASC, "TRIGGER_GROUP" ASC) LOCAL
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
@ -5499,8 +5496,6 @@ STORAGE (
CREATE INDEX "IDX_QRTZ_J_REQ_RECOVERY"
ON "QRTZ_JOB_DETAILS" ("SCHED_NAME" ASC, "REQUESTS_RECOVERY" ASC) LOCAL
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2
@ -5622,8 +5617,10 @@ ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "SYS_C008696" CHECK ("START_TIME" IS
-- Indexes structure for table QRTZ_TRIGGERS
-- ----------------------------
CREATE INDEX "IDX_QRTZ_T_C"
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "CALENDAR_NAME" ASC)
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "CALENDAR_NAME" ASC) LOCAL
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2
@ -5637,10 +5634,8 @@ STORAGE (
BUFFER_POOL DEFAULT
);
CREATE INDEX "IDX_QRTZ_T_J"
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC) LOCAL
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_NAME" ASC, "JOB_GROUP" ASC)
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2
@ -5654,8 +5649,10 @@ STORAGE (
BUFFER_POOL DEFAULT
);
CREATE INDEX "IDX_QRTZ_T_JG"
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC)
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "JOB_GROUP" ASC) LOCAL
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2
@ -5669,10 +5666,8 @@ STORAGE (
BUFFER_POOL DEFAULT
);
CREATE INDEX "IDX_QRTZ_T_NEXT_FIRE_TIME"
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "NEXT_FIRE_TIME" ASC) LOCAL
ON "QRTZ_TRIGGERS" ("SCHED_NAME" ASC, "NEXT_FIRE_TIME" ASC)
LOGGING
ONLINE
NOSORT
VISIBLE
PCTFREE 10
INITRANS 2

View File

@ -12,7 +12,7 @@
Target Server Version : 140002
File Encoding : 65001
Date: 26/05/2022 00:10:12
Date: 15/06/2022 08:13:44
*/
@ -364,17 +364,6 @@ MAXVALUE 9223372036854775807
START 1
CACHE 1;
-- ----------------------------
-- Sequence structure for system_oauth2_approve_seq
-- ----------------------------
DROP SEQUENCE IF EXISTS "system_oauth2_approve_seq";
CREATE SEQUENCE "system_oauth2_approve_seq"
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
-- ----------------------------
-- Sequence structure for system_oauth2_client_seq
-- ----------------------------
@ -386,17 +375,6 @@ MAXVALUE 9223372036854775807
START 1
CACHE 1;
-- ----------------------------
-- Sequence structure for system_oauth2_code_seq
-- ----------------------------
DROP SEQUENCE IF EXISTS "system_oauth2_code_seq";
CREATE SEQUENCE "system_oauth2_code_seq"
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
-- ----------------------------
-- Sequence structure for system_oauth2_refresh_token_seq
-- ----------------------------
@ -1745,7 +1723,8 @@ CREATE TABLE "infra_file" (
"create_time" timestamp(6) NOT NULL,
"updater" varchar(64) COLLATE "pg_catalog"."default",
"update_time" timestamp(6) NOT NULL,
"deleted" int2 NOT NULL DEFAULT 0
"deleted" int2 NOT NULL DEFAULT 0,
"name" varchar(255) COLLATE "pg_catalog"."default"
)
;
COMMENT ON COLUMN "infra_file"."id" IS '文件编号';
@ -1759,6 +1738,7 @@ COMMENT ON COLUMN "infra_file"."create_time" IS '创建时间';
COMMENT ON COLUMN "infra_file"."updater" IS '更新者';
COMMENT ON COLUMN "infra_file"."update_time" IS '更新时间';
COMMENT ON COLUMN "infra_file"."deleted" IS '是否删除';
COMMENT ON COLUMN "infra_file"."name" IS '文件名';
COMMENT ON TABLE "infra_file" IS '文件表';
-- ----------------------------
@ -3412,47 +3392,6 @@ COMMENT ON TABLE "system_oauth2_access_token" IS '刷新令牌';
BEGIN;
COMMIT;
-- ----------------------------
-- Table structure for system_oauth2_approve
-- ----------------------------
DROP TABLE IF EXISTS "system_oauth2_approve";
CREATE TABLE "system_oauth2_approve" (
"id" int8 NOT NULL,
"user_id" int8 NOT NULL,
"user_type" int2 NOT NULL,
"client_id" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
"scope" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
"approved" bool NOT NULL,
"expires_time" timestamp(6) NOT NULL,
"creator" varchar(64) COLLATE "pg_catalog"."default",
"create_time" timestamp(6) NOT NULL,
"updater" varchar(64) COLLATE "pg_catalog"."default",
"update_time" timestamp(6) NOT NULL,
"deleted" int2 NOT NULL DEFAULT 0,
"tenant_id" int8 NOT NULL
)
;
COMMENT ON COLUMN "system_oauth2_approve"."id" IS '编号';
COMMENT ON COLUMN "system_oauth2_approve"."user_id" IS '用户编号';
COMMENT ON COLUMN "system_oauth2_approve"."user_type" IS '用户类型';
COMMENT ON COLUMN "system_oauth2_approve"."client_id" IS '客户端编号';
COMMENT ON COLUMN "system_oauth2_approve"."scope" IS '授权范围';
COMMENT ON COLUMN "system_oauth2_approve"."approved" IS '是否接受';
COMMENT ON COLUMN "system_oauth2_approve"."expires_time" IS '过期时间';
COMMENT ON COLUMN "system_oauth2_approve"."creator" IS '创建者';
COMMENT ON COLUMN "system_oauth2_approve"."create_time" IS '创建时间';
COMMENT ON COLUMN "system_oauth2_approve"."updater" IS '更新者';
COMMENT ON COLUMN "system_oauth2_approve"."update_time" IS '更新时间';
COMMENT ON COLUMN "system_oauth2_approve"."deleted" IS '是否删除';
COMMENT ON COLUMN "system_oauth2_approve"."tenant_id" IS '租户编号';
COMMENT ON TABLE "system_oauth2_approve" IS 'OAuth2 批准表';
-- ----------------------------
-- Records of system_oauth2_approve
-- ----------------------------
BEGIN;
COMMIT;
-- ----------------------------
-- Table structure for system_oauth2_client
-- ----------------------------
@ -3512,51 +3451,6 @@ INSERT INTO "system_oauth2_client" ("id", "client_id", "secret", "name", "logo",
INSERT INTO "system_oauth2_client" ("id", "client_id", "secret", "name", "logo", "description", "status", "access_token_validity_seconds", "refresh_token_validity_seconds", "redirect_uris", "authorized_grant_types", "scopes", "authorities", "resource_ids", "additional_information", "creator", "create_time", "updater", "update_time", "deleted", "auto_approve_scopes") VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/277a899d573723f1fcdfb57340f00379.png', NULL, 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '[]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2022-05-25 23:45:33.005', 0, '[]');
COMMIT;
-- ----------------------------
-- Table structure for system_oauth2_code
-- ----------------------------
DROP TABLE IF EXISTS "system_oauth2_code";
CREATE TABLE "system_oauth2_code" (
"id" int8 NOT NULL,
"user_id" int8 NOT NULL,
"user_type" int2 NOT NULL,
"code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL,
"client_id" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
"scopes" varchar(255) COLLATE "pg_catalog"."default",
"expires_time" timestamp(6) NOT NULL,
"redirect_uri" varchar(255) COLLATE "pg_catalog"."default",
"state" varchar(255) COLLATE "pg_catalog"."default",
"creator" varchar(64) COLLATE "pg_catalog"."default",
"create_time" timestamp(6) NOT NULL,
"updater" varchar(64) COLLATE "pg_catalog"."default",
"update_time" timestamp(6) NOT NULL,
"deleted" int2 NOT NULL DEFAULT 0,
"tenant_id" int8 NOT NULL
)
;
COMMENT ON COLUMN "system_oauth2_code"."id" IS '编号';
COMMENT ON COLUMN "system_oauth2_code"."user_id" IS '用户编号';
COMMENT ON COLUMN "system_oauth2_code"."user_type" IS '用户类型';
COMMENT ON COLUMN "system_oauth2_code"."code" IS '授权码';
COMMENT ON COLUMN "system_oauth2_code"."client_id" IS '客户端编号';
COMMENT ON COLUMN "system_oauth2_code"."scopes" IS '授权范围';
COMMENT ON COLUMN "system_oauth2_code"."expires_time" IS '过期时间';
COMMENT ON COLUMN "system_oauth2_code"."redirect_uri" IS '可重定向的 URI 地址';
COMMENT ON COLUMN "system_oauth2_code"."state" IS '状态';
COMMENT ON COLUMN "system_oauth2_code"."creator" IS '创建者';
COMMENT ON COLUMN "system_oauth2_code"."create_time" IS '创建时间';
COMMENT ON COLUMN "system_oauth2_code"."updater" IS '更新者';
COMMENT ON COLUMN "system_oauth2_code"."update_time" IS '更新时间';
COMMENT ON COLUMN "system_oauth2_code"."deleted" IS '是否删除';
COMMENT ON COLUMN "system_oauth2_code"."tenant_id" IS '租户编号';
COMMENT ON TABLE "system_oauth2_code" IS 'OAuth2 授权码表';
-- ----------------------------
-- Records of system_oauth2_code
-- ----------------------------
BEGIN;
COMMIT;
-- ----------------------------
-- Table structure for system_oauth2_refresh_token
-- ----------------------------
@ -4025,7 +3919,7 @@ COMMIT;
DROP TABLE IF EXISTS "system_sms_channel";
CREATE TABLE "system_sms_channel" (
"id" int8 NOT NULL,
"signature" varchar(10) COLLATE "pg_catalog"."default" NOT NULL,
"signature" varchar(12) COLLATE "pg_catalog"."default" NOT NULL,
"code" varchar(63) COLLATE "pg_catalog"."default" NOT NULL,
"status" int2 NOT NULL,
"remark" varchar(255) COLLATE "pg_catalog"."default",
@ -4726,21 +4620,11 @@ SELECT setval('"system_login_log_seq"', 23, true);
-- ----------------------------
SELECT setval('"system_oauth2_access_token_seq"', 11, true);
-- ----------------------------
-- Alter sequences owned by
-- ----------------------------
SELECT setval('"system_oauth2_approve_seq"', 4, true);
-- ----------------------------
-- Alter sequences owned by
-- ----------------------------
SELECT setval('"system_oauth2_client_seq"', 1, false);
-- ----------------------------
-- Alter sequences owned by
-- ----------------------------
SELECT setval('"system_oauth2_code_seq"', 4, true);
-- ----------------------------
-- Alter sequences owned by
-- ----------------------------
@ -5168,21 +5052,11 @@ ALTER TABLE "system_notice" ADD CONSTRAINT "system_notice_pkey" PRIMARY KEY ("id
-- ----------------------------
ALTER TABLE "system_oauth2_access_token" ADD CONSTRAINT "system_oauth2_access_token_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Primary Key structure for table system_oauth2_approve
-- ----------------------------
ALTER TABLE "system_oauth2_approve" ADD CONSTRAINT "system_oauth2_approve_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Primary Key structure for table system_oauth2_client
-- ----------------------------
ALTER TABLE "system_oauth2_client" ADD CONSTRAINT "system_oauth2_client_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Primary Key structure for table system_oauth2_code
-- ----------------------------
ALTER TABLE "system_oauth2_code" ADD CONSTRAINT "system_oauth2_code_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Primary Key structure for table system_oauth2_refresh_token
-- ----------------------------

View File

@ -12,7 +12,7 @@
Target Server Version : 15004198
File Encoding : 65001
Date: 26/05/2022 01:01:02
Date: 15/06/2022 08:15:45
*/
@ -2640,7 +2640,8 @@ CREATE TABLE [dbo].[infra_file] (
[create_time] datetime2(7) NOT NULL,
[updater] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[update_time] datetime2(7) NOT NULL,
[deleted] bit DEFAULT 0 NOT NULL
[deleted] bit DEFAULT 0 NOT NULL,
[name] nvarchar(256) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
)
GO
@ -2724,6 +2725,13 @@ EXEC sp_addextendedproperty
'COLUMN', N'deleted'
GO
EXEC sp_addextendedproperty
'MS_Description', N'文件路径',
'SCHEMA', N'dbo',
'TABLE', N'infra_file',
'COLUMN', N'name'
GO
EXEC sp_addextendedproperty
'MS_Description', N'文件表',
'SCHEMA', N'dbo',
@ -9490,7 +9498,7 @@ GO
CREATE TABLE [dbo].[system_sms_channel] (
[id] bigint IDENTITY(1,1) NOT NULL,
[signature] nvarchar(10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[signature] nvarchar(12) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[code] nvarchar(63) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[status] tinyint NOT NULL,
[remark] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

View File

@ -25,7 +25,6 @@
<module>yudao-spring-boot-starter-excel</module>
<module>yudao-spring-boot-starter-test</module>
<module>yudao-spring-boot-starter-extension</module>
<module>yudao-spring-boot-starter-biz-operatelog</module>
<module>yudao-spring-boot-starter-biz-dict</module>

View File

@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.dict.core.service;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import java.util.List;
public interface DictDataFrameworkService {
/**
@ -24,12 +22,4 @@ public interface DictDataFrameworkService {
*/
DictDataRespDTO parseDictDataFromCache(String type, String label);
/**
* 获得指定类型的字典数据从缓存中
*
* @param type 字典类型
* @return 字典数据列表
*/
List<DictDataRespDTO> listDictDatasFromCache(String type);
}

View File

@ -34,6 +34,13 @@
<scope>provided</scope>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行操作日志的记录 -->
<version>${revision}</version>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.google.guava</groupId>

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.framework.operatelog.config;
import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkServiceImpl;
import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -12,4 +15,9 @@ public class YudaoOperateLogAutoConfiguration {
return new OperateLogAspect();
}
@Bean
public OperateLogFrameworkService operateLogFrameworkService(OperateLogApi operateLogApi) {
return new OperateLogFrameworkServiceImpl(operateLogApi);
}
}

View File

@ -9,9 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import com.google.common.collect.Maps;
@ -57,13 +56,13 @@ public class OperateLogAspect {
/**
* 用于记录操作内容的上下文
*
* @see OperateLogCreateReqDTO#getContent()
* @see OperateLog#getContent()
*/
private static final ThreadLocal<String> CONTENT = new ThreadLocal<>();
/**
* 用于记录拓展字段的上下文
*
* @see OperateLogCreateReqDTO#getExts()
* @see OperateLog#getExts()
*/
private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>();
@ -73,16 +72,20 @@ public class OperateLogAspect {
@Around("@annotation(apiOperation)")
public Object around(ProceedingJoinPoint joinPoint, ApiOperation apiOperation) throws Throwable {
// 可能也添加了 @ApiOperation 注解
OperateLog operateLog = getMethodAnnotation(joinPoint, OperateLog.class);
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog = getMethodAnnotation(joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog.class);
return around0(joinPoint, operateLog, apiOperation);
}
@Around("!@annotation(io.swagger.annotations.ApiOperation) && @annotation(operateLog)") // 兼容处理只添加 @OperateLog 注解的情况
public Object around(ProceedingJoinPoint joinPoint, OperateLog operateLog) throws Throwable {
public Object around(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog) throws Throwable {
return around0(joinPoint, operateLog, null);
}
private Object around0(ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation) throws Throwable {
private Object around0(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation) throws Throwable {
// 目前只有管理员才记录操作日志所以非管理员直接调用不进行记录
Integer userType = WebFrameworkUtils.getLoginUserType();
if (!Objects.equals(userType, UserTypeEnum.ADMIN.getValue())) {
@ -121,7 +124,9 @@ public class OperateLogAspect {
EXTS.remove();
}
private void log(ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation,
private void log(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation,
Date startTime, Object result, Throwable exception) {
try {
// 判断不记录的情况
@ -136,113 +141,119 @@ public class OperateLogAspect {
}
}
private void log0(ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation,
private void log0(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation,
Date startTime, Object result, Throwable exception) {
OperateLogCreateReqDTO operateLogDTO = new OperateLogCreateReqDTO();
OperateLog operateLogObj = new OperateLog();
// 补全通用字段
operateLogDTO.setTraceId(TracerUtils.getTraceId());
operateLogDTO.setStartTime(startTime);
operateLogObj.setTraceId(TracerUtils.getTraceId());
operateLogObj.setStartTime(startTime);
// 补充用户信息
fillUserFields(operateLogDTO);
fillUserFields(operateLogObj);
// 补全模块信息
fillModuleFields(operateLogDTO, joinPoint, operateLog, apiOperation);
fillModuleFields(operateLogObj, joinPoint, operateLog, apiOperation);
// 补全请求信息
fillRequestFields(operateLogDTO);
fillRequestFields(operateLogObj);
// 补全方法信息
fillMethodFields(operateLogDTO, joinPoint, operateLog, startTime, result, exception);
fillMethodFields(operateLogObj, joinPoint, operateLog, startTime, result, exception);
// 异步记录日志
operateLogFrameworkService.createOperateLogAsync(operateLogDTO);
operateLogFrameworkService.createOperateLog(operateLogObj);
}
private static void fillUserFields(OperateLogCreateReqDTO operateLogDTO) {
operateLogDTO.setUserId(WebFrameworkUtils.getLoginUserId());
operateLogDTO.setUserType(WebFrameworkUtils.getLoginUserType());
private static void fillUserFields(OperateLog operateLogObj) {
operateLogObj.setUserId(WebFrameworkUtils.getLoginUserId());
operateLogObj.setUserType(WebFrameworkUtils.getLoginUserType());
}
private static void fillModuleFields(OperateLogCreateReqDTO operateLogDTO,
ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation) {
private static void fillModuleFields(OperateLog operateLogObj,
ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation) {
// module 属性
if (operateLog != null) {
operateLogDTO.setModule(operateLog.module());
operateLogObj.setModule(operateLog.module());
}
if (StrUtil.isEmpty(operateLogDTO.getModule())) {
if (StrUtil.isEmpty(operateLogObj.getModule())) {
Api api = getClassAnnotation(joinPoint, Api.class);
if (api != null) {
// 优先读取 @API name 属性
if (StrUtil.isNotEmpty(api.value())) {
operateLogDTO.setModule(api.value());
operateLogObj.setModule(api.value());
}
// 没有的话读取 @API tags 属性
if (StrUtil.isEmpty(operateLogDTO.getModule()) && ArrayUtil.isNotEmpty(api.tags())) {
operateLogDTO.setModule(api.tags()[0]);
if (StrUtil.isEmpty(operateLogObj.getModule()) && ArrayUtil.isNotEmpty(api.tags())) {
operateLogObj.setModule(api.tags()[0]);
}
}
}
// name 属性
if (operateLog != null) {
operateLogDTO.setName(operateLog.name());
operateLogObj.setName(operateLog.name());
}
if (StrUtil.isEmpty(operateLogDTO.getName()) && apiOperation != null) {
operateLogDTO.setName(apiOperation.value());
if (StrUtil.isEmpty(operateLogObj.getName()) && apiOperation != null) {
operateLogObj.setName(apiOperation.value());
}
// type 属性
if (operateLog != null && ArrayUtil.isNotEmpty(operateLog.type())) {
operateLogDTO.setType(operateLog.type()[0].getType());
operateLogObj.setType(operateLog.type()[0].getType());
}
if (operateLogDTO.getType() == null) {
if (operateLogObj.getType() == null) {
RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint));
OperateTypeEnum operateLogType = convertOperateLogType(requestMethod);
operateLogDTO.setType(operateLogType != null ? operateLogType.getType() : null);
operateLogObj.setType(operateLogType != null ? operateLogType.getType() : null);
}
// content exts 属性
operateLogDTO.setContent(CONTENT.get());
operateLogDTO.setExts(EXTS.get());
operateLogObj.setContent(CONTENT.get());
operateLogObj.setExts(EXTS.get());
}
private static void fillRequestFields(OperateLogCreateReqDTO operateLogDTO) {
private static void fillRequestFields(OperateLog operateLogObj) {
// 获得 Request 对象
HttpServletRequest request = ServletUtils.getRequest();
if (request == null) {
return;
}
// 补全请求信息
operateLogDTO.setRequestMethod(request.getMethod());
operateLogDTO.setRequestUrl(request.getRequestURI());
operateLogDTO.setUserIp(ServletUtil.getClientIP(request));
operateLogDTO.setUserAgent(ServletUtils.getUserAgent(request));
operateLogObj.setRequestMethod(request.getMethod());
operateLogObj.setRequestUrl(request.getRequestURI());
operateLogObj.setUserIp(ServletUtil.getClientIP(request));
operateLogObj.setUserAgent(ServletUtils.getUserAgent(request));
}
private static void fillMethodFields(OperateLogCreateReqDTO operateLogDTO,
ProceedingJoinPoint joinPoint, OperateLog operateLog,
private static void fillMethodFields(OperateLog operateLogObj,
ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
Date startTime, Object result, Throwable exception) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
operateLogDTO.setJavaMethod(methodSignature.toString());
operateLogObj.setJavaMethod(methodSignature.toString());
if (operateLog == null || operateLog.logArgs()) {
operateLogDTO.setJavaMethodArgs(obtainMethodArgs(joinPoint));
operateLogObj.setJavaMethodArgs(obtainMethodArgs(joinPoint));
}
if (operateLog == null || operateLog.logResultData()) {
operateLogDTO.setResultData(obtainResultData(result));
operateLogObj.setResultData(obtainResultData(result));
}
operateLogDTO.setDuration((int) (System.currentTimeMillis() - startTime.getTime()));
operateLogObj.setDuration((int) (System.currentTimeMillis() - startTime.getTime()));
// 正常处理 resultCode resultMsg 字段
if (result != null) {
if (result instanceof CommonResult) {
CommonResult<?> commonResult = (CommonResult<?>) result;
operateLogDTO.setResultCode(commonResult.getCode());
operateLogDTO.setResultMsg(commonResult.getMsg());
operateLogObj.setResultCode(commonResult.getCode());
operateLogObj.setResultMsg(commonResult.getMsg());
} else {
operateLogDTO.setResultCode(SUCCESS.getCode());
operateLogObj.setResultCode(SUCCESS.getCode());
}
}
// 异常处理 resultCode resultMsg 字段
if (exception != null) {
operateLogDTO.setResultCode(INTERNAL_SERVER_ERROR.getCode());
operateLogDTO.setResultMsg(ExceptionUtil.getRootCauseMessage(exception));
operateLogObj.setResultCode(INTERNAL_SERVER_ERROR.getCode());
operateLogObj.setResultMsg(ExceptionUtil.getRootCauseMessage(exception));
}
}
private static boolean isLogEnable(ProceedingJoinPoint joinPoint, OperateLog operateLog) {
private static boolean isLogEnable(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog) {
// @OperateLog 注解的情况下
if (operateLog != null) {
return operateLog.enable();

View File

@ -1,87 +0,0 @@
package cn.iocoder.yudao.framework.operatelog.core.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
/**
* 操作日志创建 Request DTO
*/
@Data
public class OperateLogCreateReqDTO {
@ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
@NotEmpty(message = "链路追踪编号不能为空")
private String traceId;
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
@NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "1")
@NotNull(message = "用户类型不能为空")
private Integer userType;
@ApiModelProperty(value = "操作模块", required = true, example = "订单")
@NotEmpty(message = "操作模块不能为空")
private String module;
@ApiModelProperty(value = "操作名", required = true, example = "创建订单")
@NotEmpty(message = "操作名")
private String name;
@ApiModelProperty(value = "操作分类", required = true, example = "1", notes = "参见 SysOperateLogTypeEnum 枚举类")
@NotNull(message = "操作分类不能为空")
private Integer type;
@ApiModelProperty(value = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。")
private String content;
@ApiModelProperty(value = "拓展字段", example = "{'orderId': 1}")
private Map<String, Object> exts;
@ApiModelProperty(value = "请求方法名", required = true, example = "GET")
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
@ApiModelProperty(value = "请求地址", required = true, example = "/xxx/yyy")
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
@ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
@ApiModelProperty(value = "Java 方法名", required = true, example = "cn.iocoder.yudao.UserController.save(...)")
@NotEmpty(message = "Java 方法名不能为空")
private String javaMethod;
@ApiModelProperty(value = "Java 方法的参数")
private String javaMethodArgs;
@ApiModelProperty(value = "开始时间", required = true)
@NotNull(message = "开始时间不能为空")
private Date startTime;
@ApiModelProperty(value = "执行时长,单位:毫秒", required = true)
@NotNull(message = "执行时长不能为空")
private Integer duration;
@ApiModelProperty(value = "结果码", required = true)
@NotNull(message = "结果码不能为空")
private Integer resultCode;
@ApiModelProperty(value = "结果提示")
private String resultMsg;
@ApiModelProperty(value = "结果数据")
private String resultData;
}

View File

@ -0,0 +1,110 @@
package cn.iocoder.yudao.framework.operatelog.core.service;
import lombok.Data;
import java.util.Date;
import java.util.Map;
/**
* 操作日志
*
* @author 芋道源码
*/
@Data
public class OperateLog {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 操作模块
*/
private String module;
/**
* 操作名
*/
private String name;
/**
* 操作分类
*/
private Integer type;
/**
* 操作明细
*/
private String content;
/**
* 拓展字段
*/
private Map<String, Object> exts;
/**
* 请求方法名
*/
private String requestMethod;
/**
* 请求地址
*/
private String requestUrl;
/**
* 用户 IP
*/
private String userIp;
/**
* 浏览器 UserAgent
*/
private String userAgent;
/**
* Java 方法名
*/
private String javaMethod;
/**
* Java 方法的参数
*/
private String javaMethodArgs;
/**
* 开始时间
*/
private Date startTime;
/**
* 执行时长单位毫秒
*/
private Integer duration;
/**
* 结果码
*/
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
/**
* 结果数据
*/
private String resultData;
}

View File

@ -1,17 +1,17 @@
package cn.iocoder.yudao.framework.operatelog.core.service;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import java.util.concurrent.Future;
/**
* 操作日志 Framework Service 接口
*
* @author 芋道源码
*/
public interface OperateLogFrameworkService {
/**
* 异步记录操作日志
* 记录操作日志
*
* @param reqVO 操作日志请求
* @return true: 记录成功,false: 记录失败
* @param operateLog 操作日志请求
*/
Future<Boolean> createOperateLogAsync(OperateLogCreateReqDTO reqVO);
void createOperateLog(OperateLog operateLog);
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.framework.operatelog.core.service;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
/**
* 操作日志 Framework Service 实现类
*
* 基于 {@link OperateLogApi} 实现记录操作日志
*
* @author 芋道源码
*/
@RequiredArgsConstructor
public class OperateLogFrameworkServiceImpl implements OperateLogFrameworkService {
private final OperateLogApi operateLogApi;
@Override
@Async
public void createOperateLog(OperateLog operateLog) {
OperateLogCreateReqDTO reqDTO = BeanUtil.copyProperties(operateLog, OperateLogCreateReqDTO.class);
operateLogApi.createOperateLog(reqDTO);
}
}

View File

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yudao-framework</artifactId>
<groupId>cn.iocoder.boot</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-extension</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>扩展点组件</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 测试包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,62 +0,0 @@
package cn.iocoder.yudao.framework.extension.config;
import cn.iocoder.yudao.framework.extension.core.ExtensionBootstrap;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionContext;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionContextHolder;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description 扩展点组件自动装配
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 21:50
* @class cn.iocoder.yudao.framework.extension.config.YudaoExtensionAutoConfiguration.java
*/
@Configuration
public class YudaoExtensionAutoConfiguration {
/**
* 组件初始化
* @return
*/
@Bean(initMethod = "init")
@ConditionalOnMissingBean(ExtensionBootstrap.class)
public ExtensionBootstrap bootstrap() {
return new ExtensionBootstrap();
}
/**
* 扩展点工厂
* @return
*/
@Bean
@ConditionalOnMissingBean({ExtensionRegisterFactory.class, ExtensionFactory.class})
public ExtensionRegisterFactory registerFactory() {
return new ExtensionRegisterFactory();
}
/**
* 扩展组件上下文对象
* @return
*/
@Bean
@ConditionalOnMissingBean({ExtensionContextHolder.class, ExtensionContext.class})
public ExtensionContextHolder context() {
return new ExtensionContextHolder();
}
/**
* 扩展组件执行器
* @return
*/
@Bean
@ConditionalOnMissingBean(ExtensionExecutor.class)
public ExtensionExecutor executor() {
return new ExtensionExecutor();
}
}

View File

@ -1,142 +0,0 @@
package cn.iocoder.yudao.framework.extension.core;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.StringJoiner;
/**
* @description 业务场景 = businessId + useCase + scenario, 用来标识系统中唯一的一个场景<br/>
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 22:19
* @class cn.iocoder.yudao.framework.extension.core.BusinessScenario.java
*/
public class BusinessScenario implements Serializable {
/**
* 默认业务id
*/
public final static String DEFAULT_BUSINESS_ID = "#defaultBusinessId#";
/**
* 默认用例
*/
public final static String DEFAULT_USECASE = "#defaultUseCase#";
/**
* 默认场景
*/
public final static String DEFAULT_SCENARIO = "#defaultScenario#";
/**
* 分隔符
*/
private final static String DOT_SEPARATOR = ".";
/**
* 业务Id
*/
private String businessId;
/**
* 用例
*/
private String useCase;
/**
* 场景
*/
private String scenario;
public BusinessScenario() {
this.businessId = DEFAULT_BUSINESS_ID;
this.useCase = DEFAULT_USECASE;
this.scenario = DEFAULT_SCENARIO;
}
public BusinessScenario(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario) {
this.businessId = businessId;
this.useCase = useCase;
this.scenario = scenario;
}
public BusinessScenario(@NotNull String scenario) {
this();
this.scenario = scenario;
}
public BusinessScenario(@NotNull String useCase, @NotNull String scenario) {
this(DEFAULT_BUSINESS_ID, useCase, scenario);
}
public String getBusinessId() {
return businessId;
}
public void setBusinessId(String businessId) {
this.businessId = businessId;
}
public String getUseCase() {
return useCase;
}
public void setUseCase(String useCase) {
this.useCase = useCase;
}
public String getScenario() {
return scenario;
}
public void setScenario(String scenario) {
this.scenario = scenario;
}
/**
* 构建业务场景
* @param businessId
* @param useCase
* @param scenario
* @return
*/
public static BusinessScenario valueOf(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario) {
return new BusinessScenario(businessId, useCase, scenario);
}
/**
* 构建业务场景
* @param useCase
* @param scenario
* @return
*/
public static BusinessScenario valueOf(@NotNull String useCase, @NotNull String scenario) {
return new BusinessScenario(useCase, scenario);
}
/**
* 构建业务场景
* @param scenario
* @return
*/
public static BusinessScenario valueOf(@NotNull String scenario) {
return new BusinessScenario(scenario);
}
/**
* 业务场景唯一标识
* @return
*/
public String getUniqueIdentity(){
return new StringJoiner(DOT_SEPARATOR).add(businessId).add(useCase).add(scenario).toString();
}
@Override
public String toString() {
return "BusinessScenario{" +
"businessId='" + businessId + '\'' +
", useCase='" + useCase + '\'' +
", scenario='" + scenario + '\'' +
'}';
}
}

View File

@ -1,41 +0,0 @@
package cn.iocoder.yudao.framework.extension.core;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
/**
* @description
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:18
* @class cn.iocoder.yudao.framework.extension.core.ExtensionBootstrap.java
*/
public class ExtensionBootstrap implements ApplicationContextAware {
/**
* spring 容器
*/
private ApplicationContext applicationContext;
@Autowired
private ExtensionRegisterFactory registerFactory;
/**
* 初始化
*/
@PostConstruct
public void init() {
registerFactory.setApplicationContext(applicationContext);
registerFactory.register(null);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -1,131 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* @description 执行器通用方法
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:38
* @class cn.iocoder.yudao.framework.extension.core.context.AbstractComponentExecutor.java
*/
public abstract class AbstractComponentExecutor {
/**
* "业务" + "用例" + "场景"执行扩展组件并返回执行结果
* @param targetClazz
* @param businessId
* @param useCase
* @param scenario
* @param function
* @param <R>
* @param <T>
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String businessId, String useCase, String scenario, Function<T, R> function) {
return execute(targetClazz, BusinessScenario.valueOf(businessId, useCase, scenario), function);
}
/**
* "用例" + "场景"执行扩展组件并返回执行结果
* @param targetClazz
* @param useCase
* @param scenario
* @param function
* @param <R>
* @param <T>
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String useCase, String scenario, Function<T, R> function) {
return execute(targetClazz, BusinessScenario.valueOf(useCase, scenario), function);
}
/**
* "场景"执行扩展组件并返回执行结果
* @param targetClazz
* @param scenario
* @param function
* @param <R>
* @param <T>
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, String scenario, Function<T, R> function) {
return execute(targetClazz, BusinessScenario.valueOf(scenario), function);
}
/**
* 执行扩展组件并返回执行结果
* @param targetClazz
* @param businessScenario
* @param function
* @param <R> Response Type
* @param <T> Parameter Type
* @return
*/
public <R, T extends ExtensionPoint> R execute(Class<T> targetClazz, BusinessScenario businessScenario, Function<T, R> function) {
T component = locateComponent(targetClazz, businessScenario);
return function.apply(component);
}
/**
* "业务" + "用例" + "场景"执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param businessId
* @param useCase
* @param scenario
* @param consumer
* @param <T>
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String businessId, String useCase, String scenario, Consumer<T> consumer) {
accept(targetClazz, BusinessScenario.valueOf(businessId, useCase, scenario), consumer);
}
/**
* "场景"执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param useCase
* @param scenario
* @param consumer
* @param <T>
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String useCase, String scenario, Consumer<T> consumer) {
accept(targetClazz, BusinessScenario.valueOf(useCase, scenario), consumer);
}
/**
* "场景"执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param scenario
* @param consumer
* @param <T>
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, String scenario, Consumer<T> consumer) {
accept(targetClazz, BusinessScenario.valueOf(scenario), consumer);
}
/**
* 执行扩展组件适用于无返回值的业务
* @param targetClazz
* @param businessScenario
* @param consumer
* @param <T> Parameter Type
*/
public <T extends ExtensionPoint> void accept(Class<T> targetClazz, BusinessScenario businessScenario, Consumer<T> consumer) {
T component = locateComponent(targetClazz, businessScenario);
consumer.accept(component);
}
/**
* 获取/定位扩展点组件
* @param targetClazz
* @param businessScenario
* @param <C>
* @return
*/
protected abstract <C extends ExtensionPoint> C locateComponent(Class<C> targetClazz, BusinessScenario businessScenario);
}

View File

@ -1,56 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
/**
* @description 上下文包含各个扩展点的相关操作
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 22:15
* @class cn.iocoder.yudao.framework.extension.core.context.ExtensionContext.java
*/
public interface ExtensionContext {
/**
* 根据业务场景唯一标识获取扩展点组件实现类
* @param businessId
* @param useCase
* @param scenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(String businessId, String useCase, String scenario, Class<T> clazz);
/**
* 根据"实例" + "场景"获取扩展点组件实现类其中业务idbusinessId= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_BUSINESS_ID}
* @param useCase
* @param scenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(String useCase, String scenario, Class<T> clazz);
/**
* 根据"场景"获取扩展点组件实现类 <br/>
* 其中
* 业务idbusinessId= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_BUSINESS_ID}
* 实例useCase= {@linkplain cn.iocoder.yudao.framework.extension.core.BusinessScenario.DEFAULT_USECASE}
* @param scenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(String scenario, Class<T> clazz);
/**
* 根据业务场景唯一标识获取扩展点组件实现类
* @param businessScenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T getPoint(BusinessScenario businessScenario, Class<T> clazz);
}

View File

@ -1,45 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotNull;
/**
* @description 上下文及扩展点组件工厂的持有类
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:29
* @class cn.iocoder.yudao.framework.extension.core.context.ExtensionContextHolder.java
*/
@Component
@Slf4j
public class ExtensionContextHolder implements ExtensionContext{
@Autowired
private ExtensionFactory factory;
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull String businessId, @NotNull String useCase, @NotNull String scenario, Class<T> clazz) {
return getPoint(BusinessScenario.valueOf(businessId, useCase, scenario), clazz);
}
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull String useCase, String scenario, Class<T> clazz) {
return getPoint(BusinessScenario.valueOf(useCase, scenario), clazz);
}
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull String scenario, Class<T> clazz) {
return getPoint(BusinessScenario.valueOf(scenario), clazz);
}
@Override
public <T extends ExtensionPoint> T getPoint(@NotNull BusinessScenario businessScenario, Class<T> clazz) {
return factory.get(businessScenario, clazz);
}
}

View File

@ -1,28 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.context;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @description 扩展组件执行器
* @author Qingchen
* @version 1.0.0
* @date 2021-08-29 00:32
* @class cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor.java
*/
@Component
@Slf4j
public class ExtensionExecutor extends AbstractComponentExecutor{
@Autowired
private ExtensionContextHolder contextHolder;
@Override
protected <C extends ExtensionPoint> C locateComponent(Class<C> targetClazz, BusinessScenario businessScenario) {
return contextHolder.getPoint(businessScenario, targetClazz);
}
}

View File

@ -1,96 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.factory;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Objects;
/**
* @description 扩展定义扩展坐标标识唯一一个业务场景实现
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 23:14
* @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionDefinition.java
*/
@Setter
@Getter
public class ExtensionDefinition implements Serializable {
/**
* 业务场景唯一标识(id)
*/
private String uniqueIdentify;
/**
* 扩展点实现类名称
*/
private String extensionPointName;
/**
* 业务场景
*/
private BusinessScenario businessScenario;
/**
* 扩展点实现类
*/
private ExtensionPoint extensionPoint;
/**
* class
*/
private Class extensionPointClass;
public ExtensionDefinition() {
}
public ExtensionDefinition(@NotNull BusinessScenario businessScenario, @NotNull ExtensionPoint extensionPoint) {
this.businessScenario = businessScenario;
this.extensionPoint = extensionPoint;
this.uniqueIdentify = this.businessScenario.getUniqueIdentity();
this.extensionPointClass = this.extensionPoint.getClass();
}
/**
* 构建definition
* @param businessScenario
* @param point
* @return
*/
public static ExtensionDefinition valueOf(@NotNull BusinessScenario businessScenario, @NotNull ExtensionPoint point) {
return new ExtensionDefinition(businessScenario, point);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExtensionDefinition that = (ExtensionDefinition) o;
return Objects.equals(uniqueIdentify, that.uniqueIdentify) && Objects.equals(extensionPointName, that.extensionPointName);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((uniqueIdentify == null) ? 0 : uniqueIdentify.hashCode());
result = prime * result + ((extensionPointName == null) ? 0 : extensionPointName.hashCode());
return result;
}
@Override
public String toString() {
return "ExtensionDefinition{" +
"uniqueIdentify='" + uniqueIdentify + '\'' +
", extensionPointName='" + extensionPointName + '\'' +
'}';
}
}

View File

@ -1,29 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.factory;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
/**
* @description 扩展点工厂
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 23:04
* @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionFactory.java
*/
public interface ExtensionFactory {
/**
* 注册所有扩展点实现类
* @param basePackage
*/
void register(String basePackage);
/**
* 根据业务场景获取指定类型的扩展点
* @param businessScenario
* @param clazz
* @param <T>
* @return
*/
<T extends ExtensionPoint> T get(BusinessScenario businessScenario, Class<T> clazz);
}

View File

@ -1,86 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.factory;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import javax.validation.constraints.NotNull;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description 注册工厂
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 23:07
* @class cn.iocoder.yudao.framework.extension.core.factory.ExtensionRegisterFactory.java
*/
@Component
@Slf4j
public class ExtensionRegisterFactory implements ExtensionFactory {
/**
* spring ApplicationContext
*/
private ApplicationContext applicationContext;
/**
* 扩展点实现类集合
*/
private Map<String, ExtensionDefinition> registerExtensionBeans = new ConcurrentHashMap<>();
@Override
public void register(String basePackage) {
final Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Extension.class);
if(beans == null || beans.isEmpty()) {
return;
}
beans.values().forEach(point -> doRegister((ExtensionPoint) point));
log.info("业务场景相关扩展点注册完成,注册数量: {}", registerExtensionBeans.size());
}
@Override
public <T extends ExtensionPoint> T get(BusinessScenario businessScenario, Class<T> clazz) {
final ExtensionDefinition definition = registerExtensionBeans.get(businessScenario.getUniqueIdentity());
if(definition == null) {
log.error("获取业务场景扩展点实现失败,失败原因:尚未定义该业务场景相关扩展点。{}", businessScenario);
throw new RuntimeException("尚未定义该业务场景相关扩展点 [" + businessScenario + "]");
}
return (T) definition.getExtensionPoint();
}
/**
* 注册扩展点
* @param point
*/
private void doRegister(@NotNull ExtensionPoint point) {
Class<?> extensionClazz = point.getClass();
if (AopUtils.isAopProxy(point)) {
extensionClazz = ClassUtils.getUserClass(point);
}
Extension extension = AnnotationUtils.findAnnotation(extensionClazz, Extension.class);
final BusinessScenario businessScenario = BusinessScenario.valueOf(extension.businessId(), extension.useCase(), extension.scenario());
final ExtensionDefinition definition = ExtensionDefinition.valueOf(businessScenario, point);
final ExtensionDefinition exist = registerExtensionBeans.get(businessScenario.getUniqueIdentity());
if(exist != null && !exist.equals(definition)) {
throw new RuntimeException("相同的业务场景重复注册了不同类型的扩展点实现 :【" + definition + "】【" + exist + "");
}
registerExtensionBeans.put(businessScenario.getUniqueIdentity(), definition);
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}

View File

@ -1,8 +0,0 @@
/**
* @description core 核心
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 21:54
* @class cn.iocoder.yudao.framework.extension.core.package-info.java
*/
package cn.iocoder.yudao.framework.extension.core;

View File

@ -1,11 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.point;
/**
* @description 扩展点 <br/>
* 表示一块逻辑在不同的业务有不同的实现使用扩展点做接口申明然后用{@linkplain cn.iocoder.yudao.framework.extension.core.stereotype.Extension}扩展去实现扩展点
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 22:06
* @class cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint.java
*/
public interface ExtensionPoint {
}

View File

@ -1,41 +0,0 @@
package cn.iocoder.yudao.framework.extension.core.stereotype;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* @description 表示带注释的类是扩展组件
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 21:59
* @class cn.iocoder.yudao.framework.extension.core.stereotype.Extension.java
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Component
public @interface Extension {
/**
* 业务 <br/>
* 一个自负盈亏的财务主体比如tmall淘宝和零售通就是三个不同的业务
* @return
*/
String businessId() default BusinessScenario.DEFAULT_BUSINESS_ID;
/**
* 用例 <br/>
* 描述了用户和系统之间的互动每个用例提供了一个或多个场景比如支付订单就是一个典型的用例
* @return
*/
String useCase() default BusinessScenario.DEFAULT_USECASE;
/**
* 场景 <br/>
* 场景也被称为用例的实例Instance包括用例所有的可能情况正常的和异常的比如对于"订单支付"这个用例就有支付宝支付银行卡支付"微信支付"等多个场景
* @return
*/
String scenario() default BusinessScenario.DEFAULT_SCENARIO;
}

View File

@ -1,8 +0,0 @@
/**
* @description 扩展点组件
* @author Qingchen
* @version 1.0.0
* @date 2021-08-28 14:35
* @class cn.iocoder.yudao.framework.extension.package-info.java
*/
package cn.iocoder.yudao.framework.extension;

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.yudao.framework.extension.config.YudaoExtensionAutoConfiguration

View File

@ -1,19 +0,0 @@
package cn.iocoder.yudao.framework.extension;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @description Application
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:32
* @class cn.iocoder.yudao.framework.extension.Application.java
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -1,43 +0,0 @@
package cn.iocoder.yudao.framework.extension;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.extension.core.BusinessScenario;
import cn.iocoder.yudao.framework.extension.core.context.ExtensionExecutor;
import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.math.BigDecimal;
/**
* @description
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:30
* @class cn.iocoder.yudao.framework.extension.ExtensionTest.java
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
@Slf4j
public class ExtensionTest {
@Autowired
private ExtensionExecutor extensionExecutor;
@Test
public void unifiedOrder() {
final BusinessScenario scenario = BusinessScenario.valueOf("pay", "jsapi", "wechat");
final TransactionsCommand command = new TransactionsCommand(IdUtil.objectId(), new BigDecimal(105), "Image形象店-深圳腾大-QQ公仔", "https://www.weixin.qq.com/wxpay/pay.php");
final TransactionsResult result = extensionExecutor.execute(PayExtensionPoint.class, scenario, extension -> extension.unifiedOrder(command));
log.info("result is: {}", JSONUtil.toJsonStr(result));
Assert.assertSame("wechat", result.getChannel());
}
}

View File

@ -1,8 +0,0 @@
/**
* @description
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:25
* @class cn.iocoder.yudao.framework.extension.package-info.java
*/
package cn.iocoder.yudao.framework.extension;

View File

@ -1,22 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay;
import cn.iocoder.yudao.framework.extension.core.point.ExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
/**
* @description 支付操作接口
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:35
* @class cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint.java
*/
public interface PayExtensionPoint extends ExtensionPoint {
/**
* 统一下单获取"预支付交易会话标识"
* @param command
* @return
*/
TransactionsResult unifiedOrder(TransactionsCommand command);
}

View File

@ -1,40 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.command;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @description 下单请求
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:48
* @class cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand.java
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TransactionsCommand implements Serializable {
/**
* 订单编号
*/
private String orderNo;
/**
* 支付金额
*/
private BigDecimal amount;
/**
* 商品描述
*/
private String productDescription;
/**
* 通知地址
*/
private String notifyUrl;
}

View File

@ -1,39 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.domain;
import lombok.*;
import java.io.Serializable;
/**
* @description 下单: 预支付交易单返回结果
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:43
* @class cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult.java
*/
@Data
@AllArgsConstructor
public class TransactionsResult implements Serializable {
/**
* 预支付交易会话标识
*/
private String prepayId;
/**
* 订单编号
*/
private String orderNo;
/**
* 系统内部支付单号
*/
private String paymentNo;
/**
* 支付渠道微信 or 支付宝
*/
private String channel;
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
import lombok.extern.slf4j.Slf4j;
/**
* @description 微信 JSAPI 支付
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:38
* @class cn.iocoder.yudao.framework.extension.pay.impl.AlipayService.java
*/
@Extension(businessId = "pay", useCase = "jsapi", scenario = "alipay")
@Slf4j
public class AlipayService implements PayExtensionPoint {
@Override
public TransactionsResult unifiedOrder(TransactionsCommand command) {
log.info("微信 JSAPI 支付:{}", JSONUtil.toJsonStr(command));
return new TransactionsResult("alipay26112221580621e9b071c00d9e093b0000", command.getOrderNo(), IdUtil.objectId(), "alipay");
}
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.framework.extension.pay.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.extension.core.stereotype.Extension;
import cn.iocoder.yudao.framework.extension.pay.PayExtensionPoint;
import cn.iocoder.yudao.framework.extension.pay.command.TransactionsCommand;
import cn.iocoder.yudao.framework.extension.pay.domain.TransactionsResult;
import lombok.extern.slf4j.Slf4j;
/**
* @description 微信 JSAPI 支付
* @author Qingchen
* @version 1.0.0
* @date 2021-08-30 10:37
* @class cn.iocoder.yudao.framework.extension.pay.impl.WechatPayService.java
*/
@Extension(businessId = "pay", useCase = "jsapi", scenario = "wechat")
@Slf4j
public class WechatPayService implements PayExtensionPoint {
@Override
public TransactionsResult unifiedOrder(TransactionsCommand command) {
log.info("微信 JSAPI 支付:{}", JSONUtil.toJsonStr(command));
return new TransactionsResult("wx26112221580621e9b071c00d9e093b0000", command.getOrderNo(), IdUtil.objectId(), "wechat");
}
}

View File

@ -1,19 +0,0 @@
### 作用
为了解决同一个流程不同业务有不同处理逻辑而产生,减少代码中 if else 逻辑,降低代码的耦合性,通过统一的扩展形式来支撑业务的变化。
### 原理
https://blog.csdn.net/significantfrank/article/details/100074716
### 使用介绍
参考测试代码 `cn.iocoder.yudao.framework.extension.ExtensionTest`

View File

@ -53,6 +53,13 @@
<scope>provided</scope> <!-- 设置为 provided主要是 GlobalExceptionHandler 使用 -->
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-infra-api</artifactId> <!-- 需要使用它,进行操作日志的记录 -->
<version>${revision}</version>
</dependency>
<!-- 服务保障相关 -->
<dependency>
<groupId>io.github.resilience4j</groupId>

View File

@ -2,9 +2,14 @@ package cn.iocoder.yudao.framework.apilog.config;
import cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkServiceImpl;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkServiceImpl;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi;
import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
@ -17,6 +22,16 @@ import javax.servlet.Filter;
@AutoConfigureAfter(YudaoWebAutoConfiguration.class)
public class YudaoApiLogAutoConfiguration {
@Bean
public ApiAccessLogFrameworkService apiAccessLogFrameworkService(ApiAccessLogApi apiAccessLogApi) {
return new ApiAccessLogFrameworkServiceImpl(apiAccessLogApi);
}
@Bean
public ApiErrorLogFrameworkService apiErrorLogFrameworkService(ApiErrorLogApi apiErrorLogApi) {
return new ApiErrorLogFrameworkServiceImpl(apiErrorLogApi);
}
/**
* 创建 ApiAccessLogFilter Bean记录 API 请求日志
*/

View File

@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.apilog.core.filter;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLog;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
@ -66,16 +66,16 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
private void createApiAccessLog(HttpServletRequest request, Date beginTime,
Map<String, String> queryString, String requestBody, Exception ex) {
ApiAccessLogCreateReqDTO accessLog = new ApiAccessLogCreateReqDTO();
ApiAccessLog accessLog = new ApiAccessLog();
try {
this.buildApiAccessLogDTO(accessLog, request, beginTime, queryString, requestBody, ex);
apiAccessLogFrameworkService.createApiAccessLogAsync(accessLog);
apiAccessLogFrameworkService.createApiAccessLog(accessLog);
} catch (Throwable th) {
log.error("[createApiAccessLog][url({}) log({}) 发生异常]", request.getRequestURI(), toJsonString(accessLog), th);
}
}
private void buildApiAccessLogDTO(ApiAccessLogCreateReqDTO accessLog, HttpServletRequest request, Date beginTime,
private void buildApiAccessLogDTO(ApiAccessLog accessLog, HttpServletRequest request, Date beginTime,
Map<String, String> queryString, String requestBody, Exception ex) {
// 处理用户信息
accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request));

View File

@ -0,0 +1,85 @@
package cn.iocoder.yudao.framework.apilog.core.service;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* API 访问日志
*
* @author 芋道源码
*/
@Data
public class ApiAccessLog {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/**
* 请求方法名
*/
@NotNull(message = "http 请求方法不能为空")
private String requestMethod;
/**
* 访问地址
*/
@NotNull(message = "访问地址不能为空")
private String requestUrl;
/**
* 请求参数
*/
@NotNull(message = "请求参数不能为空")
private String requestParams;
/**
* 用户 IP
*/
@NotNull(message = "ip 不能为空")
private String userIp;
/**
* 浏览器 UA
*/
@NotNull(message = "User-Agent 不能为空")
private String userAgent;
/**
* 开始请求时间
*/
@NotNull(message = "开始请求时间不能为空")
private Date beginTime;
/**
* 结束请求时间
*/
@NotNull(message = "结束请求时间不能为空")
private Date endTime;
/**
* 执行时长单位毫秒
*/
@NotNull(message = "执行时长不能为空")
private Integer duration;
/**
* 结果码
*/
@NotNull(message = "错误码不能为空")
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
}

View File

@ -1,9 +1,5 @@
package cn.iocoder.yudao.framework.apilog.core.service;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateReqDTO;
import javax.validation.Valid;
/**
* API 访问日志 Framework Service 接口
*
@ -14,8 +10,8 @@ public interface ApiAccessLogFrameworkService {
/**
* 创建 API 访问日志
*
* @param createDTO 创建信息
* @param apiAccessLog API 访问日志
*/
void createApiAccessLogAsync(@Valid ApiAccessLogCreateReqDTO createDTO);
void createApiAccessLog(ApiAccessLog apiAccessLog);
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.framework.apilog.core.service;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
/**
* API 访问日志 Framework Service 实现类
*
* 基于 {@link ApiAccessLogApi} 服务记录访问日志
*
* @author 芋道源码
*/
@RequiredArgsConstructor
public class ApiAccessLogFrameworkServiceImpl implements ApiAccessLogFrameworkService {
private final ApiAccessLogApi apiAccessLogApi;
@Override
@Async
public void createApiAccessLog(ApiAccessLog apiAccessLog) {
ApiAccessLogCreateReqDTO reqDTO = BeanUtil.copyProperties(apiAccessLog, ApiAccessLogCreateReqDTO.class);
apiAccessLogApi.createApiAccessLog(reqDTO);
}
}

View File

@ -0,0 +1,107 @@
package cn.iocoder.yudao.framework.apilog.core.service;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* API 错误日志
*
* @author 芋道源码
*/
@Data
public class ApiErrorLog {
/**
* 链路编号
*/
private String traceId;
/**
* 账号编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/**
* 请求方法名
*/
@NotNull(message = "http 请求方法不能为空")
private String requestMethod;
/**
* 访问地址
*/
@NotNull(message = "访问地址不能为空")
private String requestUrl;
/**
* 请求参数
*/
@NotNull(message = "请求参数不能为空")
private String requestParams;
/**
* 用户 IP
*/
@NotNull(message = "ip 不能为空")
private String userIp;
/**
* 浏览器 UA
*/
@NotNull(message = "User-Agent 不能为空")
private String userAgent;
/**
* 异常时间
*/
@NotNull(message = "异常时间不能为空")
private Date exceptionTime;
/**
* 异常名
*/
@NotNull(message = "异常名不能为空")
private String exceptionName;
/**
* 异常发生的类全名
*/
@NotNull(message = "异常发生的类全名不能为空")
private String exceptionClassName;
/**
* 异常发生的类文件
*/
@NotNull(message = "异常发生的类文件不能为空")
private String exceptionFileName;
/**
* 异常发生的方法名
*/
@NotNull(message = "异常发生的方法名不能为空")
private String exceptionMethodName;
/**
* 异常发生的方法所在行
*/
@NotNull(message = "异常发生的方法所在行不能为空")
private Integer exceptionLineNumber;
/**
* 异常的栈轨迹异常的栈轨迹
*/
@NotNull(message = "异常的栈轨迹不能为空")
private String exceptionStackTrace;
/**
* 异常导致的根消息
*/
@NotNull(message = "异常导致的根消息不能为空")
private String exceptionRootCauseMessage;
/**
* 异常导致的消息
*/
@NotNull(message = "异常导致的消息不能为空")
private String exceptionMessage;
}

View File

@ -1,9 +1,5 @@
package cn.iocoder.yudao.framework.apilog.core.service;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
import javax.validation.Valid;
/**
* API 错误日志 Framework Service 接口
*
@ -14,8 +10,8 @@ public interface ApiErrorLogFrameworkService {
/**
* 创建 API 错误日志
*
* @param createDTO 创建信息
* @param apiErrorLog API 错误日志
*/
void createApiErrorLogAsync(@Valid ApiErrorLogCreateReqDTO createDTO);
void createApiErrorLog(ApiErrorLog apiErrorLog);
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.framework.apilog.core.service;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
/**
* API 错误日志 Framework Service 实现类
*
* 基于 {@link ApiErrorLogApi} 服务记录错误日志
*
* @author 芋道源码
*/
@RequiredArgsConstructor
public class ApiErrorLogFrameworkServiceImpl implements ApiErrorLogFrameworkService {
private final ApiErrorLogApi apiErrorLogApi;
@Override
@Async
public void createApiErrorLog(ApiErrorLog apiErrorLog) {
ApiErrorLogCreateReqDTO reqDTO = BeanUtil.copyProperties(apiErrorLog, ApiErrorLogCreateReqDTO.class);
apiErrorLogApi.createApiErrorLog(reqDTO);
}
}

View File

@ -3,14 +3,14 @@ package cn.iocoder.yudao.framework.web.core.handler;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLog;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -229,18 +229,18 @@ public class GlobalExceptionHandler {
private void createExceptionLog(HttpServletRequest req, Throwable e) {
// 插入错误日志
ApiErrorLogCreateReqDTO errorLog = new ApiErrorLogCreateReqDTO();
ApiErrorLog errorLog = new ApiErrorLog();
try {
// 初始化 errorLog
initExceptionLog(errorLog, req, e);
// 执行插入 errorLog
apiErrorLogFrameworkService.createApiErrorLogAsync(errorLog);
apiErrorLogFrameworkService.createApiErrorLog(errorLog);
} catch (Throwable th) {
log.error("[createExceptionLog][url({}) log({}) 发生异常]", req.getRequestURI(), JsonUtils.toJsonString(errorLog), th);
}
}
private void initExceptionLog(ApiErrorLogCreateReqDTO errorLog, HttpServletRequest request, Throwable e) {
private void initExceptionLog(ApiErrorLog errorLog, HttpServletRequest request, Throwable e) {
// 处理用户信息
errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
errorLog.setUserType(WebFrameworkUtils.getLoginUserType(request));

View File

@ -21,6 +21,13 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -1,7 +1,5 @@
package cn.iocoder.yudao.module.infra.api.file;
import cn.hutool.core.util.IdUtil;
/**
* 文件 API 接口
*
@ -15,8 +13,8 @@ public interface FileApi {
* @param content 文件内容
* @return 文件路径
*/
default String createFile(byte[] content) throws Exception {
return createFile(IdUtil.fastUUID(), content);
default String createFile(byte[] content) {
return createFile(null, null, content);
}
/**
@ -26,6 +24,18 @@ public interface FileApi {
* @param content 文件内容
* @return 文件路径
*/
String createFile(String path, byte[] content) throws Exception;
default String createFile(String path, byte[] content) {
return createFile(null, path, content);
}
/**
* 保存文件并返回文件的访问路径
*
* @param name 文件名称
* @param path 文件路径
* @param content 文件内容
* @return 文件路径
*/
String createFile(String name, String path, byte[] content);
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.infra.api.logger;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import javax.validation.Valid;
/**
* API 访问日志的 API 接口
*
* @author 芋道源码
*/
public interface ApiAccessLogApi {
/**
* 创建 API 访问日志
*
* @param createDTO 创建信息
*/
void createApiAccessLog(@Valid ApiAccessLogCreateReqDTO createDTO);
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.infra.api.logger;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import javax.validation.Valid;
/**
* API 错误日志的 API 接口
*
* @author 芋道源码
*/
public interface ApiErrorLogApi {
/**
* 创建 API 错误日志
*
* @param createDTO 创建信息
*/
void createApiErrorLog(@Valid ApiErrorLogCreateReqDTO createDTO);
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.apilog.core.service.dto;
package cn.iocoder.yudao.module.infra.api.logger.dto;
import lombok.Data;
@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* API 访问日志创建 DTO
* API 访问日志
*
* @author 芋道源码
*/

View File

@ -1,18 +1,16 @@
package cn.iocoder.yudao.framework.apilog.core.service.dto;
package cn.iocoder.yudao.module.infra.api.logger.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* API 错误日志创建 DTO
* API 错误日志
*
* @author 芋道源码
*/
@Data
@Accessors(chain = true)
public class ApiErrorLogCreateReqDTO {
/**
@ -105,4 +103,5 @@ public class ApiErrorLogCreateReqDTO {
@NotNull(message = "异常导致的消息不能为空")
private String exceptionMessage;
}

View File

@ -19,8 +19,8 @@ public class FileApiImpl implements FileApi {
private FileService fileService;
@Override
public String createFile(String path, byte[] content) throws Exception {
return fileService.createFile(path, content);
public String createFile(String name, String path, byte[] content) {
return fileService.createFile(name, path, content);
}
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.infra.api.logger;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* API 访问日志的 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiAccessLogApiImpl implements ApiAccessLogApi {
@Resource
private ApiAccessLogService apiAccessLogService;
@Override
public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {
apiAccessLogService.createApiAccessLog(createDTO);
}
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.infra.api.logger;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.service.logger.ApiErrorLogService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* API 访问日志的 API 接口
*
* @author 芋道源码
*/
@Service
@Validated
public class ApiErrorLogApiImpl implements ApiErrorLogApi {
@Resource
private ApiErrorLogService apiErrorLogService;
@Override
public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) {
apiErrorLogService.createApiErrorLog(createDTO);
}
}

View File

@ -46,7 +46,7 @@ public class FileController {
@OperateLog(logArgs = false) // 上传文件没有记录操作日志的必要
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
@RequestParam(value = "path", required = false) String path) throws Exception {
return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream())));
return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
}
@DeleteMapping("/delete")

View File

@ -16,6 +16,9 @@ public class FileRespVO {
@ApiModelProperty(value = "文件路径", required = true, example = "yudao.jpg")
private String path;
@ApiModelProperty(value = "原文件名", required = true, example = "yudao.jpg")
private String name;
@ApiModelProperty(value = "文件 URL", required = true, example = "https://www.iocoder.cn/yudao.jpg")
private String url;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.infra.convert.logger;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExcelVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogRespVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.infra.convert.logger;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogExcelVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogRespVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO;

View File

@ -33,6 +33,10 @@ public class FileDO extends BaseDO {
* 关联 {@link FileConfigDO#getId()}
*/
private Long configId;
/**
* 原文件名
*/
private String name;
/**
* 路径即文件名
*/

View File

@ -22,11 +22,12 @@ public interface FileService {
/**
* 保存文件并返回文件的访问路径
*
* @param name 文件名称
* @param path 文件路径
* @param content 文件内容
* @return 文件路径
*/
String createFile(String path, byte[] content) throws Exception;
String createFile(String name, String path, byte[] content);
/**
* 删除文件

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.file.core.client.FileClient;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -37,12 +38,17 @@ public class FileServiceImpl implements FileService {
}
@Override
public String createFile(String path, byte[] content) throws Exception {
@SneakyThrows
public String createFile(String name, String path, byte[] content) {
// 计算默认的 path
String type = FileTypeUtil.getType(new ByteArrayInputStream(content), path);
String type = FileTypeUtil.getType(new ByteArrayInputStream(content), name);
if (StrUtil.isEmpty(path)) {
path = DigestUtil.md5Hex(content) + '.' + type;
}
// 如果 name 为空则使用 path 填充
if (StrUtil.isEmpty(name)) {
name = path;
}
// 上传到文件存储器
FileClient client = fileConfigService.getMasterFileClient();
@ -52,6 +58,7 @@ public class FileServiceImpl implements FileService {
// 保存到数据库
FileDO file = new FileDO();
file.setConfigId(client.getId());
file.setName(name);
file.setPath(path);
file.setUrl(url);
file.setType(type);

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO;
import java.util.List;
@ -13,7 +13,14 @@ import java.util.List;
*
* @author 芋道源码
*/
public interface ApiAccessLogService extends ApiAccessLogFrameworkService {
public interface ApiAccessLogService {
/**
* 创建 API 访问日志
*
* @param createReqDTO API 访问日志
*/
void createApiAccessLog(ApiAccessLogCreateReqDTO createReqDTO);
/**
* 获得 API 访问日志分页

View File

@ -1,13 +1,12 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import cn.iocoder.yudao.module.infra.convert.logger.ApiAccessLogConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO;
import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiAccessLogMapper;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -26,6 +25,12 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService {
@Resource
private ApiAccessLogMapper apiAccessLogMapper;
@Override
public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) {
ApiAccessLogDO apiAccessLog = ApiAccessLogConvert.INSTANCE.convert(createDTO);
apiAccessLogMapper.insert(apiAccessLog);
}
@Override
public PageResult<ApiAccessLogDO> getApiAccessLogPage(ApiAccessLogPageReqVO pageReqVO) {
return apiAccessLogMapper.selectPage(pageReqVO);
@ -36,11 +41,4 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService {
return apiAccessLogMapper.selectList(exportReqVO);
}
@Override
@Async
public void createApiAccessLogAsync(ApiAccessLogCreateReqDTO createDTO) {
ApiAccessLogDO apiAccessLog = ApiAccessLogConvert.INSTANCE.convert(createDTO);
apiAccessLogMapper.insert(apiAccessLog);
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO;
@ -13,7 +13,14 @@ import java.util.List;
*
* @author 芋道源码
*/
public interface ApiErrorLogService extends ApiErrorLogFrameworkService {
public interface ApiErrorLogService {
/**
* 创建 API 错误日志
*
* @param createReqDTO API 错误日志
*/
void createApiErrorLog(ApiErrorLogCreateReqDTO createReqDTO);
/**
* 获得 API 错误日志分页

View File

@ -1,16 +1,15 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import cn.iocoder.yudao.module.infra.convert.logger.ApiErrorLogConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO;
import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -30,6 +29,13 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService {
@Resource
private ApiErrorLogMapper apiErrorLogMapper;
@Override
public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) {
ApiErrorLogDO apiErrorLog = ApiErrorLogConvert.INSTANCE.convert(createDTO);
apiErrorLog.setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus());
apiErrorLogMapper.insert(apiErrorLog);
}
@Override
public PageResult<ApiErrorLogDO> getApiErrorLogPage(ApiErrorLogPageReqVO pageReqVO) {
return apiErrorLogMapper.selectPage(pageReqVO);
@ -54,12 +60,4 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService {
.processUserId(processUserId).processTime(new Date()).build());
}
@Override
@Async
public void createApiErrorLogAsync(ApiErrorLogCreateReqDTO createDTO) {
ApiErrorLogDO apiErrorLog = ApiErrorLogConvert.INSTANCE.convert(createDTO);
apiErrorLog.setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus());
apiErrorLogMapper.insert(apiErrorLog);
}
}

View File

@ -80,9 +80,9 @@ public class FileServiceTest extends BaseDbUnitTest {
String url = randomString();
when(client.upload(same(content), same(path))).thenReturn(url);
when(client.getId()).thenReturn(10L);
String name = "单测文件名";
// 调用
String result = fileService.createFile(path, content);
String result = fileService.createFile(name, path, content);
// 断言
assertEquals(result, url);
// 校验数据

View File

@ -1,13 +1,13 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO;
@ -155,7 +155,7 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest {
dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue()));
// 调用
apiAccessLogService.createApiAccessLogAsync(createDTO);
apiAccessLogService.createApiAccessLog(createDTO);
// 断言
ApiAccessLogDO infApiAccessLogDO = apiAccessLogMapper.selectOne(null);
assertNotNull(infApiAccessLogDO);

View File

@ -1,12 +1,12 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO;
@ -187,7 +187,7 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest {
dto -> dto.setUserType(RandomUtil.randomEle(UserTypeEnum.values()).getValue()));
// 调用
apiErrorLogService.createApiErrorLogAsync(createDTO);
apiErrorLogService.createApiErrorLog(createDTO);
// 断言
ApiErrorLogDO infApiErrorLogDO = infApiErrorLogMapper.selectOne(null);
assertNotNull(infApiErrorLogDO);

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import java.util.Collection;
@ -45,6 +46,9 @@ public interface DeptApi {
* @param ids 部门编号数组
* @return 部门 Map
*/
Map<Long, DeptRespDTO> getDeptMap(Set<Long> ids);
default Map<Long, DeptRespDTO> getDeptMap(Set<Long> ids) {
List<DeptRespDTO> list = getDepts(ids);
return CollectionUtils.convertMap(list, DeptRespDTO::getId);
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import javax.validation.Valid;
/**
* 操作日志 API 接口
*
* @author 芋道源码
*/
public interface OperateLogApi {
/**
* 创建操作日志
*
* @param createReqDTO 请求
*/
void createOperateLog(@Valid OperateLogCreateReqDTO createReqDTO);
}

View File

@ -0,0 +1,123 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
/**
* 操作日志创建 Request DTO
*/
@Data
public class OperateLogCreateReqDTO {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 操作模块
*/
@NotEmpty(message = "操作模块不能为空")
private String module;
/**
* 操作名
*/
@NotEmpty(message = "操作名")
private String name;
/**
* 操作分类
*/
@NotNull(message = "操作分类不能为空")
private Integer type;
/**
* 操作明细
*/
private String content;
/**
* 拓展字段
*/
private Map<String, Object> exts;
/**
* 请求方法名
*/
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
/**
* 请求地址
*/
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UserAgent
*/
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
/**
* Java 方法名
*/
@NotEmpty(message = "Java 方法名不能为空")
private String javaMethod;
/**
* Java 方法的参数
*/
private String javaMethodArgs;
/**
* 开始时间
*/
@NotNull(message = "开始时间不能为空")
private Date startTime;
/**
* 执行时长单位毫秒
*/
@NotNull(message = "执行时长不能为空")
private Integer duration;
/**
* 结果码
*/
@NotNull(message = "结果码不能为空")
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
/**
* 结果数据
*/
private String resultData;
}

View File

@ -9,8 +9,6 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 部门 API 实现类
@ -40,10 +38,4 @@ public class DeptApiImpl implements DeptApi {
deptService.validDepts(ids);
}
@Override
public Map<Long, DeptRespDTO> getDeptMap(Set<Long> ids) {
Map<Long, DeptDO> depts = deptService.getDeptMap(ids);
return DeptConvert.INSTANCE.convertMap(depts);
}
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 操作日志 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class OperateLogApiImpl implements OperateLogApi {
@Resource
private OperateLogService operateLogService;
@Override
public void createOperateLog(OperateLogCreateReqDTO createReqDTO) {
operateLogService.createOperateLog(createReqDTO);
}
}

View File

@ -19,7 +19,7 @@ public class LoginLogBaseVO {
@NotNull(message = "日志类型不能为空")
private Integer logType;
@ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
@ApiModelProperty(value = "链路追踪编号", example = "89aca178-a370-411c-ae02-3f0d672be4ab")
@NotEmpty(message = "链路追踪编号不能为空")
private String traceId;
@ -36,8 +36,7 @@ public class LoginLogBaseVO {
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
@NotEmpty(message = "浏览器 UserAgent 不能为空")
@ApiModelProperty(value = "浏览器 UserAgent", example = "Mozilla/5.0")
private String userAgent;
}

View File

@ -18,8 +18,7 @@ public class LoginLogRespVO extends LoginLogBaseVO {
@ApiModelProperty(value = "日志编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户编号", required = true, example = "666")
@NotNull(message = "用户编号不能为空")
@ApiModelProperty(value = "用户编号", example = "666")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举")

View File

@ -5,7 +5,8 @@ Content-Type: application/json
tenant-id: {{adminTenentId}}
{
"code": "test_01",
"templateCode": "test_01",
"mobile": "156016913900",
"params": {
"key01": "value01",
"key02": "value02"

View File

@ -31,6 +31,4 @@ public interface DeptConvert {
DeptRespDTO convert03(DeptDO bean);
Map<Long, DeptRespDTO> convertMap(Map<Long, DeptDO> map);
}

View File

@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@ -163,11 +163,6 @@ public class DictDataServiceImpl implements DictDataService {
return DictDataConvert.INSTANCE.convert02(labelDictDataCache.get(type, label));
}
@Override
public List<DictDataRespDTO> listDictDatasFromCache(String type) {
return DictDataConvert.INSTANCE.convertList03(labelDictDataCache.row(type).values());
}
@Override
public Long createDictData(DictDataCreateReqVO reqVO) {
// 校验正确性

View File

@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.system.service.logger;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
@ -10,8 +12,17 @@ import java.util.List;
/**
* 操作日志 Service 接口
*
* @author 芋道源码
*/
public interface OperateLogService extends OperateLogFrameworkService {
public interface OperateLogService {
/**
* 记录操作日志
*
* @param createReqDTO 操作日志请求
*/
void createOperateLog(OperateLogCreateReqDTO createReqDTO);
/**
* 获得操作日志分页列表

View File

@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert;
@ -13,8 +13,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -22,7 +20,6 @@ import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH;
@ -40,19 +37,11 @@ public class OperateLogServiceImpl implements OperateLogService {
private AdminUserService userService;
@Override
@Async
public Future<Boolean> createOperateLogAsync(OperateLogCreateReqDTO reqVO) {
boolean success = false;
try {
OperateLogDO logDO = OperateLogConvert.INSTANCE.convert(reqVO);
public void createOperateLog(OperateLogCreateReqDTO createReqDTO) {
OperateLogDO logDO = OperateLogConvert.INSTANCE.convert(createReqDTO);
logDO.setJavaMethodArgs(StrUtils.maxLength(logDO.getJavaMethodArgs(), JAVA_METHOD_ARGS_MAX_LENGTH));
logDO.setResultData(StrUtils.maxLength(logDO.getResultData(), RESULT_MAX_LENGTH));
success = operateLogMapper.insert(logDO) == 1;
} catch (Throwable throwable) {
// 仅仅打印日志不对外抛出原因是还是要保留现场数据
log.error("[createOperateLogAsync][记录操作日志异常,日志为 ({})]", reqVO, throwable);
}
return new AsyncResult<>(success);
operateLogMapper.insert(logDO);
}
@Override

View File

@ -7,9 +7,10 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
@ -17,7 +18,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper;
import cn.iocoder.yudao.module.system.enums.common.SexEnum;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@ -25,8 +25,6 @@ import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
@ -49,7 +47,7 @@ public class OperateLogServiceImplTest extends BaseDbUnitTest {
private AdminUserService userService;
@Test
public void testCreateOperateLogAsync() throws InterruptedException, ExecutionException {
public void testCreateOperateLogAsync() {
String traceId = TracerUtils.getTraceId();
OperateLogCreateReqDTO reqVO = RandomUtils.randomPojo(OperateLogCreateReqDTO.class, o -> {
o.setTraceId(traceId);
@ -59,8 +57,7 @@ public class OperateLogServiceImplTest extends BaseDbUnitTest {
});
// 执行service方法
Future<Boolean> future = operateLogServiceImpl.createOperateLogAsync(reqVO);
future.get();
operateLogServiceImpl.createOperateLog(reqVO);
// 断言插入是否正确
OperateLogDO sysOperateLogDO = operateLogMapper.selectOne("trace_id", traceId);
assertPojoEquals(reqVO, sysOperateLogDO);

View File

@ -225,7 +225,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes);
// mock 方法
String avatar = randomString();
when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar);
when(fileApi.createFile(eq( avatarFileBytes))).thenReturn(avatar);
// 调用
userService.updateUserAvatar(userId, avatarFile);

View File

@ -26,8 +26,9 @@
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="文件名" align="center" prop="path" />
<el-table-column label="URL" align="center" prop="url" />
<el-table-column label="文件名" align="center" prop="name" />
<el-table-column label="文件路径" align="center" prop="path" />
<el-table-column label="文件 URL" align="center" prop="url" />
<el-table-column label="文件大小" align="center" prop="size" width="120" :formatter="sizeFormat" />
<el-table-column label="文件类型" align="center" prop="type" width="80" />
<!-- <el-table-column label="文件内容" align="center" prop="content">-->
@ -160,7 +161,7 @@ export default {
},
/** 处理上传的文件发生变化 */
handleFileChange(file, fileList) {
this.upload.data.path = file.name;
},
/** 处理文件上传中 */
handleFileUploadProgress(event, file, fileList) {