Przeglądaj źródła

Merge branch 'master' into unit_logger_system

# Conflicts:
#	src/test/resources/sql/clean.sql
#	src/test/resources/sql/create_tables.sql
wangkai 4 lat temu
rodzic
commit
75d21928a4
59 zmienionych plików z 1952 dodań i 635 usunięć
  1. 51 28
      README.md
  2. 11 1
      pom.xml
  3. 10 38
      ruoyi-ui/src/views/infra/config/index.vue
  4. 239 141
      sql/ruoyi-vue-pro.sql
  5. 9 1
      src/main/java/cn/iocoder/dashboard/framework/mybatis/config/MybatisConfiguration.java
  6. 14 4
      src/main/java/cn/iocoder/dashboard/framework/mybatis/core/dataobject/BaseDO.java
  7. 63 0
      src/main/java/cn/iocoder/dashboard/framework/mybatis/core/handler/DefaultDBFieldHandler.java
  8. 4 0
      src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java
  9. 0 1
      src/main/java/cn/iocoder/dashboard/framework/resilience4j/《芋道 Spring Boot 安全框架 Spring Security 入门》.md
  10. 1 0
      src/main/java/cn/iocoder/dashboard/framework/resilience4j/《芋道 Spring Boot 服务容错 Resilience4j 入门》.md
  11. 1 1
      src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java
  12. 2 1
      src/main/java/cn/iocoder/dashboard/framework/security/core/handler/LogoutSuccessHandlerImpl.java
  13. 21 3
      src/main/java/cn/iocoder/dashboard/framework/security/core/util/SecurityFrameworkUtils.java
  14. 6 4
      src/main/java/cn/iocoder/dashboard/framework/swagger/config/SwaggerAutoConfiguration.java
  15. 2 1
      src/main/java/cn/iocoder/dashboard/framework/web/config/WebConfiguration.java
  16. 47 49
      src/main/java/cn/iocoder/dashboard/modules/infra/controller/config/InfConfigController.java
  17. 1 1
      src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobLogController.java
  18. 10 9
      src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigMapper.java
  19. 25 21
      src/main/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigService.java
  20. 27 22
      src/main/java/cn/iocoder/dashboard/modules/infra/service/config/impl/InfConfigServiceImpl.java
  21. 2 2
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/dept/SysDeptBaseVO.java
  22. 3 2
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostBaseVO.java
  23. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostExcelVO.java
  24. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/data/SysDictDataBaseVO.java
  25. 2 2
      src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/menu/SysMenuBaseVO.java
  26. 3 2
      src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/role/SysRoleBaseVO.java
  27. 14 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/auth/SysUserSessionDO.java
  28. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/dept/SysDeptDO.java
  29. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/dept/SysPostDO.java
  30. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/permission/SysMenuDO.java
  31. 5 0
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/auth/SysUserSessionMapper.java
  32. 3 3
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java
  33. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/SysRedisKeyConstants.java
  34. 6 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java
  35. 11 4
      src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java
  36. 6 0
      src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionService.java
  37. 20 1
      src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java
  38. 48 6
      src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java
  39. 19 15
      src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
  40. 8 4
      src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictTypeServiceImpl.java
  41. 3 1
      src/main/java/cn/iocoder/dashboard/modules/system/service/notice/impl/SysNoticeServiceImpl.java
  42. 4 2
      src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java
  43. 10 0
      src/main/java/cn/iocoder/dashboard/util/object/ObjectUtils.java
  44. 46 0
      src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java
  45. 37 0
      src/test/java/cn/iocoder/dashboard/BaseDbUnitTest.java
  46. 1 0
      src/test/java/cn/iocoder/dashboard/BaseSpringBootUnitTest.java
  47. 0 2
      src/test/java/cn/iocoder/dashboard/config/RedisTestConfiguration.java
  48. 0 16
      src/test/java/cn/iocoder/dashboard/config/SecurityTestConfiguration.java
  49. 119 103
      src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java
  50. 20 2
      src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java
  51. 78 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java
  52. 274 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java
  53. 200 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java
  54. 149 20
      src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java
  55. 78 62
      src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java
  56. 164 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java
  57. 6 39
      src/test/resources/application-unit-test.yaml
  58. 2 0
      src/test/resources/sql/clean.sql
  59. 61 14
      src/test/resources/sql/create_tables.sql

+ 51 - 28
README.md

@@ -1,6 +1,6 @@
 ## 平台简介
 
-**芋道** 是基于 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) **重构**,一套**全部开源**的**企业级**的快速开发平台,毫无保留给个人及企业免费使用。
+**芋道**,一套**全部开源**的**企业级**的快速开发平台,毫无保留给个人及企业免费使用。
 
 > 有任何问题,或者想要的功能,可以在 _Issues_ 中提给艿艿。
 
@@ -17,40 +17,63 @@
 * 基础设施
 * 研发工具
 
+> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
+> 
+> 额外新增的功能,我们使用 🚀 标记。
+
+🙂 所有功能,都通过 **单元测试** 保证高质量。
+
 ### 系统功能
 
-1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置
-1. 在线用户:当前系统中活跃用户状态监控
-1. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分
-1. 菜单管理:配置系统菜单,操作权限,按钮权限标识等
-1. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限
-1. 岗位管理:配置系统用户所属担任职务
-1. 字典管理:对系统中经常使用的一些较为固定的数据进行维护
-1. 通知公告:系统通知公告信息发布维护
-1. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询
-1. 登录日志:系统登录日志记录查询包含登录异常
+
+|  | 功能 | 描述 |
+| --- | --- | --- |
+|  | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
+|  | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |
+|  | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
+|  | 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等 |
+|  | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
+|  | 岗位管理 | 配置系统用户所属担任职务 |
+|  | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
+|  | 通知公告 | 系统通知公告信息发布维护 |
+| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
+|  | 登录日志 | 系统登录日志记录查询包含登录异常 |
+
+计划新增功能:
+* 短信
+* 邮件
+* 钉钉、飞书等通知
 
 ### 基础设施
 
-1. 配置管理:对系统动态配置常用参数
-1. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志
-1. API 日志:包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题
-1. MySQL 监控:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈
-1. Redis 监控:监控 Redis 数据库的使用情况,使用的 Redis Key 管理
-1. Java 监控:基于 Spring Boot Admin 实现 Java 应用的监控
-1. 链路追踪:基于 SkyWalking 实现性能监控,特别是链路的追踪
-1. 分布式锁:基于 Redis 实现分布式锁,满足并发场景
-1. 幂等组件:基于 Redis 实现幂等组件,解决重复请求问题
-1. 服务保障:基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能
-1. 日志服务:轻量级日志中心,查看远程服务器的日志
-1. 单元测试:基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等
+|  | 功能 | 描述 |
+| --- | --- | --- |
+| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
+| | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
+| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
+|  | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
+| | Redis 监控 |监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
+| 🚀 |Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
+| 🚀 | 链路追踪 | 基于 SkyWalking 实现性能监控,特别是链路的追踪 |
+| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 |
+| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 |
+| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 |
+| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
+| 🚀 | 单元测试 |基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
+
+计划新增:
+* 工作流
+* 错误码
+* 文件服务
 
 ### 研发工具
 
-1. 表单构建:拖动表单元素生成相应的 HTML 代码
-1. 代码生成:前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载
-1. 系统接口:基于 Swagger 自动生成相关的 RESTful API 接口文档
-1. 数据库文档:基于 Screw 自动生成数据库文档
+|  | 功能 | 描述 |
+| --- | --- | --- |
+| 🚀 | 代码生成 |前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |
+| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |
+| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |
+| | 表单构建 | 拖动表单元素生成相应的 HTML 代码 |
 
 ## 在线体验
 
@@ -86,7 +109,7 @@
 | [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
 | [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
 | [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.7.0 | - |
-| [Mockito](https://junit.org/junit5/) | Java Mock 框架 | 3.6.28 | - |
+| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 3.6.28 | - |
 
 **前端**
 

+ 11 - 1
pom.xml

@@ -2,7 +2,7 @@
 <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">
-	<modelVersion>4.0.0</modelVersion>
+    <modelVersion>4.0.0</modelVersion>
 
     <groupId>cn.iocoder</groupId>
     <artifactId>dashboard</artifactId>
@@ -25,6 +25,7 @@
         <spring.boot.version>2.4.2</spring.boot.version>
         <!-- Web 相关 -->
         <knife4j.version>3.0.2</knife4j.version>
+        <swagger-annotations.version>1.5.22</swagger-annotations.version>
         <!-- DB 相关 -->
         <mysql-connector-java.version>5.1.46</mysql-connector-java.version>
         <druid.version>1.2.4</druid.version>
@@ -104,8 +105,17 @@
                     <artifactId>guava</artifactId>
                     <groupId>com.google.guava</groupId>
                 </exclusion>
+                <exclusion>
+                    <artifactId>swagger-annotations</artifactId>
+                    <groupId>io.swagger</groupId>
+                </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>${swagger-annotations.version}</version>
+        </dependency>
 
         <!-- DB 相关 -->
         <dependency>

+ 10 - 38
ruoyi-ui/src/views/infra/config/index.vue

@@ -2,24 +2,12 @@
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
       <el-form-item label="参数名称" prop="name">
-        <el-input
-          v-model="queryParams.name"
-          placeholder="请输入参数名称"
-          clearable
-          size="small"
-          style="width: 240px"
-          @keyup.enter.native="handleQuery"
-        />
+        <el-input v-model="queryParams.name" placeholder="请输入参数名称" clearable size="small" style="width: 240px"
+                  @keyup.enter.native="handleQuery"/>
       </el-form-item>
       <el-form-item label="参数键名" prop="key">
-        <el-input
-          v-model="queryParams.key"
-          placeholder="请输入参数键名"
-          clearable
-          size="small"
-          style="width: 240px"
-          @keyup.enter.native="handleQuery"
-        />
+        <el-input v-model="queryParams.key" placeholder="请输入参数键名" clearable size="small" style="width: 240px"
+                  @keyup.enter.native="handleQuery"/>
       </el-form-item>
       <el-form-item label="系统内置" prop="type">
         <el-select v-model="queryParams.type" placeholder="系统内置" clearable size="small">
@@ -56,7 +44,7 @@
           icon="el-icon-plus"
           size="mini"
           @click="handleAdd"
-          v-hasPermi="['infra:config:add']"
+          v-hasPermi="['infra:config:create']"
         >新增</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -95,31 +83,15 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['infra:config:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['infra:config:remove']"
-          >删除</el-button>
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                     v-hasPermi="['infra:config:update']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                     v-hasPermi="['infra:config:delete']">删除</el-button>
         </template>
       </el-table-column>
     </el-table>
 
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNo"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" @pagination="getList"/>
 
     <!-- 添加或修改参数配置对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>

+ 239 - 141
sql/ruoyi-vue-pro.sql

@@ -11,7 +11,7 @@
  Target Server Version : 50718
  File Encoding         : 65001
 
- Date: 07/03/2021 00:43:34
+ Date: 10/03/2021 01:31:28
 */
 
 SET NAMES utf8mb4;
@@ -37,18 +37,93 @@ CREATE TABLE `inf_api_access_log` (
   `duration` int(11) NOT NULL COMMENT '执行时长',
   `result_code` int(11) NOT NULL DEFAULT '0' COMMENT '结果码',
   `result_msg` varchar(512) DEFAULT '' COMMENT '结果提示',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=1822 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表';
+) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表';
 
 -- ----------------------------
 -- Records of inf_api_access_log
 -- ----------------------------
 BEGIN;
+INSERT INTO `inf_api_access_log` VALUES (1, 'd8909966-2abb-43b1-998f-850779178463', 0, 2, 'dashboard', 'GET', '/api/get-permission-info', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:46', '2021-03-10 01:11:47', 127, 0, '', NULL, '2021-03-10 01:11:47', NULL, '2021-03-10 01:11:47', b'0');
+INSERT INTO `inf_api_access_log` VALUES (2, 'f40ee1af-4b8e-4351-ba77-c0ca41865d01', 0, 2, 'dashboard', 'GET', '/api/system/dict-data/list-all-simple', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:46', '2021-03-10 01:11:47', 127, 0, '', NULL, '2021-03-10 01:11:47', NULL, '2021-03-10 01:11:47', b'0');
+INSERT INTO `inf_api_access_log` VALUES (3, '38657f93-449b-4c92-a412-d76c32c3ba74', 0, 2, 'dashboard', 'POST', '/api/logout', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:47', '2021-03-10 01:11:47', 3, 0, '', NULL, '2021-03-10 01:11:47', NULL, '2021-03-10 01:11:47', b'0');
+INSERT INTO `inf_api_access_log` VALUES (4, '24303cdb-dae9-4f09-b316-e9eb38023ddf', 0, 2, 'dashboard', 'POST', '/api/logout', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:48', '2021-03-10 01:11:48', 2, 0, '', NULL, '2021-03-10 01:11:48', NULL, '2021-03-10 01:11:48', b'0');
+INSERT INTO `inf_api_access_log` VALUES (5, 'fe324978-a665-4e25-8e16-ee78750de461', 0, 2, 'dashboard', 'GET', '/api/system/captcha/get-image', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:47', '2021-03-10 01:11:50', 2698, 0, '', NULL, '2021-03-10 01:11:50', NULL, '2021-03-10 01:11:50', b'0');
+INSERT INTO `inf_api_access_log` VALUES (6, '205b39bd-471c-4e0c-bbeb-f9ad836d47c7', 0, 2, 'dashboard', 'GET', '/api/system/captcha/get-image', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:49', '2021-03-10 01:11:50', 1157, 0, '', NULL, '2021-03-10 01:11:50', NULL, '2021-03-10 01:11:50', b'0');
+INSERT INTO `inf_api_access_log` VALUES (7, 'aff42e1b-73d9-431d-95b9-7a7d18595a5b', 0, 2, 'dashboard', 'POST', '/api/login', '{\"query\":{},\"body\":\"{\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\"admin123\\\",\\\"code\\\":\\\"1nfjj\\\",\\\"uuid\\\":\\\"8466085c41534a948632f82140e8d9e1\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:53', '2021-03-10 01:11:53', 35, 1002000003, '验证码不存在', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `inf_api_access_log` VALUES (8, '25f0e932-cf92-4b95-b3fb-5a4896bd9241', 0, 2, 'dashboard', 'GET', '/api/system/captcha/get-image', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:53', '2021-03-10 01:11:53', 13, 0, '', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `inf_api_access_log` VALUES (9, 'ad750e4c-5310-4e42-9e41-0871033ca55d', 0, 2, 'dashboard', 'POST', '/api/login', '{\"query\":{},\"body\":\"{\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\"admin123\\\",\\\"code\\\":\\\"1nfjj\\\",\\\"uuid\\\":\\\"8466085c41534a948632f82140e8d9e1\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:53', '2021-03-10 01:11:53', 273, 0, '', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `inf_api_access_log` VALUES (10, '0e1a7560-d447-4e95-935a-e3f6cf4a222d', 1, 2, 'dashboard', 'GET', '/api/system/dict-data/list-all-simple', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:53', '2021-03-10 01:11:53', 31, 0, '', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `inf_api_access_log` VALUES (11, '0bf76082-8584-4725-ad8e-d23b44f1a886', 1, 2, 'dashboard', 'GET', '/api/get-permission-info', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:53', '2021-03-10 01:11:53', 34, 0, '', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `inf_api_access_log` VALUES (12, 'f9aed1f8-5a1d-4175-946a-e58e2772e4a3', 1, 2, 'dashboard', 'GET', '/api/list-menus', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:53', '2021-03-10 01:11:53', 12, 0, '', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `inf_api_access_log` VALUES (13, '2feeb4ff-e8a6-48a9-8370-9a1b8b1dea5e', 0, 2, 'dashboard', 'GET', '/api/system/file/get/add5ec1891a7d97d2cc1d60847e16294.jpg', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:11:54', '2021-03-10 01:11:54', 26, 0, '', NULL, '2021-03-10 01:11:54', NULL, '2021-03-10 01:11:54', b'0');
+INSERT INTO `inf_api_access_log` VALUES (14, '36b77d6f-30d3-483e-ad79-196975d8fe0b', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:02', '2021-03-10 01:12:02', 31, 0, '', NULL, '2021-03-10 01:12:02', NULL, '2021-03-10 01:12:02', b'0');
+INSERT INTO `inf_api_access_log` VALUES (15, 'e50a5433-90b7-4e8f-9d1a-59f15c1a4e0a', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:07', '2021-03-10 01:12:07', 16, 0, '', NULL, '2021-03-10 01:12:07', NULL, '2021-03-10 01:12:07', b'0');
+INSERT INTO `inf_api_access_log` VALUES (16, 'b1ef7809-57f1-4aad-99cb-f53d1c85ae8a', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"106\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:07', '2021-03-10 01:12:07', 11, 0, '', NULL, '2021-03-10 01:12:07', NULL, '2021-03-10 01:12:07', b'0');
+INSERT INTO `inf_api_access_log` VALUES (17, '18c41274-8fc2-4012-8d63-14fe72a0cc64', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":106,\\\"status\\\":0,\\\"createTime\\\":1609837428000,\\\"name\\\":\\\"配置管理\\\",\\\"permission\\\":\\\"\\\",\\\"type\\\":2,\\\"sort\\\":1,\\\"parentId\\\":2,\\\"path\\\":\\\"config\\\",\\\"icon\\\":\\\"edit\\\",\\\"component\\\":\\\"infra/config/index\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:09', '2021-03-10 01:12:10', 54, 0, '', NULL, '2021-03-10 01:12:10', NULL, '2021-03-10 01:12:10', b'0');
+INSERT INTO `inf_api_access_log` VALUES (18, '3ec30780-7d9e-40fd-b9e1-df0758530bc9', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:10', '2021-03-10 01:12:10', 15, 0, '', NULL, '2021-03-10 01:12:10', NULL, '2021-03-10 01:12:10', b'0');
+INSERT INTO `inf_api_access_log` VALUES (19, '3a0dd3e6-60e8-43cc-82aa-d63d332dcd74', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1032\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:12', '2021-03-10 01:12:12', 7, 0, '', NULL, '2021-03-10 01:12:12', NULL, '2021-03-10 01:12:12', b'0');
+INSERT INTO `inf_api_access_log` VALUES (20, '3dc6e855-0aff-48f2-a236-a5255385de82', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:12', '2021-03-10 01:12:12', 15, 0, '', NULL, '2021-03-10 01:12:12', NULL, '2021-03-10 01:12:12', b'0');
+INSERT INTO `inf_api_access_log` VALUES (21, '0eab1e77-e039-4924-b6f5-cdcd73ad9897', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1032,\\\"status\\\":0,\\\"createTime\\\":1609837428000,\\\"name\\\":\\\"配置新增\\\",\\\"permission\\\":\\\"infra:config:create\\\",\\\"type\\\":3,\\\"sort\\\":2,\\\"parentId\\\":106,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:18', '2021-03-10 01:12:18', 18, 0, '', NULL, '2021-03-10 01:12:18', NULL, '2021-03-10 01:12:18', b'0');
+INSERT INTO `inf_api_access_log` VALUES (22, '5d309b5e-76be-4776-be3c-e961e3144269', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:18', '2021-03-10 01:12:18', 14, 0, '', NULL, '2021-03-10 01:12:18', NULL, '2021-03-10 01:12:18', b'0');
+INSERT INTO `inf_api_access_log` VALUES (23, '359ddde9-67d2-427c-8738-17fb0773f3ca', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:25', '2021-03-10 01:12:25', 13, 0, '', NULL, '2021-03-10 01:12:25', NULL, '2021-03-10 01:12:25', b'0');
+INSERT INTO `inf_api_access_log` VALUES (24, 'cab05ea8-98e4-4b81-a629-696e6c47c680', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1033\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:25', '2021-03-10 01:12:25', 5, 0, '', NULL, '2021-03-10 01:12:25', NULL, '2021-03-10 01:12:25', b'0');
+INSERT INTO `inf_api_access_log` VALUES (25, '291cb66f-21d9-4798-a3c1-d3b0270d3850', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1033,\\\"status\\\":0,\\\"createTime\\\":1609837428000,\\\"name\\\":\\\"配置修改\\\",\\\"permission\\\":\\\"infra:config:update\\\",\\\"type\\\":3,\\\"sort\\\":3,\\\"parentId\\\":106,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:30', '2021-03-10 01:12:30', 19, 0, '', NULL, '2021-03-10 01:12:30', NULL, '2021-03-10 01:12:30', b'0');
+INSERT INTO `inf_api_access_log` VALUES (26, '5cf67e7f-8b32-4b17-96a6-325dfcba865f', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:30', '2021-03-10 01:12:30', 14, 0, '', NULL, '2021-03-10 01:12:30', NULL, '2021-03-10 01:12:30', b'0');
+INSERT INTO `inf_api_access_log` VALUES (27, '869bcc0c-2d7c-4a80-9fda-11b412162c0d', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1034\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:31', '2021-03-10 01:12:31', 7, 0, '', NULL, '2021-03-10 01:12:31', NULL, '2021-03-10 01:12:31', b'0');
+INSERT INTO `inf_api_access_log` VALUES (28, '5c110575-2d45-4353-a653-50796f3ffc36', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:31', '2021-03-10 01:12:31', 14, 0, '', NULL, '2021-03-10 01:12:31', NULL, '2021-03-10 01:12:31', b'0');
+INSERT INTO `inf_api_access_log` VALUES (29, '4bd68903-d159-4728-aaa0-cfcc810bf65d', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1034,\\\"status\\\":0,\\\"createTime\\\":1609837428000,\\\"name\\\":\\\"配置删除\\\",\\\"permission\\\":\\\"infra:config:delete\\\",\\\"type\\\":3,\\\"sort\\\":4,\\\"parentId\\\":106,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:36', '2021-03-10 01:12:36', 18, 0, '', NULL, '2021-03-10 01:12:36', NULL, '2021-03-10 01:12:36', b'0');
+INSERT INTO `inf_api_access_log` VALUES (30, 'f42d28d1-1442-44f6-aaa9-b200307e0755', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:36', '2021-03-10 01:12:36', 13, 0, '', NULL, '2021-03-10 01:12:36', NULL, '2021-03-10 01:12:36', b'0');
+INSERT INTO `inf_api_access_log` VALUES (31, 'c2ad9fea-1e4f-4f19-8ad3-8ffac3a2ad6a', 1, 2, 'dashboard', 'GET', '/api/infra/config/page', '{\"query\":{\"pageNo\":\"1\",\"pageSize\":\"10\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:12:40', '2021-03-10 01:12:40', 119, 0, '', NULL, '2021-03-10 01:12:40', NULL, '2021-03-10 01:12:40', b'0');
+INSERT INTO `inf_api_access_log` VALUES (32, 'a3ce04b6-103e-4567-9f3a-22a516957122', 1, 2, 'dashboard', 'GET', '/api/system/dict-data/list-all-simple', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:41', '2021-03-10 01:25:41', 225, 0, '', NULL, '2021-03-10 01:25:41', NULL, '2021-03-10 01:25:41', b'0');
+INSERT INTO `inf_api_access_log` VALUES (33, '82f37563-862a-4f50-9e5b-1c15b3b672d5', 1, 2, 'dashboard', 'GET', '/api/get-permission-info', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:41', '2021-03-10 01:25:41', 225, 0, '', NULL, '2021-03-10 01:25:41', NULL, '2021-03-10 01:25:41', b'0');
+INSERT INTO `inf_api_access_log` VALUES (34, '8469ee76-cdf6-4cf2-ae6b-91573e06d0c9', 1, 2, 'dashboard', 'GET', '/api/list-menus', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:41', '2021-03-10 01:25:41', 16, 0, '', NULL, '2021-03-10 01:25:41', NULL, '2021-03-10 01:25:41', b'0');
+INSERT INTO `inf_api_access_log` VALUES (35, '27f7ffa8-7ce3-42d4-8e65-1a6996dde9d4', 0, 2, 'dashboard', 'GET', '/api/system/file/get/add5ec1891a7d97d2cc1d60847e16294.jpg', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:42', '2021-03-10 01:25:42', 28, 0, '', NULL, '2021-03-10 01:25:42', NULL, '2021-03-10 01:25:42', b'0');
+INSERT INTO `inf_api_access_log` VALUES (36, '23254cf0-c51f-4a52-8838-fc7ebbce3042', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:42', '2021-03-10 01:25:42', 47, 0, '', NULL, '2021-03-10 01:25:42', NULL, '2021-03-10 01:25:42', b'0');
+INSERT INTO `inf_api_access_log` VALUES (37, '215c6c13-12e7-442a-805f-3efc0bf646e4', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"110\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:49', '2021-03-10 01:25:49', 13, 0, '', NULL, '2021-03-10 01:25:49', NULL, '2021-03-10 01:25:49', b'0');
+INSERT INTO `inf_api_access_log` VALUES (38, '56ee2e75-5775-4a26-a9e7-972876ed891e', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:49', '2021-03-10 01:25:49', 20, 0, '', NULL, '2021-03-10 01:25:49', NULL, '2021-03-10 01:25:49', b'0');
+INSERT INTO `inf_api_access_log` VALUES (39, '680c28fa-764e-4de5-8dc0-909ab842eb43', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":110,\\\"status\\\":0,\\\"createTime\\\":1609837428000,\\\"name\\\":\\\"定时任务\\\",\\\"permission\\\":\\\"\\\",\\\"type\\\":2,\\\"sort\\\":2,\\\"parentId\\\":2,\\\"path\\\":\\\"job\\\",\\\"icon\\\":\\\"job\\\",\\\"component\\\":\\\"infra/job/index\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:51', '2021-03-10 01:25:51', 56, 0, '', NULL, '2021-03-10 01:25:51', NULL, '2021-03-10 01:25:51', b'0');
+INSERT INTO `inf_api_access_log` VALUES (40, '74a051a8-4150-442c-8986-6b22ae166ae6', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:25:51', '2021-03-10 01:25:51', 22, 0, '', NULL, '2021-03-10 01:25:51', NULL, '2021-03-10 01:25:51', b'0');
+INSERT INTO `inf_api_access_log` VALUES (41, '5228cabc-3ff5-4c3a-a9d0-a7c14a9e92a5', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:26:02', '2021-03-10 01:26:02', 17, 0, '', NULL, '2021-03-10 01:26:02', NULL, '2021-03-10 01:26:02', b'0');
+INSERT INTO `inf_api_access_log` VALUES (42, 'c659072d-1d29-469b-b84b-b6ed4b6c964e', 1, 2, 'dashboard', 'POST', '/api/system/menu/create', '{\"query\":{},\"body\":\"{\\\"parentId\\\":110,\\\"name\\\":\\\"任务查询\\\",\\\"type\\\":3,\\\"sort\\\":1,\\\"status\\\":0,\\\"permission\\\":\\\"infra:job:query\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:26:19', '2021-03-10 01:26:19', 29, 0, '', NULL, '2021-03-10 01:26:19', NULL, '2021-03-10 01:26:19', b'0');
+INSERT INTO `inf_api_access_log` VALUES (43, '1627b483-95b0-4ddc-b4f8-c27f931fde1a', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:26:19', '2021-03-10 01:26:19', 17, 0, '', NULL, '2021-03-10 01:26:19', NULL, '2021-03-10 01:26:19', b'0');
+INSERT INTO `inf_api_access_log` VALUES (44, '6c497f1e-da23-4ca6-bb04-1a5c0bb768ad', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1078\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:27:42', '2021-03-10 01:27:43', 188, 0, '', NULL, '2021-03-10 01:27:43', NULL, '2021-03-10 01:27:43', b'0');
+INSERT INTO `inf_api_access_log` VALUES (45, 'ba231b78-1b76-4116-b54d-a42abc10ac9b', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:27:42', '2021-03-10 01:27:43', 188, 0, '', NULL, '2021-03-10 01:27:43', NULL, '2021-03-10 01:27:43', b'0');
+INSERT INTO `inf_api_access_log` VALUES (46, '1440ae67-0972-4d04-9efe-9080acc615bb', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:27:45', '2021-03-10 01:27:46', 20, 0, '', NULL, '2021-03-10 01:27:46', NULL, '2021-03-10 01:27:46', b'0');
+INSERT INTO `inf_api_access_log` VALUES (47, '391845d4-1e42-492d-bc44-4ef878be4b41', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:27:50', '2021-03-10 01:27:50', 21, 0, '', NULL, '2021-03-10 01:27:50', NULL, '2021-03-10 01:27:50', b'0');
+INSERT INTO `inf_api_access_log` VALUES (48, 'dd2b9b7e-df39-497c-bd1a-456a5af54799', 1, 2, 'dashboard', 'POST', '/api/system/menu/create', '{\"query\":{},\"body\":\"{\\\"parentId\\\":1078,\\\"name\\\":\\\"日志查询\\\",\\\"type\\\":3,\\\"sort\\\":1,\\\"status\\\":0,\\\"permission\\\":\\\"infra:api-error-log:query\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:04', '2021-03-10 01:28:04', 45, 0, '', NULL, '2021-03-10 01:28:04', NULL, '2021-03-10 01:28:04', b'0');
+INSERT INTO `inf_api_access_log` VALUES (49, '292da48c-21a0-4066-8a3a-40ddd0e9c759', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:04', '2021-03-10 01:28:04', 23, 0, '', NULL, '2021-03-10 01:28:04', NULL, '2021-03-10 01:28:04', b'0');
+INSERT INTO `inf_api_access_log` VALUES (50, '13432c7e-35c4-451f-9aa7-438f7f5c646a', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1078\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:07', '2021-03-10 01:28:07', 13, 0, '', NULL, '2021-03-10 01:28:07', NULL, '2021-03-10 01:28:07', b'0');
+INSERT INTO `inf_api_access_log` VALUES (51, 'f06ad98f-7136-4157-83d6-9ff18b76c701', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:07', '2021-03-10 01:28:07', 20, 0, '', NULL, '2021-03-10 01:28:07', NULL, '2021-03-10 01:28:07', b'0');
+INSERT INTO `inf_api_access_log` VALUES (52, '255cc516-6b95-404c-ae2c-38d713ca3a59', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1078,\\\"status\\\":0,\\\"createTime\\\":1614274379000,\\\"name\\\":\\\"访问日志\\\",\\\"permission\\\":\\\"\\\",\\\"type\\\":2,\\\"sort\\\":1,\\\"parentId\\\":1083,\\\"path\\\":\\\"api-access-log\\\",\\\"icon\\\":\\\"log\\\",\\\"component\\\":\\\"infra/apiAccessLog/index\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:09', '2021-03-10 01:28:09', 33, 0, '', NULL, '2021-03-10 01:28:09', NULL, '2021-03-10 01:28:09', b'0');
+INSERT INTO `inf_api_access_log` VALUES (53, '0b75788a-e1cb-43f7-959e-4f8cbb40b3cc', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:09', '2021-03-10 01:28:09', 18, 0, '', NULL, '2021-03-10 01:28:09', NULL, '2021-03-10 01:28:09', b'0');
+INSERT INTO `inf_api_access_log` VALUES (54, 'aebfea9a-ae91-4746-bf71-d315da4f5d49', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1082\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:11', '2021-03-10 01:28:11', 8, 0, '', NULL, '2021-03-10 01:28:11', NULL, '2021-03-10 01:28:11', b'0');
+INSERT INTO `inf_api_access_log` VALUES (55, '149f2f74-9d4b-491f-b016-19c5b381fcc7', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:11', '2021-03-10 01:28:11', 15, 0, '', NULL, '2021-03-10 01:28:11', NULL, '2021-03-10 01:28:11', b'0');
+INSERT INTO `inf_api_access_log` VALUES (56, 'aeec1ebf-5aeb-4888-a2dd-60c473ae6b78', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1082,\\\"status\\\":0,\\\"createTime\\\":1614274379000,\\\"name\\\":\\\"日志导出\\\",\\\"permission\\\":\\\"infra:api-access-log:export\\\",\\\"type\\\":3,\\\"sort\\\":2,\\\"parentId\\\":1078,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:13', '2021-03-10 01:28:13', 23, 0, '', NULL, '2021-03-10 01:28:13', NULL, '2021-03-10 01:28:13', b'0');
+INSERT INTO `inf_api_access_log` VALUES (57, 'd2cc4ee9-d289-4886-be34-0f93edb52bc0', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:13', '2021-03-10 01:28:13', 16, 0, '', NULL, '2021-03-10 01:28:13', NULL, '2021-03-10 01:28:13', b'0');
+INSERT INTO `inf_api_access_log` VALUES (58, '73efd4a2-fe8b-4819-a657-6aca7425e7c0', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1085\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:15', '2021-03-10 01:28:15', 9, 0, '', NULL, '2021-03-10 01:28:15', NULL, '2021-03-10 01:28:15', b'0');
+INSERT INTO `inf_api_access_log` VALUES (59, 'f222df67-e4c0-419f-a022-4bc304319f4d', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:15', '2021-03-10 01:28:15', 17, 0, '', NULL, '2021-03-10 01:28:15', NULL, '2021-03-10 01:28:15', b'0');
+INSERT INTO `inf_api_access_log` VALUES (60, 'd304f696-6bd3-4218-b73a-7cff04565b54', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1085,\\\"status\\\":0,\\\"createTime\\\":1614297200000,\\\"name\\\":\\\"日志处理\\\",\\\"permission\\\":\\\"infra:api-error-log:update-status\\\",\\\"type\\\":3,\\\"sort\\\":2,\\\"parentId\\\":1084,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:18', '2021-03-10 01:28:18', 23, 0, '', NULL, '2021-03-10 01:28:18', NULL, '2021-03-10 01:28:18', b'0');
+INSERT INTO `inf_api_access_log` VALUES (61, '224f263e-0e4f-49a8-8205-2de44ba8e045', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:18', '2021-03-10 01:28:18', 16, 0, '', NULL, '2021-03-10 01:28:18', NULL, '2021-03-10 01:28:18', b'0');
+INSERT INTO `inf_api_access_log` VALUES (62, '9fd2373f-a641-4865-ae3f-259b4386d816', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1086\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:19', '2021-03-10 01:28:19', 7, 0, '', NULL, '2021-03-10 01:28:19', NULL, '2021-03-10 01:28:19', b'0');
+INSERT INTO `inf_api_access_log` VALUES (63, 'a97c2b96-9486-4bde-a532-bbb8f077a393', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:19', '2021-03-10 01:28:19', 15, 0, '', NULL, '2021-03-10 01:28:19', NULL, '2021-03-10 01:28:19', b'0');
+INSERT INTO `inf_api_access_log` VALUES (64, '1cbb3fa8-9a84-4568-8089-c74c2ff38d80', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1086,\\\"status\\\":0,\\\"createTime\\\":1614297200000,\\\"name\\\":\\\"日志导出\\\",\\\"permission\\\":\\\"infra:api-error-log:export\\\",\\\"type\\\":3,\\\"sort\\\":3,\\\"parentId\\\":1084,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:21', '2021-03-10 01:28:21', 21, 0, '', NULL, '2021-03-10 01:28:21', NULL, '2021-03-10 01:28:21', b'0');
+INSERT INTO `inf_api_access_log` VALUES (65, '7f913e0c-0dfd-45cc-bb7d-eb55e7eb653d', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:21', '2021-03-10 01:28:21', 16, 0, '', NULL, '2021-03-10 01:28:21', NULL, '2021-03-10 01:28:21', b'0');
+INSERT INTO `inf_api_access_log` VALUES (66, '6b39ec06-2bf5-4d92-9245-18223625251f', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:34', '2021-03-10 01:28:34', 13, 0, '', NULL, '2021-03-10 01:28:34', NULL, '2021-03-10 01:28:34', b'0');
+INSERT INTO `inf_api_access_log` VALUES (67, '74045997-4753-48b6-98ee-1de5106d8633', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:28:47', '2021-03-10 01:28:47', 14, 0, '', NULL, '2021-03-10 01:28:47', NULL, '2021-03-10 01:28:47', b'0');
+INSERT INTO `inf_api_access_log` VALUES (68, '14dcf39c-9b29-4cd0-8c08-9a17cd0234f6', 1, 2, 'dashboard', 'POST', '/api/system/menu/create', '{\"query\":{},\"body\":\"{\\\"parentId\\\":1084,\\\"name\\\":\\\"日志查询\\\",\\\"type\\\":3,\\\"sort\\\":1,\\\"status\\\":0,\\\"permission\\\":\\\"infra:api-error-log:query\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:09', '2021-03-10 01:29:09', 19, 0, '', NULL, '2021-03-10 01:29:09', NULL, '2021-03-10 01:29:09', b'0');
+INSERT INTO `inf_api_access_log` VALUES (69, '6ed66070-c685-4871-9321-372161cb71f7', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:09', '2021-03-10 01:29:09', 15, 0, '', NULL, '2021-03-10 01:29:09', NULL, '2021-03-10 01:29:09', b'0');
+INSERT INTO `inf_api_access_log` VALUES (70, 'f47ae56b-6de3-40b2-9da8-b86f38491645', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1088\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:24', '2021-03-10 01:29:24', 8, 0, '', NULL, '2021-03-10 01:29:24', NULL, '2021-03-10 01:29:24', b'0');
+INSERT INTO `inf_api_access_log` VALUES (71, 'c498e660-4608-4051-bda3-3d980e6873f0', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:24', '2021-03-10 01:29:24', 18, 0, '', NULL, '2021-03-10 01:29:24', NULL, '2021-03-10 01:29:24', b'0');
+INSERT INTO `inf_api_access_log` VALUES (72, '7a9be5f0-16b7-4924-9352-c8c6bdb36f6d', 1, 2, 'dashboard', 'GET', '/api/system/menu/get', '{\"query\":{\"id\":\"1088\"},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:32', '2021-03-10 01:29:32', 7, 0, '', NULL, '2021-03-10 01:29:32', NULL, '2021-03-10 01:29:32', b'0');
+INSERT INTO `inf_api_access_log` VALUES (73, '7dcc44ce-63f0-4013-b4ee-332de28e473d', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:32', '2021-03-10 01:29:32', 16, 0, '', NULL, '2021-03-10 01:29:32', NULL, '2021-03-10 01:29:32', b'0');
+INSERT INTO `inf_api_access_log` VALUES (74, 'a7541572-c68d-443e-95f6-69d1f6f55fab', 1, 2, 'dashboard', 'POST', '/api/system/menu/update', '{\"query\":{},\"body\":\"{\\\"id\\\":1088,\\\"status\\\":0,\\\"createTime\\\":1615310884000,\\\"name\\\":\\\"日志查询\\\",\\\"permission\\\":\\\"infra:api-access-log:query\\\",\\\"type\\\":3,\\\"sort\\\":1,\\\"parentId\\\":1078,\\\"path\\\":\\\"\\\",\\\"icon\\\":\\\"\\\",\\\"component\\\":\\\"\\\"}\"}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:38', '2021-03-10 01:29:38', 22, 0, '', NULL, '2021-03-10 01:29:38', NULL, '2021-03-10 01:29:38', b'0');
+INSERT INTO `inf_api_access_log` VALUES (75, '822a488f-fc4a-4981-924c-40deba7b8a25', 1, 2, 'dashboard', 'GET', '/api/system/menu/list', '{\"query\":{},\"body\":null}', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '2021-03-10 01:29:38', '2021-03-10 01:29:38', 14, 0, '', NULL, '2021-03-10 01:29:38', NULL, '2021-03-10 01:29:38', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -78,13 +153,13 @@ CREATE TABLE `inf_api_error_log` (
   `process_status` tinyint(4) NOT NULL COMMENT '处理状态',
   `process_time` datetime DEFAULT NULL COMMENT '处理时间',
   `process_user_id` int(11) DEFAULT '0' COMMENT '处理用户编号',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=3 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志';
 
 -- ----------------------------
 -- Records of inf_api_error_log
@@ -105,9 +180,9 @@ CREATE TABLE `inf_config` (
   `value` varchar(500) NOT NULL DEFAULT '' COMMENT '参数键值',
   `sensitive` bit(1) NOT NULL COMMENT '是否敏感',
   `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -138,9 +213,9 @@ CREATE TABLE `inf_job` (
   `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
   `retry_interval` int(11) NOT NULL DEFAULT '0' COMMENT '重试间隔',
   `monitor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '监控超时时间',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -169,18 +244,69 @@ CREATE TABLE `inf_job_log` (
   `duration` int(11) DEFAULT NULL COMMENT '执行时长',
   `status` tinyint(4) NOT NULL COMMENT '任务状态',
   `result` varchar(4000) DEFAULT '' COMMENT '结果数据',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=4458 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表';
+) ENGINE=InnoDB AUTO_INCREMENT=52 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表';
 
 -- ----------------------------
 -- Records of inf_job_log
 -- ----------------------------
 BEGIN;
+INSERT INTO `inf_job_log` VALUES (1, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:17:51', '2021-03-09 21:17:51', 61, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:17:51', NULL, '2021-03-09 21:17:51', b'0');
+INSERT INTO `inf_job_log` VALUES (2, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:18:00', '2021-03-09 21:18:00', 16, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:18:00', NULL, '2021-03-09 21:18:00', b'0');
+INSERT INTO `inf_job_log` VALUES (3, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:19:00', '2021-03-09 21:19:00', 10, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:19:00', NULL, '2021-03-09 21:19:00', b'0');
+INSERT INTO `inf_job_log` VALUES (4, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:20:00', '2021-03-09 21:20:00', 12, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:20:00', NULL, '2021-03-09 21:20:00', b'0');
+INSERT INTO `inf_job_log` VALUES (5, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:21:00', '2021-03-09 21:21:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:21:00', NULL, '2021-03-09 21:21:00', b'0');
+INSERT INTO `inf_job_log` VALUES (6, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:22:00', '2021-03-09 21:22:00', 9, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:22:00', NULL, '2021-03-09 21:22:00', b'0');
+INSERT INTO `inf_job_log` VALUES (7, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:23:00', '2021-03-09 21:23:00', 10, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:23:00', NULL, '2021-03-09 21:23:00', b'0');
+INSERT INTO `inf_job_log` VALUES (8, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:24:00', '2021-03-09 21:24:00', 11, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:24:00', NULL, '2021-03-09 21:24:00', b'0');
+INSERT INTO `inf_job_log` VALUES (9, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:25:00', '2021-03-09 21:25:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:25:00', NULL, '2021-03-09 21:25:00', b'0');
+INSERT INTO `inf_job_log` VALUES (10, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:26:00', '2021-03-09 21:26:00', 11, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:26:00', NULL, '2021-03-09 21:26:00', b'0');
+INSERT INTO `inf_job_log` VALUES (11, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:27:00', '2021-03-09 21:27:00', 12, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:27:00', NULL, '2021-03-09 21:27:00', b'0');
+INSERT INTO `inf_job_log` VALUES (12, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:28:00', '2021-03-09 21:28:00', 6, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:28:00', NULL, '2021-03-09 21:28:00', b'0');
+INSERT INTO `inf_job_log` VALUES (13, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:29:00', '2021-03-09 21:29:00', 9, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:29:00', NULL, '2021-03-09 21:29:00', b'0');
+INSERT INTO `inf_job_log` VALUES (14, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:30:00', '2021-03-09 21:30:00', 6, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:30:00', NULL, '2021-03-09 21:30:00', b'0');
+INSERT INTO `inf_job_log` VALUES (15, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:31:00', '2021-03-09 21:31:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:31:00', NULL, '2021-03-09 21:31:00', b'0');
+INSERT INTO `inf_job_log` VALUES (16, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:32:00', '2021-03-09 21:32:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:32:00', NULL, '2021-03-09 21:32:00', b'0');
+INSERT INTO `inf_job_log` VALUES (17, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-09 21:49:02', '2021-03-09 21:49:02', 87, 1, '移除在线会话数量为 0 个', NULL, '2021-03-09 21:49:02', NULL, '2021-03-09 21:49:02', b'0');
+INSERT INTO `inf_job_log` VALUES (18, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 00:55:34', '2021-03-10 00:55:34', 60, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 00:55:34', NULL, '2021-03-10 00:55:34', b'0');
+INSERT INTO `inf_job_log` VALUES (19, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 00:56:00', '2021-03-10 00:56:00', 16, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 00:56:00', NULL, '2021-03-10 00:56:00', b'0');
+INSERT INTO `inf_job_log` VALUES (20, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 00:57:00', '2021-03-10 00:57:00', 9, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 00:57:00', NULL, '2021-03-10 00:57:00', b'0');
+INSERT INTO `inf_job_log` VALUES (21, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 00:58:00', '2021-03-10 00:58:00', 17, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 00:58:00', NULL, '2021-03-10 00:58:00', b'0');
+INSERT INTO `inf_job_log` VALUES (22, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 00:59:00', '2021-03-10 00:59:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 00:59:00', NULL, '2021-03-10 00:59:00', b'0');
+INSERT INTO `inf_job_log` VALUES (23, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:00:00', '2021-03-10 01:00:00', 10, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:00:00', NULL, '2021-03-10 01:00:00', b'0');
+INSERT INTO `inf_job_log` VALUES (24, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:01:00', '2021-03-10 01:01:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:01:00', NULL, '2021-03-10 01:01:00', b'0');
+INSERT INTO `inf_job_log` VALUES (25, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:02:00', '2021-03-10 01:02:00', 9, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:02:00', NULL, '2021-03-10 01:02:00', b'0');
+INSERT INTO `inf_job_log` VALUES (26, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:03:00', '2021-03-10 01:03:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:03:00', NULL, '2021-03-10 01:03:00', b'0');
+INSERT INTO `inf_job_log` VALUES (27, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:04:00', '2021-03-10 01:04:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:04:00', NULL, '2021-03-10 01:04:00', b'0');
+INSERT INTO `inf_job_log` VALUES (28, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:05:00', '2021-03-10 01:05:00', 16, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:05:00', NULL, '2021-03-10 01:05:00', b'0');
+INSERT INTO `inf_job_log` VALUES (29, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:06:00', '2021-03-10 01:06:00', 15, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:06:00', NULL, '2021-03-10 01:06:00', b'0');
+INSERT INTO `inf_job_log` VALUES (30, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:07:00', '2021-03-10 01:07:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:07:00', NULL, '2021-03-10 01:07:00', b'0');
+INSERT INTO `inf_job_log` VALUES (31, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:08:00', '2021-03-10 01:08:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:08:00', NULL, '2021-03-10 01:08:00', b'0');
+INSERT INTO `inf_job_log` VALUES (32, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:09:00', '2021-03-10 01:09:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:09:00', NULL, '2021-03-10 01:09:00', b'0');
+INSERT INTO `inf_job_log` VALUES (33, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:10:00', '2021-03-10 01:10:00', 16, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:10:00', NULL, '2021-03-10 01:10:00', b'0');
+INSERT INTO `inf_job_log` VALUES (34, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:11:00', '2021-03-10 01:11:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:11:00', NULL, '2021-03-10 01:11:00', b'0');
+INSERT INTO `inf_job_log` VALUES (35, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:12:00', '2021-03-10 01:12:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:12:00', NULL, '2021-03-10 01:12:00', b'0');
+INSERT INTO `inf_job_log` VALUES (36, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:13:00', '2021-03-10 01:13:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:13:00', NULL, '2021-03-10 01:13:00', b'0');
+INSERT INTO `inf_job_log` VALUES (37, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:14:00', '2021-03-10 01:14:00', 6, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:14:00', NULL, '2021-03-10 01:14:00', b'0');
+INSERT INTO `inf_job_log` VALUES (38, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:15:00', '2021-03-10 01:15:00', 5, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:15:00', NULL, '2021-03-10 01:15:00', b'0');
+INSERT INTO `inf_job_log` VALUES (39, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:16:00', '2021-03-10 01:16:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:16:00', NULL, '2021-03-10 01:16:00', b'0');
+INSERT INTO `inf_job_log` VALUES (40, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:17:00', '2021-03-10 01:17:00', 9, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:17:00', NULL, '2021-03-10 01:17:00', b'0');
+INSERT INTO `inf_job_log` VALUES (41, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:18:00', '2021-03-10 01:18:00', 6, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:18:00', NULL, '2021-03-10 01:18:00', b'0');
+INSERT INTO `inf_job_log` VALUES (42, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:19:00', '2021-03-10 01:19:00', 6, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:19:00', NULL, '2021-03-10 01:19:00', b'0');
+INSERT INTO `inf_job_log` VALUES (43, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:20:00', '2021-03-10 01:20:00', 7, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:20:00', NULL, '2021-03-10 01:20:00', b'0');
+INSERT INTO `inf_job_log` VALUES (44, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:21:00', '2021-03-10 01:21:00', 5, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:21:00', NULL, '2021-03-10 01:21:00', b'0');
+INSERT INTO `inf_job_log` VALUES (45, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:23:09', '2021-03-10 01:23:09', 60, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:23:09', NULL, '2021-03-10 01:23:09', b'0');
+INSERT INTO `inf_job_log` VALUES (46, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:25:41', '2021-03-10 01:25:41', 92, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:25:41', NULL, '2021-03-10 01:25:41', b'0');
+INSERT INTO `inf_job_log` VALUES (47, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:26:00', '2021-03-10 01:26:00', 10, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:26:00', NULL, '2021-03-10 01:26:00', b'0');
+INSERT INTO `inf_job_log` VALUES (48, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:27:42', '2021-03-10 01:27:42', 61, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:27:42', NULL, '2021-03-10 01:27:42', b'0');
+INSERT INTO `inf_job_log` VALUES (49, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:28:00', '2021-03-10 01:28:00', 14, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:28:00', NULL, '2021-03-10 01:28:00', b'0');
+INSERT INTO `inf_job_log` VALUES (50, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:29:00', '2021-03-10 01:29:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:29:00', NULL, '2021-03-10 01:29:00', b'0');
+INSERT INTO `inf_job_log` VALUES (51, 3, 'sysUserSessionTimeoutJob', NULL, 1, '2021-03-10 01:30:00', '2021-03-10 01:30:00', 8, 1, '移除在线会话数量为 0 个', NULL, '2021-03-10 01:30:00', NULL, '2021-03-10 01:30:00', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -196,9 +322,9 @@ CREATE TABLE `sys_dept` (
   `phone` varchar(11) DEFAULT NULL COMMENT '联系电话',
   `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
   `status` tinyint(4) NOT NULL COMMENT '部门状态(0正常 1停用)',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -232,9 +358,9 @@ CREATE TABLE `sys_dict_data` (
   `dict_type` varchar(100) NOT NULL DEFAULT '' COMMENT '字典类型',
   `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
   `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -310,9 +436,9 @@ CREATE TABLE `sys_dict_type` (
   `type` varchar(100) NOT NULL DEFAULT '' COMMENT '字典类型',
   `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
   `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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,
@@ -349,9 +475,9 @@ DROP TABLE IF EXISTS `sys_file`;
 CREATE TABLE `sys_file` (
   `id` varchar(188) NOT NULL COMMENT '文件路径',
   `content` blob NOT NULL COMMENT '文件内容',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -376,18 +502,20 @@ CREATE TABLE `sys_login_log` (
   `result` tinyint(4) NOT NULL COMMENT '登陆结果',
   `user_ip` varchar(50) NOT NULL COMMENT '用户 IP',
   `user_agent` varchar(512) NOT NULL COMMENT '浏览器 UA',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=127 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录';
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录';
 
 -- ----------------------------
 -- Records of sys_login_log
 -- ----------------------------
 BEGIN;
+INSERT INTO `sys_login_log` VALUES (1, 100, '4143cdab-ff1d-46ec-8333-bc48483c4c4b', 'admin', 30, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
+INSERT INTO `sys_login_log` VALUES (2, 100, '783e9c51-4a58-46aa-85f1-66cac5512465', 'admin', 0, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:11:53', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -405,13 +533,13 @@ CREATE TABLE `sys_menu` (
   `icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
   `component` varchar(255) DEFAULT NULL COMMENT '组件路径',
   `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=1087 DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表';
+) ENGINE=InnoDB AUTO_INCREMENT=1090 DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表';
 
 -- ----------------------------
 -- Records of sys_menu
@@ -427,11 +555,11 @@ INSERT INTO `sys_menu` VALUES (102, '菜单管理', 'system:menu:list', 2, 3, 1,
 INSERT INTO `sys_menu` VALUES (103, '部门管理', 'system:dept:list', 2, 4, 1, 'dept', 'tree', 'system/dept/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
 INSERT INTO `sys_menu` VALUES (104, '岗位管理', 'system:post:list', 2, 5, 1, 'post', 'post', 'system/post/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
 INSERT INTO `sys_menu` VALUES (105, '字典管理', 'system:dict:list', 2, 6, 1, 'dict', 'dict', 'system/dict/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
-INSERT INTO `sys_menu` VALUES (106, '配置管理', 'infra:config:list', 2, 1, 2, 'config', 'edit', 'infra/config/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-08 20:03:57', b'0');
+INSERT INTO `sys_menu` VALUES (106, '配置管理', '', 2, 1, 2, 'config', 'edit', 'infra/config/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:10', b'0');
 INSERT INTO `sys_menu` VALUES (107, '通知公告', 'system:notice:list', 2, 8, 1, 'notice', 'message', 'system/notice/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
 INSERT INTO `sys_menu` VALUES (108, '日志管理', '', 1, 9, 1, 'log', 'log', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:34:28', b'0');
 INSERT INTO `sys_menu` VALUES (109, '在线用户', 'system:user-session:list', 2, 10, 1, 'user-session', 'online', 'system/session/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-26 08:21:20', b'0');
-INSERT INTO `sys_menu` VALUES (110, '定时任务', 'infra:job:query', 2, 2, 2, 'job', 'job', 'infra/job/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-07 13:01:36', b'0');
+INSERT INTO `sys_menu` VALUES (110, '定时任务', '', 2, 2, 2, 'job', 'job', 'infra/job/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:25:51', b'0');
 INSERT INTO `sys_menu` VALUES (111, 'MySQL 监控', '', 2, 4, 2, 'druid', 'druid', 'infra/druid/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-26 02:18:32', b'0');
 INSERT INTO `sys_menu` VALUES (112, 'Java 监控', '', 2, 6, 2, 'admin-server', 'server', 'infra/server', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-26 02:18:41', b'0');
 INSERT INTO `sys_menu` VALUES (113, 'Redis 监控', '', 2, 5, 2, 'redis', 'redis', 'infra/redis/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-26 02:18:37', b'0');
@@ -471,9 +599,9 @@ INSERT INTO `sys_menu` VALUES (1028, '字典修改', 'system:dict:edit', 3, 3, 1
 INSERT INTO `sys_menu` VALUES (1029, '字典删除', 'system:dict:remove', 3, 4, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
 INSERT INTO `sys_menu` VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
 INSERT INTO `sys_menu` VALUES (1031, '配置查询', 'infra:config:query', 3, 1, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:00', b'0');
-INSERT INTO `sys_menu` VALUES (1032, '配置新增', 'infra:config:add', 3, 2, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:05', b'0');
-INSERT INTO `sys_menu` VALUES (1033, '配置修改', 'infra:config:edit', 3, 3, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:33:52', b'0');
-INSERT INTO `sys_menu` VALUES (1034, '配置删除', 'infra:config:remove', 3, 4, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:12', b'0');
+INSERT INTO `sys_menu` VALUES (1032, '配置新增', 'infra:config:create', 3, 2, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:18', b'0');
+INSERT INTO `sys_menu` VALUES (1033, '配置修改', 'infra:config:update', 3, 3, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:30', b'0');
+INSERT INTO `sys_menu` VALUES (1034, '配置删除', 'infra:config:delete', 3, 4, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:36', b'0');
 INSERT INTO `sys_menu` VALUES (1035, '配置导出', 'infra:config:export', 3, 5, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:19', b'0');
 INSERT INTO `sys_menu` VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
 INSERT INTO `sys_menu` VALUES (1037, '公告新增', 'system:notice:add', 3, 2, 107, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
@@ -511,15 +639,18 @@ INSERT INTO `sys_menu` VALUES (1074, '测试示例表导出', 'tool:test-demo:ex
 INSERT INTO `sys_menu` VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', 0, '', '2021-02-07 13:03:10', '', '2021-02-07 13:03:10', b'0');
 INSERT INTO `sys_menu` VALUES (1076, '数据库文档', '', 2, 5, 3, 'db-doc', 'table', 'tool/dbDoc/index', 0, '', '2021-02-08 01:41:47', '', '2021-02-08 01:49:00', b'0');
 INSERT INTO `sys_menu` VALUES (1077, '链路追踪', '', 2, 7, 2, 'skywalking', 'eye-open', 'infra/skywalking', 0, '', '2021-02-08 20:41:31', '', '2021-02-26 02:18:45', b'0');
-INSERT INTO `sys_menu` VALUES (1078, '访问日志', 'infra:api-access-log:query', 2, 1, 1083, 'api-access-log', 'log', 'infra/apiAccessLog/index', 0, '', '2021-02-26 01:32:59', '', '2021-02-26 07:53:46', b'0');
+INSERT INTO `sys_menu` VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'log', 'infra/apiAccessLog/index', 0, '', '2021-02-26 01:32:59', '1', '2021-03-10 01:28:09', b'0');
 INSERT INTO `sys_menu` VALUES (1079, 'API 访问日志表创建', 'system:api-access-log:create', 3, 1, 1078, '', '', '', 1, '', '2021-02-26 01:32:59', '', '2021-02-26 02:21:00', b'1');
 INSERT INTO `sys_menu` VALUES (1080, 'API 访问日志表更新', 'system:api-access-log:update', 3, 2, 1078, '', '', '', 1, '', '2021-02-26 01:32:59', '', '2021-02-26 02:21:08', b'1');
 INSERT INTO `sys_menu` VALUES (1081, 'API 访问日志表删除', 'system:api-access-log:delete', 3, 3, 1078, '', '', '', 1, '', '2021-02-26 01:32:59', '', '2021-02-26 02:21:27', b'1');
-INSERT INTO `sys_menu` VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 4, 1078, '', '', '', 0, '', '2021-02-26 01:32:59', '', '2021-02-26 02:23:22', b'0');
+INSERT INTO `sys_menu` VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', 0, '', '2021-02-26 01:32:59', '1', '2021-03-10 01:28:13', b'0');
 INSERT INTO `sys_menu` VALUES (1083, 'API 日志', '', 2, 3, 2, 'log', 'log', NULL, 0, '', '2021-02-26 02:18:24', '', '2021-02-26 02:20:17', b'0');
 INSERT INTO `sys_menu` VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'log', 'infra/apiErrorLog/index', 0, '', '2021-02-26 07:53:20', '', '2021-02-26 07:54:40', b'0');
-INSERT INTO `sys_menu` VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 1, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '', '2021-02-26 07:53:20', b'0');
-INSERT INTO `sys_menu` VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 4, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '', '2021-02-26 07:53:20', b'0');
+INSERT INTO `sys_menu` VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '1', '2021-03-10 01:28:18', b'0');
+INSERT INTO `sys_menu` VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '1', '2021-03-10 01:28:21', b'0');
+INSERT INTO `sys_menu` VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', 0, '1', '2021-03-10 01:26:19', '1', '2021-03-10 01:26:19', b'0');
+INSERT INTO `sys_menu` VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', 0, '1', '2021-03-10 01:28:04', '1', '2021-03-10 01:29:38', b'0');
+INSERT INTO `sys_menu` VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', 0, '1', '2021-03-10 01:29:09', '1', '2021-03-10 01:29:09', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -532,9 +663,9 @@ CREATE TABLE `sys_notice` (
   `content` text NOT NULL COMMENT '公告内容',
   `notice_type` tinyint(4) NOT NULL COMMENT '公告类型(1通知 2公告)',
   `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -573,18 +704,31 @@ CREATE TABLE `sys_operate_log` (
   `result_code` int(11) NOT NULL DEFAULT '0' COMMENT '结果码',
   `result_msg` varchar(512) DEFAULT '' COMMENT '结果提示',
   `result_data` varchar(4000) DEFAULT '' COMMENT '结果数据',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=11 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志记录';
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志记录';
 
 -- ----------------------------
 -- Records of sys_operate_log
 -- ----------------------------
 BEGIN;
+INSERT INTO `sys_operate_log` VALUES (1, 'de0ba312-0b69-4362-b674-7da54cacfb06', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"配置管理\",\"permission\":\"\",\"type\":2,\"sort\":1,\"parentId\":2,\"path\":\"config\",\"icon\":\"edit\",\"component\":\"infra/config/index\",\"status\":0,\"id\":106}}', '2021-03-10 01:12:09', 27, 0, '', 'true', NULL, '2021-03-10 01:12:10', NULL, '2021-03-10 01:12:10', b'0');
+INSERT INTO `sys_operate_log` VALUES (2, '17138b71-73b5-40c0-b735-57a1aab63a8d', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"配置新增\",\"permission\":\"infra:config:create\",\"type\":3,\"sort\":2,\"parentId\":106,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1032}}', '2021-03-10 01:12:18', 16, 0, '', 'true', NULL, '2021-03-10 01:12:18', NULL, '2021-03-10 01:12:18', b'0');
+INSERT INTO `sys_operate_log` VALUES (3, '74aff106-7785-4b36-b48f-0ff46d7af074', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"配置修改\",\"permission\":\"infra:config:update\",\"type\":3,\"sort\":3,\"parentId\":106,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1033}}', '2021-03-10 01:12:30', 16, 0, '', 'true', NULL, '2021-03-10 01:12:30', NULL, '2021-03-10 01:12:30', b'0');
+INSERT INTO `sys_operate_log` VALUES (4, '2cdfcdb3-2059-426b-8d18-4f08ac3d685b', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"配置删除\",\"permission\":\"infra:config:delete\",\"type\":3,\"sort\":4,\"parentId\":106,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1034}}', '2021-03-10 01:12:36', 14, 0, '', 'true', NULL, '2021-03-10 01:12:36', NULL, '2021-03-10 01:12:36', b'0');
+INSERT INTO `sys_operate_log` VALUES (5, '72652932-6219-4298-b057-86afde0ce065', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"定时任务\",\"permission\":\"\",\"type\":2,\"sort\":2,\"parentId\":2,\"path\":\"job\",\"icon\":\"job\",\"component\":\"infra/job/index\",\"status\":0,\"id\":110}}', '2021-03-10 01:25:51', 28, 0, '', 'true', NULL, '2021-03-10 01:25:51', NULL, '2021-03-10 01:25:51', b'0');
+INSERT INTO `sys_operate_log` VALUES (6, '9160878f-9a8d-47d9-bb54-271263dbc63c', 1, '菜单', '创建菜单', 2, '', '', 'POST', '/api/system/menu/create', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.createMenu(SysMenuCreateReqVO)', '{\"reqVO\":{\"name\":\"任务查询\",\"permission\":\"infra:job:query\",\"type\":3,\"sort\":1,\"parentId\":110,\"path\":null,\"icon\":null,\"component\":null,\"status\":0}}', '2021-03-10 01:26:19', 16, 0, '', '1087', NULL, '2021-03-10 01:26:19', NULL, '2021-03-10 01:26:19', b'0');
+INSERT INTO `sys_operate_log` VALUES (7, 'b6e1fbd8-1a2d-4d83-8cab-306dbdecb062', 1, '菜单', '创建菜单', 2, '', '', 'POST', '/api/system/menu/create', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.createMenu(SysMenuCreateReqVO)', '{\"reqVO\":{\"name\":\"日志查询\",\"permission\":\"infra:api-error-log:query\",\"type\":3,\"sort\":1,\"parentId\":1078,\"path\":null,\"icon\":null,\"component\":null,\"status\":0}}', '2021-03-10 01:28:04', 24, 0, '', '1088', NULL, '2021-03-10 01:28:04', NULL, '2021-03-10 01:28:04', b'0');
+INSERT INTO `sys_operate_log` VALUES (8, 'be86e04e-0dc9-4a68-8df0-b03ef0ed25cb', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"访问日志\",\"permission\":\"\",\"type\":2,\"sort\":1,\"parentId\":1083,\"path\":\"api-access-log\",\"icon\":\"log\",\"component\":\"infra/apiAccessLog/index\",\"status\":0,\"id\":1078}}', '2021-03-10 01:28:09', 21, 0, '', 'true', NULL, '2021-03-10 01:28:09', NULL, '2021-03-10 01:28:09', b'0');
+INSERT INTO `sys_operate_log` VALUES (9, 'f744da18-ddc7-43ed-a85c-f88104734dbc', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"日志导出\",\"permission\":\"infra:api-access-log:export\",\"type\":3,\"sort\":2,\"parentId\":1078,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1082}}', '2021-03-10 01:28:13', 18, 0, '', 'true', NULL, '2021-03-10 01:28:13', NULL, '2021-03-10 01:28:13', b'0');
+INSERT INTO `sys_operate_log` VALUES (10, '3ebdb770-e942-4574-85b5-77f641a3ec54', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"日志处理\",\"permission\":\"infra:api-error-log:update-status\",\"type\":3,\"sort\":2,\"parentId\":1084,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1085}}', '2021-03-10 01:28:18', 18, 0, '', 'true', NULL, '2021-03-10 01:28:18', NULL, '2021-03-10 01:28:18', b'0');
+INSERT INTO `sys_operate_log` VALUES (11, '51d05bc9-b8a1-44a8-a141-f139b1843f0c', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"日志导出\",\"permission\":\"infra:api-error-log:export\",\"type\":3,\"sort\":3,\"parentId\":1084,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1086}}', '2021-03-10 01:28:21', 16, 0, '', 'true', NULL, '2021-03-10 01:28:21', NULL, '2021-03-10 01:28:21', b'0');
+INSERT INTO `sys_operate_log` VALUES (12, 'b5829295-81a5-47e1-9755-328f020d7037', 1, '菜单', '创建菜单', 2, '', '', 'POST', '/api/system/menu/create', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.createMenu(SysMenuCreateReqVO)', '{\"reqVO\":{\"name\":\"日志查询\",\"permission\":\"infra:api-error-log:query\",\"type\":3,\"sort\":1,\"parentId\":1084,\"path\":null,\"icon\":null,\"component\":null,\"status\":0}}', '2021-03-10 01:29:09', 14, 0, '', '1089', NULL, '2021-03-10 01:29:09', NULL, '2021-03-10 01:29:09', b'0');
+INSERT INTO `sys_operate_log` VALUES (13, 'f8797735-d948-43f9-9701-dac4533cee31', 1, '菜单', '修改菜单', 2, '', '', 'POST', '/api/system/menu/update', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', 'CommonResult cn.iocoder.dashboard.modules.system.controller.permission.SysMenuController.updateMenu(SysMenuUpdateReqVO)', '{\"reqVO\":{\"name\":\"日志查询\",\"permission\":\"infra:api-access-log:query\",\"type\":3,\"sort\":1,\"parentId\":1078,\"path\":\"\",\"icon\":\"\",\"component\":\"\",\"status\":0,\"id\":1088}}', '2021-03-10 01:29:38', 17, 0, '', 'true', NULL, '2021-03-10 01:29:38', NULL, '2021-03-10 01:29:38', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -598,9 +742,9 @@ CREATE TABLE `sys_post` (
   `sort` int(4) NOT NULL COMMENT '显示顺序',
   `status` tinyint(4) NOT NULL COMMENT '状态(0正常 1停用)',
   `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -631,9 +775,9 @@ CREATE TABLE `sys_role` (
   `status` tinyint(4) NOT NULL COMMENT '角色状态(0正常 1停用)',
   `type` tinyint(4) NOT NULL COMMENT '角色类型',
   `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -656,9 +800,9 @@ CREATE TABLE `sys_role_menu` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
   `role_id` bigint(20) NOT NULL COMMENT '角色ID',
   `menu_id` bigint(20) NOT NULL COMMENT '菜单ID',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -843,9 +987,9 @@ CREATE TABLE `sys_user` (
   `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
   `login_ip` varchar(50) DEFAULT '' COMMENT '最后登录IP',
   `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -870,9 +1014,9 @@ CREATE TABLE `sys_user_role` (
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
   `user_id` bigint(20) NOT NULL COMMENT '用户ID',
   `role_id` bigint(20) NOT NULL COMMENT '角色ID',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime DEFAULT NULL COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `update_time` datetime DEFAULT NULL COMMENT '更新时间',
   `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除',
   PRIMARY KEY (`id`) USING BTREE
@@ -898,11 +1042,13 @@ DROP TABLE IF EXISTS `sys_user_session`;
 CREATE TABLE `sys_user_session` (
   `id` varchar(32) NOT NULL COMMENT '会话编号',
   `user_id` bigint(20) NOT NULL COMMENT '用户编号',
+  `session_timeout` datetime NOT NULL COMMENT '会话超时时间',
+  `username` varchar(30) NOT NULL COMMENT '用户账号',
   `user_ip` varchar(50) NOT NULL COMMENT '用户 IP',
   `user_agent` varchar(512) NOT NULL COMMENT '浏览器 UA',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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
@@ -912,68 +1058,7 @@ CREATE TABLE `sys_user_session` (
 -- Records of sys_user_session
 -- ----------------------------
 BEGIN;
-INSERT INTO `sys_user_session` VALUES ('015797486c564c01b128cb2662bfa1f9', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 03:20:22', '', '2021-02-08 03:20:22', b'0');
-INSERT INTO `sys_user_session` VALUES ('019f009268e24cc1957c46763eef1fd4', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-07 08:36:48', '', '2021-02-14 20:04:33', b'0');
-INSERT INTO `sys_user_session` VALUES ('037f130370a744a4b1db19aef205b8ae', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 20:38:37', '', '2021-02-08 20:38:37', b'0');
-INSERT INTO `sys_user_session` VALUES ('04d51ff81ad54d05ab2f29e66b2a02f2', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 17:46:10', '', '2021-02-11 00:58:19', b'0');
-INSERT INTO `sys_user_session` VALUES ('055057e3356b4c249d56a6627ca057a7', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-04 16:54:24', '', '2021-03-05 01:25:51', b'0');
-INSERT INTO `sys_user_session` VALUES ('064ba2d647704f57bdf36a1803a724d7', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 02:17:35', '', '2021-02-27 12:04:09', b'0');
-INSERT INTO `sys_user_session` VALUES ('0df60899301d4080bd4164f24bccf18b', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-07 13:05:42', '', '2021-02-14 22:57:44', b'0');
-INSERT INTO `sys_user_session` VALUES ('1127b5eb9b0c4f9fa382d4d98a8a4a38', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 06:49:00', '', '2021-02-10 11:10:31', b'0');
-INSERT INTO `sys_user_session` VALUES ('11aa2d7861d445349790804fa8676754', 1, '127.0.0.1', 'Mozilla/5.0 (Linux; Android 10; PCT-AL10 Build/HUAWEIPCT-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045513 Mobile Safari/537.36 MMWEBID/2883 MicroMessenger/8.0.1.1841(0x28000159) Process/tools WeChat/arm64 Weixin NetType/4G Language/zh_CN ABI/arm64', '', '2021-02-09 00:06:03', '', '2021-02-09 00:06:03', b'0');
-INSERT INTO `sys_user_session` VALUES ('135db2c6d88a4f41aaf4df46f3a3e0ea', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-06 01:44:25', '', '2021-03-06 01:44:25', b'0');
-INSERT INTO `sys_user_session` VALUES ('1bcac32d34b94422893f10718f643320', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 12:14:10', '', '2021-02-09 12:14:10', b'0');
-INSERT INTO `sys_user_session` VALUES ('20109910c52e4b02bbc0531212bff8cb', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-06 02:39:48', '', '2021-02-06 02:39:48', b'0');
-INSERT INTO `sys_user_session` VALUES ('2024509755b3444690c2a1dddaebd812', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 06:22:30', '', '2021-02-05 06:22:30', b'0');
-INSERT INTO `sys_user_session` VALUES ('260facb728964db7a3df8461b4eebe86', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 23:10:08', '', '2021-02-08 23:10:08', b'0');
-INSERT INTO `sys_user_session` VALUES ('27858c1f13c64a2a8889063932419885', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 18:27:13', '', '2021-02-20 16:11:21', b'0');
-INSERT INTO `sys_user_session` VALUES ('27d6db8abb3b4ed88d446ad489b9db23', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-07 06:38:34', '', '2021-02-14 10:57:34', b'0');
-INSERT INTO `sys_user_session` VALUES ('27dbe0b1051b41eb9efe6558af7cd681', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-06 00:51:14', '', '2021-03-06 19:10:23', b'0');
-INSERT INTO `sys_user_session` VALUES ('285af833677642448bbd19c40a279825', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 04:17:09', '', '2021-02-18 20:23:05', b'0');
-INSERT INTO `sys_user_session` VALUES ('31e5ff8584794ca58460ecf68a177c3f', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-06 11:48:57', '', '2021-02-12 20:56:44', b'0');
-INSERT INTO `sys_user_session` VALUES ('39cdef31685d4e93931a053d88ff0279', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 08:09:33', '', '2021-02-05 08:09:33', b'0');
-INSERT INTO `sys_user_session` VALUES ('3e111c66356d47da8ffc2755bfa3db52', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 14:00:25', '', '2021-02-09 14:00:25', b'0');
-INSERT INTO `sys_user_session` VALUES ('3f308ac8ff26481e829261dd14babbbb', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 01:33:07', '', '2021-02-17 22:01:24', b'0');
-INSERT INTO `sys_user_session` VALUES ('452d44e0616c4dca93485ce67ac946df', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-06 03:41:56', '', '2021-03-06 21:59:07', b'0');
-INSERT INTO `sys_user_session` VALUES ('50274d6c400f42f7bd5391a12858e262', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 11:45:04', '', '2021-02-26 11:45:04', b'0');
-INSERT INTO `sys_user_session` VALUES ('5636ae58b9644ea1b4ed934b025b76ea', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 04:24:59', '', '2021-02-09 18:40:06', b'0');
-INSERT INTO `sys_user_session` VALUES ('5891c4873bf746989a132929449d5f2b', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-06 01:55:18', '', '2021-03-06 20:55:38', b'0');
-INSERT INTO `sys_user_session` VALUES ('597956fbc5b34363981530b24e1b5327', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-06 13:47:15', '', '2021-02-12 20:36:16', b'0');
-INSERT INTO `sys_user_session` VALUES ('599102a1e8414ab59eddaf5492f98dad', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 06:40:37', '', '2021-02-27 21:25:52', b'0');
-INSERT INTO `sys_user_session` VALUES ('5a9b736ccaa8452394c57ac82bd0815e', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 10:57:52', '', '2021-02-10 16:52:48', b'0');
-INSERT INTO `sys_user_session` VALUES ('5aaeaa5c89434c6bbfa6c5af55097093', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 01:28:32', '', '2021-02-27 10:34:25', b'0');
-INSERT INTO `sys_user_session` VALUES ('5b6787e6cbfa4c7faba0dc825fc02816', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 17:25:20', '', '2021-02-20 14:49:27', b'0');
-INSERT INTO `sys_user_session` VALUES ('604ac07123a445ee8a81e58db1d6d695', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 16:33:53', '', '2021-02-05 16:33:53', b'0');
-INSERT INTO `sys_user_session` VALUES ('648563ff4a7f454dac0385cca0581fb3', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 09:34:50', '', '2021-02-19 09:55:44', b'0');
-INSERT INTO `sys_user_session` VALUES ('64fd3d0a54754b8fa13b62d2f261b1e2', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 01:36:09', '', '2021-02-09 16:05:22', b'0');
-INSERT INTO `sys_user_session` VALUES ('661be9d3983e4e2eb8b346c1329015f5', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-06 19:46:45', '', '2021-02-13 12:02:29', b'0');
-INSERT INTO `sys_user_session` VALUES ('6acbf1f210ff4c6594acb3505f0c3738', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-07 12:16:36', '', '2021-02-14 22:37:22', b'0');
-INSERT INTO `sys_user_session` VALUES ('6e7e89c4948f45658eb74878457ac611', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 21:29:20', '', '2021-02-23 01:54:44', b'0');
-INSERT INTO `sys_user_session` VALUES ('73c66b705ed94e18bc53df61abc2d102', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-06 15:00:55', '', '2021-02-06 15:00:55', b'0');
-INSERT INTO `sys_user_session` VALUES ('73cc914671034f3190f09f520d1b39e9', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-01-26 08:29:27', '', '2021-01-26 08:29:50', b'1');
-INSERT INTO `sys_user_session` VALUES ('7b008d71139f48a4903aeaab0bbbef2e', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-06 04:38:15', '', '2021-03-06 04:38:15', b'0');
-INSERT INTO `sys_user_session` VALUES ('7cbd0fdfb9304f298abb9ee2f58f7230', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 20:02:24', '', '2021-02-08 20:02:24', b'0');
-INSERT INTO `sys_user_session` VALUES ('830a1687977b44969025177ad3b6d051', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-10 01:56:00', '', '2021-02-10 01:56:00', b'0');
-INSERT INTO `sys_user_session` VALUES ('8331dbbca7be4348a3d2d02bf559b65e', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 13:29:04', '', '2021-02-10 19:06:26', b'0');
-INSERT INTO `sys_user_session` VALUES ('897714de63634dba9ac235247f9860c2', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-03-06 06:27:27', '', '2021-03-06 06:27:27', b'0');
-INSERT INTO `sys_user_session` VALUES ('8d7668c1276344ecbffaf7e4420595d7', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 09:56:09', '', '2021-02-19 19:17:42', b'0');
-INSERT INTO `sys_user_session` VALUES ('9a3a5b8dee1841b69d70454ce23a53a3', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 00:09:49', '', '2021-02-27 01:27:20', b'0');
-INSERT INTO `sys_user_session` VALUES ('9cc71dc2d7a24b978db1bfe0e4bae349', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-01-26 08:30:01', '', '2021-01-26 08:30:01', b'0');
-INSERT INTO `sys_user_session` VALUES ('9e47f4bfee5e444194530de88900e259', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 20:25:02', '', '2021-02-23 01:54:51', b'0');
-INSERT INTO `sys_user_session` VALUES ('a07756b7a4b24117b0bd14ec2c68b516', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 07:47:21', '', '2021-02-27 23:12:38', b'0');
-INSERT INTO `sys_user_session` VALUES ('a1d01dbed7ff4b6392c3f27c18ce8778', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-07 07:36:14', '', '2021-02-14 12:13:56', b'0');
-INSERT INTO `sys_user_session` VALUES ('a63c2208dd824440999bee9abc22ea7a', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-25 20:45:24', '', '2021-02-25 20:45:24', b'0');
-INSERT INTO `sys_user_session` VALUES ('a7c495d00e2e4543ba943b4edb8c8176', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-26 03:44:46', '', '2021-02-27 12:50:23', b'0');
-INSERT INTO `sys_user_session` VALUES ('a93edff183c447719ecb627d40ca22a6', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 20:28:51', '', '2021-02-05 20:28:51', b'0');
-INSERT INTO `sys_user_session` VALUES ('aa22b7a5754b440e957ec47b832c9fd6', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-06 21:22:31', '', '2021-02-06 21:22:31', b'0');
-INSERT INTO `sys_user_session` VALUES ('b3881aa0b09b4bcdaf9e5ce5f2bbf15a', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 20:18:33', '', '2021-02-09 20:18:33', b'0');
-INSERT INTO `sys_user_session` VALUES ('bafb6445d05a4ee1bd9cdcf2ee83aea9', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 13:57:15', '', '2021-02-09 13:57:15', b'0');
-INSERT INTO `sys_user_session` VALUES ('c1ede4001ac945f8844b3c7abdc86119', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 03:05:18', '', '2021-02-08 03:05:18', b'0');
-INSERT INTO `sys_user_session` VALUES ('c527dcd973454664a75bbf5dbeae834a', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 17:06:03', '', '2021-02-22 20:33:03', b'0');
-INSERT INTO `sys_user_session` VALUES ('df87c2afa8de4559a091292434df9fd8', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-09 20:05:45', '', '2021-02-23 00:25:16', b'0');
-INSERT INTO `sys_user_session` VALUES ('e3ad1ef8b9aa4b329855b29c7b372e8f', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 06:21:44', '', '2021-02-05 06:21:44', b'0');
-INSERT INTO `sys_user_session` VALUES ('ea0d48776db84da4ac0f4c2adf62c366', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-08 07:02:03', '', '2021-02-08 07:02:03', b'0');
-INSERT INTO `sys_user_session` VALUES ('f881f7dc67d04cd29574657fdde32a62', 1, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', '', '2021-02-05 08:53:20', '', '2021-02-05 08:53:20', b'0');
+INSERT INTO `sys_user_session` VALUES ('f853b50d064340a581e9a49bba9411fc', 1, '2021-03-10 01:55:41', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-10 01:25:41', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -1000,13 +1085,13 @@ CREATE TABLE `tool_codegen_column` (
   `list_operation_condition` varchar(32) NOT NULL DEFAULT '=' COMMENT 'List 查询操作的条件类型',
   `list_operation_result` bit(1) NOT NULL COMMENT '是否为 List 查询操作的返回字段',
   `html_type` varchar(32) NOT NULL COMMENT '显示类型',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=369 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表字段定义';
+) ENGINE=InnoDB AUTO_INCREMENT=381 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表字段定义';
 
 -- ----------------------------
 -- Records of tool_codegen_column
@@ -1018,9 +1103,9 @@ INSERT INTO `tool_codegen_column` VALUES (234, 20, 'status', 'tinyint(4)', '状
 INSERT INTO `tool_codegen_column` VALUES (235, 20, 'type', 'tinyint(4)', '类型', b'0', b'0', '0', 4, 'Integer', 'type', 'sys_operate_type', '2', b'1', b'1', b'1', '=', b'1', 'select', '', '2021-02-06 01:33:25', '', '2021-02-06 03:26:05', b'0');
 INSERT INTO `tool_codegen_column` VALUES (236, 20, 'category', 'tinyint(4)', '分类', b'0', b'0', '0', 5, 'Integer', 'category', 'inf_redis_timeout_type', '3', b'1', b'1', b'1', '=', b'1', 'radio', '', '2021-02-06 01:33:25', '', '2021-02-06 13:17:53', b'0');
 INSERT INTO `tool_codegen_column` VALUES (237, 20, 'remark', 'varchar(500)', '备注', b'1', b'0', '0', 6, 'String', 'remark', '', '我是备注', b'1', b'1', b'1', '=', b'1', 'input', '', '2021-02-06 01:33:25', '', '2021-02-06 03:26:08', b'0');
-INSERT INTO `tool_codegen_column` VALUES (238, 20, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 7, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 01:33:25', '', '2021-02-06 03:26:09', b'0');
+INSERT INTO `tool_codegen_column` VALUES (238, 20, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 7, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 01:33:25', '', '2021-02-06 03:26:09', b'0');
 INSERT INTO `tool_codegen_column` VALUES (239, 20, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 8, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '', '2021-02-06 01:33:25', '', '2021-02-06 07:50:41', b'0');
-INSERT INTO `tool_codegen_column` VALUES (240, 20, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 9, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 01:33:25', '', '2021-02-06 03:26:13', b'0');
+INSERT INTO `tool_codegen_column` VALUES (240, 20, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 9, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 01:33:25', '', '2021-02-06 03:26:13', b'0');
 INSERT INTO `tool_codegen_column` VALUES (241, 20, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 10, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', '=', b'0', 'datetime', '', '2021-02-06 01:33:25', '', '2021-02-06 08:02:20', b'0');
 INSERT INTO `tool_codegen_column` VALUES (242, 20, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 11, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'1', '=', b'0', 'radio', '', '2021-02-06 01:33:25', '', '2021-02-06 07:52:14', b'0');
 INSERT INTO `tool_codegen_column` VALUES (243, 21, 'id', 'int(5)', '参数主键', b'0', b'1', '1', 1, 'Integer', 'id', '', NULL, b'0', b'1', b'0', '=', b'1', 'input', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
@@ -1031,9 +1116,9 @@ INSERT INTO `tool_codegen_column` VALUES (247, 21, 'key', 'varchar(100)', '参
 INSERT INTO `tool_codegen_column` VALUES (248, 21, 'value', 'varchar(500)', '参数键值', b'0', b'0', '0', 6, 'String', 'value', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-06 19:51:35', '', '2021-03-06 02:20:02', b'0');
 INSERT INTO `tool_codegen_column` VALUES (249, 21, 'sensitive', 'bit(1)', '是否敏感', b'0', b'0', '0', 7, 'Boolean', 'sensitive', '', NULL, b'1', b'1', b'0', '=', b'1', 'radio', '', '2021-02-06 19:51:35', '', '2021-03-06 02:20:02', b'0');
 INSERT INTO `tool_codegen_column` VALUES (250, 21, 'remark', 'varchar(500)', '备注', b'1', b'0', '0', 8, 'String', 'remark', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-06 19:51:35', '', '2021-03-06 02:20:02', b'0');
-INSERT INTO `tool_codegen_column` VALUES (251, 21, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
+INSERT INTO `tool_codegen_column` VALUES (251, 21, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (252, 21, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 10, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
-INSERT INTO `tool_codegen_column` VALUES (253, 21, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
+INSERT INTO `tool_codegen_column` VALUES (253, 21, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (254, 21, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 12, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (255, 21, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 13, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-02-06 19:51:35', '', '2021-02-06 19:51:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (256, 23, 'job_id', 'bigint(20)', '任务ID', b'0', b'1', '1', 1, 'Long', 'jobId', '', NULL, b'0', b'1', b'0', '=', b'1', 'input', '', '2021-02-06 20:29:26', '', '2021-02-07 06:38:51', b'1');
@@ -1044,9 +1129,9 @@ INSERT INTO `tool_codegen_column` VALUES (260, 23, 'cron_expression', 'varchar(2
 INSERT INTO `tool_codegen_column` VALUES (261, 23, 'misfire_policy', 'varchar(20)', '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', b'1', b'0', '0', 6, 'String', 'misfirePolicy', '', NULL, b'1', b'1', b'1', '=', b'1', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:47:14', b'1');
 INSERT INTO `tool_codegen_column` VALUES (262, 23, 'concurrent', 'char(1)', '是否并发执行(0允许 1禁止)', b'1', b'0', '0', 7, 'String', 'concurrent', '', NULL, b'1', b'1', b'1', '=', b'1', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:47:14', b'1');
 INSERT INTO `tool_codegen_column` VALUES (263, 23, 'status', 'char(1)', '状态(0正常 1暂停)', b'1', b'0', '0', 8, 'String', 'status', '', NULL, b'1', b'1', b'1', '=', b'1', 'radio', '', '2021-02-06 20:29:26', '', '2021-02-06 20:46:49', b'1');
-INSERT INTO `tool_codegen_column` VALUES (264, 23, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:46:49', b'1');
+INSERT INTO `tool_codegen_column` VALUES (264, 23, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:46:49', b'1');
 INSERT INTO `tool_codegen_column` VALUES (265, 23, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 10, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '', '2021-02-06 20:29:26', '', '2021-02-06 20:46:49', b'1');
-INSERT INTO `tool_codegen_column` VALUES (266, 23, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:46:49', b'1');
+INSERT INTO `tool_codegen_column` VALUES (266, 23, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:46:49', b'1');
 INSERT INTO `tool_codegen_column` VALUES (267, 23, 'update_time', 'datetime', '更新时间', b'1', b'0', '0', 12, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-02-06 20:29:26', '', '2021-02-06 20:47:14', b'1');
 INSERT INTO `tool_codegen_column` VALUES (268, 23, 'remark', 'varchar(500)', '备注信息', b'1', b'0', '0', 13, 'String', 'remark', '', NULL, b'1', b'1', b'1', '=', b'1', 'input', '', '2021-02-06 20:29:26', '', '2021-02-06 20:47:14', b'1');
 INSERT INTO `tool_codegen_column` VALUES (269, 24, 'id', 'bigint(20)', '任务编号', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '', '2021-02-07 06:39:34', '', '2021-02-07 06:44:19', b'0');
@@ -1060,9 +1145,9 @@ INSERT INTO `tool_codegen_column` VALUES (276, 24, 'execute_end_time', 'datetime
 INSERT INTO `tool_codegen_column` VALUES (277, 24, 'fire_prev_time', 'datetime', '上一次触发时间', b'1', b'0', '0', 9, 'Date', 'firePrevTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '', '2021-02-07 06:39:34', '', '2021-02-07 07:53:27', b'0');
 INSERT INTO `tool_codegen_column` VALUES (278, 24, 'fire_next_time', 'datetime', '下一次触发时间', b'1', b'0', '0', 10, 'Date', 'fireNextTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '', '2021-02-07 06:39:34', '', '2021-02-07 07:53:27', b'0');
 INSERT INTO `tool_codegen_column` VALUES (279, 24, 'monitor_timeout', 'int(11)', '监控超时时间', b'1', b'0', '0', 11, 'Integer', 'monitorTimeout', '', '1000', b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-07 06:39:34', '', '2021-02-07 06:44:19', b'0');
-INSERT INTO `tool_codegen_column` VALUES (280, 24, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 12, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-07 06:39:34', '', '2021-02-07 06:39:34', b'0');
+INSERT INTO `tool_codegen_column` VALUES (280, 24, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 12, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-07 06:39:34', '', '2021-02-07 06:39:34', b'0');
 INSERT INTO `tool_codegen_column` VALUES (281, 24, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 13, 'Date', 'createTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '', '2021-02-07 06:39:34', '', '2021-02-07 06:44:19', b'0');
-INSERT INTO `tool_codegen_column` VALUES (282, 24, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 14, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-07 06:39:34', '', '2021-02-07 06:39:34', b'0');
+INSERT INTO `tool_codegen_column` VALUES (282, 24, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 14, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-07 06:39:34', '', '2021-02-07 06:39:34', b'0');
 INSERT INTO `tool_codegen_column` VALUES (283, 24, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 15, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-02-07 06:39:34', '', '2021-02-07 06:39:34', b'0');
 INSERT INTO `tool_codegen_column` VALUES (284, 24, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 16, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-02-07 06:39:34', '', '2021-02-07 06:39:34', b'0');
 INSERT INTO `tool_codegen_column` VALUES (285, 24, 'retry_count', 'int(11)', '重试次数', b'0', b'0', '0', 11, 'Integer', 'retryCount', '', NULL, b'1', b'1', b'1', '=', b'1', 'input', '', '2021-02-08 04:17:27', '', '2021-02-08 04:17:27', b'0');
@@ -1077,9 +1162,9 @@ INSERT INTO `tool_codegen_column` VALUES (293, 25, 'end_time', 'datetime', '结
 INSERT INTO `tool_codegen_column` VALUES (294, 25, 'duration', 'int(11)', '执行时长', b'1', b'0', '0', 8, 'Integer', 'duration', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-08 04:58:41', '', '2021-02-08 05:06:07', b'0');
 INSERT INTO `tool_codegen_column` VALUES (295, 25, 'status', 'tinyint(4)', '任务状态', b'0', b'0', '0', 9, 'Integer', 'status', 'inf_job_log_status', NULL, b'1', b'1', b'1', '=', b'1', 'radio', '', '2021-02-08 04:58:41', '', '2021-02-08 10:21:07', b'0');
 INSERT INTO `tool_codegen_column` VALUES (296, 25, 'result', 'varchar(4000)', '结果数据', b'1', b'0', '0', 10, 'String', 'result', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-08 04:58:41', '', '2021-02-08 05:06:07', b'0');
-INSERT INTO `tool_codegen_column` VALUES (297, 25, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 11, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-08 04:58:41', '', '2021-02-08 04:58:41', b'0');
+INSERT INTO `tool_codegen_column` VALUES (297, 25, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 11, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-08 04:58:41', '', '2021-02-08 04:58:41', b'0');
 INSERT INTO `tool_codegen_column` VALUES (298, 25, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 12, 'Date', 'createTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '', '2021-02-08 04:58:41', '', '2021-02-08 05:06:07', b'0');
-INSERT INTO `tool_codegen_column` VALUES (299, 25, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 13, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-08 04:58:41', '', '2021-02-08 04:58:41', b'0');
+INSERT INTO `tool_codegen_column` VALUES (299, 25, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 13, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-08 04:58:41', '', '2021-02-08 04:58:41', b'0');
 INSERT INTO `tool_codegen_column` VALUES (300, 25, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 14, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-02-08 04:58:41', '', '2021-02-08 04:58:41', b'0');
 INSERT INTO `tool_codegen_column` VALUES (301, 25, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 15, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-02-08 04:58:41', '', '2021-02-08 04:58:41', b'0');
 INSERT INTO `tool_codegen_column` VALUES (302, 26, 'id', 'bigint(20)', '日志主键', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:18:03', b'0');
@@ -1097,9 +1182,9 @@ INSERT INTO `tool_codegen_column` VALUES (314, 26, 'end_time', 'datetime', '结
 INSERT INTO `tool_codegen_column` VALUES (315, 26, 'duration', 'int(11)', '执行时长', b'0', b'0', '0', 14, 'Integer', 'duration', '', '100', b'1', b'1', b'1', '>=', b'1', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:29:12', b'0');
 INSERT INTO `tool_codegen_column` VALUES (316, 26, 'result_code', 'int(11)', '结果码', b'0', b'0', '0', 15, 'Integer', 'resultCode', '', '0', b'1', b'1', b'1', '=', b'1', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:29:12', b'0');
 INSERT INTO `tool_codegen_column` VALUES (317, 26, 'result_msg', 'varchar(512)', '结果提示', b'1', b'0', '0', 16, 'String', 'resultMsg', '', '芋道源码,牛逼!', b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:30:58', b'0');
-INSERT INTO `tool_codegen_column` VALUES (318, 26, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 17, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:13:35', b'0');
+INSERT INTO `tool_codegen_column` VALUES (318, 26, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 17, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:13:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (319, 26, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 18, 'Date', 'createTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '', '2021-02-26 00:13:35', '', '2021-02-26 00:33:02', b'0');
-INSERT INTO `tool_codegen_column` VALUES (320, 26, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 19, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:13:35', b'0');
+INSERT INTO `tool_codegen_column` VALUES (320, 26, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 19, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-26 00:13:35', '', '2021-02-26 00:13:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (321, 26, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 20, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-02-26 00:13:35', '', '2021-02-26 00:13:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (322, 26, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 21, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-02-26 00:13:35', '', '2021-02-26 00:13:35', b'0');
 INSERT INTO `tool_codegen_column` VALUES (323, 27, 'id', 'int(11)', '编号', b'0', b'1', '1', 1, 'Integer', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '', '2021-02-26 06:54:49', '', '2021-02-26 06:58:23', b'0');
@@ -1122,7 +1207,7 @@ INSERT INTO `tool_codegen_column` VALUES (339, 27, 'exception_file_name', 'varch
 INSERT INTO `tool_codegen_column` VALUES (340, 27, 'exception_method_name', 'varchar(512)', '异常发生的方法名', b'0', b'0', '0', 18, 'String', 'exceptionMethodName', '', NULL, b'1', b'1', b'0', 'LIKE', b'1', 'input', '', '2021-02-26 06:54:49', '', '2021-02-26 07:10:19', b'0');
 INSERT INTO `tool_codegen_column` VALUES (341, 27, 'exception_line_number', 'int(11)', '异常发生的方法所在行', b'0', b'0', '0', 19, 'Integer', 'exceptionLineNumber', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-02-26 06:54:49', '', '2021-02-26 07:10:19', b'0');
 INSERT INTO `tool_codegen_column` VALUES (342, 27, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 20, 'Date', 'createTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '', '2021-02-26 06:54:49', '', '2021-02-26 06:56:14', b'0');
-INSERT INTO `tool_codegen_column` VALUES (343, 27, 'update_by', 'varchar(64)', '更新者', b'0', b'0', '0', 21, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-26 06:54:49', '', '2021-02-26 06:56:14', b'0');
+INSERT INTO `tool_codegen_column` VALUES (343, 27, 'updater', 'varchar(64)', '更新者', b'0', b'0', '0', 21, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-02-26 06:54:49', '', '2021-02-26 06:56:14', b'0');
 INSERT INTO `tool_codegen_column` VALUES (344, 27, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 22, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-02-26 06:54:49', '', '2021-02-26 06:54:49', b'0');
 INSERT INTO `tool_codegen_column` VALUES (345, 27, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 23, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-02-26 06:54:49', '', '2021-02-26 06:54:49', b'0');
 INSERT INTO `tool_codegen_column` VALUES (346, 27, 'process_status', 'tinyint(4)', '处理状态', b'0', b'0', '0', 20, 'Integer', 'processStatus', 'inf_api_error_log_process_status', '0', b'1', b'1', b'1', '=', b'1', 'radio', '', '2021-02-26 07:01:49', '', '2021-02-26 07:11:29', b'0');
@@ -1133,9 +1218,9 @@ INSERT INTO `tool_codegen_column` VALUES (350, 28, 'name', 'varchar(100)', '字
 INSERT INTO `tool_codegen_column` VALUES (351, 28, 'dict_type', 'varchar(100)', '字典类型', b'0', b'0', '0', 3, 'String', 'dictType', '', NULL, b'1', b'1', b'1', '=', b'1', 'select', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_column` VALUES (352, 28, 'status', 'tinyint(4)', '状态(0正常 1停用)', b'0', b'0', '0', 4, 'Integer', 'status', '', NULL, b'1', b'1', b'1', '=', b'1', 'radio', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_column` VALUES (353, 28, 'remark', 'varchar(500)', '备注', b'1', b'0', '0', 5, 'String', 'remark', '', NULL, b'1', b'1', b'1', '=', b'1', 'input', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
-INSERT INTO `tool_codegen_column` VALUES (354, 28, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 6, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
+INSERT INTO `tool_codegen_column` VALUES (354, 28, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 6, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_column` VALUES (355, 28, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 7, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
-INSERT INTO `tool_codegen_column` VALUES (356, 28, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 8, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
+INSERT INTO `tool_codegen_column` VALUES (356, 28, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 8, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_column` VALUES (357, 28, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 9, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_column` VALUES (358, 28, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 10, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_column` VALUES (359, 29, 'id', 'bigint(20)', '字典主键', b'0', b'1', '1', 1, 'Long', 'id', '', NULL, b'0', b'1', b'0', '=', b'1', 'input', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
@@ -1143,11 +1228,23 @@ INSERT INTO `tool_codegen_column` VALUES (360, 29, 'name', 'varchar(100)', '字
 INSERT INTO `tool_codegen_column` VALUES (361, 29, 'type', 'varchar(100)', '字典类型', b'0', b'0', '0', 3, 'String', 'type', '', NULL, b'1', b'1', b'1', 'LIKE', b'1', 'select', '', '2021-03-06 03:52:57', '', '2021-03-06 03:54:48', b'0');
 INSERT INTO `tool_codegen_column` VALUES (362, 29, 'status', 'tinyint(4)', '状态(0正常 1停用)', b'0', b'0', '0', 4, 'Integer', 'status', '', NULL, b'1', b'1', b'1', '=', b'1', 'radio', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
 INSERT INTO `tool_codegen_column` VALUES (363, 29, 'remark', 'varchar(500)', '备注', b'1', b'0', '0', 5, 'String', 'remark', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-03-06 03:52:57', '', '2021-03-06 03:54:48', b'0');
-INSERT INTO `tool_codegen_column` VALUES (364, 29, 'create_by', 'varchar(64)', '创建者', b'1', b'0', '0', 6, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
+INSERT INTO `tool_codegen_column` VALUES (364, 29, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 6, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
 INSERT INTO `tool_codegen_column` VALUES (365, 29, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 7, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
-INSERT INTO `tool_codegen_column` VALUES (366, 29, 'update_by', 'varchar(64)', '更新者', b'1', b'0', '0', 8, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
+INSERT INTO `tool_codegen_column` VALUES (366, 29, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 8, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
 INSERT INTO `tool_codegen_column` VALUES (367, 29, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 9, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
 INSERT INTO `tool_codegen_column` VALUES (368, 29, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 10, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-03-06 03:52:57', '', '2021-03-06 03:52:57', b'0');
+INSERT INTO `tool_codegen_column` VALUES (369, 30, 'id', 'bigint(20)', '字典编码', b'0', b'1', '1', 1, 'Long', 'id', '', NULL, b'0', b'1', b'0', '=', b'1', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
+INSERT INTO `tool_codegen_column` VALUES (370, 30, 'sort', 'int(4)', '字典排序', b'0', b'0', '0', 2, 'Integer', 'sort', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:38', b'0');
+INSERT INTO `tool_codegen_column` VALUES (371, 30, 'label', 'varchar(100)', '字典标签', b'0', b'0', '0', 3, 'String', 'label', '', NULL, b'1', b'1', b'1', 'LIKE', b'1', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:38', b'0');
+INSERT INTO `tool_codegen_column` VALUES (372, 30, 'value', 'varchar(100)', '字典键值', b'0', b'0', '0', 4, 'String', 'value', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:38', b'0');
+INSERT INTO `tool_codegen_column` VALUES (373, 30, 'dict_type', 'varchar(100)', '字典类型', b'0', b'0', '0', 5, 'String', 'dictType', '', NULL, b'1', b'1', b'1', 'LIKE', b'1', 'select', '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:38', b'0');
+INSERT INTO `tool_codegen_column` VALUES (374, 30, 'status', 'tinyint(4)', '状态(0正常 1停用)', b'0', b'0', '0', 6, 'Integer', 'status', '', NULL, b'1', b'1', b'1', 'LIKE', b'1', 'radio', '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:38', b'0');
+INSERT INTO `tool_codegen_column` VALUES (375, 30, 'remark', 'varchar(500)', '备注', b'1', b'0', '0', 7, 'String', 'remark', '', NULL, b'1', b'1', b'0', '=', b'1', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:38', b'0');
+INSERT INTO `tool_codegen_column` VALUES (376, 30, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 8, 'String', 'createBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
+INSERT INTO `tool_codegen_column` VALUES (377, 30, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 9, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
+INSERT INTO `tool_codegen_column` VALUES (378, 30, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 10, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
+INSERT INTO `tool_codegen_column` VALUES (379, 30, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 11, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
+INSERT INTO `tool_codegen_column` VALUES (380, 30, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 12, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -1167,13 +1264,13 @@ CREATE TABLE `tool_codegen_table` (
   `author` varchar(50) NOT NULL COMMENT '作者',
   `template_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '模板类型',
   `parent_menu_id` bigint(20) DEFAULT NULL COMMENT '父菜单编号',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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=30 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表定义';
+) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表定义';
 
 -- ----------------------------
 -- Records of tool_codegen_table
@@ -1189,6 +1286,7 @@ INSERT INTO `tool_codegen_table` VALUES (26, 1, 'inf_api_access_log', 'API 访
 INSERT INTO `tool_codegen_table` VALUES (27, 1, 'inf_api_error_log', 'API 错误日志', NULL, 'infra', 'apiErrorLog', 'InfApiErrorLog', 'API 错误日志', '芋道源码', 1, 1083, '', '2021-02-26 06:54:49', '', '2021-02-26 07:53:03', b'0');
 INSERT INTO `tool_codegen_table` VALUES (28, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dictType', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
 INSERT INTO `tool_codegen_table` VALUES (29, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dict', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:52:57', '', '2021-03-06 04:03:52', b'0');
+INSERT INTO `tool_codegen_table` VALUES (30, 1, 'sys_dict_data', '字典数据表', NULL, 'system', 'type', 'SysDictData', '字典数据', '芋道源码', 1, NULL, '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:47', b'0');
 COMMIT;
 
 -- ----------------------------
@@ -1202,9 +1300,9 @@ CREATE TABLE `tool_test_demo` (
   `type` tinyint(4) NOT NULL COMMENT '类型',
   `category` tinyint(4) NOT NULL COMMENT '分类',
   `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
+  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
+  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
   `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

+ 9 - 1
src/main/java/cn/iocoder/dashboard/framework/mybatis/config/MybatisConfiguration.java

@@ -1,5 +1,7 @@
 package cn.iocoder.dashboard.framework.mybatis.config;
 
+import cn.iocoder.dashboard.framework.mybatis.core.handler.DefaultDBFieldHandler;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import org.apache.ibatis.annotations.Mapper;
@@ -13,7 +15,8 @@ import org.springframework.context.annotation.Configuration;
  * @author 芋道源码
  */
 @Configuration
-@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class)
+@MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class,
+        lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试
 public class MybatisConfiguration {
 
     @Bean
@@ -23,4 +26,9 @@ public class MybatisConfiguration {
         return mybatisPlusInterceptor;
     }
 
+    @Bean
+    public MetaObjectHandler defaultMetaObjectHandler(){
+        return new DefaultDBFieldHandler(); // 自动填充参数类
+    }
+
 }

+ 14 - 4
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/dataobject/BaseDO.java

@@ -1,5 +1,7 @@
 package cn.iocoder.dashboard.framework.mybatis.core.dataobject;
 
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import lombok.Data;
 
@@ -15,19 +17,27 @@ public class BaseDO implements Serializable {
     /**
      * 创建时间
      */
+    @TableField(fill = FieldFill.INSERT)
     private Date createTime;
     /**
      * 最后更新时间
      */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
     private Date updateTime;
     /**
-     * 创建者 TODO 芋艿:迁移成编号
+     * 创建者,目前使用 SysUser 的 id 编号
+     *
+     * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
      */
-    private String createBy;
+    @TableField(fill = FieldFill.INSERT)
+    private String creator;
     /**
-     * 更新者 TODO 芋艿:迁移成编号
+     * 更新者,目前使用 SysUser 的 id 编号
+     *
+     * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
      */
-    private String updateBy;
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updater;
     /**
      * 是否删除
      */

+ 63 - 0
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/handler/DefaultDBFieldHandler.java

@@ -0,0 +1,63 @@
+package cn.iocoder.dashboard.framework.mybatis.core.handler;
+
+import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.dashboard.framework.security.core.LoginUser;
+import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * 通用参数填充实现类
+ *
+ * 如果没有显式的对通用参数进行赋值,这里会对通用参数进行填充、赋值
+ *
+ * @author hexiaowu
+ */
+public class DefaultDBFieldHandler implements MetaObjectHandler {
+
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
+            LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
+            BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
+            Date current = new Date();
+
+            // 创建时间为空,则以当前时间为插入时间
+            if (Objects.isNull(baseDO.getCreateTime())) {
+                baseDO.setCreateTime(current);
+            }
+            // 更新时间为空,则以当前时间为更新时间
+            if (Objects.isNull(baseDO.getUpdateTime())) {
+                baseDO.setUpdateTime(current);
+            }
+            // 当前登录用户不为空,创建人为空,则当前登录用户为创建人
+            if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getCreator())) {
+                baseDO.setCreator(loginUser.getId().toString());
+            }
+            // 当前登录用户不为空,更新人为空,则当前登录用户为更新人
+            if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getUpdater())) {
+                baseDO.setUpdater(loginUser.getId().toString());
+            }
+        }
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        Object modifyTime = getFieldValByName("updateTime", metaObject);
+        Object modifier = getFieldValByName("updater", metaObject);
+        // 获取登录用户信息
+        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
+
+        // 更新时间为空,则以当前时间为更新时间
+        if (Objects.isNull(modifyTime)) {
+            setFieldValByName("updateTime", new Date(), metaObject);
+        }
+        // 当前登录用户不为空,更新人为空,则当前登录用户为更新人
+        if (Objects.nonNull(loginUser) && Objects.isNull(modifier)) {
+            setFieldValByName("updater", loginUser.getId().toString(), metaObject);
+        }
+    }
+}

+ 4 - 0
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java

@@ -28,6 +28,10 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
         return selectOne(new QueryWrapper<T>().eq(field, value));
     }
 
+    default Integer selectCount(String field, Object value) {
+        return selectCount(new QueryWrapper<T>().eq(field, value));
+    }
+
     default List<T> selectList() {
         return selectList(new QueryWrapper<>());
     }

+ 0 - 1
src/main/java/cn/iocoder/dashboard/framework/resilience4j/《芋道 Spring Boot 安全框架 Spring Security 入门》.md

@@ -1 +0,0 @@
-<http://www.iocoder.cn/Spring-Boot/Spring-Security/?github>

+ 1 - 0
src/main/java/cn/iocoder/dashboard/framework/resilience4j/《芋道 Spring Boot 服务容错 Resilience4j 入门》.md

@@ -0,0 +1 @@
+<https://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao>

+ 1 - 1
src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java

@@ -152,7 +152,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
                     .anyRequest().authenticated()
                 .and()
                 .headers().frameOptions().disable();
-        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
+        httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler);
         // 添加 JWT Filter
         httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
     }

+ 2 - 1
src/main/java/cn/iocoder/dashboard/framework/security/core/handler/LogoutSuccessHandlerImpl.java

@@ -1,6 +1,7 @@
 package cn.iocoder.dashboard.framework.security.core.handler;
 
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.dashboard.common.pojo.CommonResult;
 import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
 import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
 import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
@@ -36,6 +37,6 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
             securityFrameworkService.logout(token);
         }
         // 返回成功
-        ServletUtils.writeJSON(response, null);
+        ServletUtils.writeJSON(response, CommonResult.success(null));
     }
 }

+ 21 - 3
src/main/java/cn/iocoder/dashboard/framework/security/core/util/SecurityFrameworkUtils.java

@@ -2,7 +2,10 @@ package cn.iocoder.dashboard.framework.security.core.util;
 
 import cn.iocoder.dashboard.framework.security.core.LoginUser;
 import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils;
+import org.springframework.lang.Nullable;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 import org.springframework.util.StringUtils;
@@ -40,9 +43,20 @@ public class SecurityFrameworkUtils {
 
     /**
      * 获取当前用户
+     *
+     * @return 当前用户
      */
+    @Nullable
     public static LoginUser getLoginUser() {
-        return (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        SecurityContext context = SecurityContextHolder.getContext();
+        if (context == null) {
+            return null;
+        }
+        Authentication authentication = context.getAuthentication();
+        if (authentication == null) {
+            return null;
+        }
+        return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
     }
 
     /**
@@ -50,8 +64,10 @@ public class SecurityFrameworkUtils {
      *
      * @return 用户编号
      */
+    @Nullable
     public static Long getLoginUserId() {
-        return getLoginUser().getId();
+        LoginUser loginUser = getLoginUser();
+        return loginUser != null ? loginUser.getId() : null;
     }
 
     /**
@@ -59,8 +75,10 @@ public class SecurityFrameworkUtils {
      *
      * @return 角色编号数组
      */
+    @Nullable
     public static Set<Long> getLoginUserRoleIds() {
-        return getLoginUser().getRoleIds();
+        LoginUser loginUser = getLoginUser();
+        return loginUser != null ? loginUser.getRoleIds() : null;
     }
 
     /**

+ 6 - 4
src/main/java/cn/iocoder/dashboard/framework/swagger/config/SwaggerAutoConfiguration.java

@@ -10,15 +10,17 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpHeaders;
 import springfox.documentation.builders.ApiInfoBuilder;
 import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.service.*;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.Contact;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.service.SecurityScheme;
 import springfox.documentation.spi.DocumentationType;
 import springfox.documentation.spi.service.contexts.SecurityContext;
 import springfox.documentation.spring.web.plugins.Docket;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
-import springfox.documentation.service.ApiKey;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 

+ 2 - 1
src/main/java/cn/iocoder/dashboard/framework/web/config/WebConfiguration.java

@@ -27,9 +27,10 @@ public class WebConfiguration implements WebMvcConfigurer {
 
     @Override
     public void configurePathMatch(PathMatchConfigurer configurer) {
+        // 设置 API 前缀,仅仅匹配 controller 包下的
         configurer.addPathPrefix(webProperties.getApiPrefix(), clazz ->
                 clazz.isAnnotationPresent(RestController.class)
-                && clazz.getPackage().getName().startsWith(webProperties.getControllerPackage()));
+                && clazz.getPackage().getName().startsWith(webProperties.getControllerPackage())); // 仅仅匹配 controller 包
     }
 
     // ========== Filter 相关 ==========

+ 47 - 49
src/main/java/cn/iocoder/dashboard/modules/infra/controller/config/InfConfigController.java

@@ -1,11 +1,9 @@
 package cn.iocoder.dashboard.modules.infra.controller.config;
 
-import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.dashboard.common.pojo.CommonResult;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.dashboard.framework.idempotent.core.annotation.Idempotent;
-import cn.iocoder.dashboard.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver;
+import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.*;
 import cn.iocoder.dashboard.modules.infra.convert.config.InfConfigConvert;
 import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
@@ -13,95 +11,95 @@ import cn.iocoder.dashboard.modules.infra.service.config.InfConfigService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
 import java.io.IOException;
 import java.util.List;
 
+import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
+import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.CONFIG_GET_VALUE_ERROR_IF_SENSITIVE;
 
 @Api(tags = "参数配置")
 @RestController
 @RequestMapping("/infra/config")
+@Validated
 public class InfConfigController {
 
     @Resource
     private InfConfigService configService;
 
-    @ApiOperation("获取参数配置分页")
-    @GetMapping("/page")
-//    @PreAuthorize("@ss.hasPermi('infra:config:list')")
-    public CommonResult<PageResult<InfConfigRespVO>> getConfigPage(@Validated InfConfigPageReqVO reqVO) {
-        PageResult<InfConfigDO> page = configService.getConfigPage(reqVO);
-        return success(InfConfigConvert.INSTANCE.convertPage(page));
+    @PostMapping("/create")
+    @ApiOperation("创建参数配置")
+    @PreAuthorize("@ss.hasPermission('infra:config:create')")
+    public CommonResult<Long> createConfig(@Valid @RequestBody InfConfigCreateReqVO reqVO) {
+        return success(configService.createConfig(reqVO));
     }
 
-    @ApiOperation("导出参数配置")
-    @GetMapping("/export")
-//    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
-//    @PreAuthorize("@ss.hasPermi('infra:config:export')")
-    public void exportSysConfig(HttpServletResponse response, @Validated InfConfigExportReqVO reqVO) throws IOException {
-        List<InfConfigDO> list = configService.getConfigList(reqVO);
-        // 拼接数据
-        List<InfConfigExcelVO> excelDataList = InfConfigConvert.INSTANCE.convertList(list);
-        // 输出
-        ExcelUtils.write(response, "参数配置.xls", "配置列表",
-                InfConfigExcelVO.class, excelDataList);
+    @PutMapping("/update")
+    @ApiOperation("修改参数配置")
+    @PreAuthorize("@ss.hasPermission('infra:config:update')")
+    public CommonResult<Boolean> updateConfig(@Valid @RequestBody InfConfigUpdateReqVO reqVO) {
+        configService.updateConfig(reqVO);
+        return success(true);
     }
 
-    @ApiOperation("获得参数配置")
+    @DeleteMapping("/delete")
+    @ApiOperation("删除参数配置")
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('infra:config:delete')")
+    public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
+        configService.deleteConfig(id);
+        return success(true);
+    }
+
     @GetMapping(value = "/get")
-//    @PreAuthorize("@ss.hasPermi('infra:config:query')")
+    @ApiOperation("获得参数配置")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('infra:config:query')")
     public CommonResult<InfConfigRespVO> getConfig(@RequestParam("id") Long id) {
         return success(InfConfigConvert.INSTANCE.convert(configService.getConfig(id)));
     }
 
+    @GetMapping(value = "/get-value-by-key")
     @ApiOperation(value = "根据参数键名查询参数值", notes = "敏感配置,不允许返回给前端")
     @ApiImplicitParam(name = "key", value = "参数键", required = true, example = "yunai.biz.username", dataTypeClass = String.class)
-    @GetMapping(value = "/get-value-by-key")
     public CommonResult<String> getConfigKey(@RequestParam("key") String key) {
         InfConfigDO config = configService.getConfigByKey(key);
         if (config == null) {
             return null;
         }
         if (config.getSensitive()) {
-            throw ServiceExceptionUtil.exception(CONFIG_GET_VALUE_ERROR_IF_SENSITIVE);
+            throw exception(CONFIG_GET_VALUE_ERROR_IF_SENSITIVE);
         }
         return success(config.getValue());
     }
 
-    @ApiOperation("新增参数配置")
-    @PostMapping("/create")
-//    @PreAuthorize("@ss.hasPermi('infra:config:add')")
-//    @Log(title = "参数管理", businessType = BusinessType.INSERT)
-    @Idempotent(timeout = 60, keyResolver = ExpressionIdempotentKeyResolver.class, keyArg = "#reqVO.key")
-    public CommonResult<Long> createConfig(@Validated @RequestBody InfConfigCreateReqVO reqVO) {
-        return success(configService.createConfig(reqVO));
-    }
-
-    @ApiOperation("修改参数配置")
-    @PutMapping("/update")
-//    @PreAuthorize("@ss.hasPermi('infra:config:edit')")
-//    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
-    @Idempotent(timeout = 60)
-    public CommonResult<Boolean> updateConfig(@Validated @RequestBody InfConfigUpdateReqVO reqVO) {
-        configService.updateConfig(reqVO);
-        return success(true);
+    @GetMapping("/page")
+    @ApiOperation("获取参数配置分页")
+    @PreAuthorize("@ss.hasPermission('infra:config:query')")
+    public CommonResult<PageResult<InfConfigRespVO>> getConfigPage(@Valid InfConfigPageReqVO reqVO) {
+        PageResult<InfConfigDO> page = configService.getConfigPage(reqVO);
+        return success(InfConfigConvert.INSTANCE.convertPage(page));
     }
 
-    @ApiOperation("删除参数配置")
-    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
-    @DeleteMapping("/delete")
-//    @PreAuthorize("@ss.hasPermi('infra:config:remove')")
-//    @Log(title = "参数管理", businessType = BusinessType.DELETE)
-    public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
-        configService.deleteConfig(id);
-        return success(true);
+    @GetMapping("/export")
+    @ApiOperation("导出参数配置")
+    @PreAuthorize("@ss.hasPermission('infra:config:export')")
+    @OperateLog(type = EXPORT)
+    public void exportSysConfig(@Valid InfConfigExportReqVO reqVO,
+                                HttpServletResponse response) throws IOException {
+        List<InfConfigDO> list = configService.getConfigList(reqVO);
+        // 拼接数据
+        List<InfConfigExcelVO> datas = InfConfigConvert.INSTANCE.convertList(list);
+        // 输出
+        ExcelUtils.write(response, "参数配置.xls", "数据", InfConfigExcelVO.class, datas);
     }
 
 }

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobLogController.java

@@ -75,7 +75,7 @@ public class InfJobLogController {
         List<InfJobLogDO> list = jobLogService.getJobLogList(exportReqVO);
         // 导出 Excel
         List<InfJobLogExcelVO> datas = InfJobLogConvert.INSTANCE.convertList02(list);
-        ExcelUtils.write(response, "定时任务.xls", "数据", InfJobLogExcelVO.class, datas);
+        ExcelUtils.write(response, "任务日志.xls", "数据", InfJobLogExcelVO.class, datas);
     }
 
 }

+ 10 - 9
src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigMapper.java

@@ -14,20 +14,21 @@ import java.util.List;
 @Mapper
 public interface InfConfigMapper extends BaseMapperX<InfConfigDO> {
 
-    default PageResult<InfConfigDO> selectPage(InfConfigPageReqVO reqVO) {
-        return selectPage(reqVO,
-                new QueryWrapperX<InfConfigDO>().likeIfPresent("name", reqVO.getName())
-                        .likeIfPresent("`key`", reqVO.getKey())
-                        .eqIfPresent("`type`", reqVO.getType())
-                        .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
-    }
-
     default InfConfigDO selectByKey(String key) {
         return selectOne(new QueryWrapper<InfConfigDO>().eq("`key`", key));
     }
 
+    default PageResult<InfConfigDO> selectPage(InfConfigPageReqVO reqVO) {
+        return selectPage(reqVO, new QueryWrapperX<InfConfigDO>()
+                .likeIfPresent("name", reqVO.getName())
+                .likeIfPresent("`key`", reqVO.getKey())
+                .eqIfPresent("`type`", reqVO.getType())
+                .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
+    }
+
     default List<InfConfigDO> selectList(InfConfigExportReqVO reqVO) {
-        return selectList(new QueryWrapperX<InfConfigDO>().likeIfPresent("name", reqVO.getName())
+        return selectList(new QueryWrapperX<InfConfigDO>()
+                .likeIfPresent("name", reqVO.getName())
                 .likeIfPresent("`key`", reqVO.getKey())
                 .eqIfPresent("`type`", reqVO.getType())
                 .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));

+ 25 - 21
src/main/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigService.java

@@ -7,28 +7,37 @@ import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigPageReqV
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigUpdateReqVO;
 import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
 
+import javax.validation.Valid;
 import java.util.List;
 
 /**
  * 参数配置 Service 接口
+ *
+ * @author 芋道源码
  */
 public interface InfConfigService {
 
     /**
-     * 获得参数配置分页列表
+     * 创建参数配置
      *
-     * @param reqVO 分页条件
-     * @return 分页列表
+     * @param reqVO 创建信息
+     * @return 配置编号
      */
-    PageResult<InfConfigDO> getConfigPage(InfConfigPageReqVO reqVO);
+    Long createConfig(@Valid InfConfigCreateReqVO reqVO);
 
     /**
-     * 获得参数配置列表
+     * 更新参数配置
      *
-     * @param reqVO 列表
-     * @return 列表
+     * @param reqVO 更新信息
      */
-    List<InfConfigDO> getConfigList(InfConfigExportReqVO reqVO);
+    void updateConfig(@Valid InfConfigUpdateReqVO reqVO);
+
+    /**
+     * 删除参数配置
+     *
+     * @param id 配置编号
+     */
+    void deleteConfig(Long id);
 
     /**
      * 获得参数配置
@@ -47,25 +56,20 @@ public interface InfConfigService {
     InfConfigDO getConfigByKey(String key);
 
     /**
-     * 创建参数配置
+     * 获得参数配置分页列表
      *
-     * @param reqVO 创建信息
-     * @return 配置编号
+     * @param reqVO 分页条件
+     * @return 分页列表
      */
-    Long createConfig(InfConfigCreateReqVO reqVO);
+    PageResult<InfConfigDO> getConfigPage(@Valid InfConfigPageReqVO reqVO);
 
     /**
-     * 更新参数配置
+     * 获得参数配置列表
      *
-     * @param reqVO 更新信息
+     * @param reqVO 列表
+     * @return 列表
      */
-    void updateConfig(InfConfigUpdateReqVO reqVO);
+    List<InfConfigDO> getConfigList(@Valid InfConfigExportReqVO reqVO);
 
-    /**
-     * 删除参数配置
-     *
-     * @param id 配置编号
-     */
-    void deleteConfig(Long id);
 
 }

+ 27 - 22
src/main/java/cn/iocoder/dashboard/modules/infra/service/config/impl/InfConfigServiceImpl.java

@@ -12,8 +12,10 @@ import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
 import cn.iocoder.dashboard.modules.infra.enums.config.InfConfigTypeEnum;
 import cn.iocoder.dashboard.modules.infra.mq.producer.config.InfConfigProducer;
 import cn.iocoder.dashboard.modules.infra.service.config.InfConfigService;
+import com.google.common.annotations.VisibleForTesting;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 
@@ -26,6 +28,7 @@ import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
  */
 @Service
 @Slf4j
+@Validated
 public class InfConfigServiceImpl implements InfConfigService {
 
     @Resource
@@ -34,26 +37,6 @@ public class InfConfigServiceImpl implements InfConfigService {
     @Resource
     private InfConfigProducer configProducer;
 
-    @Override
-    public PageResult<InfConfigDO> getConfigPage(InfConfigPageReqVO reqVO) {
-        return configMapper.selectPage(reqVO);
-    }
-
-    @Override
-    public List<InfConfigDO> getConfigList(InfConfigExportReqVO reqVO) {
-        return configMapper.selectList(reqVO);
-    }
-
-    @Override
-    public InfConfigDO getConfig(Long id) {
-        return configMapper.selectById(id);
-    }
-
-    @Override
-    public InfConfigDO getConfigByKey(String key) {
-        return configMapper.selectByKey(key);
-    }
-
     @Override
     public Long createConfig(InfConfigCreateReqVO reqVO) {
         // 校验正确性
@@ -92,6 +75,26 @@ public class InfConfigServiceImpl implements InfConfigService {
         configProducer.sendConfigRefreshMessage();
     }
 
+    @Override
+    public InfConfigDO getConfig(Long id) {
+        return configMapper.selectById(id);
+    }
+
+    @Override
+    public InfConfigDO getConfigByKey(String key) {
+        return configMapper.selectByKey(key);
+    }
+
+    @Override
+    public PageResult<InfConfigDO> getConfigPage(InfConfigPageReqVO reqVO) {
+        return configMapper.selectPage(reqVO);
+    }
+
+    @Override
+    public List<InfConfigDO> getConfigList(InfConfigExportReqVO reqVO) {
+        return configMapper.selectList(reqVO);
+    }
+
     private void checkCreateOrUpdate(Long id, String key) {
         // 校验自己存在
         checkConfigExists(id);
@@ -99,7 +102,8 @@ public class InfConfigServiceImpl implements InfConfigService {
         checkConfigKeyUnique(id, key);
     }
 
-    private InfConfigDO checkConfigExists(Long id) {
+    @VisibleForTesting
+    public InfConfigDO checkConfigExists(Long id) {
         if (id == null) {
             return null;
         }
@@ -110,7 +114,8 @@ public class InfConfigServiceImpl implements InfConfigService {
         return config;
     }
 
-    private void checkConfigKeyUnique(Long id, String key) {
+    @VisibleForTesting
+    public void checkConfigKeyUnique(Long id, String key) {
         InfConfigDO config = configMapper.selectByKey(key);
         if (config == null) {
             return;

+ 2 - 2
src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/dept/SysDeptBaseVO.java

@@ -25,8 +25,8 @@ public class SysDeptBaseVO {
     private Long parentId;
 
     @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
-    @NotBlank(message = "显示顺序不能为空")
-    private String sort;
+    @NotNull(message = "显示顺序不能为空")
+    private Integer sort;
 
     @ApiModelProperty(value = "负责人", example = "芋道")
     private String leader;

+ 3 - 2
src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostBaseVO.java

@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 
 /**
@@ -24,8 +25,8 @@ public class SysPostBaseVO {
     private String code;
 
     @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
-    @NotBlank(message = "显示顺序不能为空")
-    private String sort;
+    @NotNull(message = "显示顺序不能为空")
+    private Integer sort;
 
     @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
     private Integer status;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/controller/dept/vo/post/SysPostExcelVO.java

@@ -23,7 +23,7 @@ public class SysPostExcelVO {
     private String name;
 
     @ExcelProperty("岗位排序")
-    private String sort;
+    private Integer sort;
 
     @ExcelProperty(value = "状态", converter = DictConvert.class)
     @DictFormat(SYS_COMMON_STATUS)

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/data/SysDictDataBaseVO.java

@@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
 public class SysDictDataBaseVO {
 
     @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
-    @NotBlank(message = "显示顺序不能为空")
+    @NotNull(message = "显示顺序不能为空")
     private Integer sort;
 
     @ApiModelProperty(value = "字典标签", required = true, example = "芋道")

+ 2 - 2
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/menu/SysMenuBaseVO.java

@@ -28,8 +28,8 @@ public class SysMenuBaseVO {
     private Integer type;
 
     @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
-    @NotBlank(message = "显示顺序不能为空")
-    private String sort;
+    @NotNull(message = "显示顺序不能为空")
+    private Integer sort;
 
     @ApiModelProperty(value = "父菜单 ID", required = true, example = "1024")
     @NotNull(message = "父菜单 ID 不能为空")

+ 3 - 2
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/role/SysRoleBaseVO.java

@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 
 /**
@@ -24,8 +25,8 @@ public class SysRoleBaseVO {
     private String code;
 
     @ApiModelProperty(value = "显示顺序不能为空", required = true, example = "1024")
-    @NotBlank(message = "显示顺序不能为空")
-    private String sort;
+    @NotNull(message = "显示顺序不能为空")
+    private Integer sort;
 
     @ApiModelProperty(value = "角色类型", required = true, example = "1", notes = "见 SysRoleTypeEnum 枚举")
     private Integer type;

+ 14 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/auth/SysUserSessionDO.java

@@ -10,6 +10,8 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.util.Date;
+
 /**
  * 在线用户表
  *
@@ -36,6 +38,14 @@ public class SysUserSessionDO extends BaseDO {
      * 关联 {@link SysUserDO#getId()}
      */
     private Long userId;
+
+    /**
+     * 用户账号
+     *
+     * 冗余,因为账号可以变更
+     */
+    private String username;
+
     /**
      * 用户 IP
      */
@@ -44,5 +54,9 @@ public class SysUserSessionDO extends BaseDO {
      * 浏览器 UA
      */
     private String userAgent;
+    /**
+     * 会话超时时间
+     */
+    private Date sessionTimeout;
 
 }

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/dept/SysDeptDO.java

@@ -35,7 +35,7 @@ public class SysDeptDO extends BaseDO {
     /**
      * 显示顺序
      */
-    private String sort;
+    private Integer sort;
     /**
      * 负责人
      */

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/dept/SysPostDO.java

@@ -34,7 +34,7 @@ public class SysPostDO extends BaseDO {
     /**
      * 岗位排序
      */
-    private String sort;
+    private Integer sort;
     /**
      * 状态
      *

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/permission/SysMenuDO.java

@@ -49,7 +49,7 @@ public class SysMenuDO extends BaseDO {
     /**
      * 显示顺序
      */
-    private String sort;
+    private Integer sort;
     /**
      * 父菜单ID
      */

+ 5 - 0
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/auth/SysUserSessionMapper.java

@@ -8,6 +8,8 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.Collection;
+import java.util.Date;
+import java.util.List;
 
 @Mapper
 public interface SysUserSessionMapper extends BaseMapperX<SysUserSessionDO> {
@@ -18,4 +20,7 @@ public interface SysUserSessionMapper extends BaseMapperX<SysUserSessionDO> {
                 .likeIfPresent("user_ip", reqVO.getUserIp()));
     }
 
+    default List<SysUserSessionDO> selectListBySessionTimoutLt() {
+        return selectList(new QueryWrapperX<SysUserSessionDO>().lt("session_timeout",new Date()));
+    }
 }

+ 3 - 3
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java

@@ -15,13 +15,13 @@ import java.util.List;
 @Mapper
 public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
 
-    default SysDictDataDO selectByDictTypeAndLabel(String dictType, String label) {
+    default SysDictDataDO selectByDictTypeAndValue(String dictType, String value) {
         return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
-                .eq("label", label));
+                .eq("value", value));
     }
 
     default int selectCountByDictType(String dictType) {
-        return selectCount(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType));
+        return selectCount("dict_type", dictType);
     }
 
     default PageResult<SysDictDataDO> selectPage(SysDictDataPageReqVO reqVO) {

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/SysRedisKeyConstants.java

@@ -16,7 +16,7 @@ public interface SysRedisKeyConstants {
 
     RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登陆用户的缓存",
             "login_user:%s", // 参数为 sessionId
-            STRING, LoginUser.class, Duration.ofMinutes(30));
+            STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
 
     RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",
             "captcha_code:%s", // 参数为 uuid

+ 6 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java

@@ -1,11 +1,13 @@
 package cn.iocoder.dashboard.modules.system.dal.redis.auth;
 
 import cn.iocoder.dashboard.framework.security.core.LoginUser;
+import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
 import cn.iocoder.dashboard.util.json.JsonUtils;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Repository;
 
 import javax.annotation.Resource;
+import java.time.Duration;
 
 import static cn.iocoder.dashboard.modules.system.dal.redis.SysRedisKeyConstants.LOGIN_USER;
 
@@ -19,6 +21,8 @@ public class SysLoginUserRedisDAO {
 
     @Resource
     private StringRedisTemplate stringRedisTemplate;
+    @Resource
+    private SysUserSessionService sysUserSessionService;
 
     public LoginUser get(String sessionId) {
         String redisKey = formatKey(sessionId);
@@ -27,7 +31,8 @@ public class SysLoginUserRedisDAO {
 
     public void set(String sessionId, LoginUser loginUser) {
         String redisKey = formatKey(sessionId);
-        stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser), LOGIN_USER.getTimeout());
+        stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser),
+                Duration.ofMillis(sysUserSessionService.getSessionTimeoutMillis()));
     }
 
     public void delete(String sessionId) {

+ 11 - 4
src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java

@@ -1,23 +1,30 @@
 package cn.iocoder.dashboard.modules.system.job.auth;
 
 import cn.iocoder.dashboard.framework.quartz.core.handler.JobHandler;
+import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
+
 /**
  * 用户 Session 超时 Job
  *
- * @author 芋道源码
+ * @author 
  */
 @Component
 @Slf4j
 public class SysUserSessionTimeoutJob implements JobHandler {
 
+    @Resource
+    private SysUserSessionService sysUserSessionService;
+
     @Override
     public String execute(String param) throws Exception {
-//        System.out.println("执行了一次任务");
-        log.info("[execute][执行任务:{}]", param);
-        return null;
+        // 执行过期
+        Long timeoutCount = sysUserSessionService.clearSessionTimeout();
+        // 返回结果,记录每次的超时数量
+        return String.format("移除在线会话数量为 %s 个", timeoutCount);
     }
 
 }

+ 6 - 0
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionService.java

@@ -60,4 +60,10 @@ public interface SysUserSessionService {
      */
     PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO);
 
+    /**
+     * 移除超时的在线用户
+     *
+     * @return {@link Long } 移出的超时用户数量
+     **/
+    long clearSessionTimeout();
 }

+ 20 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java

@@ -160,7 +160,26 @@ public class SysAuthServiceImpl implements SysAuthService {
 
     @Override
     public void logout(String token) {
-//        AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); TODO 需要搞一搞
+        // 查询用户信息
+        LoginUser loginUser = userSessionService.getLoginUser(token);
+        if (loginUser == null) {
+            return;
+        }
+        // 删除 session
+        userSessionService.deleteUserSession(token);
+        // 记录登出日子和
+        this.createLogoutLog(loginUser.getUsername());
+    }
+
+    private void createLogoutLog(String username) {
+        SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
+        reqVO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
+        reqVO.setTraceId(TracerUtils.getTraceId());
+        reqVO.setUsername(username);
+        reqVO.setUserAgent(ServletUtils.getUserAgent());
+        reqVO.setUserIp(ServletUtils.getClientIP());
+        reqVO.setResult(SysLoginResultEnum.SUCCESS.getResult());
+        loginLogService.createLoginLog(reqVO);
     }
 
     @Override

+ 48 - 6
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java

@@ -6,20 +6,28 @@ import cn.hutool.core.util.StrUtil;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
 import cn.iocoder.dashboard.framework.security.core.LoginUser;
+import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
 import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
-import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
+import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
 import cn.iocoder.dashboard.modules.system.dal.redis.auth.SysLoginUserRedisDAO;
+import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
+import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
 import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
+import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
 import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
+import com.google.common.collect.Lists;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.Date;
+import java.time.Duration;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.dashboard.util.date.DateUtils.addTime;
 
 /**
  * 在线用户 Session Service 实现类
@@ -31,14 +39,14 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
 
     @Resource
     private SecurityProperties securityProperties;
-
     @Resource
     private SysLoginUserRedisDAO loginUserRedisDAO;
     @Resource
     private SysUserSessionMapper userSessionMapper;
-
     @Resource
     private SysUserService userService;
+    @Resource
+    private SysLoginLogService loginLogService;
 
     @Override
     public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
@@ -49,7 +57,9 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
         loginUserRedisDAO.set(sessionId, loginUser);
         // 写入 DB 中
         SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
-                .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).build();
+                .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
+                .sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
+                .build();
         userSessionMapper.insert(userSession);
         // 返回 Session 编号
         return sessionId;
@@ -62,7 +72,9 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
         loginUserRedisDAO.set(sessionId, loginUser);
         // 更新 DB 中
         SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
+        updateObj.setUsername(loginUser.getUsername());
         updateObj.setUpdateTime(new Date());
+        updateObj.setSessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())));
         userSessionMapper.updateById(updateObj);
     }
 
@@ -97,6 +109,36 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
         return userSessionMapper.selectPage(reqVO, userIds);
     }
 
+    @Override
+    public long clearSessionTimeout() {
+        // 获取db里已经超时的用户列表
+        List<SysUserSessionDO> sessionTimeoutDOS = userSessionMapper.selectListBySessionTimoutLt();
+        Map<String, SysUserSessionDO> timeoutSessionDOMap = sessionTimeoutDOS
+                .stream()
+                .filter(sessionDO -> loginUserRedisDAO.get(sessionDO.getId()) == null)
+                .collect(Collectors.toMap(SysUserSessionDO::getId, o -> o));
+        // 确认已经超时,按批次移出在线用户列表
+        if (CollUtil.isNotEmpty(timeoutSessionDOMap)) {
+            Lists.partition(new ArrayList<>(timeoutSessionDOMap.keySet()), 100).forEach(userSessionMapper::deleteBatchIds);
+            //记录用户超时退出日志
+            createTimeoutLogoutLog(timeoutSessionDOMap.values());
+        }
+        return timeoutSessionDOMap.size();
+    }
+
+    private void createTimeoutLogoutLog(Collection<SysUserSessionDO> timeoutSessionDOS) {
+        for (SysUserSessionDO timeoutSessionDO : timeoutSessionDOS) {
+            SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
+            reqVO.setLogType(SysLoginLogTypeEnum.LOGOUT_TIMEOUT.getType());
+            reqVO.setTraceId(TracerUtils.getTraceId());
+            reqVO.setUsername(timeoutSessionDO.getUsername());
+            reqVO.setUserAgent(timeoutSessionDO.getUserAgent());
+            reqVO.setUserIp(timeoutSessionDO.getUserIp());
+            reqVO.setResult(SysLoginResultEnum.SUCCESS.getResult());
+            loginLogService.createLoginLog(reqVO);
+        }
+    }
+
     /**
      * 生成 Session 编号,目前采用 UUID 算法
      *

+ 19 - 15
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java

@@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.dict.impl;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
-import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO;
@@ -10,12 +9,13 @@ import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataEx
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataPageReqVO;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataUpdateReqVO;
 import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert;
-import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableTable;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -28,6 +28,7 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 
+import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
 
 /**
@@ -156,7 +157,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
     @Override
     public Long createDictData(SysDictDataCreateReqVO reqVO) {
         // 校验正确性
-        this.checkCreateOrUpdate(null, reqVO.getLabel(), reqVO.getDictType());
+        this.checkCreateOrUpdate(null, reqVO.getValue(), reqVO.getDictType());
         // 插入字典类型
         SysDictDataDO dictData = SysDictDataConvert.INSTANCE.convert(reqVO);
         dictDataMapper.insert(dictData);
@@ -168,7 +169,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
     @Override
     public void updateDictData(SysDictDataUpdateReqVO reqVO) {
         // 校验正确性
-        this.checkCreateOrUpdate(reqVO.getId(), reqVO.getLabel(), reqVO.getDictType());
+        this.checkCreateOrUpdate(reqVO.getId(), reqVO.getValue(), reqVO.getDictType());
         // 更新字典类型
         SysDictDataDO updateObj = SysDictDataConvert.INSTANCE.convert(reqVO);
         dictDataMapper.updateById(updateObj);
@@ -191,46 +192,49 @@ public class SysDictDataServiceImpl implements SysDictDataService {
         return dictDataMapper.selectCountByDictType(dictType);
     }
 
-    private void checkCreateOrUpdate(Long id, String label, String dictType) {
+    private void checkCreateOrUpdate(Long id, String value, String dictType) {
         // 校验自己存在
         checkDictDataExists(id);
         // 校验字典类型有效
         checkDictTypeValid(dictType);
         // 校验字典数据的值的唯一性
-        checkDictDataValueUnique(id, dictType, label);
+        checkDictDataValueUnique(id, dictType, value);
     }
 
-    private void checkDictDataValueUnique(Long id, String dictType, String label) {
-        SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndLabel(dictType, label);
+    @VisibleForTesting
+    public void checkDictDataValueUnique(Long id, String dictType, String value) {
+        SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndValue(dictType, value);
         if (dictData == null) {
             return;
         }
         // 如果 id 为空,说明不用比较是否为相同 id 的字典数据
         if (id == null) {
-            throw ServiceExceptionUtil.exception(DICT_DATA_VALUE_DUPLICATE);
+            throw exception(DICT_DATA_VALUE_DUPLICATE);
         }
         if (!dictData.getId().equals(id)) {
-            throw ServiceExceptionUtil.exception(DICT_DATA_VALUE_DUPLICATE);
+            throw exception(DICT_DATA_VALUE_DUPLICATE);
         }
     }
 
-    private void checkDictDataExists(Long id) {
+    @VisibleForTesting
+    public void checkDictDataExists(Long id) {
         if (id == null) {
             return;
         }
         SysDictDataDO dictData = dictDataMapper.selectById(id);
         if (dictData == null) {
-            throw ServiceExceptionUtil.exception(DICT_DATA_NOT_EXISTS);
+            throw exception(DICT_DATA_NOT_EXISTS);
         }
     }
 
-    private void checkDictTypeValid(String type) {
+    @VisibleForTesting
+    public void checkDictTypeValid(String type) {
         SysDictTypeDO dictType = dictTypeService.getDictType(type);
         if (dictType == null) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_EXISTS);
+            throw exception(DICT_TYPE_NOT_EXISTS);
         }
         if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_ENABLE);
+            throw exception(DICT_TYPE_NOT_ENABLE);
         }
     }
 

+ 8 - 4
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictTypeServiceImpl.java

@@ -10,6 +10,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
+import com.google.common.annotations.VisibleForTesting;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -97,8 +98,9 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         checkDictTypeUnique(id, type);
     }
 
-    private void checkDictTypeNameUnique(Long id, String type) {
-        SysDictTypeDO dictType = dictTypeMapper.selectByName(type);
+    @VisibleForTesting
+    public void checkDictTypeNameUnique(Long id, String name) {
+        SysDictTypeDO dictType = dictTypeMapper.selectByName(name);
         if (dictType == null) {
             return;
         }
@@ -111,7 +113,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         }
     }
 
-    private void checkDictTypeUnique(Long id, String type) {
+    @VisibleForTesting
+    public void checkDictTypeUnique(Long id, String type) {
         SysDictTypeDO dictType = dictTypeMapper.selectByType(type);
         if (dictType == null) {
             return;
@@ -125,7 +128,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         }
     }
 
-    private SysDictTypeDO checkDictTypeExists(Long id) {
+    @VisibleForTesting
+    public SysDictTypeDO checkDictTypeExists(Long id) {
         if (id == null) {
             return null;
         }

+ 3 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/notice/impl/SysNoticeServiceImpl.java

@@ -9,6 +9,7 @@ import cn.iocoder.dashboard.modules.system.convert.notice.SysNoticeConvert;
 import cn.iocoder.dashboard.modules.system.dal.mysql.notice.SysNoticeMapper;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.notice.SysNoticeDO;
 import cn.iocoder.dashboard.modules.system.service.notice.SysNoticeService;
+import com.google.common.annotations.VisibleForTesting;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -60,7 +61,8 @@ public class SysNoticeServiceImpl implements SysNoticeService {
         noticeMapper.deleteById(id);
     }
 
-    private void checkNoticeExists(Long id) {
+    @VisibleForTesting
+    public void checkNoticeExists(Long id) {
         if (id == null) {
             return;
         }

+ 4 - 2
src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java

@@ -2,6 +2,8 @@ package cn.iocoder.dashboard.util.collection;
 
 import cn.hutool.core.util.ArrayUtil;
 
+import java.util.function.Consumer;
+
 /**
  * Array 工具类
  *
@@ -18,11 +20,11 @@ public class ArrayUtils {
      * @return 结果数组
      */
     @SafeVarargs
-    public static <T> T[] append(T object, T... newElements) {
+    public static <T> Consumer<T>[] append(Consumer<T> object, Consumer<T>... newElements) {
         if (object == null) {
             return newElements;
         }
-        T[] result = ArrayUtil.newArray(object.getClass(), 1 + newElements.length);
+        Consumer<T>[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length);
         result[0] = object;
         System.arraycopy(newElements, 0, result, 1, newElements.length);
         return result;

+ 10 - 0
src/main/java/cn/iocoder/dashboard/util/object/ObjectUtils.java

@@ -19,4 +19,14 @@ public class ObjectUtils {
         return result;
     }
 
+    public static <T extends Comparable<T>> T max(T obj1, T obj2) {
+        if (obj1 == null) {
+            return obj2;
+        }
+        if (obj2 == null) {
+            return obj1;
+        }
+        return obj1.compareTo(obj2) > 0 ? obj1 : obj2;
+    }
+
 }

+ 46 - 0
src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java

@@ -0,0 +1,46 @@
+package cn.iocoder.dashboard;
+
+import cn.iocoder.dashboard.config.RedisTestConfiguration;
+import cn.iocoder.dashboard.framework.datasource.config.DataSourceConfiguration;
+import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration;
+import cn.iocoder.dashboard.framework.redis.config.RedisConfig;
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
+import org.redisson.spring.starter.RedissonAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+
+/**
+ * 依赖内存 DB 的单元测试
+ *
+ * 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法
+ *
+ * @author 芋道源码
+ */
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class)
+@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
+@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
+public class BaseDbAndRedisUnitTest {
+
+    @Import({
+            // DB 配置类
+            DataSourceConfiguration.class, // 自己的 DB 配置类
+            DataSourceAutoConfiguration.class, // Spring DB 自动配置类
+            DruidDataSourceAutoConfigure.class, // Druid 自动配置类
+            // MyBatis 配置类
+            MybatisConfiguration.class, // 自己的 MyBatis 配置类
+            MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
+            // Redis 配置类
+            RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
+            RedisAutoConfiguration.class, // Spring Redis 自动配置类
+            RedisConfig.class, // 自己的 Redis 配置类
+            RedissonAutoConfiguration.class, // Redisson 自动高配置类
+    })
+    public static class Application {
+    }
+
+}

+ 37 - 0
src/test/java/cn/iocoder/dashboard/BaseDbUnitTest.java

@@ -0,0 +1,37 @@
+package cn.iocoder.dashboard;
+
+import cn.iocoder.dashboard.framework.datasource.config.DataSourceConfiguration;
+import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration;
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+
+/**
+ * 依赖内存 DB 的单元测试
+ *
+ * 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法
+ *
+ * @author 芋道源码
+ */
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class)
+@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
+@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
+public class BaseDbUnitTest {
+
+    @Import({
+            // DB 配置类
+            DataSourceConfiguration.class, // 自己的 DB 配置类
+            DataSourceAutoConfiguration.class, // Spring DB 自动配置类
+            DruidDataSourceAutoConfigure.class, // Druid 自动配置类
+            // MyBatis 配置类
+            MybatisConfiguration.class, // 自己的 MyBatis 配置类
+            MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
+    })
+    public static class Application {
+    }
+
+}

+ 1 - 0
src/test/java/cn/iocoder/dashboard/BaseSpringBootUnitTest.java

@@ -12,6 +12,7 @@ import javax.annotation.Resource;
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
 @ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
 @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
+@Deprecated
 public class BaseSpringBootUnitTest {
 
     @Resource

+ 0 - 2
src/test/java/cn/iocoder/dashboard/config/RedisTestConfiguration.java

@@ -8,12 +8,10 @@ import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Lazy;
 
 import java.io.IOException;
 
 @Configuration(proxyBeanMethods = false)
-@Lazy(false) // 禁用懒加载,因为需要保证 Redis Server 必须先启动
 @EnableConfigurationProperties(RedisProperties.class)
 @AutoConfigureBefore({RedisAutoConfiguration.class, RedissonAutoConfiguration.class}) // 在 Redis 自动配置前,进行初始化
 public class RedisTestConfiguration {

+ 0 - 16
src/test/java/cn/iocoder/dashboard/config/SecurityTestConfiguration.java

@@ -1,16 +0,0 @@
-package cn.iocoder.dashboard.config;
-
-import org.mockito.Mockito;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authentication.AuthenticationManager;
-
-@Configuration
-public class SecurityTestConfiguration {
-
-    @Bean
-    public AuthenticationManager authenticationManager() {
-        return Mockito.mock(AuthenticationManager.class);
-    }
-
-}

+ 119 - 103
src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java

@@ -1,6 +1,6 @@
 package cn.iocoder.dashboard.modules.infra.service.config;
 
-import cn.iocoder.dashboard.BaseSpringBootUnitTest;
+import cn.iocoder.dashboard.BaseDbUnitTest;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigCreateReqVO;
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigExportReqVO;
@@ -15,6 +15,7 @@ import cn.iocoder.dashboard.util.collection.ArrayUtils;
 import cn.iocoder.dashboard.util.object.ObjectUtils;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
 import java.util.List;
@@ -24,8 +25,7 @@ import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
 import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
-import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
-import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static cn.iocoder.dashboard.util.RandomUtils.*;
 import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.times;
@@ -36,7 +36,8 @@ import static org.mockito.Mockito.verify;
  *
  * @author 芋道源码
  */
-public class InfConfigServiceTest extends BaseSpringBootUnitTest {
+@Import(InfConfigServiceImpl.class)
+public class InfConfigServiceTest extends BaseDbUnitTest {
 
     @Resource
     private InfConfigServiceImpl configService;
@@ -46,6 +47,120 @@ public class InfConfigServiceTest extends BaseSpringBootUnitTest {
     @MockBean
     private InfConfigProducer configProducer;
 
+    @Test
+    public void testCreateConfig_success() {
+        // 准备参数
+        InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
+
+        // 调用
+        Long configId = configService.createConfig(reqVO);
+        // 断言
+        assertNotNull(configId);
+        // 校验记录的属性是否正确
+        InfConfigDO config = configMapper.selectById(configId);
+        assertPojoEquals(reqVO, config);
+        assertEquals(InfConfigTypeEnum.CUSTOM.getType(), config.getType());
+        // 校验调用
+        verify(configProducer, times(1)).sendConfigRefreshMessage();
+    }
+
+    @Test
+    public void testUpdateConfig_success() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO();
+        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class, o -> {
+            o.setId(dbConfig.getId()); // 设置更新的 ID
+        });
+
+        // 调用
+        configService.updateConfig(reqVO);
+        // 校验是否更新正确
+        InfConfigDO config = configMapper.selectById(reqVO.getId()); // 获取最新的
+        assertPojoEquals(reqVO, config);
+        // 校验调用
+        verify(configProducer, times(1)).sendConfigRefreshMessage();
+    }
+
+    @Test
+    public void testDeleteConfig_success() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO(o -> {
+            o.setType(InfConfigTypeEnum.CUSTOM.getType()); // 只能删除 CUSTOM 类型
+        });
+        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbConfig.getId();
+
+        // 调用
+        configService.deleteConfig(id);
+        // 校验数据不存在了
+        assertNull(configMapper.selectById(id));
+        // 校验调用
+        verify(configProducer, times(1)).sendConfigRefreshMessage();
+    }
+
+    @Test
+    public void testDeleteConfig_canNotDeleteSystemType() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO(o -> {
+            o.setType(InfConfigTypeEnum.SYSTEM.getType()); // SYSTEM 不允许删除
+        });
+        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbConfig.getId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> configService.deleteConfig(id), CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE);
+    }
+
+    @Test
+    public void testCheckConfigExists_success() {
+        // mock 数据
+        InfConfigDO dbConfigDO = randomInfConfigDO();
+        configMapper.insert(dbConfigDO);// @Sql: 先插入出一条存在的数据
+
+        // 调用成功
+        configService.checkConfigExists(dbConfigDO.getId());
+    }
+
+    @Test
+    public void testCheckConfigExist_notExists() {
+        assertServiceException(() -> configService.checkConfigExists(randomLongId()), CONFIG_NOT_EXISTS);
+    }
+
+    @Test
+    public void testCheckConfigKeyUnique_success() {
+        // 调用,成功
+        configService.checkConfigKeyUnique(randomLongId(), randomString());
+    }
+
+    @Test
+    public void testCheckConfigKeyUnique_keyDuplicateForCreate() {
+        // 准备参数
+        String key = randomString();
+        // mock 数据
+        configMapper.insert(randomInfConfigDO(o -> o.setKey(key)));
+
+        // 调用,校验异常
+        assertServiceException(() -> configService.checkConfigKeyUnique(null, key),
+                CONFIG_KEY_DUPLICATE);
+    }
+
+    @Test
+    public void testCheckConfigKeyUnique_keyDuplicateForUpdate() {
+        // 准备参数
+        Long id = randomLongId();
+        String key = randomString();
+        // mock 数据
+        configMapper.insert(randomInfConfigDO(o -> o.setKey(key)));
+
+        // 调用,校验异常
+        assertServiceException(() -> configService.checkConfigKeyUnique(id, key),
+                CONFIG_KEY_DUPLICATE);
+    }
+
     @Test
     public void testGetConfigPage() {
         // mock 数据
@@ -128,105 +243,6 @@ public class InfConfigServiceTest extends BaseSpringBootUnitTest {
         assertPojoEquals(dbConfig, config);
     }
 
-    @Test
-    public void testCreateConfig_success() {
-        // 准备参数
-        InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
-
-        // 调用
-        Long configId = configService.createConfig(reqVO);
-        // 断言
-        assertNotNull(configId);
-        // 校验记录的属性是否正确
-        InfConfigDO config = configMapper.selectById(configId);
-        assertPojoEquals(reqVO, config);
-        assertEquals(InfConfigTypeEnum.CUSTOM.getType(), config.getType());
-        // 校验调用
-        verify(configProducer, times(1)).sendConfigRefreshMessage();
-    }
-
-    @Test
-    public void testCreateConfig_keyDuplicate() {
-        // 准备参数
-        InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
-        // mock 数据
-        configMapper.insert(randomInfConfigDO(o -> { // @Sql
-            o.setKey(reqVO.getKey()); // 模拟 key 重复
-        }));
-
-        // 调用, 并断言异常
-        assertServiceException(() -> configService.createConfig(reqVO), CONFIG_KEY_DUPLICATE);
-    }
-
-    @Test
-    public void testUpdateConfig_success() {
-        // mock 数据
-        InfConfigDO dbConfig = randomInfConfigDO();
-        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class, o -> {
-            o.setId(dbConfig.getId()); // 设置更新的 ID
-        });
-
-        // 调用
-        configService.updateConfig(reqVO);
-        // 校验是否更新正确
-        InfConfigDO config = configMapper.selectById(reqVO.getId()); // 获取最新的
-        assertPojoEquals(reqVO, config);
-        // 校验调用
-        verify(configProducer, times(1)).sendConfigRefreshMessage();
-    }
-
-    @Test
-    public void testUpdateConfig_notExists() {
-        // 准备参数
-        InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class);
-
-        // 调用, 并断言异常
-        assertServiceException(() -> configService.updateConfig(reqVO), CONFIG_NOT_EXISTS);
-    }
-
-    @Test
-    public void testDeleteConfig_success() {
-        // mock 数据
-        InfConfigDO dbConfig = randomInfConfigDO(o -> {
-            o.setType(InfConfigTypeEnum.CUSTOM.getType()); // 只能删除 CUSTOM 类型
-        });
-        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        Long id = dbConfig.getId();
-
-        // 调用
-        configService.deleteConfig(id);
-        // 校验数据不存在了
-        assertNull(configMapper.selectById(id));
-        // 校验调用
-        verify(configProducer, times(1)).sendConfigRefreshMessage();
-    }
-
-    @Test
-    public void testDeleteConfig_canNotDeleteSystemType() {
-        // mock 数据
-        InfConfigDO dbConfig = randomInfConfigDO(o -> {
-            o.setType(InfConfigTypeEnum.SYSTEM.getType()); // SYSTEM 不允许删除
-        });
-        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        Long id = dbConfig.getId();
-
-        // 调用, 并断言异常
-        assertServiceException(() -> configService.deleteConfig(id), CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE);
-    }
-
-    @Test
-    public void testDeleteConfig_notExists() {
-        // 准备参数
-        Long id = randomLongId();
-
-        // 调用, 并断言异常
-        assertServiceException(() -> configService.deleteConfig(id), CONFIG_NOT_EXISTS);
-    }
-
     // ========== 随机对象 ==========
 
     @SafeVarargs

+ 20 - 2
src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java

@@ -1,15 +1,19 @@
 package cn.iocoder.dashboard.modules.system.service.auth;
 
-import cn.iocoder.dashboard.BaseSpringBootUnitTest;
+import cn.iocoder.dashboard.BaseDbUnitTest;
 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
 import cn.iocoder.dashboard.framework.security.core.LoginUser;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
 import cn.iocoder.dashboard.modules.system.service.auth.impl.SysAuthServiceImpl;
+import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
+import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
 import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
 import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
 import cn.iocoder.dashboard.util.AssertUtils;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
 import javax.annotation.Resource;
@@ -21,7 +25,13 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
-public class SysAuthServiceImplTest extends BaseSpringBootUnitTest {
+/**
+ * {@link SysAuthServiceImpl} 的单元测试
+ *
+ * @author 芋道源码
+ */
+@Import(SysAuthServiceImpl.class)
+public class SysAuthServiceImplTest extends BaseDbUnitTest {
 
     @Resource
     private SysAuthServiceImpl authService;
@@ -30,6 +40,14 @@ public class SysAuthServiceImplTest extends BaseSpringBootUnitTest {
     private SysUserService userService;
     @MockBean
     private SysPermissionService permissionService;
+    @MockBean
+    private AuthenticationManager authenticationManager;
+    @MockBean
+    private SysCaptchaService captchaService;
+    @MockBean
+    private SysLoginLogService loginLogService;
+    @MockBean
+    private SysUserSessionService userSessionService;
 
     @Test
     public void testLoadUserByUsername_success() {

+ 78 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java

@@ -0,0 +1,78 @@
+package cn.iocoder.dashboard.modules.system.service.auth;
+
+import cn.hutool.core.date.DateUtil;
+import cn.iocoder.dashboard.BaseDbAndRedisUnitTest;
+import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
+import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
+import cn.iocoder.dashboard.modules.system.dal.redis.auth.SysLoginUserRedisDAO;
+import cn.iocoder.dashboard.modules.system.service.auth.impl.SysUserSessionServiceImpl;
+import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl;
+import cn.iocoder.dashboard.modules.system.service.logger.impl.SysLoginLogServiceImpl;
+import cn.iocoder.dashboard.modules.system.service.user.SysUserServiceImpl;
+import cn.iocoder.dashboard.util.AssertUtils;
+import cn.iocoder.dashboard.util.RandomUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * SysUserSessionServiceImpl Tester.
+ *
+ * @author Lyon
+ * @version 1.0
+ * @since <pre>3月 8, 2021</pre>
+ */
+@Import(
+        SysUserSessionServiceImpl.class)
+public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
+
+    @Resource
+    SysUserSessionServiceImpl sysUserSessionService;
+    @Resource
+    SysUserSessionMapper sysUserSessionMapper;
+    @MockBean
+    SecurityProperties securityProperties;
+    @MockBean
+    SysDeptServiceImpl sysDeptService;
+    @MockBean
+    SysUserServiceImpl sysUserService;
+    @MockBean
+    SysLoginLogServiceImpl sysLoginLogService;
+    @MockBean
+    SysLoginUserRedisDAO sysLoginUserRedisDAO;
+
+    @Test
+    public void testClearSessionTimeout_success() throws Exception {
+        // 准备超时数据 120 条, 在线用户 1 条
+        int expectedTimeoutCount = 120, expectedTotal = 1;
+
+        // 准备数据
+        List<SysUserSessionDO> prepareData = Stream
+                .iterate(0, i -> i)
+                .limit(expectedTimeoutCount)
+                .map(i -> RandomUtils.randomPojo(SysUserSessionDO.class, o -> o.setSessionTimeout(DateUtil.offsetSecond(new Date(), -1))))
+                .collect(Collectors.toList());
+        SysUserSessionDO sessionDO = RandomUtils.randomPojo(SysUserSessionDO.class, o -> o.setSessionTimeout(DateUtil.offsetMinute(new Date(), 30)));
+        prepareData.add(sessionDO);
+        prepareData.forEach(sysUserSessionMapper::insert);
+
+        //清空超时数据
+        long actualTimeoutCount = sysUserSessionService.clearSessionTimeout();
+        //校验
+        assertEquals(expectedTimeoutCount, actualTimeoutCount);
+        List<SysUserSessionDO> userSessionDOS = sysUserSessionMapper.selectList();
+        assertEquals(expectedTotal, userSessionDOS.size());
+        AssertUtils.assertPojoEquals(sessionDO, userSessionDOS.get(0), "updateTime");
+    }
+
+} 

+ 274 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java

@@ -0,0 +1,274 @@
+package cn.iocoder.dashboard.modules.system.service.dept;
+
+import cn.iocoder.dashboard.BaseDbUnitTest;
+import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptCreateReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptUpdateReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysDeptMapper;
+import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum;
+import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer;
+import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
+import cn.iocoder.dashboard.util.object.ObjectUtils;
+import com.google.common.collect.Multimap;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import static cn.hutool.core.bean.BeanUtil.getFieldValue;
+import static cn.hutool.core.util.RandomUtil.randomEle;
+import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
+import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
+import static cn.iocoder.dashboard.util.RandomUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+/**
+ * {@link SysDeptServiceImpl} 的单元测试类
+ *
+ * @author niudehua
+ */
+@Import(SysDeptServiceImpl.class)
+class SysDeptServiceTest extends BaseDbUnitTest {
+
+    @Resource
+    private SysDeptServiceImpl deptService;
+    @Resource
+    private SysDeptMapper deptMapper;
+    @MockBean
+    private SysDeptProducer deptProducer;
+
+    @Test
+    @SuppressWarnings("unchecked")
+    void testInitLocalCache() {
+        // mock 数据
+        SysDeptDO deptDO1 = randomDeptDO();
+        deptMapper.insert(deptDO1);
+        SysDeptDO deptDO2 = randomDeptDO();
+        deptMapper.insert(deptDO2);
+
+        // 调用
+        deptService.initLocalCache();
+        // 断言 deptCache 缓存
+        Map<Long, SysDeptDO> deptCache = (Map<Long, SysDeptDO>) getFieldValue(deptService, "deptCache");
+        assertEquals(2, deptCache.size());
+        assertPojoEquals(deptDO1, deptCache.get(deptDO1.getId()));
+        assertPojoEquals(deptDO2, deptCache.get(deptDO2.getId()));
+        // 断言 parentDeptCache 缓存
+        Multimap<Long, SysDeptDO> parentDeptCache = (Multimap<Long, SysDeptDO>) getFieldValue(deptService, "parentDeptCache");
+        assertEquals(2, parentDeptCache.size());
+        assertPojoEquals(deptDO1, parentDeptCache.get(deptDO1.getParentId()));
+        assertPojoEquals(deptDO2, parentDeptCache.get(deptDO2.getParentId()));
+        // 断言 maxUpdateTime 缓存
+        Date maxUpdateTime = (Date) getFieldValue(deptService, "maxUpdateTime");
+        assertEquals(ObjectUtils.max(deptDO1.getUpdateTime(), deptDO2.getUpdateTime()), maxUpdateTime);
+
+    }
+
+    @Test
+    void testListDepts() {
+        // mock 数据
+        SysDeptDO dept = randomPojo(SysDeptDO.class, o -> { // 等会查询到
+            o.setName("开发部");
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        deptMapper.insert(dept);
+        // 测试 name 不匹配
+        deptMapper.insert(ObjectUtils.clone(dept, o -> o.setName("发")));
+        // 测试 status 不匹配
+        deptMapper.insert(ObjectUtils.clone(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+        // 准备参数
+        SysDeptListReqVO reqVO = new SysDeptListReqVO();
+        reqVO.setName("开");
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        // 调用
+        List<SysDeptDO> sysDeptDOS = deptService.listDepts(reqVO);
+        // 断言
+        assertEquals(1, sysDeptDOS.size());
+        assertPojoEquals(dept, sysDeptDOS.get(0));
+    }
+
+    @Test
+    void testCreateDept_success() {
+        // 准备参数
+        SysDeptCreateReqVO reqVO = randomPojo(SysDeptCreateReqVO.class,
+            o -> {
+                o.setParentId(DeptIdEnum.ROOT.getId());
+                o.setStatus(randomCommonStatus());
+            });
+        // 调用
+        Long deptId = deptService.createDept(reqVO);
+        // 断言
+        assertNotNull(deptId);
+        // 校验记录的属性是否正确
+        SysDeptDO deptDO = deptMapper.selectById(deptId);
+        assertPojoEquals(reqVO, deptDO);
+        // 校验调用
+        verify(deptProducer, times(1)).sendDeptRefreshMessage();
+    }
+
+    @Test
+    void testUpdateDept_success() {
+        // mock 数据
+        SysDeptDO dbDeptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
+        deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class, o -> {
+            // 设置更新的 ID
+            o.setParentId(DeptIdEnum.ROOT.getId());
+            o.setId(dbDeptDO.getId());
+            o.setStatus(randomCommonStatus());
+        });
+        // 调用
+        deptService.updateDept(reqVO);
+        // 校验是否更新正确
+        SysDeptDO deptDO = deptMapper.selectById(reqVO.getId()); // 获取最新的
+        assertPojoEquals(reqVO, deptDO);
+    }
+
+    @Test
+    void testDeleteDept_success() {
+        // mock 数据
+        SysDeptDO dbDeptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
+        deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbDeptDO.getId();
+        // 调用
+        deptService.deleteDept(id);
+        // 校验数据不存在了
+        assertNull(deptMapper.selectById(id));
+    }
+
+    @Test
+    void testCheckDept_nameDuplicateForUpdate() {
+        // mock 数据
+        SysDeptDO deptDO = randomDeptDO();
+        // 设置根节点部门
+        deptDO.setParentId(DeptIdEnum.ROOT.getId());
+        deptMapper.insert(deptDO);
+        // mock 数据 稍后模拟重复它的 name
+        SysDeptDO nameDeptDO = randomDeptDO();
+        // 设置根节点部门
+        nameDeptDO.setParentId(DeptIdEnum.ROOT.getId());
+        deptMapper.insert(nameDeptDO);
+        // 准备参数
+        SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class,
+            o -> {
+                // 设置根节点部门
+                o.setParentId(DeptIdEnum.ROOT.getId());
+                // 设置更新的 ID
+                o.setId(deptDO.getId());
+                // 模拟 name 重复
+                o.setName(nameDeptDO.getName());
+            });
+        // 调用, 并断言异常
+        assertServiceException(() -> deptService.updateDept(reqVO), DEPT_NAME_DUPLICATE);
+
+    }
+
+    @Test
+    void testCheckDept_parentNotExitsForCreate() {
+        SysDeptCreateReqVO reqVO = randomPojo(SysDeptCreateReqVO.class,
+            o -> o.setStatus(randomCommonStatus()));
+        // 调用,并断言异常
+        assertServiceException(() -> deptService.createDept(reqVO), DEPT_PARENT_NOT_EXITS);
+    }
+
+    @Test
+    void testCheckDept_notFoundForDelete() {
+        // 准备参数
+        Long id = randomLongId();
+        // 调用, 并断言异常
+        assertServiceException(() -> deptService.deleteDept(id), DEPT_NOT_FOUND);
+    }
+
+    @Test
+    void testCheckDept_exitsChildrenForDelete() {
+        // mock 数据
+        SysDeptDO parentDept = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
+        deptMapper.insert(parentDept);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysDeptDO childrenDeptDO = randomPojo(SysDeptDO.class, o -> {
+            o.setParentId(parentDept.getId());
+            o.setStatus(randomCommonStatus());
+        });
+        // 插入子部门
+        deptMapper.insert(childrenDeptDO);
+        // 调用, 并断言异常
+        assertServiceException(() -> deptService.deleteDept(parentDept.getId()), DEPT_EXITS_CHILDREN);
+    }
+
+    @Test
+    void testCheckDept_parentErrorForUpdate() {
+        // mock 数据
+        SysDeptDO dbDeptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(randomCommonStatus()));
+        deptMapper.insert(dbDeptDO);
+        // 准备参数
+        SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class,
+            o -> {
+                // 设置自己为父部门
+                o.setParentId(dbDeptDO.getId());
+                // 设置更新的 ID
+                o.setId(dbDeptDO.getId());
+            });
+        // 调用, 并断言异常
+        assertServiceException(() -> deptService.updateDept(reqVO), DEPT_PARENT_ERROR);
+    }
+
+    @Test
+    void testCheckDept_notEnableForCreate() {
+        // mock 数据
+        SysDeptDO deptDO = randomPojo(SysDeptDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
+        deptMapper.insert(deptDO);
+        // 准备参数
+        SysDeptCreateReqVO reqVO = randomPojo(SysDeptCreateReqVO.class,
+            o -> {
+                // 设置未启用的部门为副部门
+                o.setParentId(deptDO.getId());
+            });
+        // 调用, 并断言异常
+        assertServiceException(() -> deptService.createDept(reqVO), DEPT_NOT_ENABLE);
+    }
+
+    @Test
+    void testCheckDept_parentIsChildForUpdate() {
+        // mock 数据
+        SysDeptDO parentDept = randomPojo(SysDeptDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        deptMapper.insert(parentDept);
+        SysDeptDO childDept = randomPojo(SysDeptDO.class, o -> {
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+            o.setParentId(parentDept.getId());
+        });
+        deptMapper.insert(childDept);
+        // 初始化本地缓存
+        deptService.initLocalCache();
+        // 准备参数
+        SysDeptUpdateReqVO reqVO = randomPojo(SysDeptUpdateReqVO.class,
+            o -> {
+                // 设置自己的子部门为父部门
+                o.setParentId(childDept.getId());
+                // 设置更新的 ID
+                o.setId(parentDept.getId());
+            });
+        // 调用, 并断言异常
+        assertServiceException(() -> deptService.updateDept(reqVO), DEPT_PARENT_IS_CHILD);
+    }
+
+    @SafeVarargs
+    private static SysDeptDO randomDeptDO(Consumer<SysDeptDO>... consumers) {
+        Consumer<SysDeptDO> consumer = (o) -> {
+            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
+        };
+        return randomPojo(SysDeptDO.class, ArrayUtils.append(consumer, consumers));
+    }
+}

+ 200 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java

@@ -0,0 +1,200 @@
+package cn.iocoder.dashboard.modules.system.service.dept;
+
+import cn.iocoder.dashboard.BaseDbUnitTest;
+import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostPageReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysPostDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysPostMapper;
+import cn.iocoder.dashboard.modules.system.service.dept.impl.SysPostServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
+import cn.iocoder.dashboard.util.object.ObjectUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static cn.hutool.core.util.RandomUtil.randomEle;
+import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
+import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
+import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
+import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link SysPostServiceImpl} 的单元测试类
+ *
+ * @author niudehua
+ */
+@Import(SysPostServiceImpl.class)
+class SysPostServiceTest extends BaseDbUnitTest {
+
+    @Resource
+    private SysPostServiceImpl postService;
+    @Resource
+    private SysPostMapper postMapper;
+
+    @Test
+    void testPagePosts() {
+        // mock 数据
+        SysPostDO postDO = randomPojo(SysPostDO.class, o -> {
+            o.setName("码仔");
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        postMapper.insert(postDO);
+        // 测试 name 不匹配
+        postMapper.insert(ObjectUtils.clone(postDO, o -> o.setName("程序员")));
+        // 测试 status 不匹配
+        postMapper.insert(ObjectUtils.clone(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+
+        // 准备参数
+        SysPostPageReqVO reqVO = new SysPostPageReqVO();
+        reqVO.setName("码");
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+
+        // 调用
+        PageResult<SysPostDO> pageResult = postService.pagePosts(reqVO);
+
+        // 断言
+        assertEquals(1, pageResult.getTotal());
+        assertEquals(1, pageResult.getList().size());
+        assertPojoEquals(postDO, pageResult.getList().get(0));
+    }
+
+    @Test
+    void testListPosts() {
+        // mock 数据
+        SysPostDO postDO = randomPojo(SysPostDO.class, o -> {
+            o.setName("码仔");
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        });
+        postMapper.insert(postDO);
+        // 测试 name 不匹配
+        postMapper.insert(ObjectUtils.clone(postDO, o -> o.setName("程序员")));
+        // 测试 status 不匹配
+        postMapper.insert(ObjectUtils.clone(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+        // 准备参数
+        SysPostExportReqVO reqVO = new SysPostExportReqVO();
+        reqVO.setName("码");
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+
+        // 调用
+        List<SysPostDO> list = postService.listPosts(reqVO);
+        // 断言
+        assertEquals(1, list.size());
+        assertPojoEquals(postDO, list.get(0));
+    }
+
+    @Test
+    void testGetPost() {
+        // mock 数据
+        SysPostDO dbPostDO = randomPostDO();
+        postMapper.insert(dbPostDO);
+        // 准备参数
+        Long id = dbPostDO.getId();
+        // 调用
+        SysPostDO post = postService.getPost(id);
+        // 断言
+        assertNotNull(post);
+        assertPojoEquals(dbPostDO, post);
+    }
+
+    @Test
+    void testCreatePost_success() {
+        // 准备参数
+        SysPostCreateReqVO reqVO = randomPojo(SysPostCreateReqVO.class,
+            o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()));
+        // 调用
+        Long postId = postService.createPost(reqVO);
+        // 断言
+        assertNotNull(postId);
+        // 校验记录的属性是否正确
+        SysPostDO post = postMapper.selectById(postId);
+        assertPojoEquals(reqVO, post);
+    }
+
+    @Test
+    void testUpdatePost_success() {
+        // mock 数据
+        SysPostDO postDO = randomPostDO();
+        postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysPostUpdateReqVO reqVO = randomPojo(SysPostUpdateReqVO.class,
+            o -> {
+                // 设置更新的 ID
+                o.setId(postDO.getId());
+                o.setStatus(randomEle(CommonStatusEnum.values()).getStatus());
+            });
+        // 调用
+        postService.updatePost(reqVO);
+        // 校验是否更新正确
+        SysPostDO post = postMapper.selectById(reqVO.getId());// 获取最新的
+        assertPojoEquals(reqVO, post);
+    }
+
+    @Test
+    void testDeletePost_success() {
+        // mock 数据
+        SysPostDO postDO = randomPostDO();
+        postMapper.insert(postDO);
+        // 准备参数
+        Long id = postDO.getId();
+        // 调用
+        postService.deletePost(id);
+        assertNull(postMapper.selectById(id));
+    }
+
+    @Test
+    void testCheckPost_notFoundForDelete() {
+        // 准备参数
+        Long id = randomLongId();
+        // 调用, 并断言异常
+        assertServiceException(() -> postService.deletePost(id), POST_NOT_FOUND);
+    }
+
+    @Test
+    void testCheckPost_nameDuplicateForCreate() {
+        // mock 数据
+        SysPostDO postDO = randomPostDO();
+        postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysPostCreateReqVO reqVO = randomPojo(SysPostCreateReqVO.class,
+            // 模拟 name 重复
+            o -> o.setName(postDO.getName()));
+        assertServiceException(() -> postService.createPost(reqVO), POST_NAME_DUPLICATE);
+    }
+
+    @Test
+    void testCheckPost_codeDuplicateForUpdate() {
+        // mock 数据
+        SysPostDO postDO = randomPostDO();
+        postMapper.insert(postDO);
+        // mock 数据 稍后模拟重复它的 code
+        SysPostDO codePostDO = randomPostDO();
+        postMapper.insert(codePostDO);
+        // 准备参数
+        SysPostUpdateReqVO reqVO = randomPojo(SysPostUpdateReqVO.class,
+            o -> {
+                // 设置更新的 ID
+                o.setId(postDO.getId());
+                // 模拟 code 重复
+                o.setCode(codePostDO.getCode());
+            });
+        // 调用, 并断言异常
+        assertServiceException(() -> postService.updatePost(reqVO), POST_CODE_DUPLICATE);
+    }
+
+    @SafeVarargs
+    private static SysPostDO randomPostDO(Consumer<SysPostDO>... consumers) {
+        Consumer<SysPostDO> consumer = (o) -> {
+            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
+        };
+        return randomPojo(SysPostDO.class, ArrayUtils.append(consumer, consumers));
+    }
+}

+ 149 - 20
src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java

@@ -1,6 +1,6 @@
 package cn.iocoder.dashboard.modules.system.service.dict;
 
-import cn.iocoder.dashboard.BaseSpringBootUnitTest;
+import cn.iocoder.dashboard.BaseDbUnitTest;
 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO;
@@ -12,14 +12,20 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
 import cn.iocoder.dashboard.modules.system.service.dict.impl.SysDictDataServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
 import cn.iocoder.dashboard.util.object.ObjectUtils;
+import com.google.common.collect.ImmutableTable;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
+import java.util.Date;
 import java.util.List;
+import java.util.function.Consumer;
 
-import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.DICT_DATA_NOT_EXISTS;
+import static cn.hutool.core.bean.BeanUtil.getFieldValue;
+import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
 import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
 import static cn.iocoder.dashboard.util.RandomUtils.*;
@@ -32,7 +38,8 @@ import static org.mockito.Mockito.*;
 *
 * @author 芋道源码
 */
-public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
+@Import(SysDictDataServiceImpl.class)
+public class SysDictDataServiceTest extends BaseDbUnitTest {
 
     @Resource
     private SysDictDataServiceImpl dictDataService;
@@ -44,6 +51,37 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
     @MockBean
     private SysDictDataProducer dictDataProducer;
 
+    /**
+     * 测试加载到新的字典数据的情况
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testInitLocalCache() {
+        // mock 数据
+        SysDictDataDO dictData01 = randomDictDataDO();
+        dictDataMapper.insert(dictData01);
+        SysDictDataDO dictData02 = randomDictDataDO();
+        dictDataMapper.insert(dictData02);
+
+        // 调用
+        dictDataService.initLocalCache();
+        // 断言 labelDictDataCache 缓存
+        ImmutableTable<String, String, SysDictDataDO> labelDictDataCache =
+                (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "labelDictDataCache");
+        assertEquals(2, labelDictDataCache.size());
+        assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));
+        assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));
+        // 断言 valueDictDataCache 缓存
+        ImmutableTable<String, String, SysDictDataDO> valueDictDataCache =
+                (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "valueDictDataCache");
+        assertEquals(2, valueDictDataCache.size());
+        assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));
+        assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));
+        // 断言 maxUpdateTime 缓存
+        Date maxUpdateTime = (Date) getFieldValue(dictDataService, "maxUpdateTime");
+        assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);
+    }
+
     @Test
     public void testGetDictDataPage() {
         // mock 数据
@@ -107,8 +145,7 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
         SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
                 o -> o.setStatus(randomCommonStatus()));
         // mock 方法
-        when(dictTypeService.getDictType(eq(reqVO.getDictType())))
-                .thenReturn(randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())));
+        when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
 
         // 调用
         Long dictDataId = dictDataService.createDictData(reqVO);
@@ -124,50 +161,142 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
     @Test
     public void testUpdateDictData_success() {
         // mock 数据
-        SysDictDataDO dbDictData = randomPojo(SysDictDataDO.class);
+        SysDictDataDO dbDictData = randomDictDataDO();
         dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
         // 准备参数
         SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
             o.setId(dbDictData.getId()); // 设置更新的 ID
+            o.setStatus(randomCommonStatus());
         });
+        // mock 方法,字典类型
+        when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
 
         // 调用
         dictDataService.updateDictData(reqVO);
         // 校验是否更新正确
         SysDictDataDO dictData = dictDataMapper.selectById(reqVO.getId()); // 获取最新的
         assertPojoEquals(reqVO, dictData);
+        // 校验调用
+        verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
     }
 
     @Test
-    public void testUpdateDictData_notExists() {
+    public void testDeleteDictData_success() {
+        // mock 数据
+        SysDictDataDO dbDictData = randomDictDataDO();
+        dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
         // 准备参数
-        SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class);
+        Long id = dbDictData.getId();
 
-        // 调用, 并断言异常
-        assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_NOT_EXISTS);
+        // 调用
+        dictDataService.deleteDictData(id);
+        // 校验数据不存在了
+        assertNull(dictDataMapper.selectById(id));
+        // 校验调用
+        verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
     }
 
     @Test
-    public void testDeleteDictData_success() {
+    public void testCheckDictDataExists_success() {
         // mock 数据
-        SysDictDataDO dbDictData = randomPojo(SysDictDataDO.class);
+        SysDictDataDO dbDictData = randomDictDataDO();
         dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
+
+        // 调用成功
+        dictDataService.checkDictDataExists(dbDictData.getId());
+    }
+
+    @Test
+    public void testCheckDictDataExists_notExists() {
+        assertServiceException(() -> dictDataService.checkDictDataExists(randomLongId()), DICT_DATA_NOT_EXISTS);
+    }
+
+    @Test
+    public void testCheckDictTypeValid_success() {
+        // mock 方法,数据类型被禁用
+        String type = randomString();
+        when(dictTypeService.getDictType(eq(type))).thenReturn(randomDictTypeDO(type));
+
+        // 调用, 成功
+        dictDataService.checkDictTypeValid(type);
+    }
+
+    @Test
+    public void testCheckDictTypeValid_notExists() {
+        assertServiceException(() -> dictDataService.checkDictTypeValid(randomString()), DICT_TYPE_NOT_EXISTS);
+    }
+
+    @Test
+    public void testCheckDictTypeValid_notEnable() {
+        // mock 方法,数据类型被禁用
+        String dictType = randomString();
+        when(dictTypeService.getDictType(eq(dictType))).thenReturn(
+                randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictDataService.checkDictTypeValid(dictType), DICT_TYPE_NOT_ENABLE);
+    }
+
+    @Test
+    public void testCheckDictDataValueUnique_success() {
+        // 调用,成功
+        dictDataService.checkDictDataValueUnique(randomLongId(), randomString(), randomString());
+    }
+
+    @Test
+    public void testCheckDictDataValueUnique_valueDuplicateForCreate() {
         // 准备参数
-        Long id = dbDictData.getId();
+        String dictType = randomString();
+        String value = randomString();
+        // mock 数据
+        dictDataMapper.insert(randomDictDataDO(o -> {
+            o.setDictType(dictType);
+            o.setValue(value);
+        }));
 
-        // 调用
-        dictDataService.deleteDictData(id);
-       // 校验数据不存在了
-       assertNull(dictDataMapper.selectById(id));
+        // 调用,校验异常
+        assertServiceException(() -> dictDataService.checkDictDataValueUnique(null, dictType, value),
+                DICT_DATA_VALUE_DUPLICATE);
     }
 
     @Test
-    public void testDeleteDictData_notExists() {
+    public void testCheckDictDataValueUnique_valueDuplicateForUpdate() {
         // 准备参数
         Long id = randomLongId();
+        String dictType = randomString();
+        String value = randomString();
+        // mock 数据
+        dictDataMapper.insert(randomDictDataDO(o -> {
+            o.setDictType(dictType);
+            o.setValue(value);
+        }));
 
-        // 调用, 并断言异常
-        assertServiceException(() -> dictDataService.deleteDictData(id), DICT_DATA_NOT_EXISTS);
+        // 调用,校验异常
+        assertServiceException(() -> dictDataService.checkDictDataValueUnique(id, dictType, value),
+                DICT_DATA_VALUE_DUPLICATE);
+    }
+
+    // ========== 随机对象 ==========
+
+    @SafeVarargs
+    private static SysDictDataDO randomDictDataDO(Consumer<SysDictDataDO>... consumers) {
+        Consumer<SysDictDataDO> consumer = (o) -> {
+            o.setStatus(randomCommonStatus()); // 保证 status 的范围
+        };
+        return randomPojo(SysDictDataDO.class, ArrayUtils.append(consumer, consumers));
+    }
+
+    /**
+     * 生成一个有效的字典类型
+     *
+     * @param type 字典类型
+     * @return SysDictTypeDO 对象
+     */
+    private static SysDictTypeDO randomDictTypeDO(String type) {
+        return randomPojo(SysDictTypeDO.class, o -> {
+            o.setType(type);
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 是开启
+        });
     }
 
 }

+ 78 - 62
src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java

@@ -1,6 +1,6 @@
 package cn.iocoder.dashboard.modules.system.service.dict;
 
-import cn.iocoder.dashboard.BaseSpringBootUnitTest;
+import cn.iocoder.dashboard.BaseDbUnitTest;
 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeCreateReqVO;
@@ -14,6 +14,7 @@ import cn.iocoder.dashboard.util.collection.ArrayUtils;
 import cn.iocoder.dashboard.util.object.ObjectUtils;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
 import java.util.List;
@@ -23,8 +24,7 @@ import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
 import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
-import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
-import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static cn.iocoder.dashboard.util.RandomUtils.*;
 import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.eq;
@@ -35,7 +35,8 @@ import static org.mockito.Mockito.when;
 *
 * @author 芋道源码
 */
-public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
+@Import(SysDictTypeServiceImpl.class)
+public class SysDictTypeServiceTest extends BaseDbUnitTest {
 
     @Resource
     private SysDictTypeServiceImpl dictTypeService;
@@ -142,32 +143,6 @@ public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
         assertPojoEquals(reqVO, dictType);
     }
 
-    @Test
-    public void testCreateDictType_nameDuplicate() {
-        // mock 数据
-        SysDictTypeDO dbDictType = randomDictTypeDO();
-        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
-                o -> o.setName(dbDictType.getName())); // 模拟 name 重复
-
-        // 调用, 并断言异常
-        assertServiceException(() -> dictTypeService.createDictType(reqVO), DICT_TYPE_NAME_DUPLICATE);
-    }
-
-    @Test
-    public void testCreateDictType_typeDuplicate() {
-        // mock 数据
-        SysDictTypeDO dbDictType = randomDictTypeDO();
-        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
-        // 准备参数
-        SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
-                o -> o.setType(dbDictType.getType())); // 模拟 type 重复
-
-        // 调用, 并断言异常
-        assertServiceException(() -> dictTypeService.createDictType(reqVO), DICT_TYPE_TYPE_DUPLICATE);
-    }
-
     @Test
     public void testUpdateDictType_success() {
         // mock 数据
@@ -187,67 +162,108 @@ public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
     }
 
     @Test
-    public void testUpdateDictType_notExists() {
+    public void testDeleteDictType_success() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
         // 准备参数
-        SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class);
+        Long id = dbDictType.getId();
 
-        // 调用, 并断言异常
-        assertServiceException(() -> dictTypeService.updateDictType(reqVO), DICT_TYPE_NOT_EXISTS);
+        // 调用
+        dictTypeService.deleteDictType(id);
+        // 校验数据不存在了
+        assertNull(dictTypeMapper.selectById(id));
     }
 
     @Test
-    public void testUpdateDictType_nameDuplicate() {
-        // mock 数据,稍后更新它
+    public void testDeleteDictType_hasChildren() {
+        // mock 数据
         SysDictTypeDO dbDictType = randomDictTypeDO();
-        dictTypeMapper.insert(dbDictType);
-        // mock 数据,ks稍后模拟重复它的名字
-        SysDictTypeDO nameDictType = randomDictTypeDO();
-        dictTypeMapper.insert(nameDictType);
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
         // 准备参数
-        SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class, o -> {
-            o.setId(dbDictType.getId()); // 设置更新的 ID
-            o.setName(nameDictType.getName()); // 模拟 name 重复
-        });
+        Long id = dbDictType.getId();
+        // mock 方法
+        when(dictDataService.countByDictType(eq(dbDictType.getType()))).thenReturn(1);
 
         // 调用, 并断言异常
-        assertServiceException(() -> dictTypeService.updateDictType(reqVO), DICT_TYPE_NAME_DUPLICATE);
+        assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN);
     }
 
     @Test
-    public void testDeleteDictType_success() {
+    public void testCheckDictDataExists_success() {
         // mock 数据
         SysDictTypeDO dbDictType = randomDictTypeDO();
         dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+
+        // 调用成功
+        dictTypeService.checkDictTypeExists(dbDictType.getId());
+    }
+
+    @Test
+    public void testCheckDictDataExists_notExists() {
+        assertServiceException(() -> dictTypeService.checkDictTypeExists(randomLongId()), DICT_TYPE_NOT_EXISTS);
+    }
+
+    @Test
+    public void testCheckDictTypeUnique_success() {
+        // 调用,成功
+        dictTypeService.checkDictTypeUnique(randomLongId(), randomString());
+    }
+
+    @Test
+    public void testCheckDictTypeUnique_valueDuplicateForCreate() {
         // 准备参数
-        Long id = dbDictType.getId();
+        String type = randomString();
+        // mock 数据
+        dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type)));
 
-        // 调用
-        dictTypeService.deleteDictType(id);
-        // 校验数据不存在了
-        assertNull(dictTypeMapper.selectById(id));
+        // 调用,校验异常
+        assertServiceException(() -> dictTypeService.checkDictTypeUnique(null, type),
+                DICT_TYPE_TYPE_DUPLICATE);
     }
 
     @Test
-    public void testDeleteDictType_notExists() {
+    public void testCheckDictTypeUnique_valueDuplicateForUpdate() {
         // 准备参数
         Long id = randomLongId();
+        String type = randomString();
+        // mock 数据
+        dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type)));
 
-        // 调用, 并断言异常
-        assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_NOT_EXISTS);
+        // 调用,校验异常
+        assertServiceException(() -> dictTypeService.checkDictTypeUnique(id, type),
+                DICT_TYPE_TYPE_DUPLICATE);
     }
 
     @Test
-    public void testDeleteDictType_hasChildren() {
+    public void testCheckDictTypNameUnique_success() {
+        // 调用,成功
+        dictTypeService.checkDictTypeNameUnique(randomLongId(), randomString());
+    }
+
+    @Test
+    public void testCheckDictTypeNameUnique_nameDuplicateForCreate() {
+        // 准备参数
+        String name = randomString();
         // mock 数据
-        SysDictTypeDO dbDictType = randomDictTypeDO();
-        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+        dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name)));
+
+        // 调用,校验异常
+        assertServiceException(() -> dictTypeService.checkDictTypeNameUnique(null, name),
+                DICT_TYPE_NAME_DUPLICATE);
+    }
+
+    @Test
+    public void testCheckDictTypeNameUnique_nameDuplicateForUpdate() {
         // 准备参数
-        Long id = dbDictType.getId();
-        // mock 方法
-        when(dictDataService.countByDictType(eq(dbDictType.getType()))).thenReturn(1);
+        Long id = randomLongId();
+        String name = randomString();
+        // mock 数据
+        dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name)));
 
-        // 调用, 并断言异常
-        assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN);
+        // 调用,校验异常
+        assertServiceException(() -> dictTypeService.checkDictTypeNameUnique(id, name),
+                DICT_TYPE_NAME_DUPLICATE);
     }
 
     // ========== 随机对象 ==========

+ 164 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java

@@ -0,0 +1,164 @@
+package cn.iocoder.dashboard.modules.system.service.notice;
+
+import cn.iocoder.dashboard.BaseDbUnitTest;
+import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.notice.vo.SysNoticeCreateReqVO;
+import cn.iocoder.dashboard.modules.system.controller.notice.vo.SysNoticePageReqVO;
+import cn.iocoder.dashboard.modules.system.controller.notice.vo.SysNoticeUpdateReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.notice.SysNoticeDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.notice.SysNoticeMapper;
+import cn.iocoder.dashboard.modules.system.enums.notice.SysNoticeTypeEnum;
+import cn.iocoder.dashboard.modules.system.service.notice.impl.SysNoticeServiceImpl;
+import cn.iocoder.dashboard.util.object.ObjectUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.Resource;
+
+import java.util.function.Consumer;
+
+import static cn.hutool.core.util.RandomUtil.randomEle;
+import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.NOTICE_NOT_FOUND;
+import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
+import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
+import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static org.junit.jupiter.api.Assertions.*;
+
+@Import(SysNoticeServiceImpl.class)
+class SysNoticeServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private SysNoticeServiceImpl sysNoticeService;
+
+    @Resource
+    private SysNoticeMapper sysNoticeMapper;
+
+    @Test
+    public void testPageNotices_success() {
+        // 插入前置数据
+        SysNoticeDO dbNotice = randomPojo(SysNoticeDO.class, o -> {
+            o.setTitle("尼古拉斯赵四来啦!");
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+            o.setType(randomEle(SysNoticeTypeEnum.values()).getType());
+        });
+        sysNoticeMapper.insert(dbNotice);
+
+        // 测试 title 不匹配
+        sysNoticeMapper.insert(ObjectUtils.clone(dbNotice, o -> o.setTitle("尼古拉斯凯奇也来啦!")));
+        // 测试 status 不匹配
+        sysNoticeMapper.insert(ObjectUtils.clone(dbNotice, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+
+
+        // 查询
+        SysNoticePageReqVO reqVO = new SysNoticePageReqVO();
+        reqVO.setTitle("尼古拉斯赵四来啦!");
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        PageResult<SysNoticeDO> pageResult = sysNoticeService.pageNotices(reqVO);
+
+        // 验证查询结果经过筛选
+        assertEquals(1, pageResult.getTotal());
+        assertEquals(1, pageResult.getList().size());
+        assertPojoEquals(dbNotice, pageResult.getList().get(0));
+
+    }
+
+    @Test
+    public void testGetNotice_success() {
+        // 插入前置数据
+        SysNoticeDO dbNotice = randomSysNoticeDO();
+        sysNoticeMapper.insert(dbNotice);
+
+        // 查询
+        SysNoticeDO notice = sysNoticeService.getNotice(dbNotice.getId());
+
+        // 验证插入与读取对象是否一致
+        assertNotNull(notice);
+        assertPojoEquals(dbNotice, notice);
+    }
+
+    @Test
+    public void testCreateNotice_success() {
+        // 准备参数
+        SysNoticeCreateReqVO reqVO = randomSysNoticeCreateReqVO();
+
+        // 校验插入是否成功
+        Long noticeId = sysNoticeService.createNotice(reqVO);
+        assertNotNull(noticeId);
+
+        // 校验插入属性是否正确
+        SysNoticeDO notice = sysNoticeMapper.selectById(noticeId);
+        assertPojoEquals(reqVO, notice);
+    }
+
+    @Test
+    public void testUpdateNotice_success() {
+        // 插入前置数据
+        SysNoticeDO dbNoticeDO = randomSysNoticeDO();
+        sysNoticeMapper.insert(dbNoticeDO);
+
+        // 准备更新参数
+        SysNoticeUpdateReqVO reqVO = randomSysNoticeUpdateReqVO(o -> o.setId(dbNoticeDO.getId()));
+
+        // 更新
+        sysNoticeService.updateNotice(reqVO);
+
+        // 检验是否更新成功
+        SysNoticeDO notice = sysNoticeMapper.selectById(reqVO.getId());
+        assertPojoEquals(reqVO, notice);
+    }
+
+    @Test
+    public void testDeleteNotice_success() {
+        // 插入前置数据
+        SysNoticeDO dbNotice = randomSysNoticeDO();
+        sysNoticeMapper.insert(dbNotice);
+
+        // 删除
+        sysNoticeService.deleteNotice(dbNotice.getId());
+
+        // 检查是否删除成功
+        assertNull(sysNoticeMapper.selectById(dbNotice.getId()));
+    }
+
+    @Test
+    public void checkNoticeExists_success() {
+        // 插入前置数据
+        SysNoticeDO dbNotice = randomSysNoticeDO();
+        sysNoticeMapper.insert(dbNotice);
+
+        // 成功调用
+        sysNoticeService.checkNoticeExists(dbNotice.getId());
+    }
+
+    @Test
+    public void checkNoticeExists_noExists() {
+        assertServiceException(() -> sysNoticeService.checkNoticeExists(randomLongId()), NOTICE_NOT_FOUND);
+    }
+
+    @SafeVarargs
+    private static SysNoticeDO randomSysNoticeDO(Consumer<SysNoticeDO>... consumers) {
+        SysNoticeDO notice = randomPojo(SysNoticeDO.class, consumers);
+        notice.setType(randomEle(SysNoticeTypeEnum.values()).getType());
+        notice.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        return notice;
+    }
+
+    @SafeVarargs
+    private static SysNoticeUpdateReqVO randomSysNoticeUpdateReqVO(Consumer<SysNoticeUpdateReqVO>... consumers) {
+        SysNoticeUpdateReqVO reqVO = randomPojo(SysNoticeUpdateReqVO.class, consumers);
+        reqVO.setType(randomEle(SysNoticeTypeEnum.values()).getType());
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        return reqVO;
+    }
+
+    private static SysNoticeCreateReqVO randomSysNoticeCreateReqVO() {
+        SysNoticeCreateReqVO reqVO = randomPojo(SysNoticeCreateReqVO.class);
+        reqVO.setType(randomEle(SysNoticeTypeEnum.values()).getType());
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        return reqVO;
+    }
+
+
+}

+ 6 - 39
src/test/resources/application-unit-test.yaml

@@ -3,21 +3,6 @@ spring:
     lazy-initialization: true # 开启懒加载,加快速度
     banner-mode: off # 单元测试,禁用 Banner
 
-  # 去除的自动配置项
-  autoconfigure:
-    exclude:
-      - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration # 单元测试,禁用 SpringSecurity
-      - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration # 单元测试,禁用 SpringSecurity
-      - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 单元测试,禁用 Quartz
-      - com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration # 单元测试,禁用 Lock4j 分布式锁
-      - org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration # 单元测试,禁用 Scheduler 定时任务
-      - org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration # 项目没有使用 Spring Data,所以禁用配置类,加速启动
-
-# Swagger 接口文档的自动配置(单元测试,禁用 Swagger)
-springfox:
-  documentation:
-    auto-startup: false
-
 --- #################### 数据库相关配置 ####################
 
 spring:
@@ -29,6 +14,9 @@ spring:
     username: sa
     password:
     schema: classpath:sql/create_tables.sql # MySQL 转 H2 的语句,使用 https://www.jooq.org/translate/ 工具
+    druid:
+      async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
+      initial-size: 1 # 单元测试,配置为 1,提升启动速度
 
   # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
   redis:
@@ -36,17 +24,13 @@ spring:
     port: 16379 # 端口(单元测试,使用 16379 端口)
     database: 0 # 数据库索引
 
---- #################### 定时任务相关配置 ####################
+mybatis:
+  lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
 
-# Quartz 配置项,对应 QuartzProperties 配置类(单元测试,禁用 Quartz)
+--- #################### 定时任务相关配置 ####################
 
 --- #################### 配置中心相关配置 ####################
 
-# Apollo 配置中心
-apollo:
-  bootstrap:
-    enabled: false # 单元测试,禁用配置中心
-
 --- #################### 服务保障相关配置 ####################
 
 # Lock4j 配置项(单元测试,禁用 Lock4j)
@@ -63,23 +47,6 @@ resilience4j:
 
 --- #################### 监控相关配置 ####################
 
-# Actuator 监控端点的配置项
-management:
-  endpoints:
-    enabled-by-default: false
-
-# Spring Boot Admin 配置项
-spring:
-  boot:
-    admin:
-      # Spring Boot Admin Client 客户端的相关配置
-      client:
-        enabled: false
-      # Spring Boot Admin Server 服务端的相关配置
-      context-path: /admin # 配置 Spring
-
-# 日志文件配置(不需要配置)
-
 --- #################### 芋道相关配置 ####################
 
 # 芋道配置项,设置当前项目所有自定义的配置

+ 2 - 0
src/test/resources/sql/clean.sql

@@ -8,6 +8,8 @@ DELETE FROM "sys_role";
 DELETE FROM "sys_role_menu";
 DELETE FROM "sys_menu";
 DELETE FROM "sys_dict_type";
+DELETE FROM "sys_user_session";
+DELETE FROM "sys_post";
 DELETE FROM "sys_login_log";
 DELETE FROM "sys_operate_log";
 DELETE FROM "sys_user";

+ 61 - 14
src/test/resources/sql/create_tables.sql

@@ -9,9 +9,9 @@ CREATE TABLE IF NOT EXISTS "inf_config" (
     "value" varchar(500) NOT NULL DEFAULT '',
     "sensitive" bit NOT NULL,
     "remark" varchar(500) DEFAULT NULL,
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
@@ -28,9 +28,9 @@ CREATE TABLE IF NOT EXISTS "sys_dept" (
     "phone" varchar(11) DEFAULT NULL,
     "email" varchar(50) DEFAULT NULL,
     "status" tinyint NOT NULL,
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
@@ -44,9 +44,9 @@ CREATE TABLE IF NOT EXISTS "sys_dict_data" (
     "dict_type" varchar(100) NOT NULL DEFAULT '',
     "status" tinyint NOT NULL DEFAULT '0',
     "remark" varchar(500) DEFAULT NULL,
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
@@ -62,9 +62,9 @@ CREATE TABLE IF NOT EXISTS "sys_role" (
     "status" tinyint NOT NULL,
     "type" tinyint NOT NULL,
     "remark" varchar(500) DEFAULT NULL,
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
@@ -74,9 +74,9 @@ CREATE TABLE IF NOT EXISTS "sys_role_menu" (
     "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
     "role_id" bigint NOT NULL,
     "menu_id" bigint NOT NULL,
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
@@ -93,9 +93,9 @@ CREATE TABLE IF NOT EXISTS "sys_menu" (
     "icon" varchar(100) DEFAULT '#',
     "component" varchar(255) DEFAULT NULL,
     "status" tinyint NOT NULL DEFAULT '0',
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
@@ -107,14 +107,61 @@ CREATE TABLE "sys_dict_type" (
     "type" varchar(100) NOT NULL DEFAULT '',
     "status" tinyint NOT NULL DEFAULT '0',
     "remark" varchar(500) DEFAULT NULL,
-    "create_by" varchar(64) DEFAULT '',
+    "creator" varchar(64) DEFAULT '',
     "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    "update_by" varchar(64) DEFAULT '',
+    "updater" varchar(64) DEFAULT '',
     "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '字典类型表';
 
+CREATE TABLE `sys_user_session` (
+    `id` varchar(32) NOT NULL,
+    `user_id` bigint DEFAULT NULL,
+    `username` varchar(50) NOT NULL DEFAULT '',
+    `user_ip` varchar(50) DEFAULT NULL,
+    `user_agent` varchar(512) DEFAULT NULL,
+    `session_timeout` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "creator" varchar(64) DEFAULT '',
+    "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    `updater` varchar(64) DEFAULT '' ,
+    "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "deleted" bit NOT NULL DEFAULT FALSE,
+    PRIMARY KEY (`id`)
+) COMMENT '用户在线 Session';
+
+CREATE TABLE IF NOT EXISTS "sys_post"
+(
+    "id"          bigint      NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "code"        varchar(64) NOT NULL,
+    "name"        varchar(50) NOT NULL,
+    "sort"        integer     NOT NULL,
+    "status"      tinyint     NOT NULL,
+    "remark"      varchar(500)         DEFAULT NULL,
+    "creator"     varchar(64)          DEFAULT '',
+    "create_time" timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updater"     varchar(64)          DEFAULT '',
+    "update_time" timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "deleted"     bit         NOT NULL DEFAULT FALSE,
+    PRIMARY KEY ("id")
+) COMMENT '岗位信息表';
+
+
+CREATE TABLE IF NOT EXISTS "sys_notice" (
+	"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+	"title" varchar(50) NOT NULL COMMENT '公告标题',
+	"content" text NOT NULL COMMENT '公告内容',
+	"notice_type" tinyint NOT NULL COMMENT '公告类型(1通知 2公告)',
+	"status" tinyint NOT NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)',
+	"creator" varchar(64) DEFAULT '' COMMENT '创建者',
+	"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	"updater" varchar(64) DEFAULT '' COMMENT '更新者',
+	"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+	"deleted" bit NOT NULL DEFAULT 0 COMMENT '是否删除',
+	PRIMARY KEY("id")
+) COMMENT '通知公告表';
+
+
 CREATE TABLE IF NOT EXISTS `sys_login_log` (
     `id`          bigint(20)   NOT NULL GENERATED BY DEFAULT AS IDENTITY,
     `log_type`    bigint(4)    NOT NULL,