From 0375fd319c9f3b08d255c814cb0f8521d8ec641b Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期三, 18 八月 2021 11:11:24 +0800
Subject: [PATCH] !78 同步dev分支 Merge pull request !78 from 疯狂的狮子Li/dev

---
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java                     |    3 
 ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java                                   |   23 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java                                 |    5 
 ruoyi-ui/src/views/register.vue                                                                     |  208 +
 ruoyi-quartz/pom.xml                                                                                |    2 
 ruoyi-ui/src/views/system/dict/index.vue                                                            |   16 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java                         |  146 
 ruoyi-ui/package.json                                                                               |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java                |   14 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java             |   17 
 ruoyi-generator/src/main/resources/vm/java/controller.java.vm                                       |   13 
 ruoyi-ui/src/api/system/dict/type.js                                                                |    9 
 ruoyi-ui/src/views/system/post/index.vue                                                            |   16 
 ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java          |   66 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java                                   |   41 
 ruoyi-generator/pom.xml                                                                             |    2 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java                         |    8 
 ruoyi-admin/src/main/resources/application-prod.yml                                                 |   59 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java                             |    2 
 ruoyi-admin/src/main/resources/application-dev.yml                                                  |   59 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java                     |  170 
 ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java                          |   29 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java                    |   17 
 ruoyi-ui/src/store/modules/user.js                                                                  |    2 
 ruoyi-ui/src/views/system/role/index.vue                                                            |   16 
 ruoyi-ui/src/views/system/menu/index.vue                                                            |    2 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java                       |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java                                  |   44 
 pom.xml                                                                                             |   42 
 ruoyi-ui/src/api/system/user.js                                                                     |   17 
 ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java                  |   69 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java                |   15 
 ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java                          |    9 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java                                | 1184 ------
 ruoyi-ui/src/api/login.js                                                                           |   14 
 ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java                  |   42 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java                           |  130 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java                            |   48 
 ruoyi-framework/pom.xml                                                                             |    2 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java                    |   28 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java                          |   73 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java                               |   28 
 ruoyi-ui/src/views/login.vue                                                                        |   12 
 ruoyi-ui/src/api/system/config.js                                                                   |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java                    |   45 
 ruoyi-demo/pom.xml                                                                                  |    2 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java                    |   13 
 ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java                     |   38 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java                    |    6 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java                     |   38 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssVo.java                                 |    0 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java                    |  116 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java                     |  100 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java                  |   27 
 ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java                                 |   34 
 ruoyi-admin/src/main/resources/i18n/messages_en_US.properties                                       |    2 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java                   |    7 
 ruoyi-ui/src/main.js                                                                                |    3 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java                     |    4 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java                         |  240 
 ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java                                |   38 
 ruoyi-ui/src/router/index.js                                                                        |   22 
 ruoyi-admin/src/main/resources/spy.properties                                                       |   26 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java     |   22 
 ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java                          |    6 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java                                      |   35 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java                       |   58 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java                       |    4 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java                          |    7 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java               |  117 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java           |   22 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java                        |   10 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java                             |   12 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOss.java                                      |    0 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java                                   |    4 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java                      |   25 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java                            |   96 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java                                |   40 
 ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties                                       |    3 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java                     |  158 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java                            |   52 
 ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java                           |   70 
 ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageStrategy.java                   |   41 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java                            |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java                    |   27 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java                    |   57 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java                                   |  160 
 ruoyi-ui/src/utils/download.js                                                                      |   91 
 ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java      |  164 
 ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml                                      |    0 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java                |   32 
 ruoyi-ui/src/components/Breadcrumb/index.vue                                                        |    2 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java                       |    6 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java     |    4 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java                            |   11 
 ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java                 |   15 
 ruoyi-generator/src/main/resources/vm/java/vo.java.vm                                               |   18 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java             |    8 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java                  |    7 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java         |   87 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java                     |  108 
 ruoyi-ui/src/views/demo/demo/index.vue                                                              |   16 
 ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java                       |    6 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java                         |   30 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java                              |    4 
 ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm                                      |    4 
 ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java                                       |   64 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java                                   |   21 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java                     |   18 
 ruoyi-oss/src/main/java/com/ruoyi/oss/properties/CloudStorageProperties.java                        |  184 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java              |   13 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java |    4 
 ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm                                             |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssMapper.java                                |    0 
 ruoyi-ui/src/views/demo/tree/index.vue                                                              |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java                |   31 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java                         |  190 
 ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageStrategy.java           |   17 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java                                    |   12 
 ruoyi-generator/src/main/resources/vm/java/bo.java.vm                                               |    4 
 ruoyi-ui/src/utils/ruoyi.js                                                                         |   24 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java                     |   30 
 ruoyi-generator/src/main/resources/vm/vue/index.vue.vm                                              |   39 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssConfigVo.java                           |   96 
 ruoyi-admin/src/main/resources/application.yml                                                      |   29 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java                          |   93 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java                |    7 
 ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml                                |   27 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java                     |   26 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java                         |   17 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java                  |   14 
 ruoyi-ui/src/api/system/oss.js                                                                      |   11 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java                         |  169 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java                          |   58 
 ruoyi-ui/src/views/tool/gen/index.vue                                                               |    2 
 ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageStrategy.java                  |   36 
 ruoyi-ui/src/views/index.vue                                                                        |   50 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java                     |   11 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java                               |   76 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java              |   23 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java               |  175 +
 ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java                        |   28 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java                             |   40 
 ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java                           |   69 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java                         |   73 
 docker/docker-compose.yml                                                                           |   31 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java                                 |   23 
 ruoyi-ui/src/views/system/user/profile/userAvatar.vue                                               |    9 
 ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java                         |   11 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java                   |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java                                 |    0 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java                                    |    7 
 ruoyi-ui/src/views/system/role/selectUser.vue                                                       |    2 
 ruoyi-system/pom.xml                                                                                |    8 
 ruoyi-ui/src/api/monitor/operlog.js                                                                 |    9 
 ruoyi-ui/src/api/system/ossConfig.js                                                                |   58 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java                       |    8 
 ruoyi-ui/src/views/monitor/operlog/index.vue                                                        |   16 
 ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java                |    8 
 ruoyi-ui/src/utils/request.js                                                                       |   10 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java                                        |   58 
 ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm                                         |    6 
 ruoyi-oss/pom.xml                                                                                   |    6 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java                             |   94 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java                    |   33 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java                        |   20 
 ruoyi-ui/src/api/monitor/jobLog.js                                                                  |    9 
 ruoyi-ui/src/api/monitor/logininfor.js                                                              |    9 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java                                 |  367 +-
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java                             |   56 
 ruoyi-ui/src/views/system/user/index.vue                                                            |   23 
 ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java                              |   14 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java                                    |  372 +-
 ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java                                  |   10 
 ruoyi-ui/src/api/demo/demo.js                                                                       |    8 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java |    6 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java                           |    4 
 ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageStrategy.java                  |   38 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java                  |   41 
 ruoyi-extend/ruoyi-monitor-admin/pom.xml                                                            |    2 
 ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java                                  |   28 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java                  |   11 
 ruoyi-generator/src/main/resources/vm/js/api.js.vm                                                  |    9 
 ruoyi-ui/src/views/monitor/job/index.vue                                                            |   16 
 ruoyi-ui/src/views/system/oss/index.vue                                                             |   75 
 README.md                                                                                           |   57 
 ruoyi-ui/src/views/system/config/index.vue                                                          |   16 
 ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java |   40 
 ruoyi-extend/pom.xml                                                                                |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssConfigMapper.java                          |   15 
 sql/ry_20210731.sql                                                                                 |    9 
 ruoyi-admin/src/main/resources/i18n/messages.properties                                             |    3 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java                 |   16 
 ruoyi-ui/src/views/system/oss/config.vue                                                            |  414 ++
 ruoyi-ui/bin/run-web.bat                                                                            |    4 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java                             |  217 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java                                |  111 
 ruoyi-ui/src/api/system/dict/data.js                                                                |    9 
 ruoyi-ui/src/views/monitor/job/log.vue                                                              |   20 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java                  |    4 
 ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java                       |    8 
 ruoyi-ui/src/api/demo/tree.js                                                                       |    9 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java                 |   21 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java                                    |   20 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java                    |   36 
 ruoyi-ui/src/views/monitor/logininfor/index.vue                                                     |   16 
 ruoyi-ui/src/views/system/dict/data.vue                                                             |   16 
 ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageStrategy.java                   |   33 
 ruoyi-admin/pom.xml                                                                                 |    2 
 ruoyi-ui/src/api/system/role.js                                                                     |   10 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java                        |   45 
 ruoyi-common/pom.xml                                                                                |   12 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java               |  108 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java                                  |  354 ++
 /dev/null                                                                                           |   40 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java                     |   12 
 ruoyi-oss/src/main/java/com/ruoyi/oss/constant/CloudConstant.java                                   |   22 
 ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java                                   |   15 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java                    |   17 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java                |   11 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java                           |   32 
 sql/oss.sql                                                                                         |   32 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java                |    8 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java                |   38 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java                    |   20 
 ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageStrategy.java                            |    6 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java                                     |   21 
 227 files changed, 6,066 insertions(+), 4,265 deletions(-)

diff --git a/README.md b/README.md
index 2779fda..778b901 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,8 @@
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE)
 [![浣跨敤IntelliJ IDEA寮�鍙戠淮鎶(https://img.shields.io/badge/IntelliJ%20IDEA-鎻愪緵鏀寔-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
 <br>
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-2.6.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
-[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.4-blue.svg)]()
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-3.0.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
+[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]()
 [![JDK-8+](https://img.shields.io/badge/JDK-8+-green.svg)]()
 [![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
 
@@ -21,51 +21,39 @@
 * 鏉冮檺璁よ瘉妗嗘灦 Spring Security銆丣wt锛屾敮鎸佸缁堢璁よ瘉绯荤粺
 * 鍏崇郴鏁版嵁搴� MySQL 閫傞厤 8.X 
 * 缂撳瓨鏁版嵁搴� Redis 閫傞厤 6.X
-* 鏁版嵁搴撳紑鍙戞鏋� Mybatis-Plus 蹇�� CRUD 澧炲姞寮�鍙戞晥鐜� 鎻掍欢鍖栨敮鎸佸悇绫婚渶姹�
+* 鏁版嵁搴撴鏋� Mybatis-Plus 蹇�� CRUD 澧炲姞寮�鍙戞晥鐜� 鎻掍欢鍖栨敮鎸佸悇绫婚渶姹�
+* 鏁版嵁搴撴鏋� 澶氭暟鎹簮妗嗘灦 dynamic-datasource 鏀寔涓讳粠涓庡绉嶇被鏁版嵁搴撳紓鏋�
+* 鏁版嵁搴撴鏋� Redis瀹㈡埛绔� 閲囩敤 Redisson 鎬ц兘鏇村己
+* 鏁版嵁搴撴鏋� 鎬ц兘鍒嗘瀽鎻掍欢 p6spy 鏇村己鍔茬殑 SQL 鍒嗘瀽
+* 搴忓垪鍖栨鏋� 缁熶竴浣跨敤 jackson 楂樻晥鍙潬
 * 缃戠粶妗嗘灦 Feign銆丱kHttp3 鎺ュ彛鍖栫鐞� HTTP 璇锋眰
-* 宸ュ叿绫绘鏋� Hutool銆丩ombok 鍑忓皯浠g爜鍐椾綑 澧炲姞瀹夊叏鎬�
+* 鍒嗗竷寮忛攣 Lock4j 娉ㄨВ閿併�佸伐鍏烽攣 澶氱澶氭牱
+* 鏂囦欢瀛樺偍 OSS 瀵硅薄瀛樺偍妯″潡 鏀寔(Minio銆佷竷鐗涖�侀樋閲屻�佽吘璁�)
 * 鐩戞帶妗嗘灦 spring-boot-admin 鍏ㄦ柟浣嶆湇鍔$洃鎺�
 * 鏍¢獙妗嗘灦 validation 澧炲己鎺ュ彛瀹夊叏鎬� 涓ヨ皑鎬�
+* Excel妗嗘灦 Alibaba EasyExcel 鎬ц兘浼樺紓 鎵╁睍鎬у己
 * 鏂囨。妗嗘灦 knife4j 缇庡寲鎺ュ彛鏂囨。
-* 搴忓垪鍖栨鏋� 缁熶竴浣跨敤 jackson 楂樻晥鍙潬
+* 宸ュ叿绫绘鏋� Hutool銆丩ombok 鍑忓皯浠g爜鍐椾綑 澧炲姞瀹夊叏鎬�
 * 浠g爜鐢熸垚鍣� 涓�閿敓鎴愬墠鍚庣浠g爜
-* 澶氭暟鎹簮妗嗘灦 dynamic-datasource 鏀寔涓讳粠涓庡绉嶇被鏁版嵁搴撳紓鏋�
-* Redis瀹㈡埛绔� 閲囩敤 Redisson 鎬ц兘鏇村己
-* 鍒嗗竷寮忛攣 Lock4j 娉ㄨВ閿併�佸伐鍏烽攣 澶氱澶氭牱
 * 閮ㄧ讲鏂瑰紡 Docker 瀹瑰櫒缂栨帓 涓�閿儴缃蹭笟鍔¢泦缇�
-* 鏂囦欢瀛樺偍 OSS 瀵硅薄瀛樺偍妯″潡 鏀寔(Minio銆佷竷鐗涖�侀樋閲屻�佽吘璁�)
+* 鍥介檯鍖� Spring 鏍囧噯鍥介檯鍖栨柟瑙e喅鏂规
 
 ## 鍙傝�冩枃妗�
 
 浣跨敤妗嗘灦鍓嶈浠旂粏闃呰鏂囨。閲嶇偣娉ㄦ剰浜嬮」
 <br>
 >[鍒濆鍖栭」鐩� 蹇呯湅](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬鍒濆鍖栭」鐩�?sort_id=4164117)
+>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬鍒濆鍖栭」鐩�?sort_id=4164117](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬鍒濆鍖栭」鐩�?sort_id=4164117)
 > 
 >[閮ㄧ讲椤圭洰 蹇呯湅](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬搴旂敤閮ㄧ讲?sort_id=4219382)
+>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬搴旂敤閮ㄧ讲?sort_id=4219382](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬搴旂敤閮ㄧ讲?sort_id=4219382)
 > 
 >[鍙傝�冩枃妗� Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
+>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
 
-## 鎻愰棶鍥涢儴鏇�
-### 涓�銆佹煡闃厀iki
-浼樺厛鍦╜wiki->閲嶇偣浜嬮」`锛屾煡鎵炬槸鍚︽湁鐩稿叧闂鍙婅В鍐虫柟妗堬紝灏ゅ叾鏄鏋舵洿鏂板悗浜х敓鐨勯棶棰橈紝澶氫細鍦╳iki涓彁鍙�
+## 杞欢鏋舵瀯鍥�
 
-> [鍙傝�冩枃妗� Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
-
-### 浜屻�佸�熷姪issues
-灏濊瘯issues涓悳绱㈤棶棰樺叧閿瓧锛堣寰楅�夋嫨宸插畬鎴愶級锛岀湅鐪嬫槸鍚︽湁鍏朵粬浜烘彁鍑虹浉鍚岄棶棰�
-- `濡傛灉鏈塦閭d箞渚濇嵁璇勮涓殑瑙e喅鏂规鑷灏濊瘯瑙e喅
-- `濡傛灉娌℃湁`閭d箞鎻愪氦涓�涓柊鐨刬ssues鎻忚堪娓呮浣犵殑闂锛岄渶瑕佸寘鍚互涓嬪唴瀹癸紙浼樿川鐨刬ssues锛岃兘澶熷府鍔╀綔鑰呮洿楂樻晥鐨勫府浣犺В鍐抽棶棰橈級锛�
-    - 鍑虹幇闂鐨勬ā鍧楁垨鍔熻兘鎴栫被锛屾�讳箣浣犺璇存竻妤氬湪鍝嚭鐨勯棶棰�
-    - 鎻忚堪浜х敓闂鐨勭浉鍏虫搷浣滄祦绋嬶紝浠ヤ究澶嶇幇蹇�熻В鍐�
-    - 鎶ラ敊鐨勬棩蹇楁埅鍥撅紝涓�瀹氭槸鎴浘锛屼笉瑕佸鍒朵竴鍫嗘姤閿欑殑鏂囨湰
-> [issues](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/issues)
-
-### 涓夈�佺櫨搴�
-澶у閮芥噦锛屼笉澶氭弿杩帮紝灏嗗叧閿殑鎶ラ敊淇℃伅CC->CV鍒扮櫨搴︿腑鐪嬬湅澶т浆浠�庝箞瑙e喅鐨�
-> [鐧惧害](http://www.baidu.com)
-
-### 鍥涖�佸姞缇�
-浠ヤ笂涓夌偣宸茬粡鑳借В鍐冲ぇ瀹剁粷澶ч儴鍒嗛棶棰樹簡锛屽鏋滆繕鏈夐棶棰樻病鑳介�氳繃杩欏嚑绉嶆柟寮忚В鍐筹紝閭d箞鍔犵兢锛屽ぇ瀹朵竴璧峰湪缇ら噷鎺㈣涓�涓�
+![Plus閮ㄧ讲鏋舵瀯鍥綸(https://images.gitee.com/uploads/images/2021/0729/112230_4295e5ce_1766278.png "Plus閮ㄧ讲鏋舵瀯鍥�.png")
 
 ## 璐$尞浠g爜
 
@@ -79,7 +67,8 @@
 * ORM妗嗘灦 浣跨敤 Mybatis-Plus 绠�鍖朇RUD (涓嶆敮鎸佷富瀛愯〃)
 * Bean绠�鍖� 浣跨敤 Lombok 绠�鍖� get set toString 绛夌瓑
 * 瀹瑰櫒鏀瑰姩 Tomcat 鏀逛负 骞跺彂鎬ц兘鏇村ソ鐨� undertow
-* 鍒嗛〉绉婚櫎 pagehelper 鏀逛负 Mybatis-Plus 鍒嗛〉
+* 绉婚櫎 pagehelper 鏀逛负 Mybatis-Plus 鍒嗛〉
+* 闆嗘垚 p6spy 鏇村己鍔茬殑 SQL 鍒嗘瀽
 * 鍗囩骇 swagger 涓� knife4j
 * 闆嗘垚 Hutool 5.X 骞堕噸鍐橰uoYi閮ㄥ垎鍔熻兘
 * 闆嗘垚 Feign 鎺ュ彛鍖栫鐞� Http 璇锋眰(濡備笁鏂硅姹� 鏀粯,鐭俊,鎺ㄩ�佺瓑)
@@ -90,7 +79,8 @@
 * 闆嗘垚 dynamic-datasource 澶氭暟鎹簮(榛樿鏀寔MySQL,鍏朵粬绉嶇被闇�鑷閫傞厤)
 * 闆嗘垚 Lock4j 瀹炵幇鍒嗗竷寮� 娉ㄨВ閿併�佸伐鍏烽攣 澶氱澶氭牱
 * 澧炲姞 Docker 瀹瑰櫒缂栨帓 鎵撳寘鎻掍欢涓庨儴缃茶剼鏈�
-* 绉婚櫎 鏈湴鏂囦欢涓婁紶 鏀逛负 OSS瀵硅薄瀛樺偍 鏀寔(Minio銆佷竷鐗涖�侀樋閲屻�佽吘璁�)
+* 绉婚櫎 閫氱敤涓婁紶涓嬭浇 鏀逛负 OSS瀵硅薄瀛樺偍 鏀寔(Minio銆佷竷鐗涖�侀樋閲屻�佽吘璁�)
+* 绉婚櫎 RuoYi鑷甫 Excel 宸ュ叿 鏀逛负 EasyExcel 宸ュ叿
 
 ### 浠g爜鏀瑰姩
 
@@ -112,8 +102,9 @@
 * 鍗曟ā鍧� fast 鍒嗘敮 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/)
 * Oracle 妯″潡 oracle 鍒嗘敮 [RuoYi-Vue-Plus-oracle](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/oracle/)
 
-## 鎵爜鍔犵兢 涓�璧蜂氦娴�
-![杈撳叆鍥剧墖璇存槑](https://images.gitee.com/uploads/images/2021/0625/160026_11d949aa_1766278.jpeg "07f7121fab14e57e03e5f6a35eff6ce.jpg")
+## 鍔犵兢涓庢崘鐚�
+>[鍔犵兢涓庢崘鐚甝(https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍔犵兢涓庢崘鐚�?sort_id=4104598)
+>>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍔犵兢涓庢崘鐚�?sort_id=4104598](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍔犵兢涓庢崘鐚�?sort_id=4104598)
 
 ## 鎹愮尞浣滆��
 浣滆�呬负鍏艰亴鍋氬紑婧�,骞虫椂杩橀渶瑕佸伐浣�,濡傛灉甯埌浜嗘偍鍙互璇蜂綔鑰呭悆涓洅楗�  
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index ac065c3..228ddbf 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -18,8 +18,6 @@
       - /docker/mysql/data/:/var/lib/mysql/
       # 閰嶇疆鎸傝浇
       - /docker/mysql/conf/:/etc/mysql/conf.d/
-      # 涓绘満鏈満鏃堕棿鏂囦欢鏄犲皠 涓庢湰鏈烘椂闂村悓姝�
-      - /etc/localtime:/etc/localtime:ro
     command:
       # 灏唌ysql8.0榛樿瀵嗙爜绛栫暐 淇敼涓� 鍘熷厛 绛栫暐 (mysql8.0瀵瑰叾榛樿绛栫暐鍋氫簡鏇存敼 浼氬鑷村瘑鐮佹棤娉曞尮閰�)
       --default-authentication-plugin=mysql_native_password
@@ -37,6 +35,9 @@
     # 濡傛灉闇�瑕佹寚瀹氱増鏈� 灏辨妸 latest 鎹㈡垚鐗堟湰鍙�
     image: nginx:latest
     container_name: nginx-web
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
     ports:
       - 80:80
       - 443:443
@@ -49,8 +50,6 @@
       - /docker/nginx/html:/usr/share/nginx/html
       # 鏃ュ織鐩綍
       - /docker/nginx/log:/var/log/nginx
-      # 涓绘満鏈満鏃堕棿鏂囦欢鏄犲皠 涓庢湰鏈烘椂闂村悓姝�
-      - /etc/localtime:/etc/localtime:ro
     privileged: true
     restart: always
     networks:
@@ -62,16 +61,13 @@
     ports:
       - 6379:6379
     environment:
-      # 璁剧疆鐜鍙橀噺 鏃跺尯涓婃捣 缂栫爜UTF-8
+      # 鏃跺尯涓婃捣
       TZ: Asia/Shanghai
-      LANG: en_US.UTF-8
     volumes:
       # 閰嶇疆鏂囦欢
       - /docker/redis/conf/redis.conf:/redis.conf:rw
       # 鏁版嵁鏂囦欢
       - /docker/redis/data:/data:rw
-      # 涓绘満鏈満鏃堕棿鏂囦欢鏄犲皠 涓庢湰鏈烘椂闂村悓姝�
-      - /etc/localtime:/etc/localtime:ro
     command: "redis-server --appendonly yes"
     privileged: true
     restart: always
@@ -88,6 +84,8 @@
       # 鎺у埗鍙扮鍙�
       - 9001:9001
     environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
       # 绠$悊鍚庡彴鐢ㄦ埛鍚�
       MINIO_ACCESS_KEY: ruoyi
       # 绠$悊鍚庡彴瀵嗙爜锛屾渶灏�8涓瓧绗�
@@ -97,8 +95,6 @@
       - /docker/minio/data:/data
       # 鏄犲皠閰嶇疆鐩綍
       - /docker/minio/config:/root/.minio/
-      # 涓绘満鏈満鏃堕棿鏂囦欢鏄犲皠 涓庢湰鏈烘椂闂村悓姝�
-      - /etc/localtime:/etc/localtime:ro
     command: server --console-address ':9001' /data  # 鎸囧畾瀹瑰櫒涓殑鐩綍 /data
     privileged: true
     restart: always
@@ -107,9 +103,10 @@
         ipv4_address: 172.30.0.54
 
   ruoyi-server1:
-    image: "ruoyi/ruoyi-server:2.6.0"
+    image: "ruoyi/ruoyi-server:3.0.0"
     environment:
-      - TZ=Asia/Shanghai
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
     volumes:
       # 閰嶇疆鏂囦欢
       - /docker/server1/logs/:/ruoyi/server/logs/
@@ -121,9 +118,10 @@
         ipv4_address: 172.30.0.60
 
   ruoyi-server2:
-    image: "ruoyi/ruoyi-server:2.6.0"
+    image: "ruoyi/ruoyi-server:3.0.0"
     environment:
-      - TZ=Asia/Shanghai
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
     volumes:
       # 閰嶇疆鏂囦欢
       - /docker/server2/logs/:/ruoyi/server/logs/
@@ -135,9 +133,10 @@
         ipv4_address: 172.30.0.61
 
   ruoyi-monitor-admin:
-    image: "ruoyi/ruoyi-monitor-admin:2.6.0"
+    image: "ruoyi/ruoyi-monitor-admin:3.0.0"
     environment:
-      - TZ=Asia/Shanghai
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
     privileged: true
     restart: always
     networks:
diff --git a/pom.xml b/pom.xml
index 7c31108..cdd1f9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,14 +6,14 @@
 
     <groupId>com.ruoyi</groupId>
     <artifactId>ruoyi-vue-plus</artifactId>
-    <version>2.6.0</version>
+    <version>3.0.0</version>
 
     <name>RuoYi-Vue-Plus</name>
     <url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url>
     <description>RuoYi-Vue-Plus鍚庡彴绠$悊绯荤粺</description>
 
     <properties>
-        <ruoyi-vue-plus.version>2.6.0</ruoyi-vue-plus.version>
+        <ruoyi-vue-plus.version>3.0.0</ruoyi-vue-plus.version>
         <spring-boot.version>2.5.3</spring-boot.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -22,16 +22,19 @@
         <druid.version>1.2.6</druid.version>
         <knife4j.version>3.0.3</knife4j.version>
         <poi.version>4.1.2</poi.version>
+        <easyexcel.version>2.2.10</easyexcel.version>
         <velocity.version>1.7</velocity.version>
         <jwt.version>0.9.1</jwt.version>
         <mybatis-plus.version>3.4.3</mybatis-plus.version>
-        <hutool.version>5.7.6</hutool.version>
+        <p6spy.version>3.9.1</p6spy.version>
+        <hutool.version>5.7.7</hutool.version>
         <feign.version>3.0.3</feign.version>
-        <feign-okhttp.version>11.0</feign-okhttp.version>
-        <spring-boot-admin.version>2.4.3</spring-boot-admin.version>
+        <feign-okhttp.version>11.2</feign-okhttp.version>
+        <okhttp.version>4.9.1</okhttp.version>
+        <spring-boot-admin.version>2.5.0</spring-boot-admin.version>
         <redisson.version>3.16.1</redisson.version>
         <lock4j.version>2.2.1</lock4j.version>
-        <datasource.version>3.4.1</datasource.version>
+        <dynamic-ds.version>3.4.1</dynamic-ds.version>
 
         <!-- OSS 閰嶇疆 -->
         <qiniu.version>7.8.0</qiniu.version>
@@ -79,6 +82,12 @@
                 <version>${poi.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>easyexcel</artifactId>
+                <version>${easyexcel.version}</version>
+            </dependency>
+
             <!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
             <dependency>
                 <groupId>org.apache.velocity</groupId>
@@ -97,7 +106,7 @@
             <dependency>
                 <groupId>com.baomidou</groupId>
                 <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
-                <version>${datasource.version}</version>
+                <version>${dynamic-ds.version}</version>
             </dependency>
 
             <dependency>
@@ -109,6 +118,12 @@
                 <groupId>com.baomidou</groupId>
                 <artifactId>mybatis-plus-extension</artifactId>
                 <version>${mybatis-plus.version}</version>
+            </dependency>
+            <!-- sql鎬ц兘鍒嗘瀽鎻掍欢 -->
+            <dependency>
+                <groupId>p6spy</groupId>
+                <artifactId>p6spy</artifactId>
+                <version>${p6spy.version}</version>
             </dependency>
 
             <dependency>
@@ -127,6 +142,12 @@
                 <groupId>io.github.openfeign</groupId>
                 <artifactId>feign-okhttp</artifactId>
                 <version>${feign-okhttp.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp</artifactId>
+                <version>${okhttp.version}</version>
             </dependency>
 
             <dependency>
@@ -248,7 +269,7 @@
         <repository>
             <id>public</id>
             <name>aliyun nexus</name>
-            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <url>https://maven.aliyun.com/repository/public/</url>
             <releases>
                 <enabled>true</enabled>
             </releases>
@@ -259,7 +280,7 @@
         <pluginRepository>
             <id>public</id>
             <name>aliyun nexus</name>
-            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <url>https://maven.aliyun.com/repository/public/</url>
             <releases>
                 <enabled>true</enabled>
             </releases>
@@ -276,6 +297,7 @@
                 <!-- 鐜鏍囪瘑锛岄渶瑕佷笌閰嶇疆鏂囦欢鐨勫悕绉扮浉瀵瑰簲 -->
                 <profiles.active>local</profiles.active>
                 <logging.level>debug</logging.level>
+                <endpoints.include>'*'</endpoints.include>
             </properties>
         </profile>
         <profile>
@@ -284,6 +306,7 @@
                 <!-- 鐜鏍囪瘑锛岄渶瑕佷笌閰嶇疆鏂囦欢鐨勫悕绉扮浉瀵瑰簲 -->
                 <profiles.active>dev</profiles.active>
                 <logging.level>debug</logging.level>
+                <endpoints.include>'*'</endpoints.include>
             </properties>
             <activation>
                 <!-- 榛樿鐜 -->
@@ -295,6 +318,7 @@
             <properties>
                 <profiles.active>prod</profiles.active>
                 <logging.level>warn</logging.level>
+                <endpoints.include>health,info</endpoints.include>
             </properties>
         </profile>
 
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index ba0ad32..b46acd5 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
index 4654516..210ccee 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -8,7 +8,7 @@
 import cn.hutool.captcha.generator.RandomGenerator;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.redis.RedisCache;
@@ -107,9 +107,9 @@
 
 	private String getCodeResult(String capStr) {
 		int numberLength = captchaProperties.getNumberLength();
-		int a = Convert.toInt(StrUtil.sub(capStr, 0, numberLength).trim());
+		int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim());
 		char operator = capStr.charAt(numberLength);
-		int b = Convert.toInt(StrUtil.sub(capStr, numberLength + 1, numberLength + 1 + numberLength).trim());
+		int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim());
 		switch (operator) {
 			case '*':
 				return a * b + "";
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
deleted file mode 100644
index 04aa77b..0000000
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.ruoyi.web.controller.common;
-
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.utils.file.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-
-/**
- * 閫氱敤璇锋眰澶勭悊
- *
- * @author ruoyi
- */
-@RestController
-public class CommonController
-{
-    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
-
-    /**
-     * 閫氱敤涓嬭浇璇锋眰
-     *
-     * @param fileName 鏂囦欢鍚嶇О
-     * @param delete 鏄惁鍒犻櫎
-     */
-    @GetMapping("common/download")
-    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
-    {
-        try
-        {
-            if (!FileUtils.checkAllowDownload(fileName))
-            {
-                throw new Exception(StrUtil.format("鏂囦欢鍚嶇О({})闈炴硶锛屼笉鍏佽涓嬭浇銆� ", fileName));
-            }
-            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
-            String filePath = RuoYiConfig.getDownloadPath() + fileName;
-			File file = new File(filePath);
-            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
-            FileUtils.setAttachmentResponseHeader(response, realFileName);
-			FileUtils.writeToStream(file, response.getOutputStream());
-            if (delete)
-            {
-				FileUtils.del(file);
-            }
-        }
-        catch (Exception e)
-        {
-            log.error("涓嬭浇鏂囦欢澶辫触", e);
-        }
-    }
-
-    /**
-     * 鏈湴璧勬簮閫氱敤涓嬭浇
-     */
-    @GetMapping("/common/download/resource")
-    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
-            throws Exception
-    {
-        try
-        {
-            if (!FileUtils.checkAllowDownload(resource))
-            {
-                throw new Exception(StrUtil.format("璧勬簮鏂囦欢({})闈炴硶锛屼笉鍏佽涓嬭浇銆� ", resource));
-            }
-            // 鏈湴璧勬簮璺緞
-            String localPath = RuoYiConfig.getProfile();
-            // 鏁版嵁搴撹祫婧愬湴鍧�
-            String downloadPath = localPath + StrUtil.subAfter(resource, Constants.RESOURCE_PREFIX,false);
-            // 涓嬭浇鍚嶇О
-            String downloadName = StrUtil.subAfter(downloadPath, "/",true);
-            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
-			File file = new File(downloadPath);
-            FileUtils.setAttachmentResponseHeader(response, downloadName);
-            FileUtils.writeToStream(file, response.getOutputStream());
-        }
-        catch (Exception e)
-        {
-            log.error("涓嬭浇鏂囦欢澶辫触", e);
-        }
-    }
-}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
index b3efd5a..66749ef 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
@@ -1,50 +1,50 @@
-package com.ruoyi.web.controller.monitor;
-
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.core.domain.AjaxResult;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.*;
-
-/**
- * 缂撳瓨鐩戞帶
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/cache")
-public class CacheController
-{
-    @Autowired
-    private RedisTemplate<String, String> redisTemplate;
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping()
-    public AjaxResult getInfo() throws Exception
-    {
-        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
-        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
-        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
-
-        Map<String, Object> result = new HashMap<>(3);
-        result.put("info", info);
-        result.put("dbSize", dbSize);
-
-        List<Map<String, String>> pieList = new ArrayList<>();
-        commandStats.stringPropertyNames().forEach(key -> {
-            Map<String, String> data = new HashMap<>(2);
-            String property = commandStats.getProperty(key);
-            data.put("name", StrUtil.removePrefix(key, "cmdstat_"));
-            data.put("value", StrUtil.subBetween(property, "calls=", ",usec"));
-            pieList.add(data);
-        });
-        result.put("commandStats", pieList);
-        return AjaxResult.success(result);
-    }
-}
+package com.ruoyi.web.controller.monitor;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.core.domain.AjaxResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+/**
+ * 缂撳瓨鐩戞帶
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController
+{
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
+        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
+        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
+
+        Map<String, Object> result = new HashMap<>(3);
+        result.put("info", info);
+        result.put("dbSize", dbSize);
+
+        List<Map<String, String>> pieList = new ArrayList<>();
+        commandStats.stringPropertyNames().forEach(key -> {
+            Map<String, String> data = new HashMap<>(2);
+            String property = commandStats.getProperty(key);
+            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+            pieList.add(data);
+        });
+        result.put("commandStats", pieList);
+        return AjaxResult.success(result);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
index 2bb0b13..fb0b002 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
@@ -12,11 +12,12 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
  * 绯荤粺璁块棶璁板綍
- * 
+ *
  * @author ruoyi
  */
 @RestController
@@ -36,11 +37,10 @@
     @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysLogininfor logininfor)
+    public void export(SysLogininfor logininfor, HttpServletResponse response)
     {
         List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
-        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
-        return util.exportExcel(list, "鐧诲綍鏃ュ織");
+		ExcelUtil.exportExcel(list, "鐧诲綍鏃ュ織", SysLogininfor.class, response);
     }
 
     @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
index 97f9920..02a926d 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
@@ -12,11 +12,12 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
  * 鎿嶄綔鏃ュ織璁板綍
- * 
+ *
  * @author ruoyi
  */
 @RestController
@@ -36,11 +37,10 @@
     @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysOperLog operLog)
+    public void export(SysOperLog operLog, HttpServletResponse response)
     {
         List<SysOperLog> list = operLogService.selectOperLogList(operLog);
-        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
-        return util.exportExcel(list, "鎿嶄綔鏃ュ織");
+		ExcelUtil.exportExcel(list, "鎿嶄綔鏃ュ織", SysOperLog.class, response);
     }
 
     @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.DELETE)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
index fe630a9..f1442cc 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
@@ -1,7 +1,5 @@
 package com.ruoyi.web.controller.monitor;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.controller.BaseController;
@@ -11,6 +9,7 @@
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysUserOnline;
 import com.ruoyi.system.service.ISysUserOnlineService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,7 +23,7 @@
 
 /**
  * 鍦ㄧ嚎鐢ㄦ埛鐩戞帶
- * 
+ *
  * @author ruoyi
  */
 @RestController
@@ -46,23 +45,23 @@
         for (String key : keys)
         {
             LoginUser user = redisCache.getCacheObject(key);
-            if (Validator.isNotEmpty(ipaddr) && Validator.isNotEmpty(userName))
+            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
             {
-                if (StrUtil.equals(ipaddr, user.getIpaddr()) && StrUtil.equals(userName, user.getUsername()))
+                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
                 {
                     userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
                 }
             }
-            else if (Validator.isNotEmpty(ipaddr))
+            else if (StringUtils.isNotEmpty(ipaddr))
             {
-                if (StrUtil.equals(ipaddr, user.getIpaddr()))
+                if (StringUtils.equals(ipaddr, user.getIpaddr()))
                 {
                     userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
                 }
             }
-            else if (Validator.isNotEmpty(userName) && Validator.isNotNull(user.getUser()))
+            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
             {
-                if (StrUtil.equals(userName, user.getUsername()))
+                if (StringUtils.equals(userName, user.getUsername()))
                 {
                     userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
                 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
index c8e9191..13fdc67 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
@@ -7,7 +7,6 @@
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.system.domain.SysConfig;
 import com.ruoyi.system.service.ISysConfigService;
@@ -16,6 +15,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -43,11 +43,10 @@
     @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:config:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysConfig config)
+    public void export(SysConfig config, HttpServletResponse response)
     {
         List<SysConfig> list = configService.selectConfigList(config);
-        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
-        return util.exportExcel(list, "鍙傛暟鏁版嵁");
+		ExcelUtil.exportExcel(list, "鍙傛暟鏁版嵁", SysConfig.class, response);
     }
 
     /**
@@ -82,7 +81,7 @@
         {
             return AjaxResult.error("鏂板鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
         }
-        config.setCreateBy(SecurityUtils.getUsername());
+        config.setCreateBy(getUsername());
         return toAjax(configService.insertConfig(config));
     }
 
@@ -98,7 +97,7 @@
         {
             return AjaxResult.error("淇敼鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
         }
-        config.setUpdateBy(SecurityUtils.getUsername());
+        config.setUpdateBy(getUsername());
         return toAjax(configService.updateConfig(config));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
index ab39319..edf0b22 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
@@ -1,15 +1,14 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.ArrayUtil;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.service.ISysDeptService;
-import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -56,7 +55,7 @@
         {
             SysDept d = (SysDept) it.next();
             if (d.getDeptId().intValue() == deptId
-                    || ArrayUtils.contains(StrUtil.splitToArray(d.getAncestors(), ","), deptId + ""))
+                    || ArrayUtil.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""))
             {
                 it.remove();
             }
@@ -109,7 +108,7 @@
         {
             return AjaxResult.error("鏂板閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
         }
-        dept.setCreateBy(SecurityUtils.getUsername());
+        dept.setCreateBy(getUsername());
         return toAjax(deptService.insertDept(dept));
     }
 
@@ -129,12 +128,12 @@
         {
             return AjaxResult.error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
         }
-        else if (StrUtil.equals(UserConstants.DEPT_DISABLE, dept.getStatus())
+        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())
                 && deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0)
         {
             return AjaxResult.error("璇ラ儴闂ㄥ寘鍚湭鍋滅敤鐨勫瓙閮ㄩ棬锛�");
         }
-        dept.setUpdateBy(SecurityUtils.getUsername());
+        dept.setUpdateBy(getUsername());
         return toAjax(deptService.updateDept(dept));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
index a272a6e..6462a0c 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
@@ -1,13 +1,12 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.lang.Validator;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysDictData;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.system.service.ISysDictDataService;
 import com.ruoyi.system.service.ISysDictTypeService;
@@ -16,6 +15,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -44,11 +44,10 @@
     @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:dict:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysDictData dictData)
+    public void export(SysDictData dictData, HttpServletResponse response)
     {
         List<SysDictData> list = dictDataService.selectDictDataList(dictData);
-        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
-        return util.exportExcel(list, "瀛楀吀鏁版嵁");
+		ExcelUtil.exportExcel(list, "瀛楀吀鏁版嵁", SysDictData.class, response);
     }
 
     /**
@@ -68,7 +67,7 @@
     public AjaxResult dictType(@PathVariable String dictType)
     {
         List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
-        if (Validator.isNull(data))
+        if (StringUtils.isNull(data))
         {
             data = new ArrayList<SysDictData>();
         }
@@ -83,7 +82,7 @@
     @PostMapping
     public AjaxResult add(@Validated @RequestBody SysDictData dict)
     {
-        dict.setCreateBy(SecurityUtils.getUsername());
+        dict.setCreateBy(getUsername());
         return toAjax(dictDataService.insertDictData(dict));
     }
 
@@ -95,7 +94,7 @@
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody SysDictData dict)
     {
-        dict.setUpdateBy(SecurityUtils.getUsername());
+        dict.setUpdateBy(getUsername());
         return toAjax(dictDataService.updateDictData(dict));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
index e2e0625..eb5c0b5 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
@@ -7,7 +7,6 @@
 import com.ruoyi.common.core.domain.entity.SysDictType;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.system.service.ISysDictTypeService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -15,6 +14,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -39,11 +39,10 @@
     @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:dict:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysDictType dictType)
+    public void export(SysDictType dictType, HttpServletResponse response)
     {
         List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
-        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
-        return util.exportExcel(list, "瀛楀吀绫诲瀷");
+		ExcelUtil.exportExcel(list, "瀛楀吀绫诲瀷", SysDictType.class, response);
     }
 
     /**
@@ -68,7 +67,7 @@
         {
             return AjaxResult.error("鏂板瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
         }
-        dict.setCreateBy(SecurityUtils.getUsername());
+        dict.setCreateBy(getUsername());
         return toAjax(dictTypeService.insertDictType(dict));
     }
 
@@ -84,7 +83,7 @@
         {
             return AjaxResult.error("淇敼瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
         }
-        dict.setUpdateBy(SecurityUtils.getUsername());
+        dict.setUpdateBy(getUsername());
         return toAjax(dictTypeService.updateDictType(dict));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
index a29620c..bfb532e 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
@@ -1,6 +1,6 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.config.RuoYiConfig;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -24,6 +24,6 @@
     @RequestMapping("/")
     public String index()
     {
-        return StrUtil.format("娆㈣繋浣跨敤{}鍚庡彴绠$悊妗嗘灦锛屽綋鍓嶇増鏈細v{}锛岃閫氳繃鍓嶇鍦板潃璁块棶銆�", ruoyiConfig.getName(), ruoyiConfig.getVersion());
+        return StringUtils.format("娆㈣繋浣跨敤{}鍚庡彴绠$悊妗嗘灦锛屽綋鍓嶇増鏈細v{}锛岃閫氳繃鍓嶇鍦板潃璁块棶銆�", ruoyiConfig.getName(), ruoyiConfig.getVersion());
     }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
index b2b9efb..9971ac4 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -6,6 +6,7 @@
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginBody;
 import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.ServletUtils;
 import com.ruoyi.framework.web.service.SysLoginService;
 import com.ruoyi.framework.web.service.SysPermissionService;
@@ -88,10 +89,8 @@
     @GetMapping("getRouters")
     public AjaxResult getRouters()
     {
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        // 鐢ㄦ埛淇℃伅
-        SysUser user = loginUser.getUser();
-        List<SysMenu> menus = menuService.selectMenuTreeByUserId(user.getUserId());
+        Long userId = SecurityUtils.getUserId();
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
         return AjaxResult.success(menuService.buildMenus(menus));
     }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
index 246abf4..d679bfb 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
@@ -1,16 +1,12 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.lang.Validator;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysMenu;
-import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.service.ISysMenuService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -33,9 +29,6 @@
     @Autowired
     private ISysMenuService menuService;
 
-    @Autowired
-    private TokenService tokenService;
-
     /**
      * 鑾峰彇鑿滃崟鍒楄〃
      */
@@ -43,9 +36,7 @@
     @GetMapping("/list")
     public AjaxResult list(SysMenu menu)
     {
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        Long userId = loginUser.getUser().getUserId();
-        List<SysMenu> menus = menuService.selectMenuList(menu, userId);
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
         return AjaxResult.success(menus);
     }
 
@@ -65,9 +56,7 @@
     @GetMapping("/treeselect")
     public AjaxResult treeselect(SysMenu menu)
     {
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        Long userId = loginUser.getUser().getUserId();
-        List<SysMenu> menus = menuService.selectMenuList(menu, userId);
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
         return AjaxResult.success(menuService.buildMenuTreeSelect(menus));
     }
 
@@ -77,8 +66,7 @@
     @GetMapping(value = "/roleMenuTreeselect/{roleId}")
     public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
     {
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        List<SysMenu> menus = menuService.selectMenuList(loginUser.getUser().getUserId());
+		List<SysMenu> menus = menuService.selectMenuList(getUserId());
 		Map<String,Object> ajax = new HashMap<>();
         ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
         ajax.put("menus", menuService.buildMenuTreeSelect(menus));
@@ -97,11 +85,11 @@
         {
             return AjaxResult.error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
         }
-        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !Validator.isUrl(menu.getPath()))
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
         {
             return AjaxResult.error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
         }
-        menu.setCreateBy(SecurityUtils.getUsername());
+        menu.setCreateBy(getUsername());
         return toAjax(menuService.insertMenu(menu));
     }
 
@@ -117,7 +105,7 @@
         {
             return AjaxResult.error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
         }
-        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !Validator.isUrl(menu.getPath()))
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
         {
             return AjaxResult.error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
         }
@@ -125,7 +113,7 @@
         {
             return AjaxResult.error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屼笂绾ц彍鍗曚笉鑳介�夋嫨鑷繁");
         }
-        menu.setUpdateBy(SecurityUtils.getUsername());
+        menu.setUpdateBy(getUsername());
         return toAjax(menuService.updateMenu(menu));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
index 48d1e08..55375a9 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
@@ -17,13 +17,12 @@
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.system.domain.SysNotice;
 import com.ruoyi.system.service.ISysNoticeService;
 
 /**
  * 鍏憡 淇℃伅鎿嶄綔澶勭悊
- * 
+ *
  * @author ruoyi
  */
 @RestController
@@ -61,7 +60,7 @@
     @PostMapping
     public AjaxResult add(@Validated @RequestBody SysNotice notice)
     {
-        notice.setCreateBy(SecurityUtils.getUsername());
+        notice.setCreateBy(getUsername());
         return toAjax(noticeService.insertNotice(notice));
     }
 
@@ -73,7 +72,7 @@
     @PutMapping
     public AjaxResult edit(@Validated @RequestBody SysNotice notice)
     {
-        notice.setUpdateBy(SecurityUtils.getUsername());
+        notice.setUpdateBy(getUsername());
         return toAjax(noticeService.updateNotice(notice));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java
new file mode 100644
index 0000000..60fed2a
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java
@@ -0,0 +1,108 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.annotation.RepeatSubmit;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.validate.AddGroup;
+import com.ruoyi.common.core.validate.EditGroup;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.bo.SysOssConfigBo;
+import com.ruoyi.system.domain.vo.SysOssConfigVo;
+import com.ruoyi.system.service.ISysOssConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Arrays;
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃瓹ontroller
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Validated
+@Api(value = "浜戝瓨鍌ㄩ厤缃帶鍒跺櫒", tags = {"浜戝瓨鍌ㄩ厤缃鐞�"})
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@RestController
+@RequestMapping("/system/oss/config")
+public class SysOssConfigController extends BaseController {
+
+	private final ISysOssConfigService iSysOssConfigService;
+
+	/**
+	 * 鏌ヨ浜戝瓨鍌ㄩ厤缃垪琛�
+	 */
+	@ApiOperation("鏌ヨ浜戝瓨鍌ㄩ厤缃垪琛�")
+	@PreAuthorize("@ss.hasPermi('system:oss:list')")
+	@GetMapping("/list")
+	public TableDataInfo<SysOssConfigVo> list(@Validated SysOssConfigBo bo) {
+		return iSysOssConfigService.queryPageList(bo);
+	}
+
+	/**
+	 * 鑾峰彇浜戝瓨鍌ㄩ厤缃缁嗕俊鎭�
+	 */
+	@ApiOperation("鑾峰彇浜戝瓨鍌ㄩ厤缃缁嗕俊鎭�")
+	@PreAuthorize("@ss.hasPermi('system:oss:query')")
+	@GetMapping("/{ossConfigId}")
+	public AjaxResult<SysOssConfigVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+											  @PathVariable("ossConfigId") Integer ossConfigId) {
+		return AjaxResult.success(iSysOssConfigService.queryById(ossConfigId));
+	}
+
+	/**
+	 * 鏂板浜戝瓨鍌ㄩ厤缃�
+	 */
+	@ApiOperation("鏂板浜戝瓨鍌ㄩ厤缃�")
+	@PreAuthorize("@ss.hasPermi('system:oss:add')")
+	@Log(title = "浜戝瓨鍌ㄩ厤缃�", businessType = BusinessType.INSERT)
+	@RepeatSubmit()
+	@PostMapping()
+	public AjaxResult<Void> add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) {
+		return toAjax(iSysOssConfigService.insertByBo(bo) ? 1 : 0);
+	}
+
+	/**
+	 * 淇敼浜戝瓨鍌ㄩ厤缃�
+	 */
+	@ApiOperation("淇敼浜戝瓨鍌ㄩ厤缃�")
+	@PreAuthorize("@ss.hasPermi('system:oss:edit')")
+	@Log(title = "浜戝瓨鍌ㄩ厤缃�", businessType = BusinessType.UPDATE)
+	@RepeatSubmit()
+	@PutMapping()
+	public AjaxResult<Void> edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) {
+		return toAjax(iSysOssConfigService.updateByBo(bo) ? 1 : 0);
+	}
+
+	/**
+	 * 鍒犻櫎浜戝瓨鍌ㄩ厤缃�
+	 */
+	@ApiOperation("鍒犻櫎浜戝瓨鍌ㄩ厤缃�")
+	@PreAuthorize("@ss.hasPermi('system:oss:remove')")
+	@Log(title = "浜戝瓨鍌ㄩ厤缃�", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ossConfigIds}")
+	public AjaxResult<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+								   @PathVariable Long[] ossConfigIds) {
+		return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true) ? 1 : 0);
+	}
+
+	/**
+	 * 鐘舵�佷慨鏀�
+	 */
+	@PreAuthorize("@ss.hasPermi('system:oss:edit')")
+	@Log(title = "浜戝瓨鍌ㄧ姸鎬佷慨鏀�", businessType = BusinessType.UPDATE)
+	@PutMapping("/changeStatus")
+	public AjaxResult changeStatus(@RequestBody SysOssConfigBo bo) {
+		return toAjax(iSysOssConfigService.updateOssConfigStatus(bo));
+	}
+}
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/controller/SysOssController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
similarity index 74%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/controller/SysOssController.java
rename to ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
index 8a84c42..c7772ab 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/system/controller/SysOssController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
@@ -1,20 +1,26 @@
-package com.ruoyi.system.controller;
+package com.ruoyi.web.controller.system;
 
 
 import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.http.HttpUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.JsonUtils;
 import com.ruoyi.common.utils.file.FileUtils;
-import com.ruoyi.system.domain.bo.SysOssBo;
+import com.ruoyi.oss.constant.CloudConstant;
+import com.ruoyi.system.domain.SysConfig;
 import com.ruoyi.system.domain.SysOss;
-import com.ruoyi.system.service.ISysOssService;
+import com.ruoyi.system.domain.bo.SysOssBo;
 import com.ruoyi.system.domain.vo.SysOssVo;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ISysOssService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -49,6 +55,7 @@
 public class SysOssController extends BaseController {
 
 	private final ISysOssService iSysOssService;
+	private final ISysConfigService iSysConfigService;
 
 	/**
 	 * 鏌ヨOSS浜戝瓨鍌ㄥ垪琛�
@@ -72,8 +79,8 @@
 	@RepeatSubmit
 	@PostMapping("/upload")
 	public AjaxResult<Map<String, String>> upload(@RequestPart("file") MultipartFile file) {
-		if (file.isEmpty()) {
-			throw new CustomException("涓婁紶鏂囦欢涓嶈兘涓虹┖");
+		if (ObjectUtil.isNull(file)) {
+			throw new ServiceException("涓婁紶鏂囦欢涓嶈兘涓虹┖");
 		}
 		SysOss oss = iSysOssService.upload(file);
 		Map<String, String> map = new HashMap<>(2);
@@ -87,8 +94,8 @@
 	@GetMapping("/download/{ossId}")
 	public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
 		SysOss sysOss = iSysOssService.getById(ossId);
-		if (sysOss == null) {
-			throw new CustomException("鏂囦欢鏁版嵁涓嶅瓨鍦�!");
+		if (ObjectUtil.isNull(sysOss)) {
+			throw new ServiceException("鏂囦欢鏁版嵁涓嶅瓨鍦�!");
 		}
 		response.reset();
 		response.addHeader("Access-Control-Allow-Origin", "*");
@@ -111,4 +118,19 @@
 		return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true) ? 1 : 0);
 	}
 
+	/**
+	 * 鍙樻洿鍥剧墖鍒楄〃棰勮鐘舵��
+	 */
+	@ApiOperation("鍙樻洿鍥剧墖鍒楄〃棰勮鐘舵��")
+	@PreAuthorize("@ss.hasPermi('system:oss:edit')")
+	@Log(title = "OSS浜戝瓨鍌�" , businessType = BusinessType.UPDATE)
+	@PutMapping("/changePreviewListResource")
+	public AjaxResult<Void> changePreviewListResource(@RequestBody String body) {
+		Map<String, Boolean> map = JsonUtils.parseMap(body);
+		SysConfig config = iSysConfigService.getOne(new LambdaQueryWrapper<SysConfig>()
+			.eq(SysConfig::getConfigKey, CloudConstant.PEREVIEW_LIST_RESOURCE_KEY));
+		config.setConfigValue(map.get("previewListResource").toString());
+		return toAjax(iSysConfigService.updateConfig(config));
+	}
+
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
index b63c155..93d4d46 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -1,31 +1,25 @@
 package com.ruoyi.web.controller.system;
 
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.system.domain.SysPost;
 import com.ruoyi.system.service.ISysPostService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
 
 /**
  * 宀椾綅淇℃伅鎿嶄綔澶勭悊
- * 
+ *
  * @author ruoyi
  */
 @RestController
@@ -44,15 +38,14 @@
     {
         return postService.selectPagePostList(post);
     }
-    
+
     @Log(title = "宀椾綅绠$悊", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:post:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysPost post)
+    public void export(SysPost post, HttpServletResponse response)
     {
         List<SysPost> list = postService.selectPostList(post);
-        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
-        return util.exportExcel(list, "宀椾綅鏁版嵁");
+		ExcelUtil.exportExcel(list, "宀椾綅鏁版嵁", SysPost.class, response);
     }
 
     /**
@@ -81,7 +74,7 @@
         {
             return AjaxResult.error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
         }
-        post.setCreateBy(SecurityUtils.getUsername());
+        post.setCreateBy(getUsername());
         return toAjax(postService.insertPost(post));
     }
 
@@ -101,7 +94,7 @@
         {
             return AjaxResult.error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
         }
-        post.setUpdateBy(SecurityUtils.getUsername());
+        post.setUpdateBy(getUsername());
         return toAjax(postService.updatePost(post));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
index 39f5bc6..e106fa1 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -1,8 +1,6 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -11,8 +9,10 @@
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.domain.SysOss;
+import com.ruoyi.system.service.ISysOssService;
 import com.ruoyi.system.service.ISysUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -37,6 +37,9 @@
     @Autowired
     private TokenService tokenService;
 
+    @Autowired
+	private ISysOssService iSysOssService;
+
     /**
      * 涓汉淇℃伅
      */
@@ -59,12 +62,12 @@
     @PutMapping
     public AjaxResult updateProfile(@RequestBody SysUser user)
     {
-        if (StrUtil.isNotEmpty(user.getPhonenumber())
+        if (StringUtils.isNotEmpty(user.getPhonenumber())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
         {
             return AjaxResult.error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
         }
-        if (StrUtil.isNotEmpty(user.getEmail())
+        if (StringUtils.isNotEmpty(user.getEmail())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
         {
             return AjaxResult.error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
@@ -124,7 +127,8 @@
         if (!file.isEmpty())
         {
             LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
+			SysOss oss = iSysOssService.upload(file);
+			String avatar = oss.getUrl();
             if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
             {
 				Map<String,Object> ajax = new HashMap<>();
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
new file mode 100644
index 0000000..4c2cc7c
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
@@ -0,0 +1,38 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.model.RegisterBody;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.service.SysRegisterService;
+import com.ruoyi.system.service.ISysConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 娉ㄥ唽楠岃瘉
+ *
+ * @author ruoyi
+ */
+@RestController
+public class SysRegisterController extends BaseController
+{
+    @Autowired
+    private SysRegisterService registerService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @PostMapping("/register")
+    public AjaxResult register(@RequestBody RegisterBody user)
+    {
+        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
+        {
+            return error("褰撳墠绯荤粺娌℃湁寮�鍚敞鍐屽姛鑳斤紒");
+        }
+        String msg = registerService.register(user);
+        return StringUtils.isEmpty(msg) ? success() : error(msg);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
index 5701aa1..c8344b8 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -1,6 +1,5 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.lang.Validator;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
@@ -10,8 +9,8 @@
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.web.service.SysPermissionService;
 import com.ruoyi.framework.web.service.TokenService;
@@ -23,6 +22,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -56,11 +56,10 @@
     @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:role:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysRole role)
+    public void export(SysRole role, HttpServletResponse response)
     {
         List<SysRole> list = roleService.selectRoleList(role);
-        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
-        return util.exportExcel(list, "瑙掕壊鏁版嵁");
+		ExcelUtil.exportExcel(list, "瑙掕壊鏁版嵁", SysRole.class, response);
     }
 
     /**
@@ -89,7 +88,7 @@
         {
             return AjaxResult.error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
         }
-        role.setCreateBy(SecurityUtils.getUsername());
+        role.setCreateBy(getUsername());
         return toAjax(roleService.insertRole(role));
 
     }
@@ -111,13 +110,13 @@
         {
             return AjaxResult.error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
         }
-        role.setUpdateBy(SecurityUtils.getUsername());
+        role.setUpdateBy(getUsername());
 
         if (roleService.updateRole(role) > 0)
         {
             // 鏇存柊缂撳瓨鐢ㄦ埛鏉冮檺
             LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-            if (Validator.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
+            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
             {
                 loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
                 loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
@@ -149,7 +148,7 @@
     public AjaxResult changeStatus(@RequestBody SysRole role)
     {
         roleService.checkRoleAllowed(role);
-        role.setUpdateBy(SecurityUtils.getUsername());
+        role.setUpdateBy(getUsername());
         return toAjax(roleService.updateRoleStatus(role));
     }
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
index a67615f..9e0633c 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -1,10 +1,13 @@
 package com.ruoyi.web.controller.system;
 
-import cn.hutool.core.lang.Validator;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
@@ -12,8 +15,11 @@
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.domain.vo.SysUserExportVo;
+import com.ruoyi.system.domain.vo.SysUserImportVo;
 import com.ruoyi.system.service.ISysPostService;
 import com.ruoyi.system.service.ISysRoleService;
 import com.ruoyi.system.service.ISysUserService;
@@ -23,6 +29,8 @@
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -62,11 +70,19 @@
     @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:user:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysUser user)
+    public void export(SysUser user, HttpServletResponse response)
     {
         List<SysUser> list = userService.selectUserList(user);
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        return util.exportExcel(list, "鐢ㄦ埛鏁版嵁");
+		List<SysUserExportVo> listVo = BeanUtil.copyToList(list, SysUserExportVo.class);
+		for (int i = 0; i < list.size(); i++) {
+			SysDept dept = list.get(i).getDept();
+			SysUserExportVo vo = listVo.get(i);
+			if (ObjectUtil.isNotEmpty(dept)) {
+				vo.setDeptName(dept.getDeptName());
+				vo.setLeader(dept.getLeader());
+			}
+		}
+		ExcelUtil.exportExcel(listVo, "鐢ㄦ埛鏁版嵁", SysUserExportVo.class, response);
     }
 
     @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.IMPORT)
@@ -74,19 +90,18 @@
     @PostMapping("/importData")
     public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
     {
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        List<SysUser> userList = util.importExcel(file.getInputStream());
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+		List<SysUserImportVo> userListVo = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class);
+		List<SysUser> userList = BeanUtil.copyToList(userListVo, SysUser.class);
+		LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String operName = loginUser.getUsername();
         String message = userService.importUser(userList, updateSupport, operName);
         return AjaxResult.success(message);
     }
 
     @GetMapping("/importTemplate")
-    public AjaxResult importTemplate()
+    public void importTemplate(HttpServletResponse response)
     {
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        return util.importTemplateExcel("鐢ㄦ埛鏁版嵁");
+		ExcelUtil.exportExcel(new ArrayList<>(), "鐢ㄦ埛鏁版嵁", SysUserImportVo.class, response);
     }
 
     /**
@@ -100,7 +115,7 @@
         List<SysRole> roles = roleService.selectRoleAll();
         ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
         ajax.put("posts", postService.selectPostAll());
-        if (Validator.isNotNull(userId))
+        if (StringUtils.isNotNull(userId))
         {
             ajax.put("user", userService.selectUserById(userId));
             ajax.put("postIds", postService.selectPostListByUserId(userId));
@@ -121,17 +136,17 @@
         {
             return AjaxResult.error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
         }
-        else if (Validator.isNotEmpty(user.getPhonenumber())
+        else if (StringUtils.isNotEmpty(user.getPhonenumber())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
         {
             return AjaxResult.error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
         }
-        else if (Validator.isNotEmpty(user.getEmail())
+        else if (StringUtils.isNotEmpty(user.getEmail())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
         {
             return AjaxResult.error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
         }
-        user.setCreateBy(SecurityUtils.getUsername());
+        user.setCreateBy(getUsername());
         user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
         return toAjax(userService.insertUser(user));
     }
@@ -145,17 +160,17 @@
     public AjaxResult edit(@Validated @RequestBody SysUser user)
     {
         userService.checkUserAllowed(user);
-        if (Validator.isNotEmpty(user.getPhonenumber())
+        if (StringUtils.isNotEmpty(user.getPhonenumber())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
         {
             return AjaxResult.error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
         }
-        else if (Validator.isNotEmpty(user.getEmail())
+        else if (StringUtils.isNotEmpty(user.getEmail())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
         {
             return AjaxResult.error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
         }
-        user.setUpdateBy(SecurityUtils.getUsername());
+        user.setUpdateBy(getUsername());
         return toAjax(userService.updateUser(user));
     }
 
@@ -167,6 +182,10 @@
     @DeleteMapping("/{userIds}")
     public AjaxResult remove(@PathVariable Long[] userIds)
     {
+        if (ArrayUtil.contains(userIds, getUserId()))
+        {
+            return error("褰撳墠鐢ㄦ埛涓嶈兘鍒犻櫎");
+        }
         return toAjax(userService.deleteUserByIds(userIds));
     }
 
@@ -180,7 +199,7 @@
     {
         userService.checkUserAllowed(user);
         user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
-        user.setUpdateBy(SecurityUtils.getUsername());
+        user.setUpdateBy(getUsername());
         return toAjax(userService.resetPwd(user));
     }
 
@@ -193,7 +212,7 @@
     public AjaxResult changeStatus(@RequestBody SysUser user)
     {
         userService.checkUserAllowed(user);
-        user.setUpdateBy(SecurityUtils.getUsername());
+        user.setUpdateBy(getUsername());
         return toAjax(userService.updateUserStatus(user));
     }
 
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index 6491c85..7804994 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -4,7 +4,9 @@
     type: com.alibaba.druid.pool.DruidDataSource
     # 鍔ㄦ�佹暟鎹簮鏂囨。 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
     dynamic:
-      #璁剧疆榛樿鐨勬暟鎹簮鎴栬�呮暟鎹簮缁�,榛樿鍊煎嵆涓� master
+      # 鎬ц兘鍒嗘瀽鎻掍欢(鏈夋�ц兘鎹熻�� 涓嶅缓璁敓浜х幆澧冧娇鐢�)
+      p6spy: true
+      # 璁剧疆榛樿鐨勬暟鎹簮鎴栬�呮暟鎹簮缁�,榛樿鍊煎嵆涓� master
       primary: master
       datasource:
         # 涓诲簱鏁版嵁婧�
@@ -122,62 +124,11 @@
     admin:
       # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆
       client:
+        # 澧炲姞瀹㈡埛绔紑鍏�
+        enabled: true
         # 璁剧疆 Spring Boot Admin Server 鍦板潃
         url: http://localhost:9090/admin
         instance:
           prefer-ip: true # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP
         username: ruoyi
         password: 123456
-
-# Actuator 鐩戞帶绔偣鐨勯厤缃」
-management:
-  endpoints:
-    web:
-      # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator
-      base-path: /actuator
-      exposure:
-        # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广��
-        # 鐢熶骇鐜涓嶅缓璁斁寮�鎵�鏈� 鏍规嵁椤圭洰闇�姹傛斁寮�鍗冲彲
-        include: '*'
-  endpoint:
-    logfile:
-      external-file: ./logs/sys-console.log
-
---- # OSS 浜戝瓨鍌�(鐣岄潰 <鍙傛暟璁剧疆> 鍙垏鎹�)
-cloud-storage:
-  # minio閰嶇疆
-  minio:
-    endpoint: http://localhost:9000
-    accessKey: ruoyi
-    secretKey: ruoyi123
-    bucketName: ruoyi
-  # 涓冪墰浜戦厤缃�
-  qiniu:
-    domain: http://XXX.XXXX.com
-    prefix:
-    accessKey: XXXXXXXXXXXXXXX
-    secretKey: XXXXXXXXXXXXXXX
-    bucketName: ruoyi
-    isHttps: false
-    # z0 鍗庝笢  z1 鍗庡寳  z2 鍗庡崡  na0 鍖楃編  as0 涓滃崡浜�
-    # 涓嶅~涓鸿嚜鍔ㄨ幏鍙�(鎬ц兘浣� 鏄撳嚭闂)
-    region: z0
-  # 闃块噷浜戦厤缃�
-  aliyun:
-    endpoint: http://oss-cn-beijing.aliyuncs.com
-    prefix:
-    accessKeyId: XXXXXXXXXXXXXXX
-    accessKeySecret: XXXXXXXXXXXXXXX
-    bucketName: ruoyi
-  # 鑵捐浜戦厤缃�
-  qcloud:
-    endpoint: http://cos.ap-beijing.myqcloud.com
-    prefix:
-    secretId: XXXXXXXXXXXXXXX
-    secretKey: XXXXXXXXXXXXXXX
-    # 鑵捐浜慴ucket鍚嶈鍒� 鏍煎紡涓� BucketName-APPID 姝ゅ濉啓鐨勫瓨鍌ㄦ《鍚嶇О蹇呴』涓烘鏍煎紡
-    bucketName: ruoyi-1250000000
-    isHttps: false
-    # 鍦板煙鍚嶅弬鑰冨畼鏂规枃妗�
-    # https://cloud.tencent.com/document/product/436/6224
-    region: ap-beijing
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index 2640bc0..446d54d 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -4,7 +4,9 @@
     type: com.alibaba.druid.pool.DruidDataSource
     # 鍔ㄦ�佹暟鎹簮鏂囨。 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
     dynamic:
-      #璁剧疆榛樿鐨勬暟鎹簮鎴栬�呮暟鎹簮缁�,榛樿鍊煎嵆涓� master
+      # 鎬ц兘鍒嗘瀽鎻掍欢(鏈夋�ц兘鎹熻�� 涓嶅缓璁敓浜х幆澧冧娇鐢�)
+      p6spy: false
+      # 璁剧疆榛樿鐨勬暟鎹簮鎴栬�呮暟鎹簮缁�,榛樿鍊煎嵆涓� master
       primary: master
       datasource:
         # 涓诲簱鏁版嵁婧�
@@ -122,62 +124,11 @@
     admin:
       # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆
       client:
+        # 澧炲姞瀹㈡埛绔紑鍏�
+        enabled: true
         # 璁剧疆 Spring Boot Admin Server 鍦板潃
         url: http://172.30.0.90:9090/admin
         instance:
           prefer-ip: true # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP
         username: ruoyi
         password: 123456
-
-# Actuator 鐩戞帶绔偣鐨勯厤缃」
-management:
-  endpoints:
-    web:
-      # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator
-      base-path: /actuator
-      exposure:
-        # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广��
-        # 鐢熶骇鐜涓嶅缓璁斁寮�鎵�鏈� 鏍规嵁椤圭洰闇�姹傛斁寮�鍗冲彲
-        include: health,info
-  endpoint:
-    logfile:
-      external-file: ./logs/sys-console.log
-
---- # OSS 浜戝瓨鍌�(鐣岄潰 <鍙傛暟璁剧疆> 鍙垏鎹�)
-cloud-storage:
-  # minio閰嶇疆
-  minio:
-    endpoint: http://172.30.0.54:9000
-    accessKey: ruoyi
-    secretKey: ruoyi123
-    bucketName: ruoyi
-  # 涓冪墰浜戦厤缃�
-  qiniu:
-    domain: http://XXX.XXXX.com
-    prefix:
-    accessKey: XXXXXXXXXXXXXXX
-    secretKey: XXXXXXXXXXXXXXX
-    bucketName: ruoyi
-    isHttps: false
-    # z0 鍗庝笢  z1 鍗庡寳  z2 鍗庡崡  na0 鍖楃編  as0 涓滃崡浜�
-    # 涓嶅~涓鸿嚜鍔ㄨ幏鍙�(鎬ц兘浣� 鏄撳嚭闂)
-    region: z0
-  # 闃块噷浜戦厤缃�
-  aliyun:
-    endpoint: http://oss-cn-beijing.aliyuncs.com
-    prefix:
-    accessKeyId: XXXXXXXXXXXXXXX
-    accessKeySecret: XXXXXXXXXXXXXXX
-    bucketName: ruoyi
-  # 鑵捐浜戦厤缃�
-  qcloud:
-    endpoint: http://cos.ap-beijing.myqcloud.com
-    prefix:
-    secretId: XXXXXXXXXXXXXXX
-    secretKey: XXXXXXXXXXXXXXX
-    # 鑵捐浜慴ucket鍚嶈鍒� 鏍煎紡涓� BucketName-APPID 姝ゅ濉啓鐨勫瓨鍌ㄦ《鍚嶇О蹇呴』涓烘鏍煎紡
-    bucketName: ruoyi-1250000000
-    isHttps: false
-    # 鍦板煙鍚嶅弬鑰冨畼鏂规枃妗�
-    # https://cloud.tencent.com/document/product/436/6224
-    region: ap-beijing
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 4a52958..8b633f8 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -8,8 +8,6 @@
   copyrightYear: 2021
   # 瀹炰緥婕旂ず寮�鍏�
   demoEnabled: true
-  # 鏂囦欢璺緞
-  profile: ./ruoyi/uploadPath
   # 鑾峰彇ip鍦板潃寮�鍏�
   addressEnabled: true
 
@@ -107,6 +105,11 @@
   # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
   expireTime: 30
 
+# 閲嶅鎻愪氦
+repeat-submit:
+  # 鍏ㄥ眬闂撮殧鏃堕棿(姣)
+  intervalTime: 1000
+
 # MyBatisPlus閰嶇疆
 # https://baomidou.com/config/
 mybatis-plus:
@@ -159,8 +162,10 @@
     localCacheScope: SESSION
     # 寮�鍚疢ybatis浜岀骇缂撳瓨锛岄粯璁や负 true
     cacheEnabled: false
-    # 鏇磋缁嗙殑鏃ュ織杈撳嚭 浼氭湁鎬ц兘鎹熻��
-    # logImpl: org.apache.ibatis.logging.stdout.StdOutImpl
+    # 鏇磋缁嗙殑鏃ュ織杈撳嚭 浼氭湁鎬ц兘鎹熻�� org.apache.ibatis.logging.stdout.StdOutImpl
+    # 鍏抽棴鏃ュ織璁板綍 (鍙崟绾娇鐢� p6spy 鍒嗘瀽) org.apache.ibatis.logging.nologging.NoLoggingImpl
+    # 榛樿鏃ュ織杈撳嚭 org.apache.ibatis.logging.slf4j.Slf4jImpl
+    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
   global-config:
     # 鏄惁鎵撳嵃 Logo banner
     banner: true
@@ -223,7 +228,7 @@
   # 杩囨护寮�鍏�
   enabled: true
   # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
-  excludes: /system/notice/*
+  excludes: /system/notice
   # 鍖归厤閾炬帴
   urlPatterns: /system/*,/monitor/*,/tool/*
 
@@ -284,6 +289,20 @@
   # 鍒嗗竷寮忛攣鐨勮秴鏃舵椂闂达紝榛樿涓� 30 姣
   expire: 30000
 
+--- # Actuator 鐩戞帶绔偣鐨勯厤缃」
+management:
+  endpoints:
+    web:
+      # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator
+      base-path: /actuator
+      exposure:
+        # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广��
+        # 鐢熶骇鐜涓嶅缓璁斁寮�鎵�鏈� 鏍规嵁椤圭洰闇�姹傛斁寮�鍗冲彲
+        include: @endpoints.include@
+  endpoint:
+    logfile:
+      external-file: ./logs/sys-console.log
+
 --- # 瀹氭椂浠诲姟閰嶇疆
 spring:
   quartz:
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties
index d63aa1f..3e4694f 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -15,10 +15,11 @@
 
 user.username.not.valid=* 2鍒�20涓眽瀛椼�佸瓧姣嶃�佹暟瀛楁垨涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互闈炴暟瀛楀紑澶�
 user.password.not.valid=* 5-50涓瓧绗�
- 
+
 user.email.not.valid=閭鏍煎紡閿欒
 user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
 user.login.success=鐧诲綍鎴愬姛
+user.register.success=娉ㄥ唽鎴愬姛
 user.notfound=璇烽噸鏂扮櫥褰�
 user.forcelogout=绠$悊鍛樺己鍒堕��鍑猴紝璇烽噸鏂扮櫥褰�
 user.unknown.error=鏈煡閿欒锛岃閲嶆柊鐧诲綍
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
index 4187065..8a3fba3 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -16,8 +16,8 @@
 user.email.not.valid=
 user.mobile.phone.number.not.valid=
 user.login.success=
+user.register.success=register success
 user.notfound=
-user.forcelogout=
 user.unknown.error=
 
 ##鏂囦欢涓婁紶娑堟伅
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
index d63aa1f..3e4694f 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -15,10 +15,11 @@
 
 user.username.not.valid=* 2鍒�20涓眽瀛椼�佸瓧姣嶃�佹暟瀛楁垨涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互闈炴暟瀛楀紑澶�
 user.password.not.valid=* 5-50涓瓧绗�
- 
+
 user.email.not.valid=閭鏍煎紡閿欒
 user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
 user.login.success=鐧诲綍鎴愬姛
+user.register.success=娉ㄥ唽鎴愬姛
 user.notfound=璇烽噸鏂扮櫥褰�
 user.forcelogout=绠$悊鍛樺己鍒堕��鍑猴紝璇烽噸鏂扮櫥褰�
 user.unknown.error=鏈煡閿欒锛岃閲嶆柊鐧诲綍
diff --git a/ruoyi-admin/src/main/resources/spy.properties b/ruoyi-admin/src/main/resources/spy.properties
new file mode 100644
index 0000000..b361dbb
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/spy.properties
@@ -0,0 +1,26 @@
+# p6spy 性能分析插件配置文件
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+# 自定义日志打印
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#日志输出到控制台
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# 使用日志系统记录 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# 设置 p6spy driver 代理
+#deregisterdrivers=true
+# 取消JDBC URL前缀
+useprefix=true
+# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# 日期格式
+dateformat=yyyy-MM-dd HH:mm:ss
+# 实际驱动可多个
+#driverlist=org.h2.Driver
+# 是否开启慢SQL记录
+outagedetection=true
+# 慢SQL记录标准 2 秒
+outagedetectioninterval=2
+# 是否过滤 Log
+filter=true
+# 过滤 Log 时所排除的表名列表,以逗号分隔
+exclude=QRTZ_
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 016c457..c242a08 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -57,6 +57,11 @@
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
         </dependency>
 
         <!-- yml瑙f瀽鍣� -->
@@ -147,6 +152,11 @@
             <groupId>com.baomidou</groupId>
             <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
         </dependency>
+        <!-- sql鎬ц兘鍒嗘瀽鎻掍欢 -->
+        <dependency>
+            <groupId>p6spy</groupId>
+            <artifactId>p6spy</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>com.baomidou</groupId>
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
deleted file mode 100644
index 50482c5..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.ruoyi.common.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.math.BigDecimal;
-
-/**
- * 鑷畾涔夊鍑篍xcel鏁版嵁娉ㄨВ
- * 
- * @author ruoyi
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Excel
-{
-    /**
-     * 瀵煎嚭鏃跺湪excel涓帓搴�
-     */
-    public int sort() default Integer.MAX_VALUE;
-
-    /**
-     * 瀵煎嚭鍒癊xcel涓殑鍚嶅瓧.
-     */
-    public String name() default "";
-
-    /**
-     * 鏃ユ湡鏍煎紡, 濡�: yyyy-MM-dd
-     */
-    public String dateFormat() default "";
-
-    /**
-     * 濡傛灉鏄瓧鍏哥被鍨嬶紝璇疯缃瓧鍏哥殑type鍊� (濡�: sys_user_sex)
-     */
-    public String dictType() default "";
-
-    /**
-     * 璇诲彇鍐呭杞〃杈惧紡 (濡�: 0=鐢�,1=濂�,2=鏈煡)
-     */
-    public String readConverterExp() default "";
-
-    /**
-     * 鍒嗛殧绗︼紝璇诲彇瀛楃涓茬粍鍐呭
-     */
-    public String separator() default ",";
-
-    /**
-     * BigDecimal 绮惧害 榛樿:-1(榛樿涓嶅紑鍚疊igDecimal鏍煎紡鍖�)
-     */
-    public int scale() default -1;
-
-    /**
-     * BigDecimal 鑸嶅叆瑙勫垯 榛樿:BigDecimal.ROUND_HALF_EVEN
-     */
-    public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
-
-    /**
-     * 瀵煎嚭绫诲瀷锛�0鏁板瓧 1瀛楃涓诧級
-     */
-    public ColumnType cellType() default ColumnType.STRING;
-
-    /**
-     * 瀵煎嚭鏃跺湪excel涓瘡涓垪鐨勯珮搴� 鍗曚綅涓哄瓧绗�
-     */
-    public double height() default 14;
-
-    /**
-     * 瀵煎嚭鏃跺湪excel涓瘡涓垪鐨勫 鍗曚綅涓哄瓧绗�
-     */
-    public double width() default 16;
-
-    /**
-     * 鏂囧瓧鍚庣紑,濡�% 90 鍙樻垚90%
-     */
-    public String suffix() default "";
-
-    /**
-     * 褰撳�间负绌烘椂,瀛楁鐨勯粯璁ゅ��
-     */
-    public String defaultValue() default "";
-
-    /**
-     * 鎻愮ず淇℃伅
-     */
-    public String prompt() default "";
-
-    /**
-     * 璁剧疆鍙兘閫夋嫨涓嶈兘杈撳叆鐨勫垪鍐呭.
-     */
-    public String[] combo() default {};
-
-    /**
-     * 鏄惁瀵煎嚭鏁版嵁,搴斿闇�姹�:鏈夋椂鎴戜滑闇�瑕佸鍑轰竴浠芥ā鏉�,杩欐槸鏍囬闇�瑕佷絾鍐呭闇�瑕佺敤鎴锋墜宸ュ~鍐�.
-     */
-    public boolean isExport() default true;
-
-    /**
-     * 鍙︿竴涓被涓殑灞炴�у悕绉�,鏀寔澶氱骇鑾峰彇,浠ュ皬鏁扮偣闅斿紑
-     */
-    public String targetAttr() default "";
-
-    /**
-     * 鏄惁鑷姩缁熻鏁版嵁,鍦ㄦ渶鍚庤拷鍔犱竴琛岀粺璁℃暟鎹�诲拰
-     */
-    public boolean isStatistics() default false;
-
-    /**
-     * 瀵煎嚭瀛楁瀵归綈鏂瑰紡锛�0锛氶粯璁わ紱1锛氶潬宸︼紱2锛氬眳涓紱3锛氶潬鍙筹級
-     */
-    Align align() default Align.AUTO;
-
-    public enum Align
-    {
-        AUTO(0), LEFT(1), CENTER(2), RIGHT(3);
-        private final int value;
-
-        Align(int value)
-        {
-            this.value = value;
-        }
-
-        public int value()
-        {
-            return this.value;
-        }
-    }
-
-    /**
-     * 瀛楁绫诲瀷锛�0锛氬鍑哄鍏ワ紱1锛氫粎瀵煎嚭锛�2锛氫粎瀵煎叆锛�
-     */
-    Type type() default Type.ALL;
-
-    public enum Type
-    {
-        ALL(0), EXPORT(1), IMPORT(2);
-        private final int value;
-
-        Type(int value)
-        {
-            this.value = value;
-        }
-
-        public int value()
-        {
-            return this.value;
-        }
-    }
-
-    public enum ColumnType
-    {
-        NUMERIC(0), STRING(1), IMAGE(2);
-        private final int value;
-
-        ColumnType(int value)
-        {
-            this.value = value;
-        }
-
-        public int value()
-        {
-            return this.value;
-        }
-    }
-}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java
new file mode 100644
index 0000000..a51116b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java
@@ -0,0 +1,30 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 瀛楀吀鏍煎紡鍖�
+ *
+ * @author Lion Li
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExcelDictFormat {
+
+	/**
+	 * 濡傛灉鏄瓧鍏哥被鍨嬶紝璇疯缃瓧鍏哥殑type鍊� (濡�: sys_user_sex)
+	 */
+	String dictType() default "";
+
+	/**
+	 * 璇诲彇鍐呭杞〃杈惧紡 (濡�: 0=鐢�,1=濂�,2=鏈煡)
+	 */
+	String readConverterExp() default "";
+
+	/**
+	 * 鍒嗛殧绗︼紝璇诲彇瀛楃涓茬粍鍐呭
+	 */
+	String separator() default ",";
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
deleted file mode 100644
index 940763f..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.common.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Excel娉ㄨВ闆�
- * 
- * @author ruoyi
- */
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Excels
-{
-    Excel[] value();
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
new file mode 100644
index 0000000..5642038
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
@@ -0,0 +1,40 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.enums.LimitType;
+
+/**
+ * 闄愭祦娉ㄨВ
+ * 
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RateLimiter
+{
+    /**
+     * 闄愭祦key
+     */
+    public String key() default Constants.RATE_LIMIT_KEY;
+
+    /**
+     * 闄愭祦鏃堕棿,鍗曚綅绉�
+     */
+    public int time() default 60;
+
+    /**
+     * 闄愭祦娆℃暟
+     */
+    public int count() default 100;
+
+    /**
+     * 闄愭祦绫诲瀷
+     */
+    public LimitType limitType() default LimitType.DEFAULT;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
index 628eef1..c2bbee4 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
@@ -1,23 +1,29 @@
-package com.ruoyi.common.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 鑷畾涔夋敞瑙i槻姝㈣〃鍗曢噸澶嶆彁浜�
- * 
- * @author ruoyi
- *
- */
-@Inherited
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface RepeatSubmit
-{
-
-}
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 鑷畾涔夋敞瑙i槻姝㈣〃鍗曢噸澶嶆彁浜�
+ *
+ * @author Lion Li
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit {
+
+	/**
+	 * 榛樿浣跨敤鍏ㄥ眬閰嶇疆
+	 */
+	int intervalTime() default 0;
+
+	TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
index 682bebd..408295a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -9,7 +9,7 @@
 
 /**
  * 璇诲彇椤圭洰鐩稿叧閰嶇疆
- * 
+ *
  * @author ruoyi
  */
 
@@ -32,45 +32,13 @@
     /** 瀹炰緥婕旂ず寮�鍏� */
     private boolean demoEnabled;
 
-    /** 涓婁紶璺緞 */
-    @Getter
-    private static String profile;
-
     /** 鑾峰彇鍦板潃寮�鍏� */
     @Getter
     private static boolean addressEnabled;
-
-    public void setProfile(String profile)
-    {
-        RuoYiConfig.profile = profile;
-    }
 
     public void setAddressEnabled(boolean addressEnabled)
     {
         RuoYiConfig.addressEnabled = addressEnabled;
     }
 
-    /**
-     * 鑾峰彇澶村儚涓婁紶璺緞
-     */
-    public static String getAvatarPath()
-    {
-        return getProfile() + "/avatar";
-    }
-
-    /**
-     * 鑾峰彇涓嬭浇璺緞
-     */
-    public static String getDownloadPath()
-    {
-        return getProfile() + "/download/";
-    }
-
-    /**
-     * 鑾峰彇涓婁紶璺緞
-     */
-    public static String getUploadPath()
-    {
-        return getProfile() + "/upload";
-    }
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
index a871178..c1a6469 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -1,5 +1,7 @@
 package com.ruoyi.common.constant;
 
+import io.jsonwebtoken.Claims;
+
 /**
  * 閫氱敤甯搁噺淇℃伅
  *
@@ -48,6 +50,11 @@
     public static final String LOGOUT = "Logout";
 
     /**
+     * 娉ㄥ唽
+     */
+    public static final String REGISTER = "Register";
+
+    /**
      * 鐧诲綍澶辫触
      */
     public static final String LOGIN_FAIL = "Error";
@@ -66,6 +73,11 @@
      * 闃查噸鎻愪氦 redis key
      */
     public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+    /**
+     * 闄愭祦 redis key
+     */
+    public static final String RATE_LIMIT_KEY = "rate_limit:";
 
     /**
      * 楠岃瘉鐮佹湁鏁堟湡锛堝垎閽燂級
@@ -95,7 +107,7 @@
     /**
      * 鐢ㄦ埛鍚嶇О
      */
-    public static final String JWT_USERNAME = "sub";
+    public static final String JWT_USERNAME = Claims.SUBJECT;
 
     /**
      * 鐢ㄦ埛澶村儚
@@ -122,18 +134,9 @@
      */
     public static final String SYS_DICT_KEY = "sys_dict:";
 
-    /**
-     * 璧勬簮鏄犲皠璺緞 鍓嶇紑
-     */
-    public static final String RESOURCE_PREFIX = "/profile";
-
 	/**
 	 * RMI 杩滅▼鏂规硶璋冪敤
 	 */
 	public static final String LOOKUP_RMI = "rmi://";
 
-	/**
-	 * 璧勬簮鏄犲皠璺緞 鍓嶇紑
-	 */
-	public static final String REDIS_LOCK_KEY = "redis_lock:";
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
index eda4ab6..a936cd8 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -63,4 +63,16 @@
     /** 鏍¢獙杩斿洖缁撴灉鐮� */
     public final static String UNIQUE = "0";
     public final static String NOT_UNIQUE = "1";
+
+    /**
+     * 鐢ㄦ埛鍚嶉暱搴﹂檺鍒�
+     */
+    public static final int USERNAME_MIN_LENGTH = 2;
+    public static final int USERNAME_MAX_LENGTH = 20;
+
+    /**
+     * 瀵嗙爜闀垮害闄愬埗
+     */
+    public static final int PASSWORD_MIN_LENGTH = 5;
+    public static final int PASSWORD_MAX_LENGTH = 20;
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java b/ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java
new file mode 100644
index 0000000..58560d0
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java
@@ -0,0 +1,69 @@
+package com.ruoyi.common.convert;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.convert.Convert;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+
+/**
+ * 瀛楀吀鏍煎紡鍖栬浆鎹㈠鐞�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class ExcelDictConvert implements Converter<Object> {
+
+	@Override
+	public Class<Object> supportJavaTypeKey() {
+		return Object.class;
+	}
+
+	@Override
+	public CellDataTypeEnum supportExcelTypeKey() {
+		return null;
+	}
+
+	@Override
+	public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+		ExcelDictFormat anno = getAnnotation(contentProperty.getField());
+		String type = anno.dictType();
+		String label = cellData.getStringValue();
+		String value;
+		if (StringUtils.isBlank(type)) {
+			value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator());
+		} else {
+			value = ExcelUtil.reverseDictByExp(label, type, anno.separator());
+		}
+		return Convert.convert(contentProperty.getField().getType(), value);
+	}
+
+	@Override
+	public CellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+		if (StringUtils.isNull(object)) {
+			return new CellData<>("");
+		}
+		ExcelDictFormat anno = getAnnotation(contentProperty.getField());
+		String type = anno.dictType();
+		String value = Convert.toStr(object);
+		String label;
+		if (StringUtils.isBlank(type)) {
+			label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator());
+		} else {
+			label = ExcelUtil.convertDictByExp(value, type, anno.separator());
+		}
+		return new CellData<>(label);
+	}
+
+	private ExcelDictFormat getAnnotation(Field field) {
+		return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class);
+	}
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
index 632c0fb..3915867 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -1,7 +1,9 @@
 package com.ruoyi.common.core.controller;
 
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,6 +75,38 @@
      */
     public String redirect(String url)
     {
-        return StrUtil.format("redirect:{}", url);
+        return StringUtils.format("redirect:{}", url);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛缂撳瓨淇℃伅
+     */
+    public LoginUser getLoginUser()
+    {
+        return SecurityUtils.getLoginUser();
+    }
+
+    /**
+     * 鑾峰彇鐧诲綍鐢ㄦ埛id
+     */
+    public Long getUserId()
+    {
+        return getLoginUser().getUserId();
+    }
+
+    /**
+     * 鑾峰彇鐧诲綍閮ㄩ棬id
+     */
+    public Long getDeptId()
+    {
+        return getLoginUser().getDeptId();
+    }
+
+    /**
+     * 鑾峰彇鐧诲綍鐢ㄦ埛鍚�
+     */
+    public String getUsername()
+    {
+        return getLoginUser().getUsername();
     }
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
index d66686b..72d624a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -1,5 +1,6 @@
 package com.ruoyi.common.core.domain;
 
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -18,29 +19,50 @@
 @Data
 @NoArgsConstructor
 @Accessors(chain = true)
-public class BaseEntity implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+public class BaseEntity implements Serializable {
 
-    /** 鎼滅储鍊� */
-    private String searchValue;
+	private static final long serialVersionUID = 1L;
 
-    /** 鍒涘缓鑰� */
-    private String createBy;
+	/**
+	 * 鎼滅储鍊�
+	 */
+	@ApiModelProperty(value = "鎼滅储鍊�")
+	private String searchValue;
 
-    /** 鍒涘缓鏃堕棿 */
-    private Date createTime;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@ApiModelProperty(value = "鍒涘缓鑰�")
+	private String createBy;
 
-    /** 鏇存柊鑰� */
-    private String updateBy;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@ApiModelProperty(value = "鍒涘缓鏃堕棿")
+	private Date createTime;
 
-    /** 鏇存柊鏃堕棿 */
-    private Date updateTime;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@ApiModelProperty(value = "鏇存柊鑰�")
+	private String updateBy;
 
-    /** 澶囨敞 */
-    private String remark;
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@ApiModelProperty(value = "鏇存柊鏃堕棿")
+	private Date updateTime;
 
-    /** 璇锋眰鍙傛暟 */
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 澶囨敞
+	 */
+	@ApiModelProperty(value = "澶囨敞")
+	private String remark;
+
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@ApiModelProperty(value = "璇锋眰鍙傛暟")
+	private Map<String, Object> params = new HashMap<>();
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
index 2569fac..8db10aa 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
@@ -1,38 +1,56 @@
-package com.ruoyi.common.core.domain;
-
-import lombok.*;
-import lombok.experimental.Accessors;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tree鍩虹被
- * 
- * @author ruoyi
- */
-
-@EqualsAndHashCode(callSuper = true)
-@Data
-@NoArgsConstructor
-@Accessors(chain = true)
-public class TreeEntity extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 鐖惰彍鍗曞悕绉� */
-    private String parentName;
-
-    /** 鐖惰彍鍗旾D */
-    private Long parentId;
-
-    /** 鏄剧ず椤哄簭 */
-    private Integer orderNum;
-
-    /** 绁栫骇鍒楄〃 */
-    private String ancestors;
-
-    /** 瀛愰儴闂� */
-    private List<?> children = new ArrayList<>();
-
-}
+package com.ruoyi.common.core.domain;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree鍩虹被
+ *
+ * @author ruoyi
+ */
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@NoArgsConstructor
+@Accessors(chain = true)
+public class TreeEntity extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 鐖惰彍鍗曞悕绉�
+	 */
+	@ApiModelProperty(value = "鐖惰彍鍗曞悕绉�")
+	private String parentName;
+
+	/**
+	 * 鐖惰彍鍗旾D
+	 */
+	@ApiModelProperty(value = "鐖惰彍鍗旾D")
+	private Long parentId;
+
+	/**
+	 * 鏄剧ず椤哄簭
+	 */
+	@ApiModelProperty(value = "鏄剧ず椤哄簭")
+	private Integer orderNum;
+
+	/**
+	 * 绁栫骇鍒楄〃
+	 */
+	@ApiModelProperty(value = "绁栫骇鍒楄〃")
+	private String ancestors;
+
+	/**
+	 * 瀛愰儴闂�
+	 */
+	@ApiModelProperty(value = "瀛愰儴闂�")
+	private List<?> children = new ArrayList<>();
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
index 72240bc..62056e0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
@@ -1,7 +1,6 @@
 package com.ruoyi.common.core.domain.entity;
 
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -14,7 +13,7 @@
 
 /**
  * 閮ㄩ棬琛� sys_dept
- * 
+ *
  * @author ruoyi
  */
 
@@ -22,78 +21,107 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_dept")
-public class SysDept implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+public class SysDept implements Serializable {
+	private static final long serialVersionUID = 1L;
 
-    /** 閮ㄩ棬ID */
-    @TableId(value = "dept_id",type = IdType.AUTO)
-    private Long deptId;
+	/**
+	 * 閮ㄩ棬ID
+	 */
+	@TableId(value = "dept_id", type = IdType.AUTO)
+	private Long deptId;
 
-    /** 鐖堕儴闂↖D */
-    private Long parentId;
+	/**
+	 * 鐖堕儴闂↖D
+	 */
+	private Long parentId;
 
-    /** 绁栫骇鍒楄〃 */
-    private String ancestors;
+	/**
+	 * 绁栫骇鍒楄〃
+	 */
+	private String ancestors;
 
-    /** 閮ㄩ棬鍚嶇О */
-    @NotBlank(message = "閮ㄩ棬鍚嶇О涓嶈兘涓虹┖")
-    @Size(min = 0, max = 30, message = "閮ㄩ棬鍚嶇О闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
-    private String deptName;
+	/**
+	 * 閮ㄩ棬鍚嶇О
+	 */
+	@NotBlank(message = "閮ㄩ棬鍚嶇О涓嶈兘涓虹┖")
+	@Size(min = 0, max = 30, message = "閮ㄩ棬鍚嶇О闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
+	private String deptName;
 
-    /** 鏄剧ず椤哄簭 */
-    @NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
-    private String orderNum;
+	/**
+	 * 鏄剧ず椤哄簭
+	 */
+	@NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+	private String orderNum;
 
-    /** 璐熻矗浜� */
-    private String leader;
+	/**
+	 * 璐熻矗浜�
+	 */
+	private String leader;
 
-    /** 鑱旂郴鐢佃瘽 */
-    @Size(min = 0, max = 11, message = "鑱旂郴鐢佃瘽闀垮害涓嶈兘瓒呰繃11涓瓧绗�")
-    private String phone;
+	/**
+	 * 鑱旂郴鐢佃瘽
+	 */
+	@Size(min = 0, max = 11, message = "鑱旂郴鐢佃瘽闀垮害涓嶈兘瓒呰繃11涓瓧绗�")
+	private String phone;
 
-    /** 閭 */
-    @Email(message = "閭鏍煎紡涓嶆纭�")
-    @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
-    private String email;
+	/**
+	 * 閭
+	 */
+	@Email(message = "閭鏍煎紡涓嶆纭�")
+	@Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+	private String email;
 
-    /** 閮ㄩ棬鐘舵��:0姝e父,1鍋滅敤 */
-    private String status;
+	/**
+	 * 閮ㄩ棬鐘舵��:0姝e父,1鍋滅敤
+	 */
+	private String status;
 
-    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
-    @TableLogic
-    private String delFlag;
+	/**
+	 * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+	 */
+	@TableLogic
+	private String delFlag;
 
-    /** 鐖堕儴闂ㄥ悕绉� */
-    @TableField(exist = false)
-    private String parentName;
+	/**
+	 * 鐖堕儴闂ㄥ悕绉�
+	 */
+	@TableField(exist = false)
+	private String parentName;
 
-    /** 鍒涘缓鑰� */
-    @TableField(fill = FieldFill.INSERT)
-    private String createBy;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
 
-    /** 鍒涘缓鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createTime;
 
-    /** 鏇存柊鑰� */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateBy;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private String updateBy;
 
-    /** 鏇存柊鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date updateTime;
-    
-    /** 瀛愰儴闂� */
-    @TableField(exist = false)
-    private List<SysDept> children = new ArrayList<SysDept>();
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
 
-    /**
-     * 璇锋眰鍙傛暟
-     */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 瀛愰儴闂�
+	 */
+	@TableField(exist = false)
+	private List<SysDept> children = new ArrayList<SysDept>();
+
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@TableField(exist = false)
+	private Map<String, Object> params = new HashMap<>();
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
index c98f9fc..e8bc0f1 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
@@ -1,10 +1,11 @@
 package com.ruoyi.common.core.domain.entity;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
 import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -18,7 +19,7 @@
 
 /**
  * 瀛楀吀鏁版嵁琛� sys_dict_data
- * 
+ *
  * @author ruoyi
  */
 
@@ -26,82 +27,109 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_dict_data")
-public class SysDictData implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+@ExcelIgnoreUnannotated
+public class SysDictData implements Serializable {
+	private static final long serialVersionUID = 1L;
 
-    /** 瀛楀吀缂栫爜 */
-    @Excel(name = "瀛楀吀缂栫爜", cellType = ColumnType.NUMERIC)
-    @TableId(value = "dict_code",type = IdType.AUTO)
-    private Long dictCode;
+	/**
+	 * 瀛楀吀缂栫爜
+	 */
+	@ExcelProperty(value = "瀛楀吀缂栫爜")
+	@TableId(value = "dict_code", type = IdType.AUTO)
+	private Long dictCode;
 
-    /** 瀛楀吀鎺掑簭 */
-    @Excel(name = "瀛楀吀鎺掑簭", cellType = ColumnType.NUMERIC)
-    private Long dictSort;
+	/**
+	 * 瀛楀吀鎺掑簭
+	 */
+	@ExcelProperty(value = "瀛楀吀鎺掑簭")
+	private Long dictSort;
 
-    /** 瀛楀吀鏍囩 */
-    @Excel(name = "瀛楀吀鏍囩")
-    @NotBlank(message = "瀛楀吀鏍囩涓嶈兘涓虹┖")
-    @Size(min = 0, max = 100, message = "瀛楀吀鏍囩闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
-    private String dictLabel;
+	/**
+	 * 瀛楀吀鏍囩
+	 */
+	@ExcelProperty(value = "瀛楀吀鏍囩")
+	@NotBlank(message = "瀛楀吀鏍囩涓嶈兘涓虹┖")
+	@Size(min = 0, max = 100, message = "瀛楀吀鏍囩闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+	private String dictLabel;
 
-    /** 瀛楀吀閿�� */
-    @Excel(name = "瀛楀吀閿��")
-    @NotBlank(message = "瀛楀吀閿�间笉鑳戒负绌�")
-    @Size(min = 0, max = 100, message = "瀛楀吀閿�奸暱搴︿笉鑳借秴杩�100涓瓧绗�")
-    private String dictValue;
+	/**
+	 * 瀛楀吀閿��
+	 */
+	@ExcelProperty(value = "瀛楀吀閿��")
+	@NotBlank(message = "瀛楀吀閿�间笉鑳戒负绌�")
+	@Size(min = 0, max = 100, message = "瀛楀吀閿�奸暱搴︿笉鑳借秴杩�100涓瓧绗�")
+	private String dictValue;
 
-    /** 瀛楀吀绫诲瀷 */
-    @Excel(name = "瀛楀吀绫诲瀷")
-    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
-    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
-    private String dictType;
+	/**
+	 * 瀛楀吀绫诲瀷
+	 */
+	@ExcelProperty(value = "瀛楀吀绫诲瀷")
+	@NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+	@Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+	private String dictType;
 
-    /** 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛� */
-    @Size(min = 0, max = 100, message = "鏍峰紡灞炴�ч暱搴︿笉鑳借秴杩�100涓瓧绗�")
-    private String cssClass;
+	/**
+	 * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+	 */
+	@Size(min = 0, max = 100, message = "鏍峰紡灞炴�ч暱搴︿笉鑳借秴杩�100涓瓧绗�")
+	private String cssClass;
 
-    /** 琛ㄦ牸瀛楀吀鏍峰紡 */
-    private String listClass;
+	/**
+	 * 琛ㄦ牸瀛楀吀鏍峰紡
+	 */
+	private String listClass;
 
-    /** 鏄惁榛樿锛圷鏄� N鍚︼級 */
-    @Excel(name = "鏄惁榛樿", readConverterExp = "Y=鏄�,N=鍚�")
-    private String isDefault;
+	/**
+	 * 鏄惁榛樿锛圷鏄� N鍚︼級
+	 */
+	@ExcelProperty(value = "鏄惁榛樿", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_yes_no")
+	private String isDefault;
 
-    /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
-    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
-    private String status;
+	/**
+	 * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+	 */
+	@ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
+	private String status;
 
-    /** 鍒涘缓鑰� */
-    @TableField(fill = FieldFill.INSERT)
-    private String createBy;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
 
-    /** 鍒涘缓鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createTime;
 
-    /** 鏇存柊鑰� */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateBy;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private String updateBy;
 
-    /** 鏇存柊鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date updateTime;
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
 
-    /** 澶囨敞 */
-    private String remark;
+	/**
+	 * 澶囨敞
+	 */
+	private String remark;
 
-    /**
-     * 璇锋眰鍙傛暟
-     */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@TableField(exist = false)
+	private Map<String, Object> params = new HashMap<>();
 
-    public boolean getDefault()
-    {
-        return UserConstants.YES.equals(this.isDefault) ? true : false;
-    }
+	public boolean getDefault() {
+		return UserConstants.YES.equals(this.isDefault) ? true : false;
+	}
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
index 48ed252..1108671 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
@@ -1,9 +1,10 @@
 package com.ruoyi.common.core.domain.entity;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -17,7 +18,7 @@
 
 /**
  * 瀛楀吀绫诲瀷琛� sys_dict_type
- * 
+ *
  * @author ruoyi
  */
 
@@ -25,56 +26,73 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_dict_type")
-public class SysDictType implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+@ExcelIgnoreUnannotated
+public class SysDictType implements Serializable {
+	private static final long serialVersionUID = 1L;
 
-    /** 瀛楀吀涓婚敭 */
-    @Excel(name = "瀛楀吀涓婚敭", cellType = ColumnType.NUMERIC)
-    @TableId(value = "dict_id",type = IdType.AUTO)
-    private Long dictId;
+	/**
+	 * 瀛楀吀涓婚敭
+	 */
+	@ExcelProperty(value = "瀛楀吀涓婚敭")
+	@TableId(value = "dict_id", type = IdType.AUTO)
+	private Long dictId;
 
-    /** 瀛楀吀鍚嶇О */
-    @Excel(name = "瀛楀吀鍚嶇О")
-    @NotBlank(message = "瀛楀吀鍚嶇О涓嶈兘涓虹┖")
-    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷鍚嶇О闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
-    private String dictName;
+	/**
+	 * 瀛楀吀鍚嶇О
+	 */
+	@ExcelProperty(value = "瀛楀吀鍚嶇О")
+	@NotBlank(message = "瀛楀吀鍚嶇О涓嶈兘涓虹┖")
+	@Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷鍚嶇О闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+	private String dictName;
 
-    /** 瀛楀吀绫诲瀷 */
-    @Excel(name = "瀛楀吀绫诲瀷")
-    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
-    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
-    private String dictType;
+	/**
+	 * 瀛楀吀绫诲瀷
+	 */
+	@ExcelProperty(value = "瀛楀吀绫诲瀷")
+	@NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+	@Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+	private String dictType;
 
-    /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
-    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
-    private String status;
+	/**
+	 * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+	 */
+	@ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
+	private String status;
 
-    /** 鍒涘缓鑰� */
-    @TableField(fill = FieldFill.INSERT)
-    private String createBy;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
 
-    /** 鍒涘缓鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createTime;
 
-    /** 鏇存柊鑰� */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateBy;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private String updateBy;
 
-    /** 鏇存柊鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date updateTime;
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
 
-    /** 澶囨敞 */
-    private String remark;
+	/**
+	 * 澶囨敞
+	 */
+	private String remark;
 
-    /**
-     * 璇锋眰鍙傛暟
-     */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@TableField(exist = false)
+	private Map<String, Object> params = new HashMap<>();
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
index b9d0e8d..6fc8641 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
@@ -13,7 +13,7 @@
 
 /**
  * 鑿滃崟鏉冮檺琛� sys_menu
- * 
+ *
  * @author ruoyi
  */
 
@@ -21,88 +21,129 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_menu")
-public class SysMenu implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+public class SysMenu implements Serializable {
+	private static final long serialVersionUID = 1L;
 
-    /** 鑿滃崟ID */
-    @TableId(value = "menu_id",type = IdType.AUTO)
-    private Long menuId;
+	/**
+	 * 鑿滃崟ID
+	 */
+	@TableId(value = "menu_id", type = IdType.AUTO)
+	private Long menuId;
 
-    /** 鑿滃崟鍚嶇О */
-    @NotBlank(message = "鑿滃崟鍚嶇О涓嶈兘涓虹┖")
-    @Size(min = 0, max = 50, message = "鑿滃崟鍚嶇О闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
-    private String menuName;
+	/**
+	 * 鑿滃崟鍚嶇О
+	 */
+	@NotBlank(message = "鑿滃崟鍚嶇О涓嶈兘涓虹┖")
+	@Size(min = 0, max = 50, message = "鑿滃崟鍚嶇О闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+	private String menuName;
 
-    /** 鐖惰彍鍗曞悕绉� */
-    @TableField(exist = false)
-    private String parentName;
+	/**
+	 * 鐖惰彍鍗曞悕绉�
+	 */
+	@TableField(exist = false)
+	private String parentName;
 
-    /** 鐖惰彍鍗旾D */
-    private Long parentId;
+	/**
+	 * 鐖惰彍鍗旾D
+	 */
+	private Long parentId;
 
-    /** 鏄剧ず椤哄簭 */
-    @NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
-    private String orderNum;
+	/**
+	 * 鏄剧ず椤哄簭
+	 */
+	@NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+	private String orderNum;
 
-    /** 璺敱鍦板潃 */
-    @Size(min = 0, max = 200, message = "璺敱鍦板潃涓嶈兘瓒呰繃200涓瓧绗�")
-    private String path;
+	/**
+	 * 璺敱鍦板潃
+	 */
+	@Size(min = 0, max = 200, message = "璺敱鍦板潃涓嶈兘瓒呰繃200涓瓧绗�")
+	private String path;
 
-    /** 缁勪欢璺緞 */
-    @Size(min = 0, max = 200, message = "缁勪欢璺緞涓嶈兘瓒呰繃255涓瓧绗�")
-    private String component;
+	/**
+	 * 缁勪欢璺緞
+	 */
+	@Size(min = 0, max = 200, message = "缁勪欢璺緞涓嶈兘瓒呰繃255涓瓧绗�")
+	private String component;
 
-    /** 鏄惁涓哄閾撅紙0鏄� 1鍚︼級 */
-    private String isFrame;
+	/**
+	 * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+	 */
+	private String isFrame;
 
-    /** 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級 */
-    private String isCache;
+	/**
+	 * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+	 */
+	private String isCache;
 
-    /** 绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛� */
-    @NotBlank(message = "鑿滃崟绫诲瀷涓嶈兘涓虹┖")
-    private String menuType;
+	/**
+	 * 绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+	 */
+	@NotBlank(message = "鑿滃崟绫诲瀷涓嶈兘涓虹┖")
+	private String menuType;
 
-    /** 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛� */
-    private String visible;
-    
-    /** 鑿滃崟鐘舵�侊紙0鏄剧ず 1闅愯棌锛� */
-    private String status;
+	/**
+	 * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+	 */
+	private String visible;
 
-    /** 鏉冮檺瀛楃涓� */
-    @Size(min = 0, max = 100, message = "鏉冮檺鏍囪瘑闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
-    private String perms;
+	/**
+	 * 鑿滃崟鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+	 */
+	private String status;
 
-    /** 鑿滃崟鍥炬爣 */
-    private String icon;
+	/**
+	 * 鏉冮檺瀛楃涓�
+	 */
+	@Size(min = 0, max = 100, message = "鏉冮檺鏍囪瘑闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+	private String perms;
 
-    /** 鍒涘缓鑰� */
-    @TableField(fill = FieldFill.INSERT)
-    private String createBy;
+	/**
+	 * 鑿滃崟鍥炬爣
+	 */
+	private String icon;
 
-    /** 鍒涘缓鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
 
-    /** 鏇存柊鑰� */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateBy;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	private Date createTime;
 
-    /** 鏇存柊鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date updateTime;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private String updateBy;
 
-    /** 澶囨敞 */
-    private String remark;
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+	private Date updateTime;
 
-    /** 璇锋眰鍙傛暟 */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 澶囨敞
+	 */
+	private String remark;
 
-    /** 瀛愯彍鍗� */
-    @TableField(exist = false)
-    private List<SysMenu> children = new ArrayList<SysMenu>();
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@TableField(exist = false)
+	private Map<String, Object> params = new HashMap<>();
+
+	/**
+	 * 瀛愯彍鍗�
+	 */
+	@TableField(exist = false)
+	private List<SysMenu> children = new ArrayList<SysMenu>();
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
index a658559..5163524 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
@@ -1,9 +1,10 @@
 package com.ruoyi.common.core.domain.entity;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -25,102 +26,133 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_role")
-public class SysRole implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+@ExcelIgnoreUnannotated
+public class SysRole implements Serializable {
+	private static final long serialVersionUID = 1L;
 
-    /** 瑙掕壊ID */
-    @Excel(name = "瑙掕壊搴忓彿", cellType = ColumnType.NUMERIC)
-    @TableId(value = "role_id",type = IdType.AUTO)
-    private Long roleId;
+	/**
+	 * 瑙掕壊ID
+	 */
+	@ExcelProperty(value = "瑙掕壊搴忓彿")
+	@TableId(value = "role_id", type = IdType.AUTO)
+	private Long roleId;
 
-    /** 瑙掕壊鍚嶇О */
-    @Excel(name = "瑙掕壊鍚嶇О")
-    @NotBlank(message = "瑙掕壊鍚嶇О涓嶈兘涓虹┖")
-    @Size(min = 0, max = 30, message = "瑙掕壊鍚嶇О闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
-    private String roleName;
+	/**
+	 * 瑙掕壊鍚嶇О
+	 */
+	@ExcelProperty(value = "瑙掕壊鍚嶇О")
+	@NotBlank(message = "瑙掕壊鍚嶇О涓嶈兘涓虹┖")
+	@Size(min = 0, max = 30, message = "瑙掕壊鍚嶇О闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
+	private String roleName;
 
-    /** 瑙掕壊鏉冮檺 */
-    @Excel(name = "瑙掕壊鏉冮檺")
-    @NotBlank(message = "鏉冮檺瀛楃涓嶈兘涓虹┖")
-    @Size(min = 0, max = 100, message = "鏉冮檺瀛楃闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
-    private String roleKey;
+	/**
+	 * 瑙掕壊鏉冮檺
+	 */
+	@ExcelProperty(value = "瑙掕壊鏉冮檺")
+	@NotBlank(message = "鏉冮檺瀛楃涓嶈兘涓虹┖")
+	@Size(min = 0, max = 100, message = "鏉冮檺瀛楃闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+	private String roleKey;
 
-    /** 瑙掕壊鎺掑簭 */
-    @Excel(name = "瑙掕壊鎺掑簭")
-    @NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
-    private String roleSort;
+	/**
+	 * 瑙掕壊鎺掑簭
+	 */
+	@ExcelProperty(value = "瑙掕壊鎺掑簭")
+	@NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+	private String roleSort;
 
-    /** 鏁版嵁鑼冨洿锛�1锛氭墍鏈夋暟鎹潈闄愶紱2锛氳嚜瀹氫箟鏁版嵁鏉冮檺锛�3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺锛�4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶紱5锛氫粎鏈汉鏁版嵁鏉冮檺锛� */
-    @Excel(name = "鏁版嵁鑼冨洿", readConverterExp = "1=鎵�鏈夋暟鎹潈闄�,2=鑷畾涔夋暟鎹潈闄�,3=鏈儴闂ㄦ暟鎹潈闄�,4=鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺,5=浠呮湰浜烘暟鎹潈闄�")
-    private String dataScope;
+	/**
+	 * 鏁版嵁鑼冨洿锛�1锛氭墍鏈夋暟鎹潈闄愶紱2锛氳嚜瀹氫箟鏁版嵁鏉冮檺锛�3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺锛�4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶紱5锛氫粎鏈汉鏁版嵁鏉冮檺锛�
+	 */
+	@ExcelProperty(value = "鏁版嵁鑼冨洿", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(readConverterExp = "1=鎵�鏈夋暟鎹潈闄�,2=鑷畾涔夋暟鎹潈闄�,3=鏈儴闂ㄦ暟鎹潈闄�,4=鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺,5=浠呮湰浜烘暟鎹潈闄�")
+	private String dataScope;
 
-    /** 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級 */
-    private boolean menuCheckStrictly;
+	/**
+	 * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級
+	 */
+	private boolean menuCheckStrictly;
 
-    /** 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀� 锛� */
-    private boolean deptCheckStrictly;
+	/**
+	 * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀� 锛�
+	 */
+	private boolean deptCheckStrictly;
 
-    /** 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛� */
-    @Excel(name = "瑙掕壊鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
-    private String status;
+	/**
+	 * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+	 */
+	@ExcelProperty(value = "瑙掕壊鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
+	private String status;
 
-    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
-    @TableLogic
-    private String delFlag;
+	/**
+	 * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+	 */
+	@TableLogic
+	private String delFlag;
 
-    /** 鍒涘缓鑰� */
-    @TableField(fill = FieldFill.INSERT)
-    private String createBy;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
 
-    /** 鍒涘缓鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createTime;
 
-    /** 鏇存柊鑰� */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateBy;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private String updateBy;
 
-    /** 鏇存柊鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date updateTime;
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
 
-    /** 澶囨敞 */
-    private String remark;
+	/**
+	 * 澶囨敞
+	 */
+	private String remark;
 
-    /**
-     * 璇锋眰鍙傛暟
-     */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@TableField(exist = false)
+	private Map<String, Object> params = new HashMap<>();
 
-    /** 鐢ㄦ埛鏄惁瀛樺湪姝よ鑹叉爣璇� 榛樿涓嶅瓨鍦� */
-    @TableField(exist = false)
-    private boolean flag = false;
+	/**
+	 * 鐢ㄦ埛鏄惁瀛樺湪姝よ鑹叉爣璇� 榛樿涓嶅瓨鍦�
+	 */
+	@TableField(exist = false)
+	private boolean flag = false;
 
-    /** 鑿滃崟缁� */
-    @TableField(exist = false)
-    private Long[] menuIds;
+	/**
+	 * 鑿滃崟缁�
+	 */
+	@TableField(exist = false)
+	private Long[] menuIds;
 
-    /** 閮ㄩ棬缁勶紙鏁版嵁鏉冮檺锛� */
-    @TableField(exist = false)
-    private Long[] deptIds;
+	/**
+	 * 閮ㄩ棬缁勶紙鏁版嵁鏉冮檺锛�
+	 */
+	@TableField(exist = false)
+	private Long[] deptIds;
 
-    public SysRole(Long roleId)
-    {
-        this.roleId = roleId;
-    }
+	public SysRole(Long roleId) {
+		this.roleId = roleId;
+	}
 
-    public boolean isAdmin()
-    {
-        return isAdmin(this.roleId);
-    }
+	public boolean isAdmin() {
+		return isAdmin(this.roleId);
+	}
 
-    public static boolean isAdmin(Long roleId)
-    {
-        return roleId != null && 1L == roleId;
-    }
+	public static boolean isAdmin(Long roleId) {
+		return roleId != null && 1L == roleId;
+	}
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index 898138b..c5c82fd 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -1,13 +1,8 @@
 package com.ruoyi.common.core.domain.entity;
 
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.annotation.Excel.Type;
-import com.ruoyi.common.annotation.Excels;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -31,140 +26,167 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_user")
-public class SysUser implements Serializable
-{
-    private static final long serialVersionUID = 1L;
+public class SysUser implements Serializable {
+	private static final long serialVersionUID = 1L;
 
-    /** 鐢ㄦ埛ID */
-    @Excel(name = "鐢ㄦ埛搴忓彿", cellType = ColumnType.NUMERIC, prompt = "鐢ㄦ埛缂栧彿")
-    @TableId(value = "user_id",type = IdType.AUTO)
-    private Long userId;
+	/**
+	 * 鐢ㄦ埛ID
+	 */
+	@TableId(value = "user_id", type = IdType.AUTO)
+	private Long userId;
 
-    /** 閮ㄩ棬ID */
-    @Excel(name = "閮ㄩ棬缂栧彿", type = Type.IMPORT)
-    private Long deptId;
+	/**
+	 * 閮ㄩ棬ID
+	 */
+	private Long deptId;
 
-    /** 鐢ㄦ埛璐﹀彿 */
-    @NotBlank(message = "鐢ㄦ埛璐﹀彿涓嶈兘涓虹┖")
-    @Size(min = 0, max = 30, message = "鐢ㄦ埛璐﹀彿闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
-    @Excel(name = "鐧诲綍鍚嶇О")
-    private String userName;
+	/**
+	 * 鐢ㄦ埛璐﹀彿
+	 */
+	@NotBlank(message = "鐢ㄦ埛璐﹀彿涓嶈兘涓虹┖")
+	@Size(min = 0, max = 30, message = "鐢ㄦ埛璐﹀彿闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
+	private String userName;
 
-    /** 鐢ㄦ埛鏄电О */
-    @Size(min = 0, max = 30, message = "鐢ㄦ埛鏄电О闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
-    @Excel(name = "鐢ㄦ埛鍚嶇О")
-    private String nickName;
+	/**
+	 * 鐢ㄦ埛鏄电О
+	 */
+	@Size(min = 0, max = 30, message = "鐢ㄦ埛鏄电О闀垮害涓嶈兘瓒呰繃30涓瓧绗�")
+	private String nickName;
 
-    /** 鐢ㄦ埛閭 */
-    @Email(message = "閭鏍煎紡涓嶆纭�")
-    @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
-    @Excel(name = "鐢ㄦ埛閭")
-    private String email;
+	/**
+	 * 鐢ㄦ埛閭
+	 */
+	@Email(message = "閭鏍煎紡涓嶆纭�")
+	@Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+	private String email;
 
-    /** 鎵嬫満鍙风爜 */
-    @Size(min = 0, max = 11, message = "鎵嬫満鍙风爜闀垮害涓嶈兘瓒呰繃11涓瓧绗�")
-    @Excel(name = "鎵嬫満鍙风爜")
-    private String phonenumber;
+	/**
+	 * 鎵嬫満鍙风爜
+	 */
+	private String phonenumber;
 
-    /** 鐢ㄦ埛鎬у埆 */
-    @Excel(name = "鐢ㄦ埛鎬у埆", readConverterExp = "0=鐢�,1=濂�,2=鏈煡")
-    private String sex;
+	/**
+	 * 鐢ㄦ埛鎬у埆
+	 */
+	private String sex;
 
-    /** 鐢ㄦ埛澶村儚 */
-    private String avatar;
+	/**
+	 * 鐢ㄦ埛澶村儚
+	 */
+	private String avatar;
 
-    /** 瀵嗙爜 */
-    private String password;
+	/**
+	 * 瀵嗙爜
+	 */
+	private String password;
 
-    @JsonIgnore
-    @JsonProperty
-    public String getPassword() {
-        return password;
-    }
+	@JsonIgnore
+	@JsonProperty
+	public String getPassword() {
+		return password;
+	}
 
-    /** 鐩愬姞瀵� */
-    private String salt;
+	/**
+	 * 鐩愬姞瀵�
+	 */
+	private String salt;
 
-    /** 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛� */
-    @Excel(name = "甯愬彿鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
-    private String status;
+	/**
+	 * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+	 */
+	private String status;
 
-    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
-    @TableLogic
-    private String delFlag;
+	/**
+	 * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+	 */
+	@TableLogic
+	private String delFlag;
 
-    /** 鏈�鍚庣櫥褰旾P */
-    @Excel(name = "鏈�鍚庣櫥褰旾P", type = Type.EXPORT)
-    private String loginIp;
+	/**
+	 * 鏈�鍚庣櫥褰旾P
+	 */
+	private String loginIp;
 
-    /** 鏈�鍚庣櫥褰曟椂闂� */
-    @Excel(name = "鏈�鍚庣櫥褰曟椂闂�", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
-    private Date loginDate;
+	/**
+	 * 鏈�鍚庣櫥褰曟椂闂�
+	 */
+	private Date loginDate;
 
-    /** 鍒涘缓鑰� */
-    @TableField(fill = FieldFill.INSERT)
-    private String createBy;
+	/**
+	 * 鍒涘缓鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
 
-    /** 鍒涘缓鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
+	/**
+	 * 鍒涘缓鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createTime;
 
-    /** 鏇存柊鑰� */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    private String updateBy;
+	/**
+	 * 鏇存柊鑰�
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private String updateBy;
 
-    /** 鏇存柊鏃堕棿 */
-    @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date updateTime;
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
 
-    /** 澶囨敞 */
-    private String remark;
+	/**
+	 * 澶囨敞
+	 */
+	private String remark;
 
-    /**
-     * 璇锋眰鍙傛暟
-     */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
+	/**
+	 * 璇锋眰鍙傛暟
+	 */
+	@TableField(exist = false)
+	private Map<String, Object> params = new HashMap<>();
 
-    /** 閮ㄩ棬瀵硅薄 */
-    @Excels({
-        @Excel(name = "閮ㄩ棬鍚嶇О", targetAttr = "deptName", type = Type.EXPORT),
-        @Excel(name = "閮ㄩ棬璐熻矗浜�", targetAttr = "leader", type = Type.EXPORT)
-    })
-    @TableField(exist = false)
-    private SysDept dept;
+	/**
+	 * 閮ㄩ棬瀵硅薄
+	 */
+	@TableField(exist = false)
+	private SysDept dept;
 
-    /** 瑙掕壊瀵硅薄 */
-    @TableField(exist = false)
-    private List<SysRole> roles;
+	/**
+	 * 瑙掕壊瀵硅薄
+	 */
+	@TableField(exist = false)
+	private List<SysRole> roles;
 
-    /** 瑙掕壊缁� */
-    @TableField(exist = false)
-    private Long[] roleIds;
+	/**
+	 * 瑙掕壊缁�
+	 */
+	@TableField(exist = false)
+	private Long[] roleIds;
 
-    /** 宀椾綅缁� */
-    @TableField(exist = false)
-    private Long[] postIds;
+	/**
+	 * 宀椾綅缁�
+	 */
+	@TableField(exist = false)
+	private Long[] postIds;
 
-	/** 瑙掕壊ID */
+	/**
+	 * 瑙掕壊ID
+	 */
 	@TableField(exist = false)
 	private Long roleId;
 
-    public SysUser(Long userId)
-    {
-        this.userId = userId;
-    }
+	public SysUser(Long userId) {
+		this.userId = userId;
+	}
 
-    public boolean isAdmin()
-    {
-        return isAdmin(this.userId);
-    }
+	public boolean isAdmin() {
+		return isAdmin(this.userId);
+	}
 
-    public static boolean isAdmin(Long userId)
-    {
-        return userId != null && 1L == userId;
-    }
+	public static boolean isAdmin(Long userId) {
+		return userId != null && 1L == userId;
+	}
 
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
index e13ec1e..7bc072a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
@@ -24,6 +24,16 @@
     private static final long serialVersionUID = 1L;
 
     /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
      * 鐢ㄦ埛鍞竴鏍囪瘑
      */
     private String token;
@@ -74,6 +84,14 @@
         this.permissions = permissions;
     }
 
+    public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
+    {
+        this.userId = userId;
+        this.deptId = deptId;
+        this.user = user;
+        this.permissions = permissions;
+    }
+
     @JsonIgnore
     @Override
     public String getPassword()
@@ -81,7 +99,6 @@
         return user.getPassword();
     }
 
-	@JsonIgnore
     @Override
     public String getUsername()
     {
@@ -134,7 +151,6 @@
         return true;
     }
 
-	@JsonIgnore
     @Override
     public Collection<? extends GrantedAuthority> getAuthorities()
     {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
new file mode 100644
index 0000000..5baa887
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
@@ -0,0 +1,11 @@
+package com.ruoyi.common.core.domain.model;
+
+/**
+ * 鐢ㄦ埛娉ㄥ唽瀵硅薄
+ * 
+ * @author ruoyi
+ */
+public class RegisterBody extends LoginBody
+{
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java
index 66cf34c..2aba06e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java
@@ -1,11 +1,10 @@
 package com.ruoyi.common.core.mybatisplus.methods;
 
-import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.core.enums.SqlMethod;
 import com.baomidou.mybatisplus.core.injector.AbstractMethod;
 import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
+import com.ruoyi.common.utils.StringUtils;
 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
 import org.apache.ibatis.executor.keygen.KeyGenerator;
 import org.apache.ibatis.executor.keygen.NoKeyGenerator;
@@ -25,11 +24,11 @@
 		final String fieldSql = prepareFieldSql(tableInfo);
 		final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
 		KeyGenerator keyGenerator = new NoKeyGenerator();
-		SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
+		String sqlMethod = "insertAll";
 		String keyProperty = null;
 		String keyColumn = null;
 		// 琛ㄥ寘鍚富閿鐞嗛�昏緫,濡傛灉涓嶅寘鍚富閿綋鏅�氬瓧娈靛鐞�
-		if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) {
+		if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
 			if (tableInfo.getIdType() == IdType.AUTO) {
 				/** 鑷涓婚敭 */
 				keyGenerator = new Jdbc3KeyGenerator();
@@ -37,7 +36,7 @@
 				keyColumn = tableInfo.getKeyColumn();
 			} else {
 				if (null != tableInfo.getKeySequence()) {
-					keyGenerator = TableInfoHelper.genKeyGenerator(getMethod(sqlMethod), tableInfo, builderAssistant);
+					keyGenerator = TableInfoHelper.genKeyGenerator(sqlMethod, tableInfo, builderAssistant);
 					keyProperty = tableInfo.getKeyProperty();
 					keyColumn = tableInfo.getKeyColumn();
 				}
@@ -45,12 +44,12 @@
 		}
 		final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
 		SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
-		return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, keyGenerator, keyProperty, keyColumn);
+		return this.addInsertMappedStatement(mapperClass, modelClass, sqlMethod, sqlSource, keyGenerator, keyProperty, keyColumn);
 	}
 
 	private String prepareFieldSql(TableInfo tableInfo) {
 		StringBuilder fieldSql = new StringBuilder();
-		if (StrUtil.isNotBlank(tableInfo.getKeyColumn())) {
+		if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) {
 			fieldSql.append(tableInfo.getKeyColumn()).append(",");
 		}
 		tableInfo.getFieldList().forEach(x -> fieldSql.append(x.getColumn()).append(","));
@@ -63,7 +62,7 @@
 	private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
 		final StringBuilder valueSql = new StringBuilder();
 		valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
-		if (StrUtil.isNotBlank(tableInfo.getKeyColumn())) {
+		if (StringUtils.isNotBlank(tableInfo.getKeyColumn())) {
 			valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
 		}
 		tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
new file mode 100644
index 0000000..ad01659
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
@@ -0,0 +1,20 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 闄愭祦绫诲瀷
+ *
+ * @author ruoyi
+ */
+
+public enum LimitType
+{
+    /**
+     * 榛樿绛栫暐鍏ㄥ眬闄愭祦
+     */
+    DEFAULT,
+
+    /**
+     * 鏍规嵁璇锋眰鑰匢P杩涜闄愭祦
+     */
+    IP
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/CustomException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/CustomException.java
deleted file mode 100644
index d96c7ba..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/CustomException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.ruoyi.common.exception;
-
-/**
- * 鑷畾涔夊紓甯�
- * 
- * @author ruoyi
- */
-public class CustomException extends RuntimeException
-{
-    private static final long serialVersionUID = 1L;
-
-    private Integer code;
-
-    private String message;
-
-    public CustomException(String message)
-    {
-        this.message = message;
-    }
-
-    public CustomException(String message, Integer code)
-    {
-        this.message = message;
-        this.code = code;
-    }
-
-    public CustomException(String message, Throwable e)
-    {
-        super(message, e);
-        this.message = message;
-    }
-
-    @Override
-    public String getMessage()
-    {
-        return message;
-    }
-
-    public Integer getCode()
-    {
-        return code;
-    }
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
new file mode 100644
index 0000000..318b9ae
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
@@ -0,0 +1,58 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 鍏ㄥ眬寮傚父
+ * 
+ * @author ruoyi
+ */
+public class GlobalException extends RuntimeException
+{
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閿欒鎻愮ず
+     */
+    private String message;
+
+    /**
+     * 閿欒鏄庣粏锛屽唴閮ㄨ皟璇曢敊璇�
+     *
+     * 鍜� {@link CommonResult#getDetailMessage()} 涓�鑷寸殑璁捐
+     */
+    private String detailMessage;
+
+    /**
+     * 绌烘瀯閫犳柟娉曪紝閬垮厤鍙嶅簭鍒楀寲闂
+     */
+    public GlobalException()
+    {
+    }
+
+    public GlobalException(String message)
+    {
+        this.message = message;
+    }
+
+    public String getDetailMessage()
+    {
+        return detailMessage;
+    }
+
+    public GlobalException setDetailMessage(String detailMessage)
+    {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public GlobalException setMessage(String message)
+    {
+        this.message = message;
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
new file mode 100644
index 0000000..734e8fc
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
@@ -0,0 +1,73 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 涓氬姟寮傚父
+ * 
+ * @author ruoyi
+ */
+public final class ServiceException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閿欒鐮�
+     */
+    private Integer code;
+
+    /**
+     * 閿欒鎻愮ず
+     */
+    private String message;
+
+    /**
+     * 閿欒鏄庣粏锛屽唴閮ㄨ皟璇曢敊璇�
+     *
+     * 鍜� {@link CommonResult#getDetailMessage()} 涓�鑷寸殑璁捐
+     */
+    private String detailMessage;
+
+    /**
+     * 绌烘瀯閫犳柟娉曪紝閬垮厤鍙嶅簭鍒楀寲闂
+     */
+    public ServiceException()
+    {
+    }
+
+    public ServiceException(String message)
+    {
+        this.message = message;
+    }
+
+    public ServiceException(String message, Integer code)
+    {
+        this.message = message;
+        this.code = code;
+    }
+
+    public String getDetailMessage()
+    {
+        return detailMessage;
+    }
+
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public ServiceException setMessage(String message)
+    {
+        this.message = message;
+        return this;
+    }
+
+    public ServiceException setDetailMessage(String detailMessage)
+    {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/BaseException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/BaseException.java
rename to ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
index 026cc0a..5f97a3b 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/BaseException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
@@ -1,11 +1,11 @@
-package com.ruoyi.common.exception;
+package com.ruoyi.common.exception.base;
 
-import cn.hutool.core.lang.Validator;
 import com.ruoyi.common.utils.MessageUtils;
+import com.ruoyi.common.utils.StringUtils;
 
 /**
  * 鍩虹寮傚父
- * 
+ *
  * @author ruoyi
  */
 public class BaseException extends RuntimeException
@@ -64,7 +64,7 @@
     public String getMessage()
     {
         String message = null;
-        if (!Validator.isEmpty(code))
+        if (!StringUtils.isEmpty(code))
         {
             message = MessageUtils.message(code, args);
         }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
index 75d6dbf..b4c57f6 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
@@ -1,10 +1,10 @@
 package com.ruoyi.common.exception.file;
 
-import com.ruoyi.common.exception.BaseException;
+import com.ruoyi.common.exception.base.BaseException;
 
 /**
  * 鏂囦欢淇℃伅寮傚父绫�
- * 
+ *
  * @author ruoyi
  */
 public class FileException extends BaseException
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
index aa015f8..f25afc5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
@@ -1,10 +1,10 @@
 package com.ruoyi.common.exception.user;
 
-import com.ruoyi.common.exception.BaseException;
+import com.ruoyi.common.exception.base.BaseException;
 
 /**
  * 鐢ㄦ埛淇℃伅寮傚父绫�
- * 
+ *
  * @author ruoyi
  */
 public class UserException extends BaseException
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
index c7193e2..ffe614c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
@@ -1,48 +1,48 @@
-package com.ruoyi.common.filter;
-
-import cn.hutool.core.util.StrUtil;
-import org.springframework.http.MediaType;
-
-import javax.servlet.*;
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
-
-/**
- * Repeatable 杩囨护鍣�
- * 
- * @author ruoyi
- */
-public class RepeatableFilter implements Filter
-{
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-
-    }
-
-    @Override
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-            throws IOException, ServletException
-    {
-        ServletRequest requestWrapper = null;
-        if (request instanceof HttpServletRequest
-                && StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
-        {
-            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
-        }
-        if (null == requestWrapper)
-        {
-            chain.doFilter(request, response);
-        }
-        else
-        {
-            chain.doFilter(requestWrapper, response);
-        }
-    }
-
-    @Override
-    public void destroy()
-    {
-
-    }
-}
+package com.ruoyi.common.filter;
+
+import com.ruoyi.common.utils.StringUtils;
+import org.springframework.http.MediaType;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * Repeatable 杩囨护鍣�
+ *
+ * @author ruoyi
+ */
+public class RepeatableFilter implements Filter
+{
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException
+    {
+        ServletRequest requestWrapper = null;
+        if (request instanceof HttpServletRequest
+                && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
+        {
+            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
+        }
+        if (null == requestWrapper)
+        {
+            chain.doFilter(request, response);
+        }
+        else
+        {
+            chain.doFilter(requestWrapper, response);
+        }
+    }
+
+    @Override
+    public void destroy()
+    {
+
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
index 86fcd2e..7c14167 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
@@ -1,6 +1,6 @@
 package com.ruoyi.common.filter;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 
 import javax.servlet.*;
 import javax.servlet.http.HttpServletRequest;
@@ -8,12 +8,10 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 /**
  * 闃叉XSS鏀诲嚮鐨勮繃婊ゅ櫒
- * 
+ *
  * @author ruoyi
  */
 public class XssFilter implements Filter
@@ -23,27 +21,17 @@
      */
     public List<String> excludes = new ArrayList<>();
 
-    /**
-     * xss杩囨护寮�鍏�
-     */
-    public boolean enabled = false;
-
     @Override
     public void init(FilterConfig filterConfig) throws ServletException
     {
         String tempExcludes = filterConfig.getInitParameter("excludes");
-        String tempEnabled = filterConfig.getInitParameter("enabled");
-        if (StrUtil.isNotEmpty(tempExcludes))
+        if (StringUtils.isNotEmpty(tempExcludes))
         {
             String[] url = tempExcludes.split(",");
             for (int i = 0; url != null && i < url.length; i++)
             {
                 excludes.add(url[i]);
             }
-        }
-        if (StrUtil.isNotEmpty(tempEnabled))
-        {
-            enabled = Boolean.valueOf(tempEnabled);
         }
     }
 
@@ -64,25 +52,14 @@
 
     private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
     {
-        if (!enabled)
+        String url = request.getServletPath();
+        String method = request.getMethod();
+        // GET DELETE 涓嶈繃婊�
+        if (method == null || method.matches("GET") || method.matches("DELETE"))
         {
             return true;
         }
-        if (excludes == null || excludes.isEmpty())
-        {
-            return false;
-        }
-        String url = request.getServletPath();
-        for (String pattern : excludes)
-        {
-            Pattern p = Pattern.compile("^" + pattern);
-            Matcher m = p.matcher(url);
-            if (m.find())
-            {
-                return true;
-            }
-        }
-        return false;
+        return StringUtils.matches(url, excludes);
     }
 
     @Override
@@ -90,4 +67,4 @@
     {
 
     }
-}
\ No newline at end of file
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
index 4d36a92..700a88d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
@@ -1,9 +1,8 @@
 package com.ruoyi.common.filter;
 
 import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HtmlUtil;
+import com.ruoyi.common.utils.StringUtils;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 
@@ -59,7 +58,7 @@
 
         // 涓虹┖锛岀洿鎺ヨ繑鍥�
         String json = IoUtil.read(super.getInputStream(), StandardCharsets.UTF_8);
-        if (Validator.isEmpty(json))
+        if (StringUtils.isEmpty(json))
         {
             return super.getInputStream();
         }
@@ -103,6 +102,6 @@
     public boolean isJsonRequest()
     {
         String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
-        return StrUtil.startWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
+        return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
     }
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
index 5d1fef1..64ac8ef 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
@@ -1,187 +1,185 @@
-package com.ruoyi.common.utils;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.entity.SysDictData;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.utils.spring.SpringUtils;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * 瀛楀吀宸ュ叿绫�
- * 
- * @author ruoyi
- */
-public class DictUtils
-{
-    /**
-     * 鍒嗛殧绗�
-     */
-    public static final String SEPARATOR = ",";
-
-    /**
-     * 璁剧疆瀛楀吀缂撳瓨
-     * 
-     * @param key 鍙傛暟閿�
-     * @param dictDatas 瀛楀吀鏁版嵁鍒楄〃
-     */
-    public static void setDictCache(String key, List<SysDictData> dictDatas)
-    {
-        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
-    }
-
-    /**
-     * 鑾峰彇瀛楀吀缂撳瓨
-     * 
-     * @param key 鍙傛暟閿�
-     * @return dictDatas 瀛楀吀鏁版嵁鍒楄〃
-     */
-    public static List<SysDictData> getDictCache(String key)
-    {
-        Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
-        if (Validator.isNotNull(cacheObj))
-        {
-            List<SysDictData> dictDatas = (List<SysDictData>)cacheObj;
-            return dictDatas;
-        }
-        return null;
-    }
-
-    /**
-     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
-     * 
-     * @param dictType 瀛楀吀绫诲瀷
-     * @param dictValue 瀛楀吀鍊�
-     * @return 瀛楀吀鏍囩
-     */
-    public static String getDictLabel(String dictType, String dictValue)
-    {
-        return getDictLabel(dictType, dictValue, SEPARATOR);
-    }
-
-    /**
-     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
-     * 
-     * @param dictType 瀛楀吀绫诲瀷
-     * @param dictLabel 瀛楀吀鏍囩
-     * @return 瀛楀吀鍊�
-     */
-    public static String getDictValue(String dictType, String dictLabel)
-    {
-        return getDictValue(dictType, dictLabel, SEPARATOR);
-    }
-
-    /**
-     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
-     * 
-     * @param dictType 瀛楀吀绫诲瀷
-     * @param dictValue 瀛楀吀鍊�
-     * @param separator 鍒嗛殧绗�
-     * @return 瀛楀吀鏍囩
-     */
-    public static String getDictLabel(String dictType, String dictValue, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = getDictCache(dictType);
-
-        if (StrUtil.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas))
-        {
-            for (SysDictData dict : datas)
-            {
-                for (String value : dictValue.split(separator))
-                {
-                    if (value.equals(dict.getDictValue()))
-                    {
-                        propertyString.append(dict.getDictLabel() + separator);
-                        break;
-                    }
-                }
-            }
-        }
-        else
-        {
-            for (SysDictData dict : datas)
-            {
-                if (dictValue.equals(dict.getDictValue()))
-                {
-                    return dict.getDictLabel();
-                }
-            }
-        }
-        return StrUtil.strip(propertyString.toString(), null, separator);
-    }
-
-    /**
-     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
-     * 
-     * @param dictType 瀛楀吀绫诲瀷
-     * @param dictLabel 瀛楀吀鏍囩
-     * @param separator 鍒嗛殧绗�
-     * @return 瀛楀吀鍊�
-     */
-    public static String getDictValue(String dictType, String dictLabel, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = getDictCache(dictType);
-
-        if (StrUtil.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas))
-        {
-            for (SysDictData dict : datas)
-            {
-                for (String label : dictLabel.split(separator))
-                {
-                    if (label.equals(dict.getDictLabel()))
-                    {
-                        propertyString.append(dict.getDictValue() + separator);
-                        break;
-                    }
-                }
-            }
-        }
-        else
-        {
-            for (SysDictData dict : datas)
-            {
-                if (dictLabel.equals(dict.getDictLabel()))
-                {
-                    return dict.getDictValue();
-                }
-            }
-        }
-        return StrUtil.strip(propertyString.toString(), null, separator);
-    }
-
-    /**
-     * 鍒犻櫎鎸囧畾瀛楀吀缂撳瓨
-     * 
-     * @param key 瀛楀吀閿�
-     */
-    public static void removeDictCache(String key)
-    {
-        SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
-    }
-
-    /**
-     * 娓呯┖瀛楀吀缂撳瓨
-     */
-    public static void clearDictCache()
-    {
-        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*");
-        SpringUtils.getBean(RedisCache.class).deleteObject(keys);
-    }
-
-    /**
-     * 璁剧疆cache key
-     * 
-     * @param configKey 鍙傛暟閿�
-     * @return 缂撳瓨閿甼ey
-     */
-    public static String getCacheKey(String configKey)
-    {
-        return Constants.SYS_DICT_KEY + configKey;
-    }
-}
+package com.ruoyi.common.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.spring.SpringUtils;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀛楀吀宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+public class DictUtils
+{
+    /**
+     * 鍒嗛殧绗�
+     */
+    public static final String SEPARATOR = ",";
+
+    /**
+     * 璁剧疆瀛楀吀缂撳瓨
+     *
+     * @param key 鍙傛暟閿�
+     * @param dictDatas 瀛楀吀鏁版嵁鍒楄〃
+     */
+    public static void setDictCache(String key, List<SysDictData> dictDatas)
+    {
+        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
+    }
+
+    /**
+     * 鑾峰彇瀛楀吀缂撳瓨
+     *
+     * @param key 鍙傛暟閿�
+     * @return dictDatas 瀛楀吀鏁版嵁鍒楄〃
+     */
+    public static List<SysDictData> getDictCache(String key)
+    {
+        Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
+        if (StringUtils.isNotNull(cacheObj))
+        {
+            List<SysDictData> dictDatas = (List<SysDictData>)cacheObj;
+            return dictDatas;
+        }
+        return null;
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀鍊�
+     * @return 瀛楀吀鏍囩
+     */
+    public static String getDictLabel(String dictType, String dictValue)
+    {
+        return getDictLabel(dictType, dictValue, SEPARATOR);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictLabel 瀛楀吀鏍囩
+     * @return 瀛楀吀鍊�
+     */
+    public static String getDictValue(String dictType, String dictLabel)
+    {
+        return getDictValue(dictType, dictLabel, SEPARATOR);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀鍊�
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鏍囩
+     */
+    public static String getDictLabel(String dictType, String dictValue, String separator)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        List<SysDictData> datas = getDictCache(dictType);
+
+        if (StringUtils.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas))
+        {
+            for (SysDictData dict : datas)
+            {
+                for (String value : dictValue.split(separator))
+                {
+                    if (value.equals(dict.getDictValue()))
+                    {
+                        propertyString.append(dict.getDictLabel() + separator);
+                        break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            for (SysDictData dict : datas)
+            {
+                if (dictValue.equals(dict.getDictValue()))
+                {
+                    return dict.getDictLabel();
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictLabel 瀛楀吀鏍囩
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鍊�
+     */
+    public static String getDictValue(String dictType, String dictLabel, String separator)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        List<SysDictData> datas = getDictCache(dictType);
+
+        if (StringUtils.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas))
+        {
+            for (SysDictData dict : datas)
+            {
+                for (String label : dictLabel.split(separator))
+                {
+                    if (label.equals(dict.getDictLabel()))
+                    {
+                        propertyString.append(dict.getDictValue() + separator);
+                        break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            for (SysDictData dict : datas)
+            {
+                if (dictLabel.equals(dict.getDictLabel()))
+                {
+                    return dict.getDictValue();
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 鍒犻櫎鎸囧畾瀛楀吀缂撳瓨
+     *
+     * @param key 瀛楀吀閿�
+     */
+    public static void removeDictCache(String key)
+    {
+        SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
+    }
+
+    /**
+     * 娓呯┖瀛楀吀缂撳瓨
+     */
+    public static void clearDictCache()
+    {
+        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(Constants.SYS_DICT_KEY + "*");
+        SpringUtils.getBean(RedisCache.class).deleteObject(keys);
+    }
+
+    /**
+     * 璁剧疆cache key
+     *
+     * @param configKey 鍙傛暟閿�
+     * @return 缂撳瓨閿甼ey
+     */
+    public static String getCacheKey(String configKey)
+    {
+        return Constants.SYS_DICT_KEY + configKey;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
index ae6cc11..676de01 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
@@ -1,8 +1,6 @@
 package com.ruoyi.common.utils;
 
-import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,7 +31,7 @@
     }
 
     public static String toJsonString(Object object) {
-		if (Validator.isEmpty(object)) {
+		if (StringUtils.isNull(object)) {
 			return null;
 		}
         try {
@@ -44,7 +42,7 @@
     }
 
     public static <T> T parseObject(String text, Class<T> clazz) {
-        if (StrUtil.isEmpty(text)) {
+        if (StringUtils.isEmpty(text)) {
             return null;
         }
         try {
@@ -66,7 +64,7 @@
     }
 
     public static <T> T parseObject(String text, TypeReference<T> typeReference) {
-		if (StrUtil.isBlank(text)) {
+		if (StringUtils.isBlank(text)) {
 			return null;
 		}
         try {
@@ -77,7 +75,7 @@
     }
 
 	public static <T> Map<String, T> parseMap(String text) {
-		if (StrUtil.isBlank(text)) {
+		if (StringUtils.isBlank(text)) {
 			return null;
 		}
 		try {
@@ -88,7 +86,7 @@
 	}
 
     public static <T> List<T> parseArray(String text, Class<T> clazz) {
-        if (StrUtil.isEmpty(text)) {
+        if (StringUtils.isEmpty(text)) {
             return new ArrayList<>();
         }
         try {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
index bb3d3e2..27125ab 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
@@ -1,6 +1,5 @@
 package com.ruoyi.common.utils;
 
-import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpStatus;
 import com.baomidou.mybatisplus.core.metadata.OrderItem;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -59,7 +58,7 @@
         String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN);
         String isAsc = ServletUtils.getParameter(IS_ASC);
         PagePlus<T, K> page = new PagePlus<>(pageNum, pageSize);
-        if (StrUtil.isNotBlank(orderByColumn)) {
+        if (StringUtils.isNotBlank(orderByColumn)) {
             String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
             if ("asc".equals(isAsc)) {
                 page.addOrder(OrderItem.asc(orderBy));
@@ -91,9 +90,9 @@
 			isAsc = "desc";
 		}
         Page<T> page = new Page<>(pageNum, pageSize);
-        if (StrUtil.isNotBlank(orderByColumn)) {
+        if (StringUtils.isNotBlank(orderByColumn)) {
             String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
-			orderBy = StrUtil.toUnderlineCase(orderBy);
+			orderBy = StringUtils.toUnderScoreCase(orderBy);
 			if ("asc".equals(isAsc)) {
                 page.addOrder(OrderItem.asc(orderBy));
             } else if ("desc".equals(isAsc)) {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
index bdcc9eb..969eaf5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -5,15 +5,45 @@
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 
 /**
  * 瀹夊叏鏈嶅姟宸ュ叿绫�
- * 
+ *
  * @author ruoyi
  */
 public class SecurityUtils
 {
+    /**
+     * 鐢ㄦ埛ID
+     **/
+    public static Long getUserId()
+    {
+        try
+        {
+            return getLoginUser().getUserId();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇鐢ㄦ埛ID寮傚父", HttpStatus.HTTP_UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬ID
+     **/
+    public static Long getDeptId()
+    {
+        try
+        {
+            return getLoginUser().getDeptId();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇閮ㄩ棬ID寮傚父", HttpStatus.HTTP_UNAUTHORIZED);
+        }
+    }
+
     /**
      * 鑾峰彇鐢ㄦ埛璐︽埛
      **/
@@ -25,7 +55,7 @@
         }
         catch (Exception e)
         {
-            throw new CustomException("鑾峰彇鐢ㄦ埛璐︽埛寮傚父", HttpStatus.HTTP_UNAUTHORIZED);
+            throw new ServiceException("鑾峰彇鐢ㄦ埛璐︽埛寮傚父", HttpStatus.HTTP_UNAUTHORIZED);
         }
     }
 
@@ -40,7 +70,7 @@
         }
         catch (Exception e)
         {
-            throw new CustomException("鑾峰彇鐢ㄦ埛淇℃伅寮傚父", HttpStatus.HTTP_UNAUTHORIZED);
+            throw new ServiceException("鑾峰彇鐢ㄦ埛淇℃伅寮傚父", HttpStatus.HTTP_UNAUTHORIZED);
         }
     }
 
@@ -79,7 +109,7 @@
 
     /**
      * 鏄惁涓虹鐞嗗憳
-     * 
+     *
      * @param userId 鐢ㄦ埛ID
      * @return 缁撴灉
      */
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
index 1594291..beaa26c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
@@ -1,7 +1,6 @@
 package com.ruoyi.common.utils;
 
 import cn.hutool.core.convert.Convert;
-import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.servlet.ServletUtil;
 import cn.hutool.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -112,12 +111,12 @@
 		}
 
 		String uri = request.getRequestURI();
-		if (StrUtil.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
+		if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
 			return true;
 		}
 
 		String ajax = request.getParameter("__ajax");
-		if (StrUtil.equalsAnyIgnoreCase(ajax, "json", "xml")) {
+		if (StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml")) {
 			return true;
 		}
 		return false;
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
new file mode 100644
index 0000000..c6371cc
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -0,0 +1,354 @@
+package com.ruoyi.common.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Validator;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.core.util.StrUtil;
+
+import java.util.*;
+
+/**
+ * 瀛楃涓插伐鍏风被
+ *
+ * @author ruoyi
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+	/**
+	 * 鑾峰彇鍙傛暟涓嶄负绌哄��
+	 *
+	 * @param value defaultValue 瑕佸垽鏂殑value
+	 * @return value 杩斿洖鍊�
+	 */
+	public static <T> T nvl(T value, T defaultValue) {
+		return ObjectUtil.defaultIfNull(value, defaultValue);
+	}
+
+	/**
+	 * 鑾峰彇鍙傛暟涓嶄负绌哄��
+	 *
+	 * @param str defaultValue 瑕佸垽鏂殑value
+	 * @return value 杩斿洖鍊�
+	 */
+	public static String blankToDefault(String str, String defaultValue) {
+		return StrUtil.blankToDefault(str, defaultValue);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓狢ollection鏄惁涓虹┖锛� 鍖呭惈List锛孲et锛孮ueue
+	 *
+	 * @param coll 瑕佸垽鏂殑Collection
+	 * @return true锛氫负绌� false锛氶潪绌�
+	 */
+	public static boolean isEmpty(Collection<?> coll) {
+		return CollUtil.isEmpty(coll);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓狢ollection鏄惁闈炵┖锛屽寘鍚獿ist锛孲et锛孮ueue
+	 *
+	 * @param coll 瑕佸垽鏂殑Collection
+	 * @return true锛氶潪绌� false锛氱┖
+	 */
+	public static boolean isNotEmpty(Collection<?> coll) {
+		return !isEmpty(coll);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃暟缁勬槸鍚︿负绌�
+	 *
+	 * @param objects 瑕佸垽鏂殑瀵硅薄鏁扮粍
+	 *                * @return true锛氫负绌� false锛氶潪绌�
+	 */
+	public static boolean isEmpty(Object[] objects) {
+		return ArrayUtil.isEmpty(objects);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃暟缁勬槸鍚﹂潪绌�
+	 *
+	 * @param objects 瑕佸垽鏂殑瀵硅薄鏁扮粍
+	 * @return true锛氶潪绌� false锛氱┖
+	 */
+	public static boolean isNotEmpty(Object[] objects) {
+		return !isEmpty(objects);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃槸鍚︿负绌�
+	 *
+	 * @param object 瑕佸垽鏂殑瀵硅薄鏁扮粍
+	 *                * @return true锛氫负绌� false锛氶潪绌�
+	 */
+	public static boolean isEmpty(Object object) {
+		return ObjectUtil.isEmpty(object);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃槸鍚﹂潪绌�
+	 *
+	 * @param object 瑕佸垽鏂殑瀵硅薄鏁扮粍
+	 * @return true锛氶潪绌� false锛氱┖
+	 */
+	public static boolean isNotEmpty(Object object) {
+		return !isEmpty(object);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓狹ap鏄惁涓虹┖
+	 *
+	 * @param map 瑕佸垽鏂殑Map
+	 * @return true锛氫负绌� false锛氶潪绌�
+	 */
+	public static boolean isEmpty(Map<?, ?> map) {
+		return MapUtil.isEmpty(map);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓狹ap鏄惁涓虹┖
+	 *
+	 * @param map 瑕佸垽鏂殑Map
+	 * @return true锛氶潪绌� false锛氱┖
+	 */
+	public static boolean isNotEmpty(Map<?, ?> map) {
+		return !isEmpty(map);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓虹┖涓�
+	 *
+	 * @param str String
+	 * @return true锛氫负绌� false锛氶潪绌�
+	 */
+	public static boolean isEmpty(String str) {
+		return StrUtil.isEmpty(str);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓洪潪绌轰覆
+	 *
+	 * @param str String
+	 * @return true锛氶潪绌轰覆 false锛氱┖涓�
+	 */
+	public static boolean isNotEmpty(String str) {
+		return !isEmpty(str);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃槸鍚︿负绌�
+	 *
+	 * @param object Object
+	 * @return true锛氫负绌� false锛氶潪绌�
+	 */
+	public static boolean isNull(Object object) {
+		return ObjectUtil.isNull(object);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃槸鍚﹂潪绌�
+	 *
+	 * @param object Object
+	 * @return true锛氶潪绌� false锛氱┖
+	 */
+	public static boolean isNotNull(Object object) {
+		return !isNull(object);
+	}
+
+	/**
+	 * * 鍒ゆ柇涓�涓璞℃槸鍚︽槸鏁扮粍绫诲瀷锛圝ava鍩烘湰鍨嬪埆鐨勬暟缁勶級
+	 *
+	 * @param object 瀵硅薄
+	 * @return true锛氭槸鏁扮粍 false锛氫笉鏄暟缁�
+	 */
+	public static boolean isArray(Object object) {
+		return ArrayUtil.isArray(object);
+	}
+
+	/**
+	 * 鍘荤┖鏍�
+	 */
+	public static String trim(String str) {
+		return StrUtil.trim(str);
+	}
+
+	/**
+	 * 鎴彇瀛楃涓�
+	 *
+	 * @param str   瀛楃涓�
+	 * @param start 寮�濮�
+	 * @return 缁撴灉
+	 */
+	public static String substring(final String str, int start) {
+		return substring(str, start, str.length());
+	}
+
+	/**
+	 * 鎴彇瀛楃涓�
+	 *
+	 * @param str   瀛楃涓�
+	 * @param start 寮�濮�
+	 * @param end   缁撴潫
+	 * @return 缁撴灉
+	 */
+	public static String substring(final String str, int start, int end) {
+		return StrUtil.sub(str, start, end);
+	}
+
+	/**
+	 * 鏍煎紡鍖栨枃鏈�, {} 琛ㄧず鍗犱綅绗�<br>
+	 * 姝ゆ柟娉曞彧鏄畝鍗曞皢鍗犱綅绗� {} 鎸夌収椤哄簭鏇挎崲涓哄弬鏁�<br>
+	 * 濡傛灉鎯宠緭鍑� {} 浣跨敤 \\杞箟 { 鍗冲彲锛屽鏋滄兂杈撳嚭 {} 涔嬪墠鐨� \ 浣跨敤鍙岃浆涔夌 \\\\ 鍗冲彲<br>
+	 * 渚嬶細<br>
+	 * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br>
+	 * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+	 * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+	 *
+	 * @param template 鏂囨湰妯℃澘锛岃鏇挎崲鐨勯儴鍒嗙敤 {} 琛ㄧず
+	 * @param params   鍙傛暟鍊�
+	 * @return 鏍煎紡鍖栧悗鐨勬枃鏈�
+	 */
+	public static String format(String template, Object... params) {
+		return StrUtil.format(template, params);
+	}
+
+	/**
+	 * 鏄惁涓篽ttp(s)://寮�澶�
+	 *
+	 * @param link 閾炬帴
+	 * @return 缁撴灉
+	 */
+	public static boolean ishttp(String link) {
+		return Validator.isUrl(link);
+	}
+
+	/**
+	 * 瀛楃涓茶浆set
+	 *
+	 * @param str 瀛楃涓�
+	 * @param sep 鍒嗛殧绗�
+	 * @return set闆嗗悎
+	 */
+	public static Set<String> str2Set(String str, String sep) {
+		return new HashSet<>(str2List(str, sep, true, false));
+	}
+
+	/**
+	 * 瀛楃涓茶浆list
+	 *
+	 * @param str         瀛楃涓�
+	 * @param sep         鍒嗛殧绗�
+	 * @param filterBlank 杩囨护绾┖鐧�
+	 * @param trim        鍘绘帀棣栧熬绌虹櫧
+	 * @return list闆嗗悎
+	 */
+	public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
+		List<String> list = new ArrayList<>();
+		if (isEmpty(str)) {
+			return list;
+		}
+
+		// 杩囨护绌虹櫧瀛楃涓�
+		if (filterBlank && isBlank(str)) {
+			return list;
+		}
+		String[] split = str.split(sep);
+		for (String string : split) {
+			if (filterBlank && isBlank(string)) {
+				continue;
+			}
+			if (trim) {
+				string = trim(string);
+			}
+			list.add(string);
+		}
+
+		return list;
+	}
+
+	/**
+	 * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀寘鍚寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆鍚屾椂涓插拷鐣ュぇ灏忓啓
+	 *
+	 * @param cs                  鎸囧畾瀛楃涓�
+	 * @param searchCharSequences 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁�
+	 * @return 鏄惁鍖呭惈浠绘剰涓�涓瓧绗︿覆
+	 */
+	public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
+		return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences);
+	}
+
+	/**
+	 * 椹煎嘲杞笅鍒掔嚎鍛藉悕
+	 */
+	public static String toUnderScoreCase(String str) {
+		return StrUtil.toUnderlineCase(str);
+	}
+
+	/**
+	 * 鏄惁鍖呭惈瀛楃涓�
+	 *
+	 * @param str  楠岃瘉瀛楃涓�
+	 * @param strs 瀛楃涓茬粍
+	 * @return 鍖呭惈杩斿洖true
+	 */
+	public static boolean inStringIgnoreCase(String str, String... strs) {
+		return StrUtil.equalsAnyIgnoreCase(str, strs);
+	}
+
+	/**
+	 * 灏嗕笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆杞崲涓洪┘宄板紡銆傚鏋滆浆鎹㈠墠鐨勪笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆涓虹┖锛屽垯杩斿洖绌哄瓧绗︿覆銆� 渚嬪锛欻ELLO_WORLD->HelloWorld
+	 *
+	 * @param name 杞崲鍓嶇殑涓嬪垝绾垮ぇ鍐欐柟寮忓懡鍚嶇殑瀛楃涓�
+	 * @return 杞崲鍚庣殑椹煎嘲寮忓懡鍚嶇殑瀛楃涓�
+	 */
+	public static String convertToCamelCase(String name) {
+		return StrUtil.upperFirst(StrUtil.toCamelCase(name));
+	}
+
+	/**
+	 * 椹煎嘲寮忓懡鍚嶆硶 渚嬪锛歶ser_name->userName
+	 */
+	public static String toCamelCase(String s) {
+		return StrUtil.toCamelCase(s);
+	}
+
+	/**
+	 * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀尮閰嶆寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆
+	 *
+	 * @param str  鎸囧畾瀛楃涓�
+	 * @param strs 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁�
+	 * @return 鏄惁鍖归厤
+	 */
+	public static boolean matches(String str, List<String> strs) {
+		if (isEmpty(str) || isEmpty(strs)) {
+			return false;
+		}
+		for (String pattern : strs) {
+			if (isMatch(pattern, str)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 鍒ゆ柇url鏄惁涓庤鍒欓厤缃�:
+	 * ? 琛ㄧず鍗曚釜瀛楃;
+	 * * 琛ㄧず涓�灞傝矾寰勫唴鐨勪换鎰忓瓧绗︿覆锛屼笉鍙法灞傜骇;
+	 * ** 琛ㄧず浠绘剰灞傝矾寰�;
+	 *
+	 * @param pattern 鍖归厤瑙勫垯
+	 * @param url     闇�瑕佸尮閰嶇殑url
+	 * @return
+	 */
+	public static boolean isMatch(String pattern, String url) {
+		return ReUtil.isMatch(pattern, url);
+	}
+
+	@SuppressWarnings("unchecked")
+	public static <T> T cast(Object obj) {
+		return (T) obj;
+	}
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
deleted file mode 100644
index 25f5306..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ruoyi.common.utils.file;
-
-import java.io.File;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * 鏂囦欢绫诲瀷宸ュ叿绫�
- *
- * @author ruoyi
- */
-public class FileTypeUtils
-{
-    /**
-     * 鑾峰彇鏂囦欢绫诲瀷
-     * <p>
-     * 渚嬪: ruoyi.txt, 杩斿洖: txt
-     * 
-     * @param file 鏂囦欢鍚�
-     * @return 鍚庣紑锛堜笉鍚�".")
-     */
-    public static String getFileType(File file)
-    {
-        if (null == file)
-        {
-            return StringUtils.EMPTY;
-        }
-        return getFileType(file.getName());
-    }
-
-    /**
-     * 鑾峰彇鏂囦欢绫诲瀷
-     * <p>
-     * 渚嬪: ruoyi.txt, 杩斿洖: txt
-     *
-     * @param fileName 鏂囦欢鍚�
-     * @return 鍚庣紑锛堜笉鍚�".")
-     */
-    public static String getFileType(String fileName)
-    {
-        int separatorIndex = fileName.lastIndexOf(".");
-        if (separatorIndex < 0)
-        {
-            return "";
-        }
-        return fileName.substring(separatorIndex + 1).toLowerCase();
-    }
-
-    /**
-     * 鑾峰彇鏂囦欢绫诲瀷
-     * 
-     * @param photoByte 鏂囦欢瀛楄妭鐮�
-     * @return 鍚庣紑锛堜笉鍚�".")
-     */
-    public static String getFileExtendName(byte[] photoByte)
-    {
-        String strFileExtendName = "JPG";
-        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
-                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
-        {
-            strFileExtendName = "GIF";
-        }
-        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
-        {
-            strFileExtendName = "JPG";
-        }
-        else if ((photoByte[0] == 66) && (photoByte[1] == 77))
-        {
-            strFileExtendName = "BMP";
-        }
-        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
-        {
-            strFileExtendName = "PNG";
-        }
-        return strFileExtendName;
-    }
-}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
deleted file mode 100644
index 22d53c7..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
+++ /dev/null
@@ -1,239 +0,0 @@
-package com.ruoyi.common.utils.file;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
-import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
-import com.ruoyi.common.exception.file.InvalidExtensionException;
-import com.ruoyi.common.utils.DateUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * 鏂囦欢涓婁紶宸ュ叿绫�
- *
- * @author ruoyi
- */
-public class FileUploadUtils
-{
-    /**
-     * 榛樿澶у皬 50M
-     */
-    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
-
-    /**
-     * 榛樿鐨勬枃浠跺悕鏈�澶ч暱搴� 100
-     */
-    public static final int DEFAULT_FILE_NAME_LENGTH = 100;
-
-    /**
-     * 榛樿涓婁紶鐨勫湴鍧�
-     */
-    private static String defaultBaseDir = RuoYiConfig.getProfile();
-
-    public static void setDefaultBaseDir(String defaultBaseDir)
-    {
-        FileUploadUtils.defaultBaseDir = defaultBaseDir;
-    }
-
-    public static String getDefaultBaseDir()
-    {
-        return defaultBaseDir;
-    }
-
-    /**
-     * 浠ラ粯璁ら厤缃繘琛屾枃浠朵笂浼�
-     *
-     * @param file 涓婁紶鐨勬枃浠�
-     * @return 鏂囦欢鍚嶇О
-     * @throws Exception
-     */
-    public static final String upload(MultipartFile file) throws IOException
-    {
-        try
-        {
-            return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
-        }
-        catch (Exception e)
-        {
-            throw new IOException(e.getMessage(), e);
-        }
-    }
-
-    /**
-     * 鏍规嵁鏂囦欢璺緞涓婁紶
-     *
-     * @param baseDir 鐩稿搴旂敤鐨勫熀鐩綍
-     * @param file 涓婁紶鐨勬枃浠�
-     * @return 鏂囦欢鍚嶇О
-     * @throws IOException
-     */
-    public static final String upload(String baseDir, MultipartFile file) throws IOException
-    {
-        try
-        {
-            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
-        }
-        catch (Exception e)
-        {
-            throw new IOException(e.getMessage(), e);
-        }
-    }
-
-    /**
-     * 鏂囦欢涓婁紶
-     *
-     * @param baseDir 鐩稿搴旂敤鐨勫熀鐩綍
-     * @param file 涓婁紶鐨勬枃浠�
-     * @param allowedExtension 涓婁紶鏂囦欢绫诲瀷
-     * @return 杩斿洖涓婁紶鎴愬姛鐨勬枃浠跺悕
-     * @throws FileSizeLimitExceededException 濡傛灉瓒呭嚭鏈�澶уぇ灏�
-     * @throws FileNameLengthLimitExceededException 鏂囦欢鍚嶅お闀�
-     * @throws IOException 姣斿璇诲啓鏂囦欢鍑洪敊鏃�
-     * @throws InvalidExtensionException 鏂囦欢鏍¢獙寮傚父
-     */
-    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
-            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
-            InvalidExtensionException
-    {
-        int fileNamelength = file.getOriginalFilename().length();
-        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
-        {
-            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
-        }
-
-        assertAllowed(file, allowedExtension);
-
-        String fileName = extractFilename(file);
-
-        File desc = getAbsoluteFile(baseDir, fileName);
-		desc = FileUtil.touch(desc);
-		FileUtil.writeFromStream(file.getInputStream(), desc);
-        String pathFileName = getPathFileName(baseDir, fileName);
-        return pathFileName;
-    }
-
-    /**
-     * 缂栫爜鏂囦欢鍚�
-     */
-    public static final String extractFilename(MultipartFile file)
-    {
-        String fileName = file.getOriginalFilename();
-        String extension = getExtension(file);
-        fileName = DateUtils.datePath() + "/" + IdUtil.fastUUID() + "." + extension;
-        return fileName;
-    }
-
-    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
-    {
-        File desc = new File(uploadDir + File.separator + fileName);
-
-        if (!desc.exists())
-        {
-            if (!desc.getParentFile().exists())
-            {
-                desc.getParentFile().mkdirs();
-            }
-        }
-        return desc;
-    }
-
-    private static final String getPathFileName(String uploadDir, String fileName) throws IOException
-    {
-        int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
-        String currentDir = StrUtil.subSuf(uploadDir, dirLastIndex);
-        String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
-        return pathFileName;
-    }
-
-    /**
-     * 鏂囦欢澶у皬鏍¢獙
-     *
-     * @param file 涓婁紶鐨勬枃浠�
-     * @return
-     * @throws FileSizeLimitExceededException 濡傛灉瓒呭嚭鏈�澶уぇ灏�
-     * @throws InvalidExtensionException
-     */
-    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
-            throws FileSizeLimitExceededException, InvalidExtensionException
-    {
-        long size = file.getSize();
-        if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
-        {
-            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
-        }
-
-        String fileName = file.getOriginalFilename();
-        String extension = getExtension(file);
-        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
-        {
-            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
-            {
-                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
-                        fileName);
-            }
-            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
-            {
-                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
-                        fileName);
-            }
-            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
-            {
-                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
-                        fileName);
-            }
-            else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
-            {
-                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
-                        fileName);
-            }
-            else
-            {
-                throw new InvalidExtensionException(allowedExtension, extension, fileName);
-            }
-        }
-
-    }
-
-    /**
-     * 鍒ゆ柇MIME绫诲瀷鏄惁鏄厑璁哥殑MIME绫诲瀷
-     *
-     * @param extension
-     * @param allowedExtension
-     * @return
-     */
-    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
-    {
-        for (String str : allowedExtension)
-        {
-            if (str.equalsIgnoreCase(extension))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * 鑾峰彇鏂囦欢鍚嶇殑鍚庣紑
-     *
-     * @param file 琛ㄥ崟鏂囦欢
-     * @return 鍚庣紑鍚�
-     */
-    public static final String getExtension(MultipartFile file)
-    {
-        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
-        if (Validator.isEmpty(extension))
-        {
-            extension = MimeTypeUtils.getExtension(file.getContentType());
-        }
-        return extension;
-    }
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
index bc953de..dc3aea2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -1,12 +1,9 @@
 package com.ruoyi.common.utils.file;
 
 import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
 
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.*;
+import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 
@@ -17,77 +14,6 @@
  */
 public class FileUtils extends FileUtil
 {
-    public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
-
-    /**
-     * 鏂囦欢鍚嶇О楠岃瘉
-     *
-     * @param filename 鏂囦欢鍚嶇О
-     * @return true 姝e父 false 闈炴硶
-     */
-    public static boolean isValidFilename(String filename)
-    {
-        return filename.matches(FILENAME_PATTERN);
-    }
-
-    /**
-     * 妫�鏌ユ枃浠舵槸鍚﹀彲涓嬭浇
-     *
-     * @param resource 闇�瑕佷笅杞界殑鏂囦欢
-     * @return true 姝e父 false 闈炴硶
-     */
-    public static boolean checkAllowDownload(String resource)
-    {
-        // 绂佹鐩綍涓婅烦绾у埆
-        if (StrUtil.contains(resource, ".."))
-        {
-            return false;
-        }
-
-        // 妫�鏌ュ厑璁镐笅杞界殑鏂囦欢瑙勫垯
-        if (ArrayUtil.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
-        {
-            return true;
-        }
-
-        // 涓嶅湪鍏佽涓嬭浇鐨勬枃浠惰鍒�
-        return false;
-    }
-
-    /**
-     * 涓嬭浇鏂囦欢鍚嶉噸鏂扮紪鐮�
-     *
-     * @param request 璇锋眰瀵硅薄
-     * @param fileName 鏂囦欢鍚�
-     * @return 缂栫爜鍚庣殑鏂囦欢鍚�
-     */
-    public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
-    {
-        final String agent = request.getHeader("USER-AGENT");
-        String filename = fileName;
-        if (agent.contains("MSIE"))
-        {
-            // IE娴忚鍣�
-            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
-            filename = filename.replace("+", " ");
-        }
-        else if (agent.contains("Firefox"))
-        {
-            // 鐏嫄娴忚鍣�
-            filename = new String(fileName.getBytes(), "ISO8859-1");
-        }
-        else if (agent.contains("Chrome"))
-        {
-            // google娴忚鍣�
-            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
-        }
-        else
-        {
-            // 鍏跺畠娴忚鍣�
-            filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
-        }
-        return filename;
-    }
 
     /**
      * 涓嬭浇鏂囦欢鍚嶉噸鏂扮紪鐮�
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java
deleted file mode 100644
index 94dcf45..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.ruoyi.common.utils.file;
-
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import org.apache.poi.util.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Arrays;
-
-/**
- * 鍥剧墖澶勭悊宸ュ叿绫�
- *
- * @author ruoyi
- */
-public class ImageUtils
-{
-    private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
-
-    public static byte[] getImage(String imagePath)
-    {
-        InputStream is = getFile(imagePath);
-        try
-        {
-            return IOUtils.toByteArray(is);
-        }
-        catch (Exception e)
-        {
-            log.error("鍥剧墖鍔犺浇寮傚父 {}", e);
-            return null;
-        }
-        finally
-        {
-            IOUtils.closeQuietly(is);
-        }
-    }
-
-    public static InputStream getFile(String imagePath)
-    {
-        try
-        {
-            byte[] result = readFile(imagePath);
-            result = Arrays.copyOf(result, result.length);
-            return new ByteArrayInputStream(result);
-        }
-        catch (Exception e)
-        {
-            log.error("鑾峰彇鍥剧墖寮傚父 {}", e);
-        }
-        return null;
-    }
-
-    /**
-     * 璇诲彇鏂囦欢涓哄瓧鑺傛暟鎹�
-     * 
-     * @param key 鍦板潃
-     * @return 瀛楄妭鏁版嵁
-     */
-    public static byte[] readFile(String url)
-    {
-        InputStream in = null;
-        ByteArrayOutputStream baos = null;
-        try
-        {
-            if (url.startsWith("http"))
-            {
-                // 缃戠粶鍦板潃
-                URL urlObj = new URL(url);
-                URLConnection urlConnection = urlObj.openConnection();
-                urlConnection.setConnectTimeout(30 * 1000);
-                urlConnection.setReadTimeout(60 * 1000);
-                urlConnection.setDoInput(true);
-                in = urlConnection.getInputStream();
-            }
-            else
-            {
-                // 鏈満鍦板潃
-                String localPath = RuoYiConfig.getProfile();
-                String downloadPath = localPath + StrUtil.subAfter(url, Constants.RESOURCE_PREFIX,false);
-                in = new FileInputStream(downloadPath);
-            }
-            return IOUtils.toByteArray(in);
-        }
-        catch (Exception e)
-        {
-            log.error("鑾峰彇鏂囦欢璺緞寮傚父 {}", e);
-            return null;
-        }
-        finally
-        {
-            IOUtils.closeQuietly(in);
-            IOUtils.closeQuietly(baos);
-        }
-    }
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
deleted file mode 100644
index f968f1a..0000000
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.common.utils.file;
-
-/**
- * 濯掍綋绫诲瀷宸ュ叿绫�
- * 
- * @author ruoyi
- */
-public class MimeTypeUtils
-{
-    public static final String IMAGE_PNG = "image/png";
-
-    public static final String IMAGE_JPG = "image/jpg";
-
-    public static final String IMAGE_JPEG = "image/jpeg";
-
-    public static final String IMAGE_BMP = "image/bmp";
-
-    public static final String IMAGE_GIF = "image/gif";
-    
-    public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
-
-    public static final String[] FLASH_EXTENSION = { "swf", "flv" };
-
-    public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
-            "asf", "rm", "rmvb" };
-
-    public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };
-
-    public static final String[] DEFAULT_ALLOWED_EXTENSION = {
-            // 鍥剧墖
-            "bmp", "gif", "jpg", "jpeg", "png",
-            // word excel powerpoint
-            "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
-            // 鍘嬬缉鏂囦欢
-            "rar", "zip", "gz", "bz2",
-            // 瑙嗛鏍煎紡
-            "mp4", "avi", "rmvb",
-            // pdf
-            "pdf" };
-
-    public static String getExtension(String prefix)
-    {
-        switch (prefix)
-        {
-            case IMAGE_PNG:
-                return "png";
-            case IMAGE_JPG:
-                return "jpg";
-            case IMAGE_JPEG:
-                return "jpeg";
-            case IMAGE_BMP:
-                return "bmp";
-            case IMAGE_GIF:
-                return "gif";
-            default:
-                return "";
-        }
-    }
-}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
index d6c262a..03c608a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
@@ -1,12 +1,12 @@
 package com.ruoyi.common.utils.ip;
 
 import cn.hutool.core.net.NetUtil;
-import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HtmlUtil;
 import cn.hutool.http.HttpUtil;
 import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.StringUtils;
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.Map;
@@ -38,7 +38,7 @@
 					.body("ip=" + ip + "&json=true", Constants.GBK)
 					.execute()
 					.body();
-				if (StrUtil.isEmpty(rspStr)) {
+				if (StringUtils.isEmpty(rspStr)) {
 					log.error("鑾峰彇鍦扮悊浣嶇疆寮傚父 {}", ip);
 					return UNKNOWN;
 				}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
index 96843d1..f242d8c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -1,1072 +1,150 @@
 package com.ruoyi.common.utils.poi;
 
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.annotation.Excel.Type;
-import com.ruoyi.common.annotation.Excels;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.exception.CustomException;
-import com.ruoyi.common.utils.DateUtils;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
 import com.ruoyi.common.utils.DictUtils;
-import com.ruoyi.common.utils.file.FileTypeUtils;
-import com.ruoyi.common.utils.file.ImageUtils;
-import com.ruoyi.common.utils.reflect.ReflectUtils;
-import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.file.FileUtils;
 
-import java.io.*;
-import java.lang.reflect.Field;
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.util.*;
-import java.util.stream.Collectors;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
 
 /**
  * Excel鐩稿叧澶勭悊
  *
  * @author ruoyi
  */
-public class ExcelUtil<T>
-{
-    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+public class ExcelUtil {
 
-    /**
-     * Excel sheet鏈�澶ц鏁帮紝榛樿65536
-     */
-    public static final int sheetSize = 65536;
+	/**
+	 * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist锛圗asyExcel锛�
+	 *
+	 * @param is 杈撳叆娴�
+	 * @return 杞崲鍚庨泦鍚�
+	 */
+	public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
+		return EasyExcel.read(is).autoCloseStream(false).sheet().doReadSync();
+	}
 
-    /**
-     * 宸ヤ綔琛ㄥ悕绉�
-     */
-    private String sheetName;
+	/**
+	 * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟锛圗asyExcel锛�
+	 *
+	 * @param list      瀵煎嚭鏁版嵁闆嗗悎
+	 * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+	 * @return 缁撴灉
+	 */
+	public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) {
+		try {
+			String filename = encodingFilename(sheetName);
+			response.reset();
+			response.addHeader("Access-Control-Allow-Origin", "*");
+			response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+			FileUtils.setAttachmentResponseHeader(response, URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()));
+			response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
+			ServletOutputStream os = response.getOutputStream();
+			EasyExcel.write(os, clazz)
+				.autoCloseStream(false)
+				// 鑷姩閫傞厤
+				.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
+				.sheet(sheetName).doWrite(list);
+		} catch (IOException e) {
+			throw new RuntimeException("瀵煎嚭Excel寮傚父");
+		}
+	}
 
-    /**
-     * 瀵煎嚭绫诲瀷锛圗XPORT:瀵煎嚭鏁版嵁锛汭MPORT锛氬鍏ユā鏉匡級
-     */
-    private Type type;
+	/**
+	 * 瑙f瀽瀵煎嚭鍊� 0=鐢�,1=濂�,2=鏈煡
+	 *
+	 * @param propertyValue 鍙傛暟鍊�
+	 * @param converterExp  缈昏瘧娉ㄨВ
+	 * @param separator     鍒嗛殧绗�
+	 * @return 瑙f瀽鍚庡��
+	 */
+	public static String convertByExp(String propertyValue, String converterExp, String separator) {
+		StringBuilder propertyString = new StringBuilder();
+		String[] convertSource = converterExp.split(",");
+		for (String item : convertSource) {
+			String[] itemArray = item.split("=");
+			if (StringUtils.containsAny(separator, propertyValue)) {
+				for (String value : propertyValue.split(separator)) {
+					if (itemArray[0].equals(value)) {
+						propertyString.append(itemArray[1] + separator);
+						break;
+					}
+				}
+			} else {
+				if (itemArray[0].equals(propertyValue)) {
+					return itemArray[1];
+				}
+			}
+		}
+		return StringUtils.stripEnd(propertyString.toString(), separator);
+	}
 
-    /**
-     * 宸ヤ綔钖勫璞�
-     */
-    private Workbook wb;
+	/**
+	 * 鍙嶅悜瑙f瀽鍊� 鐢�=0,濂�=1,鏈煡=2
+	 *
+	 * @param propertyValue 鍙傛暟鍊�
+	 * @param converterExp  缈昏瘧娉ㄨВ
+	 * @param separator     鍒嗛殧绗�
+	 * @return 瑙f瀽鍚庡��
+	 */
+	public static String reverseByExp(String propertyValue, String converterExp, String separator) {
+		StringBuilder propertyString = new StringBuilder();
+		String[] convertSource = converterExp.split(",");
+		for (String item : convertSource) {
+			String[] itemArray = item.split("=");
+			if (StringUtils.containsAny(separator, propertyValue)) {
+				for (String value : propertyValue.split(separator)) {
+					if (itemArray[1].equals(value)) {
+						propertyString.append(itemArray[0] + separator);
+						break;
+					}
+				}
+			} else {
+				if (itemArray[1].equals(propertyValue)) {
+					return itemArray[0];
+				}
+			}
+		}
+		return StringUtils.stripEnd(propertyString.toString(), separator);
+	}
 
-    /**
-     * 宸ヤ綔琛ㄥ璞�
-     */
-    private Sheet sheet;
+	/**
+	 * 瑙f瀽瀛楀吀鍊�
+	 *
+	 * @param dictValue 瀛楀吀鍊�
+	 * @param dictType  瀛楀吀绫诲瀷
+	 * @param separator 鍒嗛殧绗�
+	 * @return 瀛楀吀鏍囩
+	 */
+	public static String convertDictByExp(String dictValue, String dictType, String separator) {
+		return DictUtils.getDictLabel(dictType, dictValue, separator);
+	}
 
-    /**
-     * 鏍峰紡鍒楄〃
-     */
-    private Map<String, CellStyle> styles;
+	/**
+	 * 鍙嶅悜瑙f瀽鍊煎瓧鍏稿��
+	 *
+	 * @param dictLabel 瀛楀吀鏍囩
+	 * @param dictType  瀛楀吀绫诲瀷
+	 * @param separator 鍒嗛殧绗�
+	 * @return 瀛楀吀鍊�
+	 */
+	public static String reverseDictByExp(String dictLabel, String dictType, String separator) {
+		return DictUtils.getDictValue(dictType, dictLabel, separator);
+	}
 
-    /**
-     * 瀵煎叆瀵煎嚭鏁版嵁鍒楄〃
-     */
-    private List<T> list;
+	/**
+	 * 缂栫爜鏂囦欢鍚�
+	 */
+	public static String encodingFilename(String filename) {
+		return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
+	}
 
-    /**
-     * 娉ㄨВ鍒楄〃
-     */
-    private List<Object[]> fields;
-
-    /**
-     * 鏈�澶ч珮搴�
-     */
-    private short maxHeight;
-
-    /**
-     * 缁熻鍒楄〃
-     */
-    private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
-
-    /**
-     * 鏁板瓧鏍煎紡
-     */
-    private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
-
-    /**
-     * 瀹炰綋瀵硅薄
-     */
-    public Class<T> clazz;
-
-    public ExcelUtil(Class<T> clazz)
-    {
-        this.clazz = clazz;
-    }
-
-    public void init(List<T> list, String sheetName, Type type)
-    {
-        if (list == null)
-        {
-            list = new ArrayList<T>();
-        }
-        this.list = list;
-        this.sheetName = sheetName;
-        this.type = type;
-        createExcelField();
-        createWorkbook();
-    }
-
-    /**
-     * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist
-     *
-     * @param is 杈撳叆娴�
-     * @return 杞崲鍚庨泦鍚�
-     */
-    public List<T> importExcel(InputStream is) throws Exception
-    {
-        return importExcel(StrUtil.EMPTY, is);
-    }
-
-    /**
-     * 瀵筫xcel琛ㄥ崟鎸囧畾琛ㄦ牸绱㈠紩鍚嶈浆鎹㈡垚list
-     *
-     * @param sheetName 琛ㄦ牸绱㈠紩鍚�
-     * @param is 杈撳叆娴�
-     * @return 杞崲鍚庨泦鍚�
-     */
-    public List<T> importExcel(String sheetName, InputStream is) throws Exception
-    {
-        this.type = Type.IMPORT;
-        this.wb = WorkbookFactory.create(is);
-        List<T> list = new ArrayList<T>();
-        Sheet sheet = null;
-        if (Validator.isNotEmpty(sheetName))
-        {
-            // 濡傛灉鎸囧畾sheet鍚�,鍒欏彇鎸囧畾sheet涓殑鍐呭.
-            sheet = wb.getSheet(sheetName);
-        }
-        else
-        {
-            // 濡傛灉浼犲叆鐨剆heet鍚嶄笉瀛樺湪鍒欓粯璁ゆ寚鍚戠1涓猻heet.
-            sheet = wb.getSheetAt(0);
-        }
-
-        if (sheet == null)
-        {
-            throw new IOException("鏂囦欢sheet涓嶅瓨鍦�");
-        }
-
-        int rows = sheet.getPhysicalNumberOfRows();
-
-        if (rows > 0)
-        {
-            // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁excel鍒楃殑搴忓彿鍜宖ield.
-            Map<String, Integer> cellMap = new HashMap<String, Integer>();
-            // 鑾峰彇琛ㄥご
-            Row heard = sheet.getRow(0);
-            for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
-            {
-                Cell cell = heard.getCell(i);
-                if (Validator.isNotNull(cell))
-                {
-                    String value = this.getCellValue(heard, i).toString();
-                    cellMap.put(value, i);
-                }
-                else
-                {
-                    cellMap.put(null, i);
-                }
-            }
-            // 鏈夋暟鎹椂鎵嶅鐞� 寰楀埌绫荤殑鎵�鏈塮ield.
-            Field[] allFields = clazz.getDeclaredFields();
-            // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁鍒楃殑搴忓彿鍜宖ield.
-            Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
-            for (int col = 0; col < allFields.length; col++)
-            {
-                Field field = allFields[col];
-                Excel attr = field.getAnnotation(Excel.class);
-                if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
-                {
-                    // 璁剧疆绫荤殑绉佹湁瀛楁灞炴�у彲璁块棶.
-                    field.setAccessible(true);
-                    Integer column = cellMap.get(attr.name());
-                    if (column != null)
-                    {
-                        fieldsMap.put(column, field);
-                    }
-                }
-            }
-            for (int i = 1; i < rows; i++)
-            {
-                // 浠庣2琛屽紑濮嬪彇鏁版嵁,榛樿绗竴琛屾槸琛ㄥご.
-                Row row = sheet.getRow(i);
-                if(row == null)
-                {
-                    continue;
-                }
-                T entity = null;
-                for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
-                {
-                    Object val = this.getCellValue(row, entry.getKey());
-
-                    // 濡傛灉涓嶅瓨鍦ㄥ疄渚嬪垯鏂板缓.
-                    entity = (entity == null ? clazz.newInstance() : entity);
-                    // 浠巑ap涓緱鍒板搴斿垪鐨刦ield.
-                    Field field = fieldsMap.get(entry.getKey());
-                    // 鍙栧緱绫诲瀷,骞舵牴鎹璞$被鍨嬭缃��.
-                    Class<?> fieldType = field.getType();
-                    if (String.class == fieldType)
-                    {
-                        String s = Convert.toStr(val);
-                        if (StrUtil.endWith(s, ".0"))
-                        {
-                            val = StrUtil.subBefore(s, ".0",false);
-                        }
-                        else
-                        {
-                            String dateFormat = field.getAnnotation(Excel.class).dateFormat();
-                            if (Validator.isNotEmpty(dateFormat))
-                            {
-                                val = DateUtils.parseDateToStr(dateFormat, (Date) val);
-                            }
-                            else
-                            {
-                                val = Convert.toStr(val);
-                            }
-                        }
-                    }
-                    else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && Validator.isNumber(Convert.toStr(val)))
-                    {
-                        val = Convert.toInt(val);
-                    }
-                    else if (Long.TYPE == fieldType || Long.class == fieldType)
-                    {
-                        val = Convert.toLong(val);
-                    }
-                    else if (Double.TYPE == fieldType || Double.class == fieldType)
-                    {
-                        val = Convert.toDouble(val);
-                    }
-                    else if (Float.TYPE == fieldType || Float.class == fieldType)
-                    {
-                        val = Convert.toFloat(val);
-                    }
-                    else if (BigDecimal.class == fieldType)
-                    {
-                        val = Convert.toBigDecimal(val);
-                    }
-                    else if (Date.class == fieldType)
-                    {
-                        if (val instanceof String)
-                        {
-                            val = DateUtils.parseDate(val);
-                        }
-                        else if (val instanceof Double)
-                        {
-                            val = DateUtil.getJavaDate((Double) val);
-                        }
-                    }
-                    else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
-                    {
-                        val = Convert.toBool(val, false);
-                    }
-                    if (Validator.isNotNull(fieldType))
-                    {
-                        Excel attr = field.getAnnotation(Excel.class);
-                        String propertyName = field.getName();
-                        if (Validator.isNotEmpty(attr.targetAttr()))
-                        {
-                            propertyName = field.getName() + "." + attr.targetAttr();
-                        }
-                        else if (Validator.isNotEmpty(attr.readConverterExp()))
-                        {
-                            val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
-                        }
-                        else if (Validator.isNotEmpty(attr.dictType()))
-                        {
-                            val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
-                        }
-                        ReflectUtils.invokeSetter(entity, propertyName, val);
-                    }
-                }
-                list.add(entity);
-            }
-        }
-        return list;
-    }
-
-    /**
-     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
-     *
-     * @param list 瀵煎嚭鏁版嵁闆嗗悎
-     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
-     * @return 缁撴灉
-     */
-    public AjaxResult exportExcel(List<T> list, String sheetName)
-    {
-        this.init(list, sheetName, Type.EXPORT);
-        return exportExcel();
-    }
-
-    /**
-     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
-     *
-     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
-     * @return 缁撴灉
-     */
-    public AjaxResult importTemplateExcel(String sheetName)
-    {
-        this.init(null, sheetName, Type.IMPORT);
-        return exportExcel();
-    }
-
-    /**
-     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
-     *
-     * @return 缁撴灉
-     */
-    public AjaxResult exportExcel()
-    {
-        OutputStream out = null;
-        try
-        {
-            // 鍙栧嚭涓�鍏辨湁澶氬皯涓猻heet.
-            double sheetNo = Math.ceil(list.size() / sheetSize);
-            for (int index = 0; index <= sheetNo; index++)
-            {
-                createSheet(sheetNo, index);
-
-                // 浜х敓涓�琛�
-                Row row = sheet.createRow(0);
-                int column = 0;
-                // 鍐欏叆鍚勪釜瀛楁鐨勫垪澶村悕绉�
-                for (Object[] os : fields)
-                {
-                    Excel excel = (Excel) os[1];
-                    this.createCell(excel, row, column++);
-                }
-                if (Type.EXPORT.equals(type))
-                {
-                    fillExcelData(index, row);
-                    addStatisticsRow();
-                }
-            }
-            String filename = encodingFilename(sheetName);
-            out = new FileOutputStream(getAbsoluteFile(filename));
-            wb.write(out);
-            return AjaxResult.success(filename);
-        }
-        catch (Exception e)
-        {
-            log.error("瀵煎嚭Excel寮傚父{}", e.getMessage());
-            throw new CustomException("瀵煎嚭Excel澶辫触锛岃鑱旂郴缃戠珯绠$悊鍛橈紒");
-        }
-        finally
-        {
-            if (wb != null)
-            {
-                try
-                {
-                    wb.close();
-                }
-                catch (IOException e1)
-                {
-                    e1.printStackTrace();
-                }
-            }
-            if (out != null)
-            {
-                try
-                {
-                    out.close();
-                }
-                catch (IOException e1)
-                {
-                    e1.printStackTrace();
-                }
-            }
-        }
-    }
-
-    /**
-     * 濉厖excel鏁版嵁
-     *
-     * @param index 搴忓彿
-     * @param row 鍗曞厓鏍艰
-     */
-    public void fillExcelData(int index, Row row)
-    {
-        int startNo = index * sheetSize;
-        int endNo = Math.min(startNo + sheetSize, list.size());
-        for (int i = startNo; i < endNo; i++)
-        {
-            row = sheet.createRow(i + 1 - startNo);
-            // 寰楀埌瀵煎嚭瀵硅薄.
-            T vo = (T) list.get(i);
-            int column = 0;
-            for (Object[] os : fields)
-            {
-                Field field = (Field) os[0];
-                Excel excel = (Excel) os[1];
-                // 璁剧疆瀹炰綋绫荤鏈夊睘鎬у彲璁块棶
-                field.setAccessible(true);
-                this.addCell(excel, row, vo, field, column++);
-            }
-        }
-    }
-
-    /**
-     * 鍒涘缓琛ㄦ牸鏍峰紡
-     *
-     * @param wb 宸ヤ綔钖勫璞�
-     * @return 鏍峰紡鍒楄〃
-     */
-    private Map<String, CellStyle> createStyles(Workbook wb)
-    {
-        // 鍐欏叆鍚勬潯璁板綍,姣忔潯璁板綍瀵瑰簲excel琛ㄤ腑鐨勪竴琛�
-        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
-        CellStyle style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.THIN);
-        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        Font dataFont = wb.createFont();
-        dataFont.setFontName("Arial");
-        dataFont.setFontHeightInPoints((short) 10);
-        style.setFont(dataFont);
-        styles.put("data", style);
-
-        style = wb.createCellStyle();
-        style.cloneStyleFrom(styles.get("data"));
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-        Font headerFont = wb.createFont();
-        headerFont.setFontName("Arial");
-        headerFont.setFontHeightInPoints((short) 10);
-        headerFont.setBold(true);
-        headerFont.setColor(IndexedColors.WHITE.getIndex());
-        style.setFont(headerFont);
-        styles.put("header", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        Font totalFont = wb.createFont();
-        totalFont.setFontName("Arial");
-        totalFont.setFontHeightInPoints((short) 10);
-        style.setFont(totalFont);
-        styles.put("total", style);
-
-        style = wb.createCellStyle();
-        style.cloneStyleFrom(styles.get("data"));
-        style.setAlignment(HorizontalAlignment.LEFT);
-        styles.put("data1", style);
-
-        style = wb.createCellStyle();
-        style.cloneStyleFrom(styles.get("data"));
-        style.setAlignment(HorizontalAlignment.CENTER);
-        styles.put("data2", style);
-
-        style = wb.createCellStyle();
-        style.cloneStyleFrom(styles.get("data"));
-        style.setAlignment(HorizontalAlignment.RIGHT);
-        styles.put("data3", style);
-
-        return styles;
-    }
-
-    /**
-     * 鍒涘缓鍗曞厓鏍�
-     */
-    public Cell createCell(Excel attr, Row row, int column)
-    {
-        // 鍒涘缓鍒�
-        Cell cell = row.createCell(column);
-        // 鍐欏叆鍒椾俊鎭�
-        cell.setCellValue(attr.name());
-        setDataValidation(attr, row, column);
-        cell.setCellStyle(styles.get("header"));
-        return cell;
-    }
-
-    /**
-     * 璁剧疆鍗曞厓鏍间俊鎭�
-     *
-     * @param value 鍗曞厓鏍煎��
-     * @param attr 娉ㄨВ鐩稿叧
-     * @param cell 鍗曞厓鏍间俊鎭�
-     */
-    public void setCellVo(Object value, Excel attr, Cell cell)
-    {
-        if (ColumnType.STRING == attr.cellType())
-        {
-            cell.setCellValue(Validator.isNull(value) ? attr.defaultValue() : value + attr.suffix());
-        }
-        else if (ColumnType.NUMERIC == attr.cellType())
-        {
-            if (Validator.isNotNull(value))
-            {
-                cell.setCellValue(StrUtil.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
-            }
-        }
-        else if (ColumnType.IMAGE == attr.cellType())
-        {
-            ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
-                    cell.getRow().getRowNum() + 1);
-            String imagePath = Convert.toStr(value);
-            if (Validator.isNotEmpty(imagePath))
-            {
-                byte[] data = ImageUtils.getImage(imagePath);
-                getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
-                        cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
-            }
-        }
-    }
-
-    /**
-     * 鑾峰彇鐢诲竷
-     */
-    public static Drawing<?> getDrawingPatriarch(Sheet sheet)
-    {
-        if (sheet.getDrawingPatriarch() == null)
-        {
-            sheet.createDrawingPatriarch();
-        }
-        return sheet.getDrawingPatriarch();
-    }
-
-    /**
-     * 鑾峰彇鍥剧墖绫诲瀷,璁剧疆鍥剧墖鎻掑叆绫诲瀷
-     */
-    public int getImageType(byte[] value)
-    {
-        String type = FileTypeUtils.getFileExtendName(value);
-        if ("JPG".equalsIgnoreCase(type))
-        {
-            return Workbook.PICTURE_TYPE_JPEG;
-        }
-        else if ("PNG".equalsIgnoreCase(type))
-        {
-            return Workbook.PICTURE_TYPE_PNG;
-        }
-        return Workbook.PICTURE_TYPE_JPEG;
-    }
-
-    /**
-     * 鍒涘缓琛ㄦ牸鏍峰紡
-     */
-    public void setDataValidation(Excel attr, Row row, int column)
-    {
-        if (attr.name().indexOf("娉細") >= 0)
-        {
-            sheet.setColumnWidth(column, 6000);
-        }
-        else
-        {
-            // 璁剧疆鍒楀
-            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
-        }
-        // 濡傛灉璁剧疆浜嗘彁绀轰俊鎭垯榧犳爣鏀句笂鍘绘彁绀�.
-        if (Validator.isNotEmpty(attr.prompt()))
-        {
-            // 杩欓噷榛樿璁句簡2-101鍒楁彁绀�.
-            setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
-        }
-        // 濡傛灉璁剧疆浜哻ombo灞炴�у垯鏈垪鍙兘閫夋嫨涓嶈兘杈撳叆
-        if (attr.combo().length > 0)
-        {
-            // 杩欓噷榛樿璁句簡2-101鍒楀彧鑳介�夋嫨涓嶈兘杈撳叆.
-            setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
-        }
-    }
-
-    /**
-     * 娣诲姞鍗曞厓鏍�
-     */
-    public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
-    {
-        Cell cell = null;
-        try
-        {
-            // 璁剧疆琛岄珮
-            row.setHeight(maxHeight);
-            // 鏍规嵁Excel涓缃儏鍐靛喅瀹氭槸鍚﹀鍑�,鏈変簺鎯呭喌闇�瑕佷繚鎸佷负绌�,甯屾湜鐢ㄦ埛濉啓杩欎竴鍒�.
-            if (attr.isExport())
-            {
-                // 鍒涘缓cell
-                cell = row.createCell(column);
-                int align = attr.align().value();
-                cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : "")));
-
-                // 鐢ㄤ簬璇诲彇瀵硅薄涓殑灞炴��
-                Object value = getTargetValue(vo, field, attr);
-                String dateFormat = attr.dateFormat();
-                String readConverterExp = attr.readConverterExp();
-                String separator = attr.separator();
-                String dictType = attr.dictType();
-                if (Validator.isNotEmpty(dateFormat) && Validator.isNotNull(value))
-                {
-                    cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
-                }
-                else if (Validator.isNotEmpty(readConverterExp) && Validator.isNotNull(value))
-                {
-                    cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
-                }
-                else if (Validator.isNotEmpty(dictType) && Validator.isNotNull(value))
-                {
-                    cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator));
-                }
-                else if (value instanceof BigDecimal && -1 != attr.scale())
-                {
-                    cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());
-                }
-                else
-                {
-                    // 璁剧疆鍒楃被鍨�
-                    setCellVo(value, attr, cell);
-                }
-                addStatisticsData(column, Convert.toStr(value), attr);
-            }
-        }
-        catch (Exception e)
-        {
-            log.error("瀵煎嚭Excel澶辫触{}", e);
-        }
-        return cell;
-    }
-
-    /**
-     * 璁剧疆 POI XSSFSheet 鍗曞厓鏍兼彁绀�
-     *
-     * @param sheet 琛ㄥ崟
-     * @param promptTitle 鎻愮ず鏍囬
-     * @param promptContent 鎻愮ず鍐呭
-     * @param firstRow 寮�濮嬭
-     * @param endRow 缁撴潫琛�
-     * @param firstCol 寮�濮嬪垪
-     * @param endCol 缁撴潫鍒�
-     */
-    public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
-            int firstCol, int endCol)
-    {
-        DataValidationHelper helper = sheet.getDataValidationHelper();
-        DataValidationConstraint constraint = helper.createCustomConstraint("DD1");
-        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
-        DataValidation dataValidation = helper.createValidation(constraint, regions);
-        dataValidation.createPromptBox(promptTitle, promptContent);
-        dataValidation.setShowPromptBox(true);
-        sheet.addValidationData(dataValidation);
-    }
-
-    /**
-     * 璁剧疆鏌愪簺鍒楃殑鍊煎彧鑳借緭鍏ラ鍒剁殑鏁版嵁,鏄剧ず涓嬫媺妗�.
-     *
-     * @param sheet 瑕佽缃殑sheet.
-     * @param textlist 涓嬫媺妗嗘樉绀虹殑鍐呭
-     * @param firstRow 寮�濮嬭
-     * @param endRow 缁撴潫琛�
-     * @param firstCol 寮�濮嬪垪
-     * @param endCol 缁撴潫鍒�
-     * @return 璁剧疆濂界殑sheet.
-     */
-    public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol)
-    {
-        DataValidationHelper helper = sheet.getDataValidationHelper();
-        // 鍔犺浇涓嬫媺鍒楄〃鍐呭
-        DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
-        // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪
-        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
-        // 鏁版嵁鏈夋晥鎬у璞�
-        DataValidation dataValidation = helper.createValidation(constraint, regions);
-        // 澶勭悊Excel鍏煎鎬ч棶棰�
-        if (dataValidation instanceof XSSFDataValidation)
-        {
-            dataValidation.setSuppressDropDownArrow(true);
-            dataValidation.setShowErrorBox(true);
-        }
-        else
-        {
-            dataValidation.setSuppressDropDownArrow(false);
-        }
-
-        sheet.addValidationData(dataValidation);
-    }
-
-    /**
-     * 瑙f瀽瀵煎嚭鍊� 0=鐢�,1=濂�,2=鏈煡
-     *
-     * @param propertyValue 鍙傛暟鍊�
-     * @param converterExp 缈昏瘧娉ㄨВ
-     * @param separator 鍒嗛殧绗�
-     * @return 瑙f瀽鍚庡��
-     */
-    public static String convertByExp(String propertyValue, String converterExp, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        String[] convertSource = converterExp.split(",");
-        for (String item : convertSource)
-        {
-            String[] itemArray = item.split("=");
-            if (StrUtil.containsAny(propertyValue, separator))
-            {
-                for (String value : propertyValue.split(separator))
-                {
-                    if (itemArray[0].equals(value))
-                    {
-                        propertyString.append(itemArray[1] + separator);
-                        break;
-                    }
-                }
-            }
-            else
-            {
-                if (itemArray[0].equals(propertyValue))
-                {
-                    return itemArray[1];
-                }
-            }
-        }
-        return StrUtil.strip(propertyString.toString(), null,separator);
-    }
-
-    /**
-     * 鍙嶅悜瑙f瀽鍊� 鐢�=0,濂�=1,鏈煡=2
-     *
-     * @param propertyValue 鍙傛暟鍊�
-     * @param converterExp 缈昏瘧娉ㄨВ
-     * @param separator 鍒嗛殧绗�
-     * @return 瑙f瀽鍚庡��
-     */
-    public static String reverseByExp(String propertyValue, String converterExp, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        String[] convertSource = converterExp.split(",");
-        for (String item : convertSource)
-        {
-            String[] itemArray = item.split("=");
-            if (StrUtil.containsAny(propertyValue, separator))
-            {
-                for (String value : propertyValue.split(separator))
-                {
-                    if (itemArray[1].equals(value))
-                    {
-                        propertyString.append(itemArray[0] + separator);
-                        break;
-                    }
-                }
-            }
-            else
-            {
-                if (itemArray[1].equals(propertyValue))
-                {
-                    return itemArray[0];
-                }
-            }
-        }
-        return StrUtil.strip(propertyString.toString(), null,separator);
-    }
-
-    /**
-     * 瑙f瀽瀛楀吀鍊�
-     *
-     * @param dictValue 瀛楀吀鍊�
-     * @param dictType 瀛楀吀绫诲瀷
-     * @param separator 鍒嗛殧绗�
-     * @return 瀛楀吀鏍囩
-     */
-    public static String convertDictByExp(String dictValue, String dictType, String separator)
-    {
-        return DictUtils.getDictLabel(dictType, dictValue, separator);
-    }
-
-    /**
-     * 鍙嶅悜瑙f瀽鍊煎瓧鍏稿��
-     *
-     * @param dictLabel 瀛楀吀鏍囩
-     * @param dictType 瀛楀吀绫诲瀷
-     * @param separator 鍒嗛殧绗�
-     * @return 瀛楀吀鍊�
-     */
-    public static String reverseDictByExp(String dictLabel, String dictType, String separator)
-    {
-        return DictUtils.getDictValue(dictType, dictLabel, separator);
-    }
-
-    /**
-     * 鍚堣缁熻淇℃伅
-     */
-    private void addStatisticsData(Integer index, String text, Excel entity)
-    {
-        if (entity != null && entity.isStatistics())
-        {
-            Double temp = 0D;
-            if (!statistics.containsKey(index))
-            {
-                statistics.put(index, temp);
-            }
-            try
-            {
-                temp = Double.valueOf(text);
-            }
-            catch (NumberFormatException e)
-            {
-            }
-            statistics.put(index, statistics.get(index) + temp);
-        }
-    }
-
-    /**
-     * 鍒涘缓缁熻琛�
-     */
-    public void addStatisticsRow()
-    {
-        if (statistics.size() > 0)
-        {
-            Cell cell = null;
-            Row row = sheet.createRow(sheet.getLastRowNum() + 1);
-            Set<Integer> keys = statistics.keySet();
-            cell = row.createCell(0);
-            cell.setCellStyle(styles.get("total"));
-            cell.setCellValue("鍚堣");
-
-            for (Integer key : keys)
-            {
-                cell = row.createCell(key);
-                cell.setCellStyle(styles.get("total"));
-                cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key)));
-            }
-            statistics.clear();
-        }
-    }
-
-    /**
-     * 缂栫爜鏂囦欢鍚�
-     */
-    public String encodingFilename(String filename)
-    {
-        filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
-        return filename;
-    }
-
-    /**
-     * 鑾峰彇涓嬭浇璺緞
-     *
-     * @param filename 鏂囦欢鍚嶇О
-     */
-    public String getAbsoluteFile(String filename)
-    {
-        String downloadPath = RuoYiConfig.getDownloadPath() + filename;
-        File desc = new File(downloadPath);
-        if (!desc.getParentFile().exists())
-        {
-            desc.getParentFile().mkdirs();
-        }
-        return downloadPath;
-    }
-
-    /**
-     * 鑾峰彇bean涓殑灞炴�у��
-     *
-     * @param vo 瀹炰綋瀵硅薄
-     * @param field 瀛楁
-     * @param excel 娉ㄨВ
-     * @return 鏈�缁堢殑灞炴�у��
-     * @throws Exception
-     */
-    private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
-    {
-        Object o = field.get(vo);
-        if (Validator.isNotEmpty(excel.targetAttr()))
-        {
-            String target = excel.targetAttr();
-            if (target.contains("."))
-            {
-                String[] targets = target.split("[.]");
-                for (String name : targets)
-                {
-                    o = getValue(o, name);
-                }
-            }
-            else
-            {
-                o = getValue(o, target);
-            }
-        }
-        return o;
-    }
-
-    /**
-     * 浠ョ被鐨勫睘鎬х殑get鏂规硶鏂规硶褰㈠紡鑾峰彇鍊�
-     *
-     * @param o
-     * @param name
-     * @return value
-     * @throws Exception
-     */
-    private Object getValue(Object o, String name) throws Exception
-    {
-        if (Validator.isNotNull(o) && Validator.isNotEmpty(name))
-        {
-            Class<?> clazz = o.getClass();
-            Field field = clazz.getDeclaredField(name);
-            field.setAccessible(true);
-            o = field.get(o);
-        }
-        return o;
-    }
-
-    /**
-     * 寰楀埌鎵�鏈夊畾涔夊瓧娈�
-     */
-    private void createExcelField()
-    {
-        this.fields = new ArrayList<Object[]>();
-        List<Field> tempFields = new ArrayList<>();
-        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
-        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
-        for (Field field : tempFields)
-        {
-            // 鍗曟敞瑙�
-            if (field.isAnnotationPresent(Excel.class))
-            {
-                putToField(field, field.getAnnotation(Excel.class));
-            }
-
-            // 澶氭敞瑙�
-            if (field.isAnnotationPresent(Excels.class))
-            {
-                Excels attrs = field.getAnnotation(Excels.class);
-                Excel[] excels = attrs.value();
-                for (Excel excel : excels)
-                {
-                    putToField(field, excel);
-                }
-            }
-        }
-        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
-        this.maxHeight = getRowHeight();
-    }
-
-    /**
-     * 鏍规嵁娉ㄨВ鑾峰彇鏈�澶ц楂�
-     */
-    public short getRowHeight()
-    {
-        double maxHeight = 0;
-        for (Object[] os : this.fields)
-        {
-            Excel excel = (Excel) os[1];
-            maxHeight = maxHeight > excel.height() ? maxHeight : excel.height();
-        }
-        return (short) (maxHeight * 20);
-    }
-
-    /**
-     * 鏀惧埌瀛楁闆嗗悎涓�
-     */
-    private void putToField(Field field, Excel attr)
-    {
-        if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
-        {
-            this.fields.add(new Object[] { field, attr });
-        }
-    }
-
-    /**
-     * 鍒涘缓涓�涓伐浣滅翱
-     */
-    public void createWorkbook()
-    {
-        this.wb = new SXSSFWorkbook(500);
-    }
-
-    /**
-     * 鍒涘缓宸ヤ綔琛�
-     *
-     * @param sheetNo sheet鏁伴噺
-     * @param index 搴忓彿
-     */
-    public void createSheet(double sheetNo, int index)
-    {
-        this.sheet = wb.createSheet();
-        this.styles = createStyles(wb);
-        // 璁剧疆宸ヤ綔琛ㄧ殑鍚嶇О.
-        if (sheetNo == 0)
-        {
-            wb.setSheetName(index, sheetName);
-        }
-        else
-        {
-            wb.setSheetName(index, sheetName + index);
-        }
-    }
-
-    /**
-     * 鑾峰彇鍗曞厓鏍煎��
-     *
-     * @param row 鑾峰彇鐨勮
-     * @param column 鑾峰彇鍗曞厓鏍煎垪鍙�
-     * @return 鍗曞厓鏍煎��
-     */
-    public Object getCellValue(Row row, int column)
-    {
-        if (row == null)
-        {
-            return row;
-        }
-        Object val = "";
-        try
-        {
-            Cell cell = row.getCell(column);
-            if (Validator.isNotNull(cell))
-            {
-                if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)
-                {
-                    val = cell.getNumericCellValue();
-                    if (DateUtil.isCellDateFormatted(cell))
-                    {
-                        val = DateUtil.getJavaDate((Double) val); // POI Excel 鏃ユ湡鏍煎紡杞崲
-                    }
-                    else
-                    {
-                        if ((Double) val % 1 != 0)
-                        {
-                            val = new BigDecimal(val.toString());
-                        }
-                        else
-                        {
-                            val = new DecimalFormat("0").format(val);
-                        }
-                    }
-                }
-                else if (cell.getCellType() == CellType.STRING)
-                {
-                    val = cell.getStringCellValue();
-                }
-                else if (cell.getCellType() == CellType.BOOLEAN)
-                {
-                    val = cell.getBooleanCellValue();
-                }
-                else if (cell.getCellType() == CellType.ERROR)
-                {
-                    val = cell.getErrorCellValue();
-                }
-
-            }
-        }
-        catch (Exception e)
-        {
-            return val;
-        }
-        return val;
-    }
 }
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
index c5d17d8..749f1ab 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
@@ -1,10 +1,9 @@
 package com.ruoyi.common.utils.reflect;
 
 import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 
 import java.lang.reflect.Method;
-import java.util.List;
 
 /**
  * 鍙嶅皠宸ュ叿绫�. 鎻愪緵璋冪敤getter/setter鏂规硶, 璁块棶绉佹湁鍙橀噺, 璋冪敤绉佹湁鏂规硶, 鑾峰彇娉涘瀷绫诲瀷Class, 琚獳OP杩囩殑鐪熷疄绫荤瓑宸ュ叿鍑芥暟.
@@ -25,8 +24,8 @@
 	@SuppressWarnings("unchecked")
 	public static <E> E invokeGetter(Object obj, String propertyName) {
 		Object object = obj;
-		for (String name : StrUtil.split(propertyName, ".")) {
-			String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(name);
+		for (String name : StringUtils.split(propertyName, ".")) {
+			String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
 			object = invoke(object, getterMethodName);
 		}
 		return (E) object;
@@ -38,13 +37,13 @@
 	 */
 	public static <E> void invokeSetter(Object obj, String propertyName, E value) {
 		Object object = obj;
-		List<String> names = StrUtil.split(propertyName, ".");
-		for (int i = 0; i < names.size(); i++) {
-			if (i < names.size() - 1) {
-				String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(names.get(i));
+		String[] names = StringUtils.split(propertyName, ".");
+		for (int i = 0; i < names.length; i++) {
+			if (i < names.length - 1) {
+				String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
 				object = invoke(object, getterMethodName);
 			} else {
-				String setterMethodName = SETTER_PREFIX + StrUtil.upperFirst(names.get(i));
+				String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
 				Method method = getMethodByName(object.getClass(), setterMethodName);
 				invoke(object, method, value);
 			}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
index a37268a..04731a5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
@@ -1,11 +1,11 @@
 package com.ruoyi.common.utils.sql;
 
-import cn.hutool.core.lang.Validator;
-import com.ruoyi.common.exception.BaseException;
+import com.ruoyi.common.exception.UtilException;
+import com.ruoyi.common.utils.StringUtils;
 
 /**
  * sql鎿嶄綔宸ュ叿绫�
- * 
+ *
  * @author ruoyi
  */
 public class SqlUtil
@@ -20,9 +20,9 @@
      */
     public static String escapeOrderBySql(String value)
     {
-        if (Validator.isNotEmpty(value) && !isValidOrderBySql(value))
+        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
         {
-            throw new BaseException("鍙傛暟涓嶇鍚堣鑼冿紝涓嶈兘杩涜鏌ヨ");
+            throw new UtilException("鍙傛暟涓嶇鍚堣鑼冿紝涓嶈兘杩涜鏌ヨ");
         }
         return value;
     }
diff --git a/ruoyi-demo/pom.xml b/ruoyi-demo/pom.xml
index 1066d2f..1393d49 100644
--- a/ruoyi-demo/pom.xml
+++ b/ruoyi-demo/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java
index 334f004..9a66fdd 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java
@@ -5,6 +5,8 @@
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.demo.domain.TestDemo;
 import com.ruoyi.demo.service.ITestDemoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -21,6 +23,7 @@
  * @author Lion Li
  * @date 2021-05-30
  */
+@Api(value = "娴嬭瘯鎵归噺鏂规硶", tags = {"娴嬭瘯鎵归噺鏂规硶"})
 @RequiredArgsConstructor(onConstructor_ = @Autowired)
 @RestController
 @RequestMapping("/demo/batch")
@@ -31,7 +34,9 @@
     /**
      * 鏂板鎵归噺鏂规硶 ( 鍏ㄩ噺瑕嗙洊濉厖 )
      */
+	@ApiOperation(value = "鏂板鎵归噺鏂规硶")
     @PostMapping()
+//	@DataSource(DataSourceType.SLAVE)
     public AjaxResult<Void> add() {
 		List<TestDemo> list = new ArrayList<>();
 		for (int i = 0; i < 1000; i++) {
@@ -41,10 +46,12 @@
     }
 
     /**
-     * 淇敼鎵归噺鏂规硶
+     * 鍒犻櫎鎵归噺鏂规硶
      */
+	@ApiOperation(value = "鍒犻櫎鎵归噺鏂规硶")
     @DeleteMapping()
-    public AjaxResult<Void> edit() {
+//	@DataSource(DataSourceType.SLAVE)
+    public AjaxResult<Void> remove() {
         return toAjax(iTestDemoService.remove(new LambdaQueryWrapper<TestDemo>()
 			.eq(TestDemo::getOrderNum, -1L)) ? 1 : 0);
     }
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
index ade20f8..a393c91 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
@@ -20,10 +20,12 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 娴嬭瘯鍗曡〃Controller
@@ -67,10 +69,9 @@
     @PreAuthorize("@ss.hasPermi('demo:demo:export')")
     @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult<TestDemoVo> export(@Validated TestDemoBo bo) {
+    public void export(@Validated TestDemoBo bo, HttpServletResponse response) {
         List<TestDemoVo> list = iTestDemoService.queryList(bo);
-        ExcelUtil<TestDemoVo> util = new ExcelUtil<TestDemoVo>(TestDemoVo.class);
-        return util.exportExcel(list, "娴嬭瘯鍗曡〃");
+		ExcelUtil.exportExcel(list, "娴嬭瘯鍗曡〃", TestDemoVo.class, response);
     }
 
     /**
@@ -90,7 +91,7 @@
     @ApiOperation("鏂板娴嬭瘯鍗曡〃")
     @PreAuthorize("@ss.hasPermi('demo:demo:add')")
     @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.INSERT)
-    @RepeatSubmit
+    @RepeatSubmit(intervalTime = 2, timeUnit = TimeUnit.SECONDS)
     @PostMapping()
     public AjaxResult<Void> add(@Validated(AddGroup.class) @RequestBody TestDemoBo bo) {
         return toAjax(iTestDemoService.insertByBo(bo) ? 1 : 0);
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java
new file mode 100644
index 0000000..8ccce2a
--- /dev/null
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java
@@ -0,0 +1,29 @@
+package com.ruoyi.demo.controller;
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.MessageUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * 娴嬭瘯鍥介檯鍖�
+ *
+ * @author Lion Li
+ */
+@RestController
+@RequestMapping("/demo/i18n")
+public class TestI18nController {
+
+	/**
+	 * 閫氳繃code鑾峰彇鍥介檯鍖栧唴瀹�
+	 * code涓� messages.properties 涓殑 key
+	 *
+	 * 娴嬭瘯浣跨敤 user.register.success
+	 */
+	@GetMapping()
+	public AjaxResult<Void> get(String code) {
+		return AjaxResult.success(MessageUtils.message(code));
+	}
+}
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java
index 8cab868..63b1743 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java
@@ -19,6 +19,7 @@
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.util.Arrays;
@@ -57,10 +58,9 @@
     @PreAuthorize("@ss.hasPermi('demo:tree:export')")
     @Log(title = "娴嬭瘯鏍戣〃", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult<TestTreeVo> export(@Validated TestTreeBo bo) {
+    public void export(@Validated TestTreeBo bo, HttpServletResponse response) {
         List<TestTreeVo> list = iTestTreeService.queryList(bo);
-        ExcelUtil<TestTreeVo> util = new ExcelUtil<TestTreeVo>(TestTreeVo.class);
-        return util.exportExcel(list, "娴嬭瘯鏍戣〃");
+		ExcelUtil.exportExcel(list, "娴嬭瘯鏍戣〃", TestTreeVo.class, response);
     }
 
     /**
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java
index 9ab4ba9..3c8e452 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestDemoVo.java
@@ -1,9 +1,11 @@
 package com.ruoyi.demo.domain.vo;
 
-import com.ruoyi.common.annotation.Excel;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+
 import java.util.Date;
 
 
@@ -16,6 +18,7 @@
  */
 @Data
 @ApiModel("娴嬭瘯鍗曡〃瑙嗗浘瀵硅薄")
+@ExcelIgnoreUnannotated
 public class TestDemoVo {
 
 	private static final long serialVersionUID = 1L;
@@ -29,63 +32,63 @@
     /**
      * 閮ㄩ棬id
      */
-	@Excel(name = "閮ㄩ棬id")
+	@ExcelProperty(value = "閮ㄩ棬id")
 	@ApiModelProperty("閮ㄩ棬id")
 	private Long deptId;
 
     /**
      * 鐢ㄦ埛id
      */
-	@Excel(name = "鐢ㄦ埛id")
+	@ExcelProperty(value = "鐢ㄦ埛id")
 	@ApiModelProperty("鐢ㄦ埛id")
 	private Long userId;
 
     /**
      * 鎺掑簭鍙�
      */
-	@Excel(name = "鎺掑簭鍙�")
+	@ExcelProperty(value = "鎺掑簭鍙�")
 	@ApiModelProperty("鎺掑簭鍙�")
 	private Long orderNum;
 
     /**
      * key閿�
      */
-	@Excel(name = "key閿�")
+	@ExcelProperty(value = "key閿�")
 	@ApiModelProperty("key閿�")
 	private String testKey;
 
     /**
      * 鍊�
      */
-	@Excel(name = "鍊�")
+	@ExcelProperty(value = "鍊�")
 	@ApiModelProperty("鍊�")
 	private String value;
 
     /**
      * 鍒涘缓鏃堕棿
      */
-	@Excel(name = "鍒涘缓鏃堕棿" , width = 30, dateFormat = "yyyy-MM-dd")
+	@ExcelProperty(value = "鍒涘缓鏃堕棿")
 	@ApiModelProperty("鍒涘缓鏃堕棿")
 	private Date createTime;
 
     /**
      * 鍒涘缓浜�
      */
-	@Excel(name = "鍒涘缓浜�")
+	@ExcelProperty(value = "鍒涘缓浜�")
 	@ApiModelProperty("鍒涘缓浜�")
 	private String createBy;
 
     /**
      * 鏇存柊鏃堕棿
      */
-	@Excel(name = "鏇存柊鏃堕棿" , width = 30, dateFormat = "yyyy-MM-dd")
+	@ExcelProperty(value = "鏇存柊鏃堕棿")
 	@ApiModelProperty("鏇存柊鏃堕棿")
 	private Date updateTime;
 
     /**
      * 鏇存柊浜�
      */
-	@Excel(name = "鏇存柊浜�")
+	@ExcelProperty(value = "鏇存柊浜�")
 	@ApiModelProperty("鏇存柊浜�")
 	private String updateBy;
 
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java
index a299c4a..dab8162 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/vo/TestTreeVo.java
@@ -1,9 +1,11 @@
 package com.ruoyi.demo.domain.vo;
 
-import com.ruoyi.common.annotation.Excel;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+
 import java.util.Date;
 
 
@@ -16,6 +18,7 @@
  */
 @Data
 @ApiModel("娴嬭瘯鏍戣〃瑙嗗浘瀵硅薄")
+@ExcelIgnoreUnannotated
 public class TestTreeVo {
 
 	private static final long serialVersionUID = 1L;
@@ -29,35 +32,35 @@
     /**
      * 鐖秈d
      */
-	@Excel(name = "鐖秈d")
+	@ExcelProperty(value = "鐖秈d")
 	@ApiModelProperty("鐖秈d")
 	private Long parentId;
 
     /**
      * 閮ㄩ棬id
      */
-	@Excel(name = "閮ㄩ棬id")
+	@ExcelProperty(value = "閮ㄩ棬id")
 	@ApiModelProperty("閮ㄩ棬id")
 	private Long deptId;
 
     /**
      * 鐢ㄦ埛id
      */
-	@Excel(name = "鐢ㄦ埛id")
+	@ExcelProperty(value = "鐢ㄦ埛id")
 	@ApiModelProperty("鐢ㄦ埛id")
 	private Long userId;
 
     /**
      * 鏍戣妭鐐瑰悕
      */
-	@Excel(name = "鏍戣妭鐐瑰悕")
+	@ExcelProperty(value = "鏍戣妭鐐瑰悕")
 	@ApiModelProperty("鏍戣妭鐐瑰悕")
 	private String treeName;
 
     /**
      * 鍒涘缓鏃堕棿
      */
-	@Excel(name = "鍒涘缓鏃堕棿" , width = 30, dateFormat = "yyyy-MM-dd")
+	@ExcelProperty(value = "鍒涘缓鏃堕棿")
 	@ApiModelProperty("鍒涘缓鏃堕棿")
 	private Date createTime;
 
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java
index 81893df..fe103ef 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java
@@ -1,7 +1,7 @@
 package com.ruoyi.demo.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -62,11 +62,11 @@
 		Map<String, Object> params = bo.getParams();
 		Object dataScope = params.get("dataScope");
 		LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
-		lqw.like(StrUtil.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
-		lqw.eq(StrUtil.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
+		lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
+		lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
 		lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
 			TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
-		lqw.apply(dataScope != null && StrUtil.isNotBlank(dataScope.toString()),
+		lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
 			dataScope != null ? dataScope.toString() : null);
 		return lqw;
 	}
diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java
index a953412..1985c1e 100644
--- a/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java
+++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java
@@ -1,7 +1,7 @@
 package com.ruoyi.demo.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.ruoyi.common.annotation.DataScope;
@@ -42,10 +42,10 @@
 		Map<String, Object> params = bo.getParams();
 		Object dataScope = params.get("dataScope");
 		LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery();
-		lqw.like(StrUtil.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
+		lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
 		lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
 			TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
-		lqw.apply(dataScope != null && StrUtil.isNotBlank(dataScope.toString()),
+		lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
 			dataScope != null ? dataScope.toString() : null);
 		return lqw;
 	}
diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml
index 4df48ba..3bfe770 100644
--- a/ruoyi-extend/pom.xml
+++ b/ruoyi-extend/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ruoyi-extend</artifactId>
diff --git a/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/ruoyi-extend/ruoyi-monitor-admin/pom.xml
index 9aca296..bada747 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/pom.xml
+++ b/ruoyi-extend/ruoyi-monitor-admin/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-extend</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml
index 41e8ca4..5fca8f9 100644
--- a/ruoyi-framework/pom.xml
+++ b/ruoyi-framework/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
index 830dbe5..773952a 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
@@ -1,13 +1,12 @@
 package com.ruoyi.framework.aspectj;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.annotation.DataScope;
 import com.ruoyi.common.core.domain.BaseEntity;
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.reflect.ReflectUtils;
 import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.framework.web.service.TokenService;
@@ -80,10 +79,10 @@
 		}
 		// 鑾峰彇褰撳墠鐨勭敤鎴�
 		LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
-		if (Validator.isNotNull(loginUser)) {
+		if (StringUtils.isNotNull(loginUser)) {
 			SysUser currentUser = loginUser.getUser();
 			// 濡傛灉鏄秴绾х鐞嗗憳锛屽垯涓嶈繃婊ゆ暟鎹�
-			if (Validator.isNotNull(currentUser) && !currentUser.isAdmin()) {
+			if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
 				dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
 					controllerDataScope.userAlias(), controllerDataScope.isUser());
 			}
@@ -101,8 +100,8 @@
 		StringBuilder sqlString = new StringBuilder();
 
 		// 灏� "." 鎻愬彇鍑�,涓嶅啓鍒悕涓哄崟琛ㄦ煡璇�,鍐欏埆鍚嶄负澶氳〃鏌ヨ
-		deptAlias = StrUtil.isNotBlank(deptAlias) ? deptAlias + "." : "";
-		userAlias = StrUtil.isNotBlank(userAlias) ? userAlias + "." : "";
+		deptAlias = StringUtils.isNotBlank(deptAlias) ? deptAlias + "." : "";
+		userAlias = StringUtils.isNotBlank(userAlias) ? userAlias + "." : "";
 
 		for (SysRole role : user.getRoles()) {
 			String dataScope = role.getDataScope();
@@ -110,19 +109,19 @@
 				sqlString = new StringBuilder();
 				break;
 			} else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {
-				sqlString.append(StrUtil.format(
+				sqlString.append(StringUtils.format(
 					" OR {}dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ",
 					deptAlias, role.getRoleId()));
 			} else if (DATA_SCOPE_DEPT.equals(dataScope)) {
-				sqlString.append(StrUtil.format(" OR {}dept_id = {} ",
+				sqlString.append(StringUtils.format(" OR {}dept_id = {} ",
 					deptAlias, user.getDeptId()));
 			} else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
-				sqlString.append(StrUtil.format(
+				sqlString.append(StringUtils.format(
 					" OR {}dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
 					deptAlias, user.getDeptId(), user.getDeptId()));
 			} else if (DATA_SCOPE_SELF.equals(dataScope)) {
 				if (isUser) {
-					sqlString.append(StrUtil.format(" OR {}user_id = {} ",
+					sqlString.append(StringUtils.format(" OR {}user_id = {} ",
 						userAlias, user.getUserId()));
 				} else {
 					// 鏁版嵁鏉冮檺涓轰粎鏈汉涓旀病鏈塽serAlias鍒悕涓嶆煡璇换浣曟暟鎹�
@@ -131,7 +130,7 @@
 			}
 		}
 
-		if (StrUtil.isNotBlank(sqlString.toString())) {
+		if (StringUtils.isNotBlank(sqlString.toString())) {
 			putDataScope(joinPoint, sqlString.substring(4));
 		}
 	}
@@ -155,14 +154,14 @@
 	 */
 	private void clearDataScope(final JoinPoint joinPoint) {
 		Object params = joinPoint.getArgs()[0];
-		if (Validator.isNotNull(params)) {
+		if (StringUtils.isNotNull(params)) {
 			putDataScope(joinPoint, "");
 		}
 	}
 
 	private static void putDataScope(JoinPoint joinPoint, String sql) {
 		Object params = joinPoint.getArgs()[0];
-		if (Validator.isNotNull(params)) {
+		if (StringUtils.isNotNull(params)) {
 			if (params instanceof BaseEntity) {
 				BaseEntity baseEntity = (BaseEntity) params;
 				baseEntity.getParams().put(DATA_SCOPE, sql);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
index f82b2ae..47e7742 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
@@ -1,8 +1,8 @@
 package com.ruoyi.framework.aspectj;
 
-import cn.hutool.core.lang.Validator;
 import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
 import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.utils.StringUtils;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
@@ -33,7 +33,7 @@
 	public Object around(ProceedingJoinPoint point) throws Throwable {
 		DataSource dataSource = getDataSource(point);
 
-		if (Validator.isNotNull(dataSource)) {
+		if (StringUtils.isNotNull(dataSource)) {
 			DynamicDataSourceContextHolder.poll();
 			String source = dataSource.value().getSource();
 			DynamicDataSourceContextHolder.push(source);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
index d5c0fe8..c902511 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
@@ -1,13 +1,12 @@
 package com.ruoyi.framework.aspectj;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.enums.BusinessStatus;
 import com.ruoyi.common.enums.HttpMethod;
 import com.ruoyi.common.utils.JsonUtils;
 import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.framework.web.service.AsyncService;
 import com.ruoyi.framework.web.service.TokenService;
@@ -104,7 +103,7 @@
             if (e != null)
             {
                 operLog.setStatus(BusinessStatus.FAIL.ordinal());
-                operLog.setErrorMsg(StrUtil.sub(e.getMessage(), 0, 2000));
+                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
             }
             // 璁剧疆鏂规硶鍚嶇О
             String className = joinPoint.getTarget().getClass().getName();
@@ -161,12 +160,12 @@
         if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
         {
             String params = argsArrayToString(joinPoint.getArgs());
-            operLog.setOperParam(StrUtil.sub(params, 0, 2000));
+            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
         }
         else
         {
             Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
-            operLog.setOperParam(StrUtil.sub(paramsMap.toString(), 0, 2000));
+            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
         }
     }
 
@@ -195,7 +194,7 @@
         if (paramsArray != null && paramsArray.length > 0)
         {
 			for (Object o : paramsArray) {
-				if (Validator.isNotNull(o) && !isFilterObject(o)) {
+				if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
 					params.append(JsonUtils.toJsonString(o)).append(" ");
 				}
 			}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
new file mode 100644
index 0000000..1e21e37
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -0,0 +1,116 @@
+package com.ruoyi.framework.aspectj;
+
+import com.ruoyi.common.annotation.RateLimiter;
+import com.ruoyi.common.enums.LimitType;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.script.RedisScript;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 闄愭祦澶勭悊
+ *
+ * @author ruoyi
+ */
+@Aspect
+@Component
+public class RateLimiterAspect
+{
+    private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
+
+    private RedisTemplate<Object, Object> redisTemplate;
+
+    private RedisScript<Long> limitScript;
+
+    @Autowired
+    public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
+    {
+        this.redisTemplate = redisTemplate;
+    }
+
+    @Autowired
+    public void setLimitScript(RedisScript<Long> limitScript)
+    {
+        this.limitScript = limitScript;
+    }
+
+    // 閰嶇疆缁囧叆鐐�
+    @Pointcut("@annotation(com.ruoyi.common.annotation.RateLimiter)")
+    public void rateLimiterPointCut()
+    {
+    }
+
+    @Before("rateLimiterPointCut()")
+    public void doBefore(JoinPoint point) throws Throwable
+    {
+        RateLimiter rateLimiter = getAnnotationRateLimiter(point);
+        String key = rateLimiter.key();
+        int time = rateLimiter.time();
+        int count = rateLimiter.count();
+
+        String combineKey = getCombineKey(rateLimiter, point);
+        List<Object> keys = Collections.singletonList(combineKey);
+        try
+        {
+            Long number = redisTemplate.execute(limitScript, keys, count, time);
+            if (StringUtils.isNull(number) || number.intValue() > count)
+            {
+                throw new ServiceException("璁块棶杩囦簬棰戠箒锛岃绋嶅悗鍐嶈瘯");
+            }
+            log.info("闄愬埗璇锋眰'{}',褰撳墠璇锋眰'{}',缂撳瓨key'{}'", count, number.intValue(), key);
+        }
+        catch (ServiceException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException("鏈嶅姟鍣ㄩ檺娴佸紓甯革紝璇风◢鍚庡啀璇�");
+        }
+    }
+
+    /**
+     * 鏄惁瀛樺湪娉ㄨВ锛屽鏋滃瓨鍦ㄥ氨鑾峰彇
+     */
+    private RateLimiter getAnnotationRateLimiter(JoinPoint joinPoint)
+    {
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null)
+        {
+            return method.getAnnotation(RateLimiter.class);
+        }
+        return null;
+    }
+
+    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
+    {
+        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
+        if (rateLimiter.limitType() == LimitType.IP)
+        {
+            stringBuffer.append(ServletUtils.getClientIP());
+        }
+        MethodSignature signature = (MethodSignature) point.getSignature();
+        Method method = signature.getMethod();
+        Class<?> targetClass = method.getDeclaringClass();
+        stringBuffer.append("-").append(targetClass.getName()).append("- ").append(method.getName());
+        return stringBuffer.toString();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java
index b4f8bfc..f35afdf 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/captcha/UnsignedMathGenerator.java
@@ -4,7 +4,7 @@
 import cn.hutool.core.math.Calculator;
 import cn.hutool.core.util.CharUtil;
 import cn.hutool.core.util.RandomUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 
 /**
  * 鏃犵鍙疯绠楃敓鎴愬櫒
@@ -45,8 +45,8 @@
 		int max = RandomUtil.randomInt(min, limit);
 		String number1 = Integer.toString(max);
 		String number2 = Integer.toString(min);
-		number1 = StrUtil.padAfter(number1, this.numberLength, CharUtil.SPACE);
-		number2 = StrUtil.padAfter(number2, this.numberLength, CharUtil.SPACE);
+		number1 = StringUtils.rightPad(number1, this.numberLength, CharUtil.SPACE);
+		number2 = StringUtils.rightPad(number2, this.numberLength, CharUtil.SPACE);
 
 		return number1 + RandomUtil.randomChar(operators) + number2 + '=';
 	}
@@ -80,6 +80,6 @@
 	 * @return 鏈�澶у��
 	 */
 	private int getLimit() {
-		return Integer.parseInt("1" + StrUtil.repeat('0', this.numberLength));
+		return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength));
 	}
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
index 183c364..072eef9 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
@@ -1,11 +1,7 @@
 package com.ruoyi.framework.config;
 
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
-
-import java.util.TimeZone;
 
 /**
  * 绋嬪簭娉ㄨВ閰嶇疆
@@ -16,11 +12,5 @@
 // 琛ㄧず閫氳繃aop妗嗘灦鏆撮湶璇ヤ唬鐞嗗璞�,AopContext鑳藉璁块棶
 @EnableAspectJAutoProxy(exposeProxy = true)
 public class ApplicationConfig {
-    /**
-     * 鏃跺尯閰嶇疆
-     */
-    @Bean
-    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
-        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
-    }
+
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java
index 2eb4eb3..e30f83c 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java
@@ -1,6 +1,6 @@
 package com.ruoyi.framework.config;
 
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -41,7 +41,7 @@
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return (throwable, method, objects) -> {
             throwable.printStackTrace();
-            throw new CustomException(
+            throw new ServiceException(
                     "Exception message - " + throwable.getMessage()
                     + ", Method name - " + method.getName()
                     + ", Parameter value - " + Arrays.toString(objects));
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
index b09bc98..459020d 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
@@ -1,10 +1,11 @@
 package com.ruoyi.framework.config;
 
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.filter.RepeatableFilter;
 import com.ruoyi.common.filter.XssFilter;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.config.properties.XssProperties;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -19,6 +20,7 @@
  * @author Lion Li
  */
 @Configuration
+@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
 public class FilterConfig {
 
     @Autowired
@@ -30,12 +32,11 @@
         FilterRegistrationBean registration = new FilterRegistrationBean();
         registration.setDispatcherTypes(DispatcherType.REQUEST);
         registration.setFilter(new XssFilter());
-        registration.addUrlPatterns(StrUtil.splitToArray(xssProperties.getUrlPatterns(), ","));
+        registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), ","));
         registration.setName("xssFilter");
         registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
         Map<String, String> initParameters = new HashMap<String, String>();
         initParameters.put("excludes", xssProperties.getExcludes());
-        initParameters.put("enabled", xssProperties.getEnabled());
         registration.setInitParameters(initParameters);
         return registration;
     }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
new file mode 100644
index 0000000..48b341b
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
@@ -0,0 +1,48 @@
+package com.ruoyi.framework.config;
+
+import cn.hutool.core.util.StrUtil;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.LocaleResolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Locale;
+
+/**
+ * 鍥介檯鍖栭厤缃�
+ *
+ * @author Lion Li
+ */
+@Configuration
+public class I18nConfig {
+
+	@Bean
+	public LocaleResolver localeResolver() {
+		return new I18nLocaleResolver();
+	}
+
+	/**
+	 * 鑾峰彇璇锋眰澶村浗闄呭寲淇℃伅
+	 */
+	static class I18nLocaleResolver implements LocaleResolver {
+
+		@NotNull
+		@Override
+		public Locale resolveLocale(HttpServletRequest httpServletRequest) {
+			String language = httpServletRequest.getHeader("content-language");
+			Locale locale = Locale.getDefault();
+			if (StrUtil.isNotBlank(language)) {
+				String[] split = language.split("_");
+				locale = new Locale(split[0], split[1]);
+			}
+			return locale;
+		}
+
+		@Override
+		public void setLocale(@NotNull HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
+
+		}
+	}
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java
index 8334b2a..4346610 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java
@@ -2,15 +2,19 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
 import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
 import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.framework.jackson.BigNumberSerializer;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanPostProcessor;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.time.LocalDateTime;
 import java.util.TimeZone;
 
@@ -34,6 +38,10 @@
 				ObjectMapper objectMapper = (ObjectMapper) bean;
 				// 鍏ㄥ眬閰嶇疆搴忓垪鍖栬繑鍥� JSON 澶勭悊
 				SimpleModule simpleModule = new SimpleModule();
+				simpleModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
+				simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);
+				simpleModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
+				simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
 				simpleModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
 				simpleModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
 				objectMapper.registerModule(simpleModule);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
index bc28657..d66d86b 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
@@ -1,6 +1,7 @@
 package com.ruoyi.framework.config;
 
 import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.config.properties.RedissonProperties;
 import org.redisson.Redisson;
 import org.redisson.api.RedissonClient;
@@ -16,6 +17,7 @@
 import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
 
 import java.io.IOException;
 import java.util.HashMap;
@@ -59,7 +61,7 @@
 			.setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
 			.setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
 			.setDatabase(redisProperties.getDatabase())
-			.setPassword(StrUtil.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
+			.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
 			.setTimeout(singleServerConfig.getTimeout())
 			.setRetryAttempts(singleServerConfig.getRetryAttempts())
 			.setRetryInterval(singleServerConfig.getRetryInterval())
@@ -89,4 +91,32 @@
 		return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE);
 	}
 
+	@Bean
+	public DefaultRedisScript<Long> limitScript() {
+		DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
+		redisScript.setScriptText(limitScriptText());
+		redisScript.setResultType(Long.class);
+		return redisScript;
+	}
+
+	/**
+	 * 闄愭祦鑴氭湰
+	 */
+	private String limitScriptText() {
+		return StrUtil.builder()
+			.append("local key = KEYS[1]\n")
+			.append("local count = tonumber(ARGV[1])\n")
+			.append("local time = tonumber(ARGV[2])\n")
+			.append("local current = redis.call('get', key);\n")
+			.append("if current and tonumber(current) > count then\n")
+			.append("    return current;\n")
+			.append("end\n")
+			.append("current = redis.call('incr', key)\n")
+			.append("if tonumber(current) == 1 then\n")
+			.append("    redis.call('expire', key, time)\n")
+			.append("end\n")
+			.append("return current;")
+			.toString();
+	}
+
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
index c3cdc94..870af3f 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -1,5 +1,6 @@
 package com.ruoyi.framework.config;
 
+import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -9,9 +10,6 @@
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
 
 /**
  * 閫氱敤閰嶇疆
@@ -27,8 +25,6 @@
     @Override
     public void addResourceHandlers(ResourceHandlerRegistry registry)
     {
-        /** 鏈湴鏂囦欢涓婁紶璺緞 */
-        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
     }
 
     /**
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
index 0a8337e..bd6ee8f 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -96,19 +96,16 @@
                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                 // 杩囨护璇锋眰
                 .authorizeRequests()
-                // 瀵逛簬鐧诲綍login 楠岃瘉鐮乧aptchaImage 鍏佽鍖垮悕璁块棶
-                .antMatchers("/login", "/captchaImage").anonymous()
+                // 瀵逛簬鐧诲綍login 娉ㄥ唽register 楠岃瘉鐮乧aptchaImage 鍏佽鍖垮悕璁块棶
+                .antMatchers("/login", "/register", "/captchaImage").anonymous()
                 .antMatchers(
                         HttpMethod.GET,
                         "/",
                         "/*.html",
                         "/**/*.html",
                         "/**/*.css",
-                        "/**/*.js",
-                        "/profile/**"
+                        "/**/*.js"
                 ).permitAll()
-                .antMatchers("/common/download**").anonymous()
-                .antMatchers("/common/download/resource**").anonymous()
                 .antMatchers("/doc.html").anonymous()
                 .antMatchers("/swagger-resources/**").anonymous()
                 .antMatchers("/webjars/**").anonymous()
@@ -128,7 +125,6 @@
         httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
         httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
     }
-
 
     /**
      * 寮烘暎鍒楀搱甯屽姞瀵嗗疄鐜�
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java
new file mode 100644
index 0000000..b948f83
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RepeatSubmitProperties.java
@@ -0,0 +1,22 @@
+package com.ruoyi.framework.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 閲嶅鎻愪氦 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "repeat-submit")
+public class RepeatSubmitProperties {
+
+    /**
+     * 闂撮殧鏃堕棿(姣)
+     */
+    private int intervalTime;
+
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
index bd0e99e..9af0a83 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
@@ -6,7 +6,7 @@
 import com.ruoyi.common.utils.ServletUtils;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import org.springframework.web.servlet.HandlerInterceptor;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -15,42 +15,36 @@
 /**
  * 闃叉閲嶅鎻愪氦鎷︽埅鍣�
  *
- * @author ruoyi
+ * 绉婚櫎缁ф壙 HandlerInterceptorAdapter 杩囨湡绫�
+ * 鏀逛负瀹炵幇 HandlerInterceptor 鎺ュ彛(瀹樻柟鎺ㄨ崘鍐欐硶)
+ *
+ * @author Lion Li
  */
 @Component
-public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
-{
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
-    {
-        if (handler instanceof HandlerMethod)
-        {
-            HandlerMethod handlerMethod = (HandlerMethod) handler;
-            Method method = handlerMethod.getMethod();
-            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
-            if (annotation != null)
-            {
-                if (this.isRepeatSubmit(request))
-                {
-                    AjaxResult ajaxResult = AjaxResult.error("涓嶅厑璁搁噸澶嶆彁浜わ紝璇风◢鍚庡啀璇�");
-                    ServletUtils.renderString(response, JsonUtils.toJsonString(ajaxResult));
-                    return false;
-                }
-            }
-            return true;
-        }
-        else
-        {
-            return super.preHandle(request, response, handler);
-        }
-    }
+public abstract class RepeatSubmitInterceptor implements HandlerInterceptor {
 
-    /**
-     * 楠岃瘉鏄惁閲嶅鎻愪氦鐢卞瓙绫诲疄鐜板叿浣撶殑闃查噸澶嶆彁浜ょ殑瑙勫垯
-     *
-     * @param request
-     * @return
-     * @throws Exception
-     */
-    public abstract boolean isRepeatSubmit(HttpServletRequest request);
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+		throws Exception {
+		if (handler instanceof HandlerMethod) {
+			HandlerMethod handlerMethod = (HandlerMethod) handler;
+			Method method = handlerMethod.getMethod();
+			RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
+			if (annotation != null) {
+				if (this.isRepeatSubmit(annotation, request)) {
+					AjaxResult ajaxResult = AjaxResult.error("涓嶅厑璁搁噸澶嶆彁浜わ紝璇风◢鍚庡啀璇�");
+					ServletUtils.renderString(response, JsonUtils.toJsonString(ajaxResult));
+					return false;
+				}
+			}
+			return true;
+		} else {
+			return HandlerInterceptor.super.preHandle(request, response, handler);
+		}
+	}
+
+	/**
+	 * 楠岃瘉鏄惁閲嶅鎻愪氦鐢卞瓙绫诲疄鐜板叿浣撶殑闃查噸澶嶆彁浜ょ殑瑙勫垯
+	 */
+	public abstract boolean isRepeatSubmit(RepeatSubmit annotation, HttpServletRequest request);
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
index bc09231..d9b3464 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
@@ -1,15 +1,19 @@
 package com.ruoyi.framework.interceptor.impl;
 
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.lang.Validator;
+import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
 import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.config.properties.RepeatSubmitProperties;
+import com.ruoyi.framework.config.properties.TokenProperties;
 import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import javax.servlet.http.HttpServletRequest;
@@ -20,45 +24,34 @@
 
 /**
  * 鍒ゆ柇璇锋眰url鍜屾暟鎹槸鍚﹀拰涓婁竴娆$浉鍚岋紝
- * 濡傛灉鍜屼笂娆$浉鍚岋紝鍒欐槸閲嶅鎻愪氦琛ㄥ崟銆� 鏈夋晥鏃堕棿涓�10绉掑唴銆�
+ * 濡傛灉鍜屼笂娆$浉鍚岋紝鍒欐槸閲嶅鎻愪氦琛ㄥ崟銆�
  *
- * @author ruoyi
+ * @author Lion Li
  */
 @Slf4j
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
 @Component
-public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
-{
-    public final String REPEAT_PARAMS = "repeatParams";
+public class SameUrlDataInterceptor extends RepeatSubmitInterceptor {
+	public final String REPEAT_PARAMS = "repeatParams";
 
-    public final String REPEAT_TIME = "repeatTime";
+	public final String REPEAT_TIME = "repeatTime";
 
-    // 浠ょ墝鑷畾涔夋爣璇�
-    @Value("${token.header}")
-    private String header;
+	private final TokenProperties tokenProperties;
+	private final RepeatSubmitProperties repeatSubmitProperties;
+	private final RedisCache redisCache;
 
-    @Autowired
-    private RedisCache redisCache;
 
-    /**
-     * 闂撮殧鏃堕棿锛屽崟浣�:绉� 榛樿10绉�
-     *
-     * 涓ゆ鐩稿悓鍙傛暟鐨勮姹傦紝濡傛灉闂撮殧鏃堕棿澶т簬璇ュ弬鏁帮紝绯荤粺涓嶄細璁ゅ畾涓洪噸澶嶆彁浜ょ殑鏁版嵁
-     */
-    private int intervalTime = 10;
-
-    public void setIntervalTime(int intervalTime)
-    {
-        this.intervalTime = intervalTime;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean isRepeatSubmit(HttpServletRequest request)
-    {
-        String nowParams = "";
-        if (request instanceof RepeatedlyRequestWrapper)
-        {
-            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+	@SuppressWarnings("unchecked")
+	@Override
+	public boolean isRepeatSubmit(RepeatSubmit repeatSubmit, HttpServletRequest request) {
+		// 濡傛灉娉ㄨВ涓嶄负0 鍒欎娇鐢ㄦ敞瑙f暟鍊�
+		long intervalTime = repeatSubmitProperties.getIntervalTime();
+		if (repeatSubmit.intervalTime() > 0) {
+			intervalTime = repeatSubmit.timeUnit().toMillis(repeatSubmit.intervalTime());
+		}
+		String nowParams = "";
+		if (request instanceof RepeatedlyRequestWrapper) {
+			RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
 			try {
 				nowParams = IoUtil.readUtf8(repeatedlyRequest.getInputStream());
 			} catch (IOException e) {
@@ -66,68 +59,57 @@
 			}
 		}
 
-        // body鍙傛暟涓虹┖锛岃幏鍙朠arameter鐨勬暟鎹�
-        if (Validator.isEmpty(nowParams))
-        {
-            nowParams = JsonUtils.toJsonString(request.getParameterMap());
-        }
-        Map<String, Object> nowDataMap = new HashMap<String, Object>();
-        nowDataMap.put(REPEAT_PARAMS, nowParams);
-        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
+		// body鍙傛暟涓虹┖锛岃幏鍙朠arameter鐨勬暟鎹�
+		if (StringUtils.isEmpty(nowParams)) {
+			nowParams = JsonUtils.toJsonString(request.getParameterMap());
+		}
+		Map<String, Object> nowDataMap = new HashMap<String, Object>();
+		nowDataMap.put(REPEAT_PARAMS, nowParams);
+		nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
 
-        // 璇锋眰鍦板潃锛堜綔涓哄瓨鏀綾ache鐨刱ey鍊硷級
-        String url = request.getRequestURI();
+		// 璇锋眰鍦板潃锛堜綔涓哄瓨鏀綾ache鐨刱ey鍊硷級
+		String url = request.getRequestURI();
 
-        // 鍞竴鍊硷紙娌℃湁娑堟伅澶村垯浣跨敤璇锋眰鍦板潃锛�
-        String submitKey = request.getHeader(header);
-        if (Validator.isEmpty(submitKey))
-        {
-            submitKey = url;
-        }
+		// 鍞竴鍊硷紙娌℃湁娑堟伅澶村垯浣跨敤璇锋眰鍦板潃锛�
+		String submitKey = request.getHeader(tokenProperties.getHeader());
+		if (StringUtils.isEmpty(submitKey)) {
+			submitKey = url;
+		}
 
-        // 鍞竴鏍囪瘑锛堟寚瀹歬ey + 娑堟伅澶达級
-        String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
+		// 鍞竴鏍囪瘑锛堟寚瀹歬ey + 娑堟伅澶达級
+		String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
 
-        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
-        if (sessionObj != null)
-        {
-            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
-            if (sessionMap.containsKey(url))
-            {
-                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
-                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
-                {
-                    return true;
-                }
-            }
-        }
-        Map<String, Object> cacheMap = new HashMap<String, Object>();
-        cacheMap.put(url, nowDataMap);
-        redisCache.setCacheObject(cacheRepeatKey, cacheMap, intervalTime, TimeUnit.SECONDS);
-        return false;
-    }
+		Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
+		if (sessionObj != null) {
+			Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
+			if (sessionMap.containsKey(url)) {
+				Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
+				if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, intervalTime)) {
+					return true;
+				}
+			}
+		}
+		Map<String, Object> cacheMap = new HashMap<String, Object>();
+		cacheMap.put(url, nowDataMap);
+		redisCache.setCacheObject(cacheRepeatKey, cacheMap, Convert.toInt(intervalTime), TimeUnit.MILLISECONDS);
+		return false;
+	}
 
-    /**
-     * 鍒ゆ柇鍙傛暟鏄惁鐩稿悓
-     */
-    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
-    {
-        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
-        String preParams = (String) preMap.get(REPEAT_PARAMS);
-        return nowParams.equals(preParams);
-    }
+	/**
+	 * 鍒ゆ柇鍙傛暟鏄惁鐩稿悓
+	 */
+	private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) {
+		String nowParams = (String) nowMap.get(REPEAT_PARAMS);
+		String preParams = (String) preMap.get(REPEAT_PARAMS);
+		return nowParams.equals(preParams);
+	}
 
-    /**
-     * 鍒ゆ柇涓ゆ闂撮殧鏃堕棿
-     */
-    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
-    {
-        long time1 = (Long) nowMap.get(REPEAT_TIME);
-        long time2 = (Long) preMap.get(REPEAT_TIME);
-        if ((time1 - time2) < (this.intervalTime * 1000))
-        {
-            return true;
-        }
-        return false;
-    }
+	/**
+	 * 鍒ゆ柇涓ゆ闂撮殧鏃堕棿
+	 */
+	private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, long intervalTime) {
+		long time1 = (Long) nowMap.get(REPEAT_TIME);
+		long time2 = (Long) preMap.get(REPEAT_TIME);
+		return (time1 - time2) < intervalTime;
+	}
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java
new file mode 100644
index 0000000..1781b94
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java
@@ -0,0 +1,42 @@
+package com.ruoyi.framework.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
+
+import java.io.IOException;
+
+/**
+ * 瓒呭嚭 JS 鏈�澶ф渶灏忓�� 澶勭悊
+ *
+ * @author Lion Li
+ */
+@JacksonStdImpl
+public class BigNumberSerializer extends NumberSerializer {
+
+	/**
+	 * 鏍规嵁 JS Number.MAX_SAFE_INTEGER 涓� Number.MIN_SAFE_INTEGER 寰楁潵
+	 */
+	private static final long MAX_SAFE_INTEGER = 9007199254740991L;
+	private static final long MIN_SAFE_INTEGER = -9007199254740991L;
+
+	/**
+	 * 鎻愪緵瀹炰緥
+	 */
+	public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class);
+
+	public BigNumberSerializer(Class<? extends Number> rawType) {
+		super(rawType);
+	}
+
+	@Override
+	public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+		// 瓒呭嚭鑼冨洿 搴忓垪鍖栦綅瀛楃涓�
+		if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
+			super.serialize(value, gen, provider);
+		} else {
+			gen.writeString(value.toString());
+		}
+	}
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java
index 2479293..ae36fc3 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java
@@ -2,8 +2,10 @@
 
 import cn.hutool.http.HttpStatus;
 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.reflection.MetaObject;
 
 import java.util.Date;
@@ -14,6 +16,7 @@
  * @author Lion Li
  * @date 2021/4/25
  */
+@Slf4j
 public class CreateAndUpdateMetaObjectHandler implements MetaObjectHandler {
 
 	@Override
@@ -21,36 +24,43 @@
 		try {
 			//鏍规嵁灞炴�у悕瀛楄缃濉厖鐨勫��
 			if (metaObject.hasGetter("createTime")) {
-				if (metaObject.getValue("createTime") == null) {
-					this.setFieldValByName("createTime", new Date(), metaObject);
-				}
+				this.setFieldValByName("createTime", new Date(), metaObject);
 			}
 			if (metaObject.hasGetter("createBy")) {
-				if (metaObject.getValue("createBy") == null) {
-					this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject);
-				}
+				this.setFieldValByName("createBy", getLoginUsername(), metaObject);
 			}
 		} catch (Exception e) {
-			throw new CustomException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
+			throw new ServiceException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
 		}
+		updateFill(metaObject);
 	}
 
 	@Override
 	public void updateFill(MetaObject metaObject) {
 		try {
 			if (metaObject.hasGetter("updateBy")) {
-				if (metaObject.getValue("updateBy") == null) {
-					this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
-				}
+				this.setFieldValByName("updateBy", getLoginUsername(), metaObject);
 			}
 			if (metaObject.hasGetter("updateTime")) {
-				if (metaObject.getValue("updateTime") == null) {
-					this.setFieldValByName("updateTime", new Date(), metaObject);
-				}
+				this.setFieldValByName("updateTime", new Date(), metaObject);
 			}
 		} catch (Exception e) {
-			throw new CustomException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
+			throw new ServiceException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
 		}
 	}
 
+	/**
+	 * 鑾峰彇鐧诲綍鐢ㄦ埛鍚�
+	 */
+	private String getLoginUsername() {
+		LoginUser loginUser;
+		try {
+			loginUser = SecurityUtils.getLoginUser();
+		} catch (Exception e) {
+			log.error("鑷姩娉ㄥ叆璀﹀憡 => 鐢ㄦ埛鏈櫥褰�");
+			return null;
+		}
+		return loginUser.getUsername();
+	}
+
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
index fb2cdaa..188e24f 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
@@ -1,8 +1,8 @@
 package com.ruoyi.framework.security.filter;
 
-import cn.hutool.core.lang.Validator;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.web.service.TokenService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -19,7 +19,7 @@
 
 /**
  * token杩囨护鍣� 楠岃瘉token鏈夋晥鎬�
- * 
+ *
  * @author ruoyi
  */
 @Component
@@ -33,7 +33,7 @@
             throws ServletException, IOException
     {
         LoginUser loginUser = tokenService.getLoginUser(request);
-        if (Validator.isNotNull(loginUser) && Validator.isNull(SecurityUtils.getAuthentication()))
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
         {
             tokenService.verifyToken(loginUser);
             UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
index 1cd8d60..5757081 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
@@ -1,6 +1,6 @@
 package com.ruoyi.framework.security.handle;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import cn.hutool.http.HttpStatus;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.JsonUtils;
@@ -29,7 +29,7 @@
             throws IOException
     {
         int code = HttpStatus.HTTP_UNAUTHORIZED;
-        String msg = StrUtil.format("璇锋眰璁块棶锛歿}锛岃璇佸け璐ワ紝鏃犳硶璁块棶绯荤粺璧勬簮", request.getRequestURI());
+        String msg = StringUtils.format("璇锋眰璁块棶锛歿}锛岃璇佸け璐ワ紝鏃犳硶璁块棶绯荤粺璧勬簮", request.getRequestURI());
         ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(code, msg)));
     }
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
index 2a12126..371a661 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
@@ -1,12 +1,12 @@
 package com.ruoyi.framework.security.handle;
 
-import cn.hutool.core.lang.Validator;
 import cn.hutool.http.HttpStatus;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.utils.JsonUtils;
 import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.web.service.AsyncService;
 import com.ruoyi.framework.web.service.TokenService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -40,7 +40,7 @@
 	public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
 		throws IOException, ServletException {
 		LoginUser loginUser = tokenService.getLoginUser(request);
-		if (Validator.isNotNull(loginUser)) {
+		if (StringUtils.isNotNull(loginUser)) {
 			String userName = loginUser.getUsername();
 			// 鍒犻櫎鐢ㄦ埛缂撳瓨璁板綍
 			tokenService.delLoginUser(loginUser.getToken());
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
index 9614a8d..9cf69ff 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
@@ -1,27 +1,25 @@
 package com.ruoyi.framework.web.exception;
 
-import cn.hutool.core.lang.Validator;
 import cn.hutool.http.HttpStatus;
 import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.exception.BaseException;
-import com.ruoyi.common.exception.CustomException;
 import com.ruoyi.common.exception.DemoModeException;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.authentication.AccountExpiredException;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
-import org.springframework.web.servlet.NoHandlerFoundException;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.validation.ConstraintViolationException;
 
 /**
  * 鍏ㄥ眬寮傚父澶勭悊鍣�
- * 
+ *
  * @author ruoyi
  */
 @RestControllerAdvice
@@ -30,59 +28,58 @@
     private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
     /**
-     * 鍩虹寮傚父
+     * 鏉冮檺鏍¢獙寮傚父
      */
-    @ExceptionHandler(BaseException.class)
-    public AjaxResult baseException(BaseException e)
+    @ExceptionHandler(AccessDeniedException.class)
+    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
     {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鏉冮檺鏍¢獙澶辫触'{}'", requestURI, e.getMessage());
+        return AjaxResult.error(HttpStatus.HTTP_FORBIDDEN, "娌℃湁鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�");
+    }
+
+    /**
+     * 璇锋眰鏂瑰紡涓嶆敮鎸�
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+            HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',涓嶆敮鎸�'{}'璇锋眰", requestURI, e.getMethod());
         return AjaxResult.error(e.getMessage());
     }
 
     /**
      * 涓氬姟寮傚父
      */
-    @ExceptionHandler(CustomException.class)
-    public AjaxResult businessException(CustomException e)
-    {
-        if (Validator.isNull(e.getCode()))
-        {
-            return AjaxResult.error(e.getMessage());
-        }
-        return AjaxResult.error(e.getCode(), e.getMessage());
-    }
-
-    @ExceptionHandler(NoHandlerFoundException.class)
-    public AjaxResult handlerNoFoundException(Exception e)
+    @ExceptionHandler(ServiceException.class)
+    public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
     {
         log.error(e.getMessage(), e);
-        return AjaxResult.error(HttpStatus.HTTP_NOT_FOUND, "璺緞涓嶅瓨鍦紝璇锋鏌ヨ矾寰勬槸鍚︽纭�");
+        Integer code = e.getCode();
+        return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
     }
 
-    @ExceptionHandler(AccessDeniedException.class)
-    public AjaxResult handleAuthorizationException(AccessDeniedException e)
+    /**
+     * 鎷︽埅鏈煡鐨勮繍琛屾椂寮傚父
+     */
+    @ExceptionHandler(RuntimeException.class)
+    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
     {
-        log.error(e.getMessage());
-        return AjaxResult.error(HttpStatus.HTTP_FORBIDDEN, "娌℃湁鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�");
-    }
-
-    @ExceptionHandler(AccountExpiredException.class)
-    public AjaxResult handleAccountExpiredException(AccountExpiredException e)
-    {
-        log.error(e.getMessage(), e);
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓鏈煡寮傚父.", requestURI, e);
         return AjaxResult.error(e.getMessage());
     }
 
-    @ExceptionHandler(UsernameNotFoundException.class)
-    public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e)
-    {
-        log.error(e.getMessage(), e);
-        return AjaxResult.error(e.getMessage());
-    }
-
+    /**
+     * 绯荤粺寮傚父
+     */
     @ExceptionHandler(Exception.class)
-    public AjaxResult handleException(Exception e)
+    public AjaxResult handleException(Exception e, HttpServletRequest request)
     {
-        log.error(e.getMessage(), e);
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓绯荤粺寮傚父.", requestURI, e);
         return AjaxResult.error(e.getMessage());
     }
 
@@ -90,7 +87,7 @@
      * 鑷畾涔夐獙璇佸紓甯�
      */
     @ExceptionHandler(BindException.class)
-    public AjaxResult validatedBindException(BindException e)
+    public AjaxResult handleBindException(BindException e)
     {
         log.error(e.getMessage(), e);
         String message = e.getAllErrors().get(0).getDefaultMessage();
@@ -111,7 +108,7 @@
      * 鑷畾涔夐獙璇佸紓甯�
      */
     @ExceptionHandler(MethodArgumentNotValidException.class)
-    public Object validExceptionHandler(MethodArgumentNotValidException e)
+    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
     {
         log.error(e.getMessage(), e);
         String message = e.getBindingResult().getFieldError().getDefaultMessage();
@@ -122,7 +119,7 @@
      * 婕旂ず妯″紡寮傚父
      */
     @ExceptionHandler(DemoModeException.class)
-    public AjaxResult demoModeException(DemoModeException e)
+    public AjaxResult handleDemoModeException(DemoModeException e)
     {
         return AjaxResult.error("婕旂ず妯″紡锛屼笉鍏佽鎿嶄綔");
     }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java
index e64fbc1..3199cdd 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/AsyncService.java
@@ -1,5 +1,6 @@
 package com.ruoyi.framework.web.service;
 
+import com.ruoyi.common.utils.StringUtils;
 import cn.hutool.http.useragent.UserAgent;
 import cn.hutool.http.useragent.UserAgentUtil;
 import com.ruoyi.common.constant.Constants;
@@ -67,7 +68,7 @@
 		logininfor.setOs(os);
 		logininfor.setMsg(message);
 		// 鏃ュ織鐘舵��
-		if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) {
+		if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
 			logininfor.setStatus(Constants.SUCCESS);
 		} else if (Constants.LOGIN_FAIL.equals(status)) {
 			logininfor.setStatus(Constants.FAIL);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
index 064efa5..af7fd57 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
@@ -1,18 +1,18 @@
 package com.ruoyi.framework.web.service;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.utils.ServletUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
 import java.util.Set;
 
 /**
  * RuoYi棣栧垱 鑷畾涔夋潈闄愬疄鐜帮紝ss鍙栬嚜SpringSecurity棣栧瓧姣�
- * 
+ *
  * @author ruoyi
  */
 @Service("ss")
@@ -33,18 +33,18 @@
 
     /**
      * 楠岃瘉鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
-     * 
+     *
      * @param permission 鏉冮檺瀛楃涓�
      * @return 鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
      */
     public boolean hasPermi(String permission)
     {
-        if (Validator.isEmpty(permission))
+        if (StringUtils.isEmpty(permission))
         {
             return false;
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getPermissions()))
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
         {
             return false;
         }
@@ -70,12 +70,12 @@
      */
     public boolean hasAnyPermi(String permissions)
     {
-        if (Validator.isEmpty(permissions))
+        if (StringUtils.isEmpty(permissions))
         {
             return false;
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getPermissions()))
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
         {
             return false;
         }
@@ -92,25 +92,25 @@
 
     /**
      * 鍒ゆ柇鐢ㄦ埛鏄惁鎷ユ湁鏌愪釜瑙掕壊
-     * 
+     *
      * @param role 瑙掕壊瀛楃涓�
      * @return 鐢ㄦ埛鏄惁鍏峰鏌愯鑹�
      */
     public boolean hasRole(String role)
     {
-        if (Validator.isEmpty(role))
+        if (StringUtils.isEmpty(role))
         {
             return false;
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getUser().getRoles()))
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
         {
             return false;
         }
         for (SysRole sysRole : loginUser.getUser().getRoles())
         {
             String roleKey = sysRole.getRoleKey();
-            if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StrUtil.trim(role)))
+            if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
             {
                 return true;
             }
@@ -137,12 +137,12 @@
      */
     public boolean hasAnyRoles(String roles)
     {
-        if (Validator.isEmpty(roles))
+        if (StringUtils.isEmpty(roles))
         {
             return false;
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (Validator.isNull(loginUser) || Validator.isEmpty(loginUser.getUser().getRoles()))
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
         {
             return false;
         }
@@ -158,13 +158,13 @@
 
     /**
      * 鍒ゆ柇鏄惁鍖呭惈鏉冮檺
-     * 
+     *
      * @param permissions 鏉冮檺鍒楄〃
      * @param permission 鏉冮檺瀛楃涓�
      * @return 鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
      */
     private boolean hasPermissions(Set<String> permissions, String permission)
     {
-        return permissions.contains(ALL_PERMISSION) || permissions.contains(StrUtil.trim(permission));
+        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
     }
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
index 3aa6d18..e3e8e71 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -4,7 +4,7 @@
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.user.CaptchaException;
 import com.ruoyi.common.exception.user.CaptchaExpireException;
 import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
@@ -85,7 +85,7 @@
             else
             {
 				asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage(), request);
-                throw new CustomException(e.getMessage());
+                throw new ServiceException(e.getMessage());
             }
         }
 		asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
new file mode 100644
index 0000000..48d40af
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
@@ -0,0 +1,117 @@
+package com.ruoyi.framework.web.service;
+
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.RegisterBody;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.exception.user.CaptchaException;
+import com.ruoyi.common.exception.user.CaptchaExpireException;
+import com.ruoyi.common.utils.MessageUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 娉ㄥ唽鏍¢獙鏂规硶
+ *
+ * @author ruoyi
+ */
+@Component
+public class SysRegisterService
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+	@Autowired
+	private AsyncService asyncService;
+
+    /**
+     * 娉ㄥ唽
+     */
+    public String register(RegisterBody registerBody)
+    {
+        String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
+
+        boolean captchaOnOff = configService.selectCaptchaOnOff();
+        // 楠岃瘉鐮佸紑鍏�
+        if (captchaOnOff)
+        {
+            validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
+        }
+
+        if (StringUtils.isEmpty(username))
+        {
+            msg = "鐢ㄦ埛鍚嶄笉鑳戒负绌�";
+        }
+        else if (StringUtils.isEmpty(password))
+        {
+            msg = "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖";
+        }
+        else if (username.length() < UserConstants.USERNAME_MIN_LENGTH
+                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
+        {
+            msg = "璐︽埛闀垮害蹇呴』鍦�2鍒�20涓瓧绗︿箣闂�";
+        }
+        else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
+                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
+        {
+            msg = "瀵嗙爜闀垮害蹇呴』鍦�5鍒�20涓瓧绗︿箣闂�";
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(username)))
+        {
+            msg = "淇濆瓨鐢ㄦ埛'" + username + "'澶辫触锛屾敞鍐岃处鍙峰凡瀛樺湪";
+        }
+        else
+        {
+            SysUser sysUser = new SysUser();
+            sysUser.setUserName(username);
+            sysUser.setNickName(username);
+            sysUser.setPassword(SecurityUtils.encryptPassword(registerBody.getPassword()));
+            boolean regFlag = userService.registerUser(sysUser);
+            if (!regFlag)
+            {
+                msg = "娉ㄥ唽澶辫触,璇疯仈绯荤郴缁熺鐞嗕汉鍛�";
+            }
+            else
+            {
+				asyncService.recordLogininfor(username, Constants.REGISTER,
+                        MessageUtils.message("user.register.success"), ServletUtils.getRequest());
+            }
+        }
+        return msg;
+    }
+
+    /**
+     * 鏍¢獙楠岃瘉鐮�
+     *
+     * @param username 鐢ㄦ埛鍚�
+     * @param code 楠岃瘉鐮�
+     * @param uuid 鍞竴鏍囪瘑
+     * @return 缁撴灉
+     */
+    public void validateCaptcha(String username, String code, String uuid)
+    {
+        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
+        String captcha = redisCache.getCacheObject(verifyKey);
+        redisCache.deleteObject(verifyKey);
+        if (captcha == null)
+        {
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha))
+        {
+            throw new CaptchaException();
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
index f834570..3414e37 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
@@ -1,6 +1,5 @@
 package com.ruoyi.framework.web.service;
 
-import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.http.useragent.UserAgent;
 import cn.hutool.http.useragent.UserAgentUtil;
@@ -8,6 +7,7 @@
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.ip.AddressUtils;
 import com.ruoyi.framework.config.properties.TokenProperties;
 import io.jsonwebtoken.Claims;
@@ -49,13 +49,17 @@
     public LoginUser getLoginUser(HttpServletRequest request) {
         // 鑾峰彇璇锋眰鎼哄甫鐨勪护鐗�
         String token = getToken(request);
-        if (Validator.isNotEmpty(token)) {
-            Claims claims = parseToken(token);
-            // 瑙f瀽瀵瑰簲鐨勬潈闄愪互鍙婄敤鎴蜂俊鎭�
-            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
-            String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
-            return user;
+        if (StringUtils.isNotEmpty(token)) {
+			try {
+				Claims claims = parseToken(token);
+				// 瑙f瀽瀵瑰簲鐨勬潈闄愪互鍙婄敤鎴蜂俊鎭�
+				String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
+				String userKey = getTokenKey(uuid);
+				LoginUser user = redisCache.getCacheObject(userKey);
+				return user;
+			} catch (Exception e) {
+
+			}
         }
         return null;
     }
@@ -64,7 +68,7 @@
      * 璁剧疆鐢ㄦ埛韬唤淇℃伅
      */
     public void setLoginUser(LoginUser loginUser) {
-        if (Validator.isNotNull(loginUser) && Validator.isNotEmpty(loginUser.getToken())) {
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
             refreshToken(loginUser);
         }
     }
@@ -73,7 +77,7 @@
      * 鍒犻櫎鐢ㄦ埛韬唤淇℃伅
      */
     public void delLoginUser(String token) {
-        if (Validator.isNotEmpty(token)) {
+        if (StringUtils.isNotEmpty(token)) {
             String userKey = getTokenKey(token);
             redisCache.deleteObject(userKey);
         }
@@ -182,7 +186,7 @@
      */
     private String getToken(HttpServletRequest request) {
         String token = request.getHeader(tokenProperties.getHeader());
-        if (Validator.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
+        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
             token = token.replace(Constants.TOKEN_PREFIX, "");
         }
         return token;
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
index 46b96ba..c8b1c7b 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
@@ -1,11 +1,5 @@
 package com.ruoyi.framework.web.service;
 
-import cn.hutool.core.lang.Validator;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.enums.UserStatus;
-import com.ruoyi.common.exception.BaseException;
-import com.ruoyi.system.service.ISysUserService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,6 +7,12 @@
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.enums.UserStatus;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysUserService;
 
 /**
  * 鐢ㄦ埛楠岃瘉澶勭悊
@@ -34,20 +34,20 @@
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
     {
         SysUser user = userService.selectUserByUserName(username);
-        if (Validator.isNull(user))
+        if (StringUtils.isNull(user))
         {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
-            throw new UsernameNotFoundException("鐧诲綍鐢ㄦ埛锛�" + username + " 涓嶅瓨鍦�");
+            throw new ServiceException("鐧诲綍鐢ㄦ埛锛�" + username + " 涓嶅瓨鍦�");
         }
         else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
         {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍒犻櫎.", username);
-            throw new BaseException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸茶鍒犻櫎");
+            throw new ServiceException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸茶鍒犻櫎");
         }
         else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
         {
             log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
-            throw new BaseException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸插仠鐢�");
+            throw new ServiceException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸插仠鐢�");
         }
 
         return createLoginUser(user);
@@ -55,6 +55,6 @@
 
     public UserDetails createLoginUser(SysUser user)
     {
-        return new LoginUser(user, permissionService.getMenuPermission(user));
+        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
     }
 }
diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml
index 5535bd7..a712e1f 100644
--- a/ruoyi-generator/pom.xml
+++ b/ruoyi-generator/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
index 5d5c6a4..5d3217c 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
@@ -1,6 +1,6 @@
 package com.ruoyi.generator.domain;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.ruoyi.common.constant.GenConstants;
@@ -204,7 +204,7 @@
     }
 
     public static boolean isSub(String tplCategory) {
-        return tplCategory != null && StrUtil.equals(GenConstants.TPL_SUB, tplCategory);
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
     }
 
     public boolean isTree() {
@@ -212,7 +212,7 @@
     }
 
     public static boolean isTree(String tplCategory) {
-        return tplCategory != null && StrUtil.equals(GenConstants.TPL_TREE, tplCategory);
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
     }
 
     public boolean isCrud() {
@@ -220,7 +220,7 @@
     }
 
     public static boolean isCrud(String tplCategory) {
-        return tplCategory != null && StrUtil.equals(GenConstants.TPL_CRUD, tplCategory);
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
     }
 
     public boolean isSuperColumn(String javaField) {
@@ -229,9 +229,9 @@
 
     public static boolean isSuperColumn(String tplCategory, String javaField) {
         if (isTree(tplCategory)) {
-            return StrUtil.equalsAnyIgnoreCase(javaField,
+            return StringUtils.equalsAnyIgnoreCase(javaField,
                     ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));
         }
-        return StrUtil.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+        return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
     }
-}
\ No newline at end of file
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
index 9e03f5d..92ba7a9 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
@@ -1,6 +1,6 @@
 package com.ruoyi.generator.domain;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.*;
@@ -150,7 +150,7 @@
     private Map<String, Object> params = new HashMap<>();
 
     public String getCapJavaField() {
-        return StrUtil.upperFirst(javaField);
+        return StringUtils.uncapitalize(javaField);
     }
 
     public boolean isPk() {
@@ -158,7 +158,7 @@
     }
 
     public boolean isPk(String isPk) {
-        return isPk != null && StrUtil.equals("1", isPk);
+        return isPk != null && StringUtils.equals("1", isPk);
     }
 
     public boolean isIncrement() {
@@ -166,7 +166,7 @@
     }
 
     public boolean isIncrement(String isIncrement) {
-        return isIncrement != null && StrUtil.equals("1", isIncrement);
+        return isIncrement != null && StringUtils.equals("1", isIncrement);
     }
 
     public boolean isRequired() {
@@ -174,7 +174,7 @@
     }
 
     public boolean isRequired(String isRequired) {
-        return isRequired != null && StrUtil.equals("1", isRequired);
+        return isRequired != null && StringUtils.equals("1", isRequired);
     }
 
     public boolean isInsert() {
@@ -182,7 +182,7 @@
     }
 
     public boolean isInsert(String isInsert) {
-        return isInsert != null && StrUtil.equals("1", isInsert);
+        return isInsert != null && StringUtils.equals("1", isInsert);
     }
 
     public boolean isEdit() {
@@ -190,7 +190,7 @@
     }
 
     public boolean isEdit(String isEdit) {
-        return isEdit != null && StrUtil.equals("1", isEdit);
+        return isEdit != null && StringUtils.equals("1", isEdit);
     }
 
     public boolean isList() {
@@ -198,7 +198,7 @@
     }
 
     public boolean isList(String isList) {
-        return isList != null && StrUtil.equals("1", isList);
+        return isList != null && StringUtils.equals("1", isList);
     }
 
     public boolean isQuery() {
@@ -206,7 +206,7 @@
     }
 
     public boolean isQuery(String isQuery) {
-        return isQuery != null && StrUtil.equals("1", isQuery);
+        return isQuery != null && StringUtils.equals("1", isQuery);
     }
 
     public boolean isSuperColumn() {
@@ -214,7 +214,7 @@
     }
 
     public static boolean isSuperColumn(String javaField) {
-        return StrUtil.equalsAnyIgnoreCase(javaField,
+        return StringUtils.equalsAnyIgnoreCase(javaField,
                 // BaseEntity
                 "createBy", "createTime", "updateBy", "updateTime", "remark",
                 // TreeEntity
@@ -227,15 +227,15 @@
 
     public static boolean isUsableColumn(String javaField) {
         // isSuperColumn()涓殑鍚嶅崟鐢ㄤ簬閬垮厤鐢熸垚澶氫綑Domain灞炴�э紝鑻ユ煇浜涘睘鎬у湪鐢熸垚椤甸潰鏃堕渶瑕佺敤鍒颁笉鑳藉拷鐣ワ紝鍒欐斁鍦ㄦ澶勭櫧鍚嶅崟
-        return StrUtil.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
+        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
     }
 
     public String readConverterExp() {
-        String remarks = StrUtil.subBetween(this.columnComment, "锛�", "锛�");
+        String remarks = StringUtils.substringBetween(this.columnComment, "锛�", "锛�");
         StringBuffer sb = new StringBuffer();
-        if (StrUtil.isNotEmpty(remarks)) {
+        if (StringUtils.isNotEmpty(remarks)) {
             for (String value : remarks.split(" ")) {
-                if (StrUtil.isNotEmpty(value)) {
+                if (StringUtils.isNotEmpty(value)) {
                     Object startStr = value.subSequence(0, 1);
                     String endStr = value.substring(1);
                     sb.append("").append(startStr).append("=").append(endStr).append(",");
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
index 86bd128..94a9975 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
@@ -2,15 +2,14 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.constant.GenConstants;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.JsonUtils;
 import com.ruoyi.common.utils.PageUtils;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -137,15 +136,15 @@
             for (GenTableColumn cenTableColumn : genTable.getColumns()) {
                 genTableColumnMapper.update(cenTableColumn,
                         new LambdaUpdateWrapper<GenTableColumn>()
-							.set(StrUtil.isBlank(cenTableColumn.getColumnComment()), GenTableColumn::getColumnComment, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsPk()), GenTableColumn::getIsPk, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsIncrement()), GenTableColumn::getIsIncrement, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsInsert()), GenTableColumn::getIsInsert, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsEdit()), GenTableColumn::getIsEdit, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsList()), GenTableColumn::getIsList, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsQuery()), GenTableColumn::getIsQuery, null)
-							.set(StrUtil.isBlank(cenTableColumn.getIsRequired()), GenTableColumn::getIsRequired, null)
-							.set(StrUtil.isBlank(cenTableColumn.getDictType()), GenTableColumn::getDictType, "")
+							.set(StringUtils.isBlank(cenTableColumn.getColumnComment()), GenTableColumn::getColumnComment, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsPk()), GenTableColumn::getIsPk, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsIncrement()), GenTableColumn::getIsIncrement, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsInsert()), GenTableColumn::getIsInsert, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsEdit()), GenTableColumn::getIsEdit, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsList()), GenTableColumn::getIsList, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsQuery()), GenTableColumn::getIsQuery, null)
+							.set(StringUtils.isBlank(cenTableColumn.getIsRequired()), GenTableColumn::getIsRequired, null)
+							.set(StringUtils.isBlank(cenTableColumn.getDictType()), GenTableColumn::getDictType, "")
 							.eq(GenTableColumn::getColumnId,cenTableColumn.getColumnId()));
             }
         }
@@ -189,7 +188,7 @@
 				}
             }
         } catch (Exception e) {
-            throw new CustomException("瀵煎叆澶辫触锛�" + e.getMessage());
+            throw new ServiceException("瀵煎叆澶辫触锛�" + e.getMessage());
         }
     }
 
@@ -260,13 +259,17 @@
         // 鑾峰彇妯℃澘鍒楄〃
         List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
         for (String template : templates) {
-            if (!StrUtil.containsAny("sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm", template)) {
+            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) {
                 // 娓叉煋妯℃澘
                 StringWriter sw = new StringWriter();
                 Template tpl = Velocity.getTemplate(template, Constants.UTF8);
                 tpl.merge(context, sw);
-                String path = getGenPath(table, template);
-                FileUtils.writeUtf8String(sw.toString(), path);
+				try {
+                	String path = getGenPath(table, template);
+                	FileUtils.writeUtf8String(sw.toString(), path);
+				} catch (Exception e) {
+					throw new ServiceException("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName());
+				}
             }
         }
     }
@@ -284,8 +287,8 @@
         List<String> tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
 
         List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
-        if (Validator.isEmpty(dbTableColumns)) {
-            throw new CustomException("鍚屾鏁版嵁澶辫触锛屽師琛ㄧ粨鏋勪笉瀛樺湪");
+        if (StringUtils.isEmpty(dbTableColumns)) {
+            throw new ServiceException("鍚屾鏁版嵁澶辫触锛屽師琛ㄧ粨鏋勪笉瀛樺湪");
         }
         List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
 
@@ -364,17 +367,17 @@
     public void validateEdit(GenTable genTable) {
         if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
 			Map<String, Object> paramsObj = genTable.getParams();
-            if (Validator.isEmpty(paramsObj.get(GenConstants.TREE_CODE))) {
-                throw new CustomException("鏍戠紪鐮佸瓧娈典笉鑳戒负绌�");
-            } else if (Validator.isEmpty(paramsObj.get(GenConstants.TREE_PARENT_CODE))) {
-                throw new CustomException("鏍戠埗缂栫爜瀛楁涓嶈兘涓虹┖");
-            } else if (Validator.isEmpty(paramsObj.get(GenConstants.TREE_NAME))) {
-                throw new CustomException("鏍戝悕绉板瓧娈典笉鑳戒负绌�");
+            if (StringUtils.isEmpty(paramsObj.get(GenConstants.TREE_CODE))) {
+                throw new ServiceException("鏍戠紪鐮佸瓧娈典笉鑳戒负绌�");
+            } else if (StringUtils.isEmpty(paramsObj.get(GenConstants.TREE_PARENT_CODE))) {
+                throw new ServiceException("鏍戠埗缂栫爜瀛楁涓嶈兘涓虹┖");
+            } else if (StringUtils.isEmpty(paramsObj.get(GenConstants.TREE_NAME))) {
+                throw new ServiceException("鏍戝悕绉板瓧娈典笉鑳戒负绌�");
             } else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) {
-                if (Validator.isEmpty(genTable.getSubTableName())) {
-                    throw new CustomException("鍏宠仈瀛愯〃鐨勮〃鍚嶄笉鑳戒负绌�");
-                } else if (Validator.isEmpty(genTable.getSubTableFkName())) {
-                    throw new CustomException("瀛愯〃鍏宠仈鐨勫閿悕涓嶈兘涓虹┖");
+                if (StringUtils.isEmpty(genTable.getSubTableName())) {
+                    throw new ServiceException("鍏宠仈瀛愯〃鐨勮〃鍚嶄笉鑳戒负绌�");
+                } else if (StringUtils.isEmpty(genTable.getSubTableFkName())) {
+                    throw new ServiceException("瀛愯〃鍏宠仈鐨勫閿悕涓嶈兘涓虹┖");
                 }
             }
         }
@@ -392,7 +395,7 @@
                 break;
             }
         }
-        if (Validator.isNull(table.getPkColumn())) {
+        if (StringUtils.isNull(table.getPkColumn())) {
             table.setPkColumn(table.getColumns().get(0));
         }
         if (GenConstants.TPL_SUB.equals(table.getTplCategory())) {
@@ -402,7 +405,7 @@
                     break;
                 }
             }
-            if (Validator.isNull(table.getSubTable().getPkColumn())) {
+            if (StringUtils.isNull(table.getSubTable().getPkColumn())) {
                 table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
             }
         }
@@ -415,7 +418,7 @@
      */
     public void setSubTable(GenTable table) {
         String subTableName = table.getSubTableName();
-        if (Validator.isNotEmpty(subTableName)) {
+        if (StringUtils.isNotEmpty(subTableName)) {
             table.setSubTable(baseMapper.selectGenTableByName(subTableName));
         }
     }
@@ -427,7 +430,7 @@
      */
     public void setTableFromOptions(GenTable genTable) {
 		Map<String, Object> paramsObj = JsonUtils.parseMap(genTable.getOptions());
-        if (Validator.isNotNull(paramsObj)) {
+        if (StringUtils.isNotNull(paramsObj)) {
             String treeCode = Convert.toStr(paramsObj.get(GenConstants.TREE_CODE));
             String treeParentCode = Convert.toStr(paramsObj.get(GenConstants.TREE_PARENT_CODE));
             String treeName = Convert.toStr(paramsObj.get(GenConstants.TREE_NAME));
@@ -451,7 +454,7 @@
      */
     public static String getGenPath(GenTable table, String template) {
         String genPath = table.getGenPath();
-        if (StrUtil.equals(genPath, "/")) {
+        if (StringUtils.equals(genPath, "/")) {
             return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
         }
         return genPath + File.separator + VelocityUtils.getFileName(template, table);
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
index 928a051..01afce0 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
@@ -1,6 +1,6 @@
 package com.ruoyi.generator.util;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.constant.GenConstants;
 import com.ruoyi.generator.config.GenConfig;
 import com.ruoyi.generator.domain.GenTable;
@@ -40,7 +40,7 @@
         column.setTableId(table.getTableId());
         column.setCreateBy(table.getCreateBy());
         // 璁剧疆java瀛楁鍚�
-        column.setJavaField(StrUtil.toCamelCase(columnName));
+        column.setJavaField(StringUtils.toCamelCase(columnName));
         // 璁剧疆榛樿绫诲瀷
         column.setJavaType(GenConstants.TYPE_STRING);
 
@@ -61,7 +61,7 @@
             column.setHtmlType(GenConstants.HTML_INPUT);
 
             // 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal
-            String[] str = StrUtil.splitToArray(StrUtil.subBetween(column.getColumnType(), "(", ")"), ",");
+            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
             if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
             {
                 column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
@@ -98,33 +98,33 @@
         }
 
         // 鏌ヨ瀛楁绫诲瀷
-        if (StrUtil.endWithIgnoreCase(columnName, "name"))
+        if (StringUtils.endsWithIgnoreCase(columnName, "name"))
         {
             column.setQueryType(GenConstants.QUERY_LIKE);
         }
         // 鐘舵�佸瓧娈佃缃崟閫夋
-        if (StrUtil.endWithIgnoreCase(columnName, "status"))
+        if (StringUtils.endsWithIgnoreCase(columnName, "status"))
         {
             column.setHtmlType(GenConstants.HTML_RADIO);
         }
         // 绫诲瀷&鎬у埆瀛楁璁剧疆涓嬫媺妗�
-        else if (StrUtil.endWithIgnoreCase(columnName, "type")
-                || StrUtil.endWithIgnoreCase(columnName, "sex"))
+        else if (StringUtils.endsWithIgnoreCase(columnName, "type")
+                || StringUtils.endsWithIgnoreCase(columnName, "sex"))
         {
             column.setHtmlType(GenConstants.HTML_SELECT);
         }
         // 鍥剧墖瀛楁璁剧疆鍥剧墖涓婁紶鎺т欢
-        else if (StrUtil.endWithIgnoreCase(columnName, "image"))
+        else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
         {
             column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
         }
         // 鏂囦欢瀛楁璁剧疆鏂囦欢涓婁紶鎺т欢
-        else if (StrUtil.endWithIgnoreCase(columnName, "file"))
+        else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
         {
             column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
         }
         // 鍐呭瀛楁璁剧疆瀵屾枃鏈帶浠�
-        else if (StrUtil.endWithIgnoreCase(columnName, "content"))
+        else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
         {
             column.setHtmlType(GenConstants.HTML_EDITOR);
         }
@@ -152,7 +152,7 @@
     {
         int lastIndex = packageName.lastIndexOf(".");
         int nameLength = packageName.length();
-        String moduleName = StrUtil.sub(packageName, lastIndex + 1, nameLength);
+        String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength);
         return moduleName;
     }
 
@@ -166,7 +166,7 @@
     {
         int lastIndex = tableName.lastIndexOf("_");
         int nameLength = tableName.length();
-        String businessName = StrUtil.sub(tableName, lastIndex + 1, nameLength);
+        String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength);
         return businessName;
     }
 
@@ -180,12 +180,12 @@
     {
         boolean autoRemovePre = GenConfig.getAutoRemovePre();
         String tablePrefix = GenConfig.getTablePrefix();
-        if (autoRemovePre && StrUtil.isNotEmpty(tablePrefix))
+        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
         {
-            String[] searchList = StrUtil.splitToArray(tablePrefix, ",");
+            String[] searchList = StringUtils.split(tablePrefix, ",");
             tableName = replaceFirst(tableName, searchList);
         }
-        return StrUtil.upperFirst(StrUtil.toCamelCase(tableName));
+        return StringUtils.convertToCamelCase(tableName);
     }
 
     /**
@@ -228,9 +228,9 @@
      */
     public static String getDbType(String columnType)
     {
-        if (StrUtil.indexOf(columnType, '(') > 0)
+        if (StringUtils.indexOf(columnType, '(') > 0)
         {
-            return StrUtil.subBefore(columnType, "(",false);
+            return StringUtils.substringBefore(columnType, "(");
         }
         else
         {
@@ -246,9 +246,9 @@
      */
     public static Integer getColumnLength(String columnType)
     {
-        if (StrUtil.indexOf(columnType, '(') > 0)
+        if (StringUtils.indexOf(columnType, '(') > 0)
         {
-            String length = StrUtil.subBetween(columnType, "(", ")");
+            String length = StringUtils.substringBetween(columnType, "(", ")");
             return Integer.valueOf(length);
         }
         else
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
index 641cf1d..098a918 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
@@ -1,11 +1,10 @@
 package com.ruoyi.generator.util;
 
 import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.constant.GenConstants;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.generator.domain.GenTable;
 import com.ruoyi.generator.domain.GenTableColumn;
 import org.apache.velocity.VelocityContext;
@@ -47,11 +46,11 @@
         VelocityContext velocityContext = new VelocityContext();
         velocityContext.put("tplCategory", genTable.getTplCategory());
         velocityContext.put("tableName", genTable.getTableName());
-        velocityContext.put("functionName", StrUtil.isNotEmpty(functionName) ? functionName : "銆愯濉啓鍔熻兘鍚嶇О銆�");
+        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "銆愯濉啓鍔熻兘鍚嶇О銆�");
         velocityContext.put("ClassName", genTable.getClassName());
-        velocityContext.put("className", StrUtil.lowerFirst(genTable.getClassName()));
+        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
         velocityContext.put("moduleName", genTable.getModuleName());
-        velocityContext.put("BusinessName", StrUtil.upperFirst(genTable.getBusinessName()));
+        velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
         velocityContext.put("businessName", genTable.getBusinessName());
         velocityContext.put("basePackage", getPackagePrefix(packageName));
         velocityContext.put("packageName", packageName);
@@ -110,15 +109,15 @@
         String subTableName = genTable.getSubTableName();
         String subTableFkName = genTable.getSubTableFkName();
         String subClassName = genTable.getSubTable().getClassName();
-        String subTableFkClassName = StrUtil.toCamelCase(subTableFkName);
+        String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
 
         context.put("subTable", subTable);
         context.put("subTableName", subTableName);
         context.put("subTableFkName", subTableFkName);
         context.put("subTableFkClassName", subTableFkClassName);
-        context.put("subTableFkclassName", StrUtil.lowerFirst(subTableFkClassName));
+        context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
         context.put("subClassName", subClassName);
-        context.put("subclassName", StrUtil.lowerFirst(subClassName));
+        context.put("subclassName", StringUtils.uncapitalize(subClassName));
         context.put("subImportList", getImportList(genTable.getSubTable()));
     }
 
@@ -172,45 +171,45 @@
         // 涓氬姟鍚嶇О
         String businessName = genTable.getBusinessName();
 
-        String javaPath = PROJECT_PATH + "/" + StrUtil.replace(packageName, ".", "/");
+        String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
         String mybatisPath = MYBATIS_PATH + "/" + moduleName;
         String vuePath = "vue";
 
         if (template.contains("domain.java.vm"))
         {
-            fileName = StrUtil.format("{}/domain/{}.java", javaPath, className);
+            fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
         }
         if (template.contains("vo.java.vm"))
         {
-            fileName = StrUtil.format("{}/domain/vo/{}Vo.java", javaPath, className);
+            fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className);
         }
 		if (template.contains("bo.java.vm"))
 		{
-			fileName = StrUtil.format("{}/domain/bo/{}Bo.java", javaPath, className);
+			fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className);
 		}
-        if (template.contains("sub-domain.java.vm") && StrUtil.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
+        if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
         {
-            fileName = StrUtil.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
+            fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
         }
         else if (template.contains("mapper.java.vm"))
         {
-            fileName = StrUtil.format("{}/mapper/{}Mapper.java", javaPath, className);
+            fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
         }
         else if (template.contains("service.java.vm"))
         {
-            fileName = StrUtil.format("{}/service/I{}Service.java", javaPath, className);
+            fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
         }
         else if (template.contains("serviceImpl.java.vm"))
         {
-            fileName = StrUtil.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
+            fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
         }
         else if (template.contains("controller.java.vm"))
         {
-            fileName = StrUtil.format("{}/controller/{}Controller.java", javaPath, className);
+            fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
         }
         else if (template.contains("mapper.xml.vm"))
         {
-            fileName = StrUtil.format("{}/{}Mapper.xml", mybatisPath, className);
+            fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
         }
         else if (template.contains("sql.vm"))
         {
@@ -218,15 +217,15 @@
         }
         else if (template.contains("api.js.vm"))
         {
-            fileName = StrUtil.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
+            fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
         }
         else if (template.contains("index.vue.vm"))
         {
-            fileName = StrUtil.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
         }
         else if (template.contains("index-tree.vue.vm"))
         {
-            fileName = StrUtil.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
         }
         return fileName;
     }
@@ -240,7 +239,7 @@
     public static String getPackagePrefix(String packageName)
     {
         int lastIndex = packageName.lastIndexOf(".");
-        String basePackage = StrUtil.sub(packageName, 0, lastIndex);
+        String basePackage = StringUtils.substring(packageName, 0, lastIndex);
         return basePackage;
     }
 
@@ -255,7 +254,7 @@
         List<GenTableColumn> columns = genTable.getColumns();
         GenTable subGenTable = genTable.getSubTable();
         HashSet<String> importList = new HashSet<String>();
-        if (Validator.isNotNull(subGenTable))
+        if (StringUtils.isNotNull(subGenTable))
         {
             importList.add("java.util.List");
         }
@@ -283,7 +282,7 @@
      */
     public static String getPermissionPrefix(String moduleName, String businessName)
     {
-        return StrUtil.format("{}:{}", moduleName, businessName);
+        return StringUtils.format("{}:{}", moduleName, businessName);
     }
 
     /**
@@ -294,7 +293,8 @@
      */
     public static String getParentMenuId(Map<String, Object> paramsObj)
     {
-        if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID))
+        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+				&& StringUtils.isNotEmpty(Convert.toStr(paramsObj.get(GenConstants.PARENT_MENU_ID))))
         {
             return Convert.toStr(paramsObj.get(GenConstants.PARENT_MENU_ID));
         }
@@ -309,11 +309,11 @@
      */
     public static String getTreecode(Map<String, Object> paramsObj)
     {
-        if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE))
+        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE))
         {
-            return StrUtil.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)));
+            return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)));
         }
-        return StrUtil.EMPTY;
+        return StringUtils.EMPTY;
     }
 
     /**
@@ -324,11 +324,11 @@
      */
     public static String getTreeParentCode(Map<String, Object> paramsObj)
     {
-        if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
         {
-            return StrUtil.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_PARENT_CODE)));
+            return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_PARENT_CODE)));
         }
-        return StrUtil.EMPTY;
+        return StringUtils.EMPTY;
     }
 
     /**
@@ -339,11 +339,11 @@
      */
     public static String getTreeName(Map<String, Object> paramsObj)
     {
-        if (Validator.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME))
+        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME))
         {
-            return StrUtil.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_NAME)));
+            return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_NAME)));
         }
-        return StrUtil.EMPTY;
+        return StringUtils.EMPTY;
     }
 
     /**
diff --git a/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
index 40174d5..8831d0c 100644
--- a/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
+++ b/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
@@ -41,7 +41,6 @@
     /**
      * $column.columnComment
      */
-	@ApiModelProperty("$column.columnComment")
 #if($column.isInsert && $column.isEdit)
 #set($Group="AddGroup.class, EditGroup.class")
 #elseif($column.isInsert)
@@ -50,11 +49,14 @@
 #set($Group="EditGroup.class")
 #end
 #if($column.isRequired == 1)
+    @ApiModelProperty(value = "$column.columnComment", required = true)
 #if($column.javaType == 'String')
     @NotBlank(message = "$column.columnComment涓嶈兘涓虹┖", groups = { $Group })
 #else
     @NotNull(message = "$column.columnComment涓嶈兘涓虹┖", groups = { $Group })
 #end
+#else
+    @ApiModelProperty(value = "$column.columnComment")
 #end
     private $column.javaType $column.javaField;
 
diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
index ba29e20..7aad267 100644
--- a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
+++ b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
@@ -2,8 +2,10 @@
 
 import java.util.List;
 import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
 
 import lombok.RequiredArgsConstructor;
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.*;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,10 +18,10 @@
 import com.ruoyi.common.core.validate.AddGroup;
 import com.ruoyi.common.core.validate.EditGroup;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import ${packageName}.domain.vo.${ClassName}Vo;
 import ${packageName}.domain.bo.${ClassName}Bo;
 import ${packageName}.service.I${ClassName}Service;
-import com.ruoyi.common.utils.poi.ExcelUtil;
 #if($table.crud || $table.sub)
 import com.ruoyi.common.core.page.TableDataInfo;
 #elseif($table.tree)
@@ -66,10 +68,9 @@
     @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
     @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult<${ClassName}Vo> export(@Validated ${ClassName}Bo bo) {
+    public void export(@Validated ${ClassName}Bo bo, HttpServletResponse response) {
         List<${ClassName}Vo> list = i${ClassName}Service.queryList(bo);
-        ExcelUtil<${ClassName}Vo> util = new ExcelUtil<${ClassName}Vo>(${ClassName}Vo.class);
-        return util.exportExcel(list, "${functionName}");
+        ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response);
     }
 
     /**
@@ -89,7 +90,7 @@
     @ApiOperation("鏂板${functionName}")
     @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')")
     @Log(title = "${functionName}", businessType = BusinessType.INSERT)
-    @RepeatSubmit
+    @RepeatSubmit()
     @PostMapping()
     public AjaxResult<Void> add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) {
         return toAjax(i${ClassName}Service.insertByBo(bo) ? 1 : 0);
@@ -101,7 +102,7 @@
     @ApiOperation("淇敼${functionName}")
     @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')")
     @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
-    @RepeatSubmit
+    @RepeatSubmit()
     @PutMapping()
     public AjaxResult<Void> edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) {
         return toAjax(i${ClassName}Service.updateByBo(bo) ? 1 : 0);
diff --git a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
index ec3cac6..32a9ac0 100644
--- a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
+++ b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -1,7 +1,7 @@
 package ${packageName}.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 #if($table.crud || $table.sub)
 import com.ruoyi.common.utils.PageUtils;
 import com.ruoyi.common.core.page.PagePlus;
@@ -61,7 +61,7 @@
 #set($mpMethod=$column.queryType.toLowerCase())
 #if($queryType != 'BETWEEN')
 #if($javaType == 'String')
-#set($condition='StrUtil.isNotBlank(bo.get'+$AttrName+'())')
+#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
 #else
 #set($condition='bo.get'+$AttrName+'() != null')
 #end
diff --git a/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
index f14d914..e97cd24 100644
--- a/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
+++ b/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
@@ -1,9 +1,12 @@
 package ${packageName}.domain.vo;
 
-import com.ruoyi.common.annotation.Excel;
 #foreach ($import in $importList)
 import ${import};
 #end
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -19,6 +22,7 @@
  */
 @Data
 @ApiModel("${functionName}瑙嗗浘瀵硅薄")
+@ExcelIgnoreUnannotated
 public class ${ClassName}Vo {
 
 	private static final long serialVersionUID = 1L;
@@ -40,12 +44,14 @@
 #else
 #set($comment=$column.columnComment)
 #end
-#if($parentheseIndex != -1)
-	@Excel(name = "${comment}" , readConverterExp = "$column.readConverterExp()")
-#elseif($column.javaType == 'Date')
-	@Excel(name = "${comment}" , width = 30, dateFormat = "yyyy-MM-dd")
+#if(${column.dictType} && ${column.dictType} != '')
+    @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "${column.dictType}")
+#elseif($parentheseIndex != -1)
+	@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
 #else
-	@Excel(name = "${comment}")
+	@ExcelProperty(value = "${comment}")
 #end
 	@ApiModelProperty("$column.columnComment")
 	private $column.javaType $column.javaField;
diff --git a/ruoyi-generator/src/main/resources/vm/js/api.js.vm b/ruoyi-generator/src/main/resources/vm/js/api.js.vm
index 296d41a..9295524 100644
--- a/ruoyi-generator/src/main/resources/vm/js/api.js.vm
+++ b/ruoyi-generator/src/main/resources/vm/js/api.js.vm
@@ -42,12 +42,3 @@
     method: 'delete'
   })
 }
-
-// 瀵煎嚭${functionName}
-export function export${BusinessName}(query) {
-  return request({
-    url: '/${moduleName}/${businessName}/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index 1ad93af..ec2f96d 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -253,7 +253,7 @@
 </template>
 
 <script>
-import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
@@ -505,7 +505,9 @@
 		  this.loading = false;
           this.getList();
           this.msgSuccess("鍒犻櫎鎴愬姛");
-        }).catch(() => {});
+      }).finally(() => {
+              this.loading = false;
+      });
     }
   }
 };
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 1fc2bcc..b4349c1 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -108,7 +108,7 @@
           plain
           icon="el-icon-download"
           size="mini"
-		  :loading="exportLoading"
+          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['${moduleName}:${businessName}:export']"
         >瀵煎嚭</el-button>
@@ -307,7 +307,8 @@
 </template>
 
 <script>
-import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "${BusinessName}",
@@ -561,7 +562,9 @@
           this.loading = false;
           this.getList();
           this.msgSuccess("鍒犻櫎鎴愬姛");
-        }).catch(() => {});
+      }).finally(() => {
+          this.loading = false;
+      });
     },
 #if($table.sub)
 	/** ${subTable.functionName}搴忓彿 */
@@ -582,35 +585,23 @@
     /** ${subTable.functionName}鍒犻櫎鎸夐挳鎿嶄綔 */
     handleDelete${subClassName}() {
       if (this.checked${subClassName}.length == 0) {
-        this.$alert("璇峰厛閫夋嫨瑕佸垹闄ょ殑${subTable.functionName}鏁版嵁", "鎻愮ず", { confirmButtonText: "纭畾", });
+        this.msgError("璇峰厛閫夋嫨瑕佸垹闄ょ殑${subTable.functionName}鏁版嵁");
       } else {
-        this.${subclassName}List.splice(this.checked${subClassName}[0].index - 1, 1);
+        const ${subclassName}List = this.${subclassName}List;
+        const checked${subClassName} = this.checked${subClassName};
+        this.${subclassName}List = ${subclassName}List.filter(function(item) {
+          return checked${subClassName}.indexOf(item.index) == -1
+        });
       }
     },
-    /** 鍗曢�夋閫変腑鏁版嵁 */
+    /** 澶嶉�夋閫変腑鏁版嵁 */
     handle${subClassName}SelectionChange(selection) {
-      if (selection.length > 1) {
-        this.$refs.${subclassName}.clearSelection();
-        this.$refs.${subclassName}.toggleRowSelection(selection.pop());
-      } else {
-        this.checked${subClassName} = selection;
-      }
+      this.checked${subClassName} = selection.map(item => item.index)
     },
 #end
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈�${functionName}鏁版嵁椤�?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return export${BusinessName}(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/${moduleName}/${businessName}/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
index d053009..2a128fb 100644
--- a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
+++ b/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -11,4 +11,4 @@
     </resultMap>
 
 
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/ruoyi-oss/pom.xml b/ruoyi-oss/pom.xml
index 6fd1bd7..06cd57f 100644
--- a/ruoyi-oss/pom.xml
+++ b/ruoyi-oss/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -21,10 +21,6 @@
         <dependency>
             <groupId>com.ruoyi</groupId>
             <artifactId>ruoyi-common</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-system</artifactId>
         </dependency>
 
         <dependency>
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/constant/CloudConstant.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/constant/CloudConstant.java
index 5b9da58..ab7c096 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/constant/CloudConstant.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/constant/CloudConstant.java
@@ -1,5 +1,8 @@
 package com.ruoyi.oss.constant;
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * 浜戝瓨鍌ㄥ父閲�
  *
@@ -8,13 +11,28 @@
 public class CloudConstant {
 
 	/**
+	 * OSS妯″潡KEY
+	 */
+	public static final String SYS_OSS_KEY = "sys_oss:";
+
+	/**
 	 * 浜戝瓨鍌ㄩ厤缃甂EY
 	 */
-	public final static String CLOUD_STORAGE_CONFIG_KEY = "sys.oss.cloudStorageService";
+	public static final String CLOUD_STORAGE_CONFIG_KEY = "CloudStorageConfig";
+
+	/**
+	 * 缂撳瓨閰嶇疆KEY
+	 */
+	public static final String CACHE_CONFIG_KEY = SYS_OSS_KEY + CLOUD_STORAGE_CONFIG_KEY;
 
 	/**
 	 * 棰勮鍒楄〃璧勬簮寮�鍏矺ey
 	 */
-	public final static String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource";
+	public static final String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource";
+
+	/**
+	 * 绯荤粺鏁版嵁ids
+	 */
+	public static final List<Integer> SYSTEM_DATA_IDS = Arrays.asList(1, 2, 3, 4);
 
 }
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java
index 3191dc4..11a571c 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java
@@ -1,9 +1,10 @@
 package com.ruoyi.oss.enumd;
 
-import com.ruoyi.oss.service.impl.AliyunCloudStorageServiceImpl;
-import com.ruoyi.oss.service.impl.MinioCloudStorageServiceImpl;
-import com.ruoyi.oss.service.impl.QcloudCloudStorageServiceImpl;
-import com.ruoyi.oss.service.impl.QiniuCloudStorageServiceImpl;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.oss.service.impl.AliyunCloudStorageStrategy;
+import com.ruoyi.oss.service.impl.MinioCloudStorageStrategy;
+import com.ruoyi.oss.service.impl.QcloudCloudStorageStrategy;
+import com.ruoyi.oss.service.impl.QiniuCloudStorageStrategy;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
@@ -19,22 +20,22 @@
 	/**
 	 * 涓冪墰浜�
 	 */
-	QINIU("qiniu", QiniuCloudStorageServiceImpl.class),
+	QINIU("qiniu", QiniuCloudStorageStrategy.class),
 
 	/**
 	 * 闃块噷浜�
 	 */
-	ALIYUN("aliyun", AliyunCloudStorageServiceImpl.class),
+	ALIYUN("aliyun", AliyunCloudStorageStrategy.class),
 
 	/**
 	 * 鑵捐浜�
 	 */
-	QCLOUD("qcloud", QcloudCloudStorageServiceImpl.class),
+	QCLOUD("qcloud", QcloudCloudStorageStrategy.class),
 
 	/**
 	 * minio
 	 */
-	MINIO("minio", MinioCloudStorageServiceImpl.class);
+	MINIO("minio", MinioCloudStorageStrategy.class);
 
 	private final String value;
 
@@ -48,4 +49,15 @@
 		}
 		return null;
 	}
+
+	public static String getServiceName(String value) {
+		for (CloudServiceEnumd clazz : values()) {
+			if (clazz.getValue().equals(value)) {
+				return StringUtils.uncapitalize(clazz.getServiceClass().getSimpleName());
+			}
+		}
+		return null;
+	}
+
+
 }
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java
index bc7e7f3..1290685 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java
@@ -1,12 +1,18 @@
 package com.ruoyi.oss.factory;
 
-import cn.hutool.core.lang.Assert;
+import cn.hutool.core.convert.Convert;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.reflect.ReflectUtils;
 import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.oss.constant.CloudConstant;
 import com.ruoyi.oss.enumd.CloudServiceEnumd;
-import com.ruoyi.oss.service.ICloudStorageService;
-import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.oss.exception.OssException;
+import com.ruoyi.oss.properties.CloudStorageProperties;
+import com.ruoyi.oss.service.ICloudStorageStrategy;
 
+import java.util.Date;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -17,29 +23,55 @@
  */
 public class OssFactory {
 
-    private static ISysConfigService sysConfigService;
+	private static RedisCache redisCache;
 
 	static {
-		OssFactory.sysConfigService = SpringUtils.getBean(ISysConfigService.class);
+		OssFactory.redisCache = SpringUtils.getBean(RedisCache.class);
 	}
 
-	private static final Map<String, ICloudStorageService> SERVICES = new ConcurrentHashMap<>();
+	/**
+	 * 鏈嶅姟瀹炰緥缂撳瓨
+	 */
+	private static final Map<String, ICloudStorageStrategy> SERVICES = new ConcurrentHashMap<>();
 
-	public static ICloudStorageService instance() {
-		String type = sysConfigService.selectConfigByKey(CloudConstant.CLOUD_STORAGE_CONFIG_KEY);
+	/**
+	 * 鏈嶅姟閰嶇疆鏇存柊鏃堕棿缂撳瓨
+	 */
+	private static final Map<String, Date> SERVICES_UPDATE_TIME = new ConcurrentHashMap<>();
+
+	/**
+	 * 鑾峰彇榛樿瀹炰緥
+	 */
+	public static ICloudStorageStrategy instance() {
+		// 鑾峰彇redis 榛樿绫诲瀷
+		String type = Convert.toStr(redisCache.getCacheObject(CloudConstant.CACHE_CONFIG_KEY));
+		if (StringUtils.isEmpty(type)) {
+			throw new OssException("鏂囦欢瀛樺偍鏈嶅姟绫诲瀷鏃犳硶鎵惧埌!");
+		}
 		return instance(type);
 	}
 
-	public static ICloudStorageService instance(String type) {
-		ICloudStorageService service = SERVICES.get(type);
-		if (service == null) {
-			service = (ICloudStorageService) SpringUtils.getBean(CloudServiceEnumd.getServiceClass(type));
+	/**
+	 * 鏍规嵁绫诲瀷鑾峰彇瀹炰緥
+	 */
+	public static ICloudStorageStrategy instance(String type) {
+		ICloudStorageStrategy service = SERVICES.get(type);
+		Date oldDate = SERVICES_UPDATE_TIME.get(type);
+		Object json = redisCache.getCacheObject(CloudConstant.SYS_OSS_KEY + type);
+		CloudStorageProperties properties = JsonUtils.parseObject(json.toString(), CloudStorageProperties.class);
+		if (properties == null) {
+			throw new OssException("绯荤粺寮傚父, '" + type + "'閰嶇疆淇℃伅涓嶅瓨鍦�!");
 		}
+		Date nowDate = properties.getUpdateTime();
+		// 鏈嶅姟瀛樺湪骞舵洿鏂版椂闂寸浉鍚屽垯杩斿洖(浣跨敤鏇存柊鏃堕棿纭繚閰嶇疆鏈�缁堜竴鑷存��)
+		if (service != null && oldDate.equals(nowDate)) {
+			return service;
+		}
+		// 鑾峰彇redis閰嶇疆淇℃伅 鍒涘缓瀵硅薄 骞剁紦瀛�
+		service = (ICloudStorageStrategy) ReflectUtils.newInstance(CloudServiceEnumd.getServiceClass(type), properties);
+		SERVICES.put(type, service);
+		SERVICES_UPDATE_TIME.put(type, nowDate);
 		return service;
 	}
 
-	public static void register(String type, ICloudStorageService iCloudStorageService) {
-		Assert.notNull(type, "type can't be null");
-		SERVICES.put(type, iCloudStorageService);
-	}
 }
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/properties/CloudStorageProperties.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/properties/CloudStorageProperties.java
index 64784a0..1c62ae2 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/properties/CloudStorageProperties.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/properties/CloudStorageProperties.java
@@ -1,9 +1,8 @@
 package com.ruoyi.oss.properties;
 
 import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
+
+import java.util.Date;
 
 /**
  * OSS浜戝瓨鍌� 閰嶇疆灞炴��
@@ -11,177 +10,46 @@
  * @author Lion Li
  */
 @Data
-@Component
-@ConfigurationProperties(prefix = "cloud-storage")
 public class CloudStorageProperties {
 
-	private Boolean previewListImage;
-
-	private QiniuProperties qiniu;
-
-	private AliyunProperties aliyun;
-
-	private QcloudProperties qcloud;
-
-	private MinioProperties minio;
+	/**
+	 * 鍩熷悕
+	 */
+	private String endpoint;
 
 	/**
-	 * 闃块噷浜� 閰嶇疆灞炴��
-	 *
-	 * @author Lion Li
+	 * 鍓嶇紑
 	 */
-	@Data
-	@NoArgsConstructor
-	public static class AliyunProperties {
-
-		/**
-		 * 闃块噷浜戠粦瀹氱殑鍩熷悕
-		 */
-		private String endpoint;
-
-		/**
-		 * 闃块噷浜戣矾寰勫墠缂�
-		 */
-		private String prefix;
-
-		/**
-		 * 闃块噷浜慉ccessKeyId
-		 */
-		private String accessKeyId;
-
-		/**
-		 * 闃块噷浜慉ccessKeySecret
-		 */
-		private String accessKeySecret;
-
-		/**
-		 * 闃块噷浜態ucketName
-		 */
-		private String bucketName;
-
-	}
+	private String prefix;
 
 	/**
-	 * Minio 閰嶇疆灞炴��
-	 *
-	 * @author Lion Li
+	 * ACCESS_KEY
 	 */
-	@Data
-	@NoArgsConstructor
-	public static class MinioProperties {
-
-		/**
-		 * minio鍩熷悕
-		 */
-		private String endpoint;
-
-		/**
-		 * minio ACCESS_KEY
-		 */
-		private String accessKey;
-
-		/**
-		 * minio SECRET_KEY
-		 */
-		private String secretKey;
-
-		/**
-		 * minio 瀛樺偍绌洪棿鍚�
-		 */
-		private String bucketName;
-
-	}
+	private String accessKey;
 
 	/**
-	 * 鑵捐浜慍OS 閰嶇疆灞炴��
-	 *
-	 * @author Lion Li
+	 * SECRET_KEY
 	 */
-	@Data
-	@NoArgsConstructor
-	public static class QcloudProperties {
-
-		/**
-		 * 鑵捐浜戠粦瀹氱殑鍩熷悕
-		 */
-		private String endpoint;
-
-		/**
-		 * 鑵捐浜戣矾寰勫墠缂�
-		 */
-		private String prefix;
-
-		/**
-		 * 鑵捐浜慡ecretId
-		 */
-		private String secretId;
-
-		/**
-		 * 鑵捐浜慡ecretKey
-		 */
-		private String secretKey;
-
-		/**
-		 * 鑵捐浜態ucketName
-		 */
-		private String bucketName;
-
-		/**
-		 * 涓冪墰鏄惁浣跨敤https
-		 */
-		private Boolean isHttps;
-
-		/**
-		 * 鑵捐浜慍OS鎵�灞炲湴鍖�
-		 */
-		private String region;
-
-	}
+	private String secretKey;
 
 	/**
-	 * 涓冪墰浜� 閰嶇疆灞炴��
-	 *
-	 * @author Lion Li
+	 * 瀛樺偍绌洪棿鍚�
 	 */
-	@Data
-	@NoArgsConstructor
-	public static class QiniuProperties {
+	private String bucketName;
 
-		/**
-		 * 涓冪墰缁戝畾鐨勫煙鍚�
-		 */
-		private String domain;
+	/**
+	 * 瀛樺偍鍖哄煙
+	 */
+	private String region;
 
-		/**
-		 * 涓冪墰璺緞鍓嶇紑
-		 */
-		private String prefix;
+	/**
+	 * 鏄惁https锛圷=鏄�,N=鍚︼級
+	 */
+	private String isHttps;
 
-		/**
-		 * 涓冪墰ACCESS_KEY
-		 */
-		private String accessKey;
-
-		/**
-		 * 涓冪墰SECRET_KEY
-		 */
-		private String secretKey;
-
-		/**
-		 * 涓冪墰瀛樺偍绌洪棿鍚�
-		 */
-		private String bucketName;
-
-		/**
-		 * 涓冪墰瀛樺偍鍖哄煙
-		 */
-		private String region;
-
-		/**
-		 * 涓冪墰鏄惁浣跨敤https
-		 */
-		private Boolean isHttps;
-
-	}
+	/**
+	 * 鏇存柊鏃堕棿
+	 */
+	private Date updateTime;
 
 }
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageService.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageStrategy.java
similarity index 93%
rename from ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageService.java
rename to ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageStrategy.java
index a23c1f5..f91fc7a 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageService.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageStrategy.java
@@ -5,11 +5,11 @@
 import java.io.InputStream;
 
 /**
- * 浜戝瓨鍌ㄦ湇鍔℃帴鍙�
+ * 浜戝瓨鍌ㄧ瓥鐣�
  *
  * @author Lion Li
  */
-public interface ICloudStorageService {
+public interface ICloudStorageStrategy {
 
 	void createBucket();
 
@@ -70,5 +70,5 @@
 	 */
 	UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
 
-    String getEndpointLink();
+	String getEndpointLink();
 }
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageService.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageStrategy.java
similarity index 75%
rename from ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageService.java
rename to ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageStrategy.java
index c757ab4..ec4dc37 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageService.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageStrategy.java
@@ -3,20 +3,22 @@
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.oss.entity.UploadResult;
-import com.ruoyi.oss.service.ICloudStorageService;
-import org.springframework.beans.factory.InitializingBean;
+import com.ruoyi.oss.properties.CloudStorageProperties;
+import com.ruoyi.oss.service.ICloudStorageStrategy;
 
 import java.io.InputStream;
 import java.util.Date;
 
 /**
- * 浜戝瓨鍌�(鏀寔涓冪墰銆侀樋閲屼簯銆佽吘璁簯銆乵inio)
+ * 浜戝瓨鍌ㄧ瓥鐣�(鏀寔涓冪墰銆侀樋閲屼簯銆佽吘璁簯銆乵inio)
  *
  * @author Lion Li
  */
-public abstract class AbstractCloudStorageService implements ICloudStorageService, InitializingBean {
+public abstract class AbstractCloudStorageStrategy implements ICloudStorageStrategy {
+
+	protected CloudStorageProperties properties;
 
 	@Override
 	public abstract void createBucket();
@@ -30,7 +32,7 @@
 		String uuid = IdUtil.fastSimpleUUID();
 		// 鏂囦欢璺緞
 		String path = DateUtil.format(new Date(), "yyyyMMdd") + "/" + uuid;
-		if (StrUtil.isNotBlank(prefix)) {
+		if (StringUtils.isNotBlank(prefix)) {
 			path = prefix + "/" + path;
 		}
 		return path + suffix;
@@ -53,9 +55,6 @@
 
 	@Override
 	public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
-
-	@Override
-	public abstract void afterPropertiesSet() throws Exception;
 
 	@Override
 	public abstract String getEndpointLink();
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageServiceImpl.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageStrategy.java
similarity index 73%
rename from ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageServiceImpl.java
rename to ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageStrategy.java
index a4b43ec..11c3476 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageServiceImpl.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageStrategy.java
@@ -1,6 +1,5 @@
 package com.ruoyi.oss.service.impl;
 
-import cn.hutool.core.util.StrUtil;
 import com.aliyun.oss.ClientConfiguration;
 import com.aliyun.oss.OSSClient;
 import com.aliyun.oss.common.auth.DefaultCredentialProvider;
@@ -8,42 +7,32 @@
 import com.aliyun.oss.model.CreateBucketRequest;
 import com.aliyun.oss.model.ObjectMetadata;
 import com.aliyun.oss.model.PutObjectRequest;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.oss.entity.UploadResult;
 import com.ruoyi.oss.enumd.CloudServiceEnumd;
 import com.ruoyi.oss.exception.OssException;
-import com.ruoyi.oss.factory.OssFactory;
 import com.ruoyi.oss.properties.CloudStorageProperties;
-import com.ruoyi.oss.properties.CloudStorageProperties.AliyunProperties;
-import com.ruoyi.oss.service.abstractd.AbstractCloudStorageService;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Service;
+import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
 /**
- * 闃块噷浜戝瓨鍌�
+ * 闃块噷浜戝瓨鍌ㄧ瓥鐣�
  *
  * @author Lion Li
  */
-@Lazy
-@Service
-public class AliyunCloudStorageServiceImpl extends AbstractCloudStorageService implements InitializingBean {
+public class AliyunCloudStorageStrategy extends AbstractCloudStorageStrategy {
 
 	private final OSSClient client;
-	private final AliyunProperties properties;
 
-	@Autowired
-	public AliyunCloudStorageServiceImpl(CloudStorageProperties properties) {
-		this.properties = properties.getAliyun();
+	public AliyunCloudStorageStrategy(CloudStorageProperties cloudStorageProperties) {
+		properties = cloudStorageProperties;
 		try {
 			ClientConfiguration configuration = new ClientConfiguration();
 			DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(
-				this.properties.getAccessKeyId(),
-				this.properties.getAccessKeySecret());
-			client = new OSSClient(this.properties.getEndpoint(), credentialProvider, configuration);
+				properties.getAccessKey(), properties.getSecretKey());
+			client = new OSSClient(properties.getEndpoint(), credentialProvider, configuration);
 			createBucket();
 		} catch (Exception e) {
 			throw new IllegalArgumentException("闃块噷浜戝瓨鍌ㄩ厤缃敊璇�! 璇锋鏌ョ郴缁熼厤缃�!");
@@ -108,17 +97,12 @@
 	}
 
 	@Override
-	public void afterPropertiesSet() throws Exception {
-		OssFactory.register(getServiceType(), this);
-	}
-
-	@Override
 	public String getEndpointLink() {
 		String endpoint = properties.getEndpoint();
 		StringBuilder sb = new StringBuilder(endpoint);
-		if (StrUtil.containsAnyIgnoreCase(endpoint, "http://")) {
+		if (StringUtils.containsAnyIgnoreCase(endpoint, "http://")) {
 			sb.insert(7, properties.getBucketName() + ".");
-		} else if (StrUtil.containsAnyIgnoreCase(endpoint, "https://")) {
+		} else if (StringUtils.containsAnyIgnoreCase(endpoint, "https://")) {
 			sb.insert(8, properties.getBucketName() + ".");
 		} else {
 			throw new OssException("Endpoint閰嶇疆閿欒");
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageServiceImpl.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageStrategy.java
similarity index 83%
rename from ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageServiceImpl.java
rename to ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageStrategy.java
index 70ed684..9edb421 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageServiceImpl.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageStrategy.java
@@ -1,43 +1,33 @@
 package com.ruoyi.oss.service.impl;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.oss.entity.UploadResult;
 import com.ruoyi.oss.enumd.CloudServiceEnumd;
 import com.ruoyi.oss.enumd.PolicyType;
 import com.ruoyi.oss.exception.OssException;
-import com.ruoyi.oss.factory.OssFactory;
 import com.ruoyi.oss.properties.CloudStorageProperties;
-import com.ruoyi.oss.properties.CloudStorageProperties.MinioProperties;
-import com.ruoyi.oss.service.abstractd.AbstractCloudStorageService;
+import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
 import io.minio.*;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.http.MediaType;
-import org.springframework.stereotype.Service;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
 /**
- * minio瀛樺偍
+ * minio瀛樺偍绛栫暐
  *
  * @author Lion Li
  */
-@Lazy
-@Service
-public class MinioCloudStorageServiceImpl extends AbstractCloudStorageService implements InitializingBean {
+public class MinioCloudStorageStrategy extends AbstractCloudStorageStrategy {
 
 	private final MinioClient minioClient;
-	private final MinioProperties properties;
 
-	@Autowired
-	public MinioCloudStorageServiceImpl(CloudStorageProperties properties) {
-		this.properties = properties.getMinio();
+	public MinioCloudStorageStrategy(CloudStorageProperties cloudStorageProperties) {
+		properties = cloudStorageProperties;
 		try {
 			minioClient = MinioClient.builder()
-				.endpoint(this.properties.getEndpoint())
-				.credentials(this.properties.getAccessKey(), this.properties.getSecretKey())
+				.endpoint(properties.getEndpoint())
+				.credentials(properties.getAccessKey(), properties.getSecretKey())
 				.build();
 			createBucket();
 		} catch (Exception e) {
@@ -80,7 +70,7 @@
 			minioClient.putObject(PutObjectArgs.builder()
 				.bucket(properties.getBucketName())
 				.object(path)
-				.contentType(StrUtil.blankToDefault(contentType, MediaType.APPLICATION_OCTET_STREAM_VALUE))
+				.contentType(StringUtils.blankToDefault(contentType, MediaType.APPLICATION_OCTET_STREAM_VALUE))
 				.stream(inputStream, inputStream.available(), -1)
 				.build());
 		} catch (Exception e) {
@@ -110,11 +100,6 @@
 	@Override
 	public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) {
 		return upload(inputStream, getPath("", suffix), contentType);
-	}
-
-	@Override
-	public void afterPropertiesSet() throws Exception {
-		OssFactory.register(getServiceType(), this);
 	}
 
 	@Override
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageServiceImpl.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageStrategy.java
similarity index 74%
rename from ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageServiceImpl.java
rename to ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageStrategy.java
index 35f008a..c30dcbd 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageServiceImpl.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageStrategy.java
@@ -1,6 +1,5 @@
 package com.ruoyi.oss.service.impl;
 
-import cn.hutool.core.util.StrUtil;
 import com.qcloud.cos.COSClient;
 import com.qcloud.cos.ClientConfig;
 import com.qcloud.cos.auth.BasicCOSCredentials;
@@ -8,45 +7,35 @@
 import com.qcloud.cos.http.HttpProtocol;
 import com.qcloud.cos.model.*;
 import com.qcloud.cos.region.Region;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.oss.entity.UploadResult;
 import com.ruoyi.oss.enumd.CloudServiceEnumd;
 import com.ruoyi.oss.exception.OssException;
-import com.ruoyi.oss.factory.OssFactory;
 import com.ruoyi.oss.properties.CloudStorageProperties;
-import com.ruoyi.oss.properties.CloudStorageProperties.QcloudProperties;
-import com.ruoyi.oss.service.abstractd.AbstractCloudStorageService;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Service;
+import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
 /**
- * 鑵捐浜戝瓨鍌�
+ * 鑵捐浜戝瓨鍌ㄧ瓥鐣�
  *
  * @author Lion Li
  */
-@Lazy
-@Service
-public class QcloudCloudStorageServiceImpl extends AbstractCloudStorageService implements InitializingBean {
+public class QcloudCloudStorageStrategy extends AbstractCloudStorageStrategy {
 
 	private final COSClient client;
-	private final QcloudProperties properties;
 
-	@Autowired
-	public QcloudCloudStorageServiceImpl(CloudStorageProperties properties) {
-		this.properties = properties.getQcloud();
+	public QcloudCloudStorageStrategy(CloudStorageProperties cloudStorageProperties) {
+		properties = cloudStorageProperties;
 		try {
 			COSCredentials credentials = new BasicCOSCredentials(
-				this.properties.getSecretId(),
-				this.properties.getSecretKey());
+				properties.getAccessKey(), properties.getSecretKey());
 			// 鍒濆鍖栧鎴风閰嶇疆
 			ClientConfig clientConfig = new ClientConfig();
 			// 璁剧疆bucket鎵�鍦ㄧ殑鍖哄煙锛屽崕鍗楋細gz 鍗庡寳锛歵j 鍗庝笢锛歴h
-			clientConfig.setRegion(new Region(this.properties.getRegion()));
-			if (this.properties.getIsHttps()) {
+			clientConfig.setRegion(new Region(properties.getRegion()));
+			if ("Y".equals(properties.getIsHttps())) {
 				clientConfig.setHttpProtocol(HttpProtocol.https);
 			} else {
 				clientConfig.setHttpProtocol(HttpProtocol.http);
@@ -116,17 +105,12 @@
 	}
 
 	@Override
-	public void afterPropertiesSet() throws Exception {
-		OssFactory.register(getServiceType(),this);
-	}
-
-	@Override
 	public String getEndpointLink() {
 		String endpoint = properties.getEndpoint();
 		StringBuilder sb = new StringBuilder(endpoint);
-		if (StrUtil.containsAnyIgnoreCase(endpoint, "http://")) {
+		if (StringUtils.containsAnyIgnoreCase(endpoint, "http://")) {
 			sb.insert(7, properties.getBucketName() + ".");
-		} else if (StrUtil.containsAnyIgnoreCase(endpoint, "https://")) {
+		} else if (StringUtils.containsAnyIgnoreCase(endpoint, "https://")) {
 			sb.insert(8, properties.getBucketName() + ".");
 		} else {
 			throw new OssException("Endpoint閰嶇疆閿欒");
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageServiceImpl.java b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageStrategy.java
similarity index 70%
rename from ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageServiceImpl.java
rename to ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageStrategy.java
index f7b4d4e..ef22513 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageServiceImpl.java
+++ b/ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageStrategy.java
@@ -10,51 +10,37 @@
 import com.ruoyi.oss.entity.UploadResult;
 import com.ruoyi.oss.enumd.CloudServiceEnumd;
 import com.ruoyi.oss.exception.OssException;
-import com.ruoyi.oss.factory.OssFactory;
 import com.ruoyi.oss.properties.CloudStorageProperties;
-import com.ruoyi.oss.properties.CloudStorageProperties.QiniuProperties;
-import com.ruoyi.oss.service.abstractd.AbstractCloudStorageService;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Service;
+import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
 
 import java.io.InputStream;
 
 /**
- * 涓冪墰浜戝瓨鍌�
+ * 涓冪墰浜戝瓨鍌ㄧ瓥鐣�
  *
  * @author Lion Li
  */
-@Lazy
-@Service
-public class QiniuCloudStorageServiceImpl extends AbstractCloudStorageService implements InitializingBean {
+public class QiniuCloudStorageStrategy extends AbstractCloudStorageStrategy {
 
 	private final UploadManager uploadManager;
 	private final BucketManager bucketManager;
 	private final String token;
-	private final QiniuProperties properties;
 
-	@Autowired
-	public QiniuCloudStorageServiceImpl(CloudStorageProperties properties) {
-		this.properties = properties.getQiniu();
+	public QiniuCloudStorageStrategy(CloudStorageProperties cloudStorageProperties) {
+		properties = cloudStorageProperties;
 		try {
-			Configuration config = new Configuration(getRegion(this.properties.getRegion()));
+			Configuration config = new Configuration(getRegion(properties.getRegion()));
 			// https璁剧疆
 			config.useHttpsDomains = false;
-			if (this.properties.getIsHttps() != null) {
-				config.useHttpsDomains = this.properties.getIsHttps();
-			}
+			config.useHttpsDomains = "Y".equals(properties.getIsHttps());
 			uploadManager = new UploadManager(config);
-			Auth auth = Auth.create(
-				this.properties.getAccessKey(),
-				this.properties.getSecretKey());
-			String bucketName = this.properties.getBucketName();
+			Auth auth = Auth.create(properties.getAccessKey(), properties.getSecretKey());
+			String bucketName = properties.getBucketName();
 			token = auth.uploadToken(bucketName);
 			bucketManager = new BucketManager(auth, config);
 
 			if (!ArrayUtil.contains(bucketManager.buckets(), bucketName)) {
-				bucketManager.createBucket(bucketName, this.properties.getRegion());
+				bucketManager.createBucket(bucketName, properties.getRegion());
 			}
 		} catch (Exception e) {
 			throw new IllegalArgumentException("涓冪墰浜戝瓨鍌ㄩ厤缃敊璇�! 璇锋鏌ョ郴缁熼厤缃�!");
@@ -116,13 +102,8 @@
 	}
 
 	@Override
-	public void afterPropertiesSet() throws Exception {
-		OssFactory.register(getServiceType(),this);
-	}
-
-	@Override
 	public String getEndpointLink() {
-		return properties.getDomain();
+		return properties.getEndpoint();
 	}
 
 	private Region getRegion(String region) {
diff --git a/ruoyi-quartz/pom.xml b/ruoyi-quartz/pom.xml
index ef70d32..1d0e309 100644
--- a/ruoyi-quartz/pom.xml
+++ b/ruoyi-quartz/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
index 2725cd8..6ceb7ba 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
@@ -1,6 +1,5 @@
 package com.ruoyi.quartz.controller;
 
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.controller.BaseController;
@@ -8,7 +7,7 @@
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.exception.job.TaskException;
-import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.quartz.domain.SysJob;
 import com.ruoyi.quartz.service.ISysJobService;
@@ -18,6 +17,7 @@
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 /**
@@ -48,11 +48,10 @@
     @PreAuthorize("@ss.hasPermi('monitor:job:export')")
     @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(SysJob sysJob)
+    public void export(SysJob sysJob, HttpServletResponse response)
     {
         List<SysJob> list = jobService.selectJobList(sysJob);
-        ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
-        return util.exportExcel(list, "瀹氭椂浠诲姟");
+		ExcelUtil.exportExcel(list, "瀹氭椂浠诲姟", SysJob.class, response);
     }
 
     /**
@@ -71,18 +70,22 @@
     @PreAuthorize("@ss.hasPermi('monitor:job:add')")
     @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody SysJob sysJob) throws SchedulerException, TaskException
+    public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
     {
-        if (!CronUtils.isValid(sysJob.getCronExpression()))
+        if (!CronUtils.isValid(job.getCronExpression()))
         {
-            return AjaxResult.error("鏂板浠诲姟'" + sysJob.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
         }
-        else if (StrUtil.containsIgnoreCase(sysJob.getInvokeTarget(), Constants.LOOKUP_RMI))
+        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
         {
-            return AjaxResult.error("鏂板浠诲姟'" + sysJob.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi://'璋冪敤");
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi://'璋冪敤");
         }
-        sysJob.setCreateBy(SecurityUtils.getUsername());
-        return toAjax(jobService.insertJob(sysJob));
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+        {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'http(s)//'璋冪敤");
+        }
+        job.setCreateBy(getUsername());
+        return toAjax(jobService.insertJob(job));
     }
 
     /**
@@ -91,18 +94,22 @@
     @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
     @Log(title = "瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody SysJob sysJob) throws SchedulerException, TaskException
+    public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
     {
-        if (!CronUtils.isValid(sysJob.getCronExpression()))
+        if (!CronUtils.isValid(job.getCronExpression()))
         {
-            return AjaxResult.error("淇敼浠诲姟'" + sysJob.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
         }
-        else if (StrUtil.containsIgnoreCase(sysJob.getInvokeTarget(), Constants.LOOKUP_RMI))
+        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
         {
-            return AjaxResult.error("淇敼浠诲姟'" + sysJob.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi://'璋冪敤");
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'rmi://'璋冪敤");
         }
-        sysJob.setUpdateBy(SecurityUtils.getUsername());
-        return toAjax(jobService.updateJob(sysJob));
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+        {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛岀洰鏍囧瓧绗︿覆涓嶅厑璁�'http(s)//'璋冪敤");
+        }
+        job.setUpdateBy(getUsername());
+        return toAjax(jobService.updateJob(job));
     }
 
     /**
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
index e7cb9f0..6fcba39 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
@@ -1,85 +1,85 @@
-package com.ruoyi.quartz.controller;
-
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.quartz.domain.SysJobLog;
-import com.ruoyi.quartz.service.ISysJobLogService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * 璋冨害鏃ュ織鎿嶄綔澶勭悊
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/jobLog")
-public class SysJobLogController extends BaseController
-{
-    @Autowired
-    private ISysJobLogService jobLogService;
-
-    /**
-     * 鏌ヨ瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysJobLog sysJobLog)
-    {
-        return jobLogService.selectPageJobLogList(sysJobLog);
-    }
-
-    /**
-     * 瀵煎嚭瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
-    @Log(title = "浠诲姟璋冨害鏃ュ織", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(SysJobLog sysJobLog)
-    {
-        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
-        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
-        return util.exportExcel(list, "璋冨害鏃ュ織");
-    }
-    
-    /**
-     * 鏍规嵁璋冨害缂栧彿鑾峰彇璇︾粏淇℃伅
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
-    @GetMapping(value = "/{configId}")
-    public AjaxResult getInfo(@PathVariable Long jobLogId)
-    {
-        return AjaxResult.success(jobLogService.selectJobLogById(jobLogId));
-    }
-
-
-    /**
-     * 鍒犻櫎瀹氭椂浠诲姟璋冨害鏃ュ織
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "瀹氭椂浠诲姟璋冨害鏃ュ織", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{jobLogIds}")
-    public AjaxResult remove(@PathVariable Long[] jobLogIds)
-    {
-        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
-    }
-
-    /**
-     * 娓呯┖瀹氭椂浠诲姟璋冨害鏃ュ織
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "璋冨害鏃ュ織", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/clean")
-    public AjaxResult clean()
-    {
-        jobLogService.cleanJobLog();
-        return AjaxResult.success();
-    }
-}
+package com.ruoyi.quartz.controller;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.quartz.domain.SysJobLog;
+import com.ruoyi.quartz.service.ISysJobLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 璋冨害鏃ュ織鎿嶄綔澶勭悊
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/jobLog")
+public class SysJobLogController extends BaseController
+{
+    @Autowired
+    private ISysJobLogService jobLogService;
+
+    /**
+     * 鏌ヨ瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJobLog sysJobLog)
+    {
+        return jobLogService.selectPageJobLogList(sysJobLog);
+    }
+
+    /**
+     * 瀵煎嚭瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "浠诲姟璋冨害鏃ュ織", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public void export(SysJobLog sysJobLog, HttpServletResponse response)
+    {
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+		ExcelUtil.exportExcel(list, "璋冨害鏃ュ織", SysJobLog.class, response);
+    }
+
+    /**
+     * 鏍规嵁璋冨害缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable Long jobLogId)
+    {
+        return AjaxResult.success(jobLogService.selectJobLogById(jobLogId));
+    }
+
+
+    /**
+     * 鍒犻櫎瀹氭椂浠诲姟璋冨害鏃ュ織
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "瀹氭椂浠诲姟璋冨害鏃ュ織", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobLogIds}")
+    public AjaxResult remove(@PathVariable Long[] jobLogIds)
+    {
+        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
+    }
+
+    /**
+     * 娓呯┖瀹氭椂浠诲姟璋冨害鏃ュ織
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "璋冨害鏃ュ織", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        jobLogService.cleanJobLog();
+        return AjaxResult.success();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
index b1c8941..416dced 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
@@ -1,11 +1,13 @@
 package com.ruoyi.quartz.domain;
 
-import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
 import com.ruoyi.common.constant.ScheduleConstants;
+import com.ruoyi.common.convert.ExcelDictConvert;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.quartz.util.CronUtils;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -28,13 +30,14 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_job")
+@ExcelIgnoreUnannotated
 public class SysJob implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
      * 浠诲姟ID
      */
-    @Excel(name = "浠诲姟搴忓彿", cellType = ColumnType.NUMERIC)
+    @ExcelProperty(value = "浠诲姟搴忓彿")
     @TableId(value = "job_id", type = IdType.AUTO)
     private Long jobId;
 
@@ -43,13 +46,14 @@
      */
     @NotBlank(message = "浠诲姟鍚嶇О涓嶈兘涓虹┖")
     @Size(min = 0, max = 64, message = "浠诲姟鍚嶇О涓嶈兘瓒呰繃64涓瓧绗�")
-    @Excel(name = "浠诲姟鍚嶇О")
+    @ExcelProperty(value = "浠诲姟鍚嶇О")
     private String jobName;
 
     /**
      * 浠诲姟缁勫悕
      */
-    @Excel(name = "浠诲姟缁勫悕")
+	@ExcelProperty(value = "浠诲姟缁勫悕", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_job_group")
     private String jobGroup;
 
     /**
@@ -57,7 +61,7 @@
      */
     @NotBlank(message = "璋冪敤鐩爣瀛楃涓蹭笉鑳戒负绌�")
     @Size(min = 0, max = 500, message = "璋冪敤鐩爣瀛楃涓查暱搴︿笉鑳借秴杩�500涓瓧绗�")
-    @Excel(name = "璋冪敤鐩爣瀛楃涓�")
+    @ExcelProperty(value = "璋冪敤鐩爣瀛楃涓�")
     private String invokeTarget;
 
     /**
@@ -65,25 +69,28 @@
      */
     @NotBlank(message = "Cron鎵ц琛ㄨ揪寮忎笉鑳戒负绌�")
     @Size(min = 0, max = 255, message = "Cron鎵ц琛ㄨ揪寮忎笉鑳借秴杩�255涓瓧绗�")
-    @Excel(name = "鎵ц琛ㄨ揪寮� ")
+    @ExcelProperty(value = "鎵ц琛ㄨ揪寮�")
     private String cronExpression;
 
     /**
      * cron璁″垝绛栫暐
      */
-    @Excel(name = "璁″垝绛栫暐 ", readConverterExp = "0=榛樿,1=绔嬪嵆瑙﹀彂鎵ц,2=瑙﹀彂涓�娆℃墽琛�,3=涓嶈Е鍙戠珛鍗虫墽琛�")
-    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
+    @ExcelProperty(value = "璁″垝绛栫暐 ", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=榛樿,1=绔嬪嵆瑙﹀彂鎵ц,2=瑙﹀彂涓�娆℃墽琛�,3=涓嶈Е鍙戠珛鍗虫墽琛�")
+	private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
 
     /**
      * 鏄惁骞跺彂鎵ц锛�0鍏佽 1绂佹锛�
      */
-    @Excel(name = "骞跺彂鎵ц", readConverterExp = "0=鍏佽,1=绂佹")
+    @ExcelProperty(value = "骞跺彂鎵ц", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(readConverterExp = "0=鍏佽,1=绂佹")
     private String concurrent;
 
     /**
      * 浠诲姟鐘舵�侊紙0姝e父 1鏆傚仠锛�
      */
-    @Excel(name = "浠诲姟鐘舵��", readConverterExp = "0=姝e父,1=鏆傚仠")
+    @ExcelProperty(value = "浠诲姟鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_job_status")
     private String status;
 
     /**
@@ -96,7 +103,6 @@
      * 鍒涘缓鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
 
     /**
@@ -109,7 +115,6 @@
      * 鏇存柊鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
 
     /**
@@ -125,7 +130,7 @@
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     public Date getNextValidTime() {
-        if (StrUtil.isNotEmpty(cronExpression)) {
+        if (StringUtils.isNotEmpty(cronExpression)) {
             return CronUtils.getNextExecution(cronExpression);
         }
         return null;
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
index b315c56..bc9074a 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
@@ -1,78 +1,82 @@
-package com.ruoyi.quartz.domain;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 瀹氭椂浠诲姟璋冨害鏃ュ織琛� sys_job_log
- * 
- * @author ruoyi
- */
-
-@Data
-@NoArgsConstructor
-@Accessors(chain = true)
-@TableName("sys_job_log")
-public class SysJobLog
-{
-    private static final long serialVersionUID = 1L;
-
-    /** ID */
-    @Excel(name = "鏃ュ織搴忓彿")
-    @TableId(value = "job_log_id", type = IdType.AUTO)
-    private Long jobLogId;
-
-    /** 浠诲姟鍚嶇О */
-    @Excel(name = "浠诲姟鍚嶇О")
-    private String jobName;
-
-    /** 浠诲姟缁勫悕 */
-    @Excel(name = "浠诲姟缁勫悕")
-    private String jobGroup;
-
-    /** 璋冪敤鐩爣瀛楃涓� */
-    @Excel(name = "璋冪敤鐩爣瀛楃涓�")
-    private String invokeTarget;
-
-    /** 鏃ュ織淇℃伅 */
-    @Excel(name = "鏃ュ織淇℃伅")
-    private String jobMessage;
-
-    /** 鎵ц鐘舵�侊紙0姝e父 1澶辫触锛� */
-    @Excel(name = "鎵ц鐘舵��", readConverterExp = "0=姝e父,1=澶辫触")
-    private String status;
-
-    /** 寮傚父淇℃伅 */
-    @Excel(name = "寮傚父淇℃伅")
-    private String exceptionInfo;
-
-    /**
-     * 鍒涘缓鏃堕棿
-     */
-    @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date createTime;
-
-    /**
-     * 璇锋眰鍙傛暟
-     */
-    @TableField(exist = false)
-    private Map<String, Object> params = new HashMap<>();
-
-    /** 寮�濮嬫椂闂� */
-    @TableField(exist = false)
-    private Date startTime;
-
-    /** 鍋滄鏃堕棿 */
-    @TableField(exist = false)
-    private Date stopTime;
-
-}
+package com.ruoyi.quartz.domain;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.baomidou.mybatisplus.annotation.*;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 瀹氭椂浠诲姟璋冨害鏃ュ織琛� sys_job_log
+ *
+ * @author ruoyi
+ */
+
+@Data
+@NoArgsConstructor
+@Accessors(chain = true)
+@TableName("sys_job_log")
+@ExcelIgnoreUnannotated
+public class SysJobLog
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    @ExcelProperty(value = "鏃ュ織搴忓彿")
+    @TableId(value = "job_log_id", type = IdType.AUTO)
+    private Long jobLogId;
+
+    /** 浠诲姟鍚嶇О */
+    @ExcelProperty(value = "浠诲姟鍚嶇О")
+    private String jobName;
+
+    /** 浠诲姟缁勫悕 */
+    @ExcelProperty(value = "浠诲姟缁勫悕", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_job_group")
+    private String jobGroup;
+
+    /** 璋冪敤鐩爣瀛楃涓� */
+    @ExcelProperty(value = "璋冪敤鐩爣瀛楃涓�")
+    private String invokeTarget;
+
+    /** 鏃ュ織淇℃伅 */
+    @ExcelProperty(value = "鏃ュ織淇℃伅")
+    private String jobMessage;
+
+    /** 鎵ц鐘舵�侊紙0姝e父 1澶辫触锛� */
+    @ExcelProperty(value = "鎵ц鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
+    private String status;
+
+    /** 寮傚父淇℃伅 */
+    @ExcelProperty(value = "寮傚父淇℃伅")
+    private String exceptionInfo;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    @TableField(exist = false)
+    private Map<String, Object> params = new HashMap<>();
+
+    /** 寮�濮嬫椂闂� */
+    @TableField(exist = false)
+    private Date startTime;
+
+    /** 鍋滄鏃堕棿 */
+    @TableField(exist = false)
+    private Date stopTime;
+
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
index f9f58b6..3ee544c 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
@@ -1,7 +1,6 @@
 package com.ruoyi.quartz.service.impl;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
@@ -27,14 +26,14 @@
     public TableDataInfo<SysJobLog> selectPageJobLogList(SysJobLog jobLog) {
         Map<String, Object> params = jobLog.getParams();
         LambdaQueryWrapper<SysJobLog> lqw = new LambdaQueryWrapper<SysJobLog>()
-                .like(StrUtil.isNotBlank(jobLog.getJobName()), SysJobLog::getJobName, jobLog.getJobName())
-                .eq(StrUtil.isNotBlank(jobLog.getJobGroup()), SysJobLog::getJobGroup, jobLog.getJobGroup())
-                .eq(StrUtil.isNotBlank(jobLog.getStatus()), SysJobLog::getStatus, jobLog.getStatus())
-                .like(StrUtil.isNotBlank(jobLog.getInvokeTarget()), SysJobLog::getInvokeTarget, jobLog.getInvokeTarget())
-                .apply(Validator.isNotEmpty(params.get("beginTime")),
+                .like(StringUtils.isNotBlank(jobLog.getJobName()), SysJobLog::getJobName, jobLog.getJobName())
+                .eq(StringUtils.isNotBlank(jobLog.getJobGroup()), SysJobLog::getJobGroup, jobLog.getJobGroup())
+                .eq(StringUtils.isNotBlank(jobLog.getStatus()), SysJobLog::getStatus, jobLog.getStatus())
+                .like(StringUtils.isNotBlank(jobLog.getInvokeTarget()), SysJobLog::getInvokeTarget, jobLog.getInvokeTarget())
+                .apply(StringUtils.isNotEmpty(params.get("beginTime")),
                         "date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')",
                         params.get("beginTime"))
-                .apply(Validator.isNotEmpty(params.get("endTime")),
+                .apply(StringUtils.isNotEmpty(params.get("endTime")),
                         "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                         params.get("endTime"));
         return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
@@ -50,14 +49,14 @@
     public List<SysJobLog> selectJobLogList(SysJobLog jobLog) {
         Map<String, Object> params = jobLog.getParams();
         return list(new LambdaQueryWrapper<SysJobLog>()
-                .like(StrUtil.isNotBlank(jobLog.getJobName()), SysJobLog::getJobName, jobLog.getJobName())
-                .eq(StrUtil.isNotBlank(jobLog.getJobGroup()), SysJobLog::getJobGroup, jobLog.getJobGroup())
-                .eq(StrUtil.isNotBlank(jobLog.getStatus()), SysJobLog::getStatus, jobLog.getStatus())
-                .like(StrUtil.isNotBlank(jobLog.getInvokeTarget()), SysJobLog::getInvokeTarget, jobLog.getInvokeTarget())
-                .apply(Validator.isNotEmpty(params.get("beginTime")),
+                .like(StringUtils.isNotBlank(jobLog.getJobName()), SysJobLog::getJobName, jobLog.getJobName())
+                .eq(StringUtils.isNotBlank(jobLog.getJobGroup()), SysJobLog::getJobGroup, jobLog.getJobGroup())
+                .eq(StringUtils.isNotBlank(jobLog.getStatus()), SysJobLog::getStatus, jobLog.getStatus())
+                .like(StringUtils.isNotBlank(jobLog.getInvokeTarget()), SysJobLog::getInvokeTarget, jobLog.getInvokeTarget())
+                .apply(StringUtils.isNotEmpty(params.get("beginTime")),
                         "date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')",
                         params.get("beginTime"))
-                .apply(Validator.isNotEmpty(params.get("endTime")),
+                .apply(StringUtils.isNotEmpty(params.get("endTime")),
                         "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                         params.get("endTime")));
     }
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
index b8ec256..835f975 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
@@ -1,6 +1,6 @@
 package com.ruoyi.quartz.service.impl;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.constant.ScheduleConstants;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
@@ -48,10 +48,10 @@
     @Override
     public TableDataInfo<SysJob> selectPageJobList(SysJob job) {
         LambdaQueryWrapper<SysJob> lqw = new LambdaQueryWrapper<SysJob>()
-                .like(StrUtil.isNotBlank(job.getJobName()), SysJob::getJobName, job.getJobName())
-                .eq(StrUtil.isNotBlank(job.getJobGroup()), SysJob::getJobGroup, job.getJobGroup())
-                .eq(StrUtil.isNotBlank(job.getStatus()), SysJob::getStatus, job.getStatus())
-                .like(StrUtil.isNotBlank(job.getInvokeTarget()), SysJob::getInvokeTarget, job.getInvokeTarget());
+                .like(StringUtils.isNotBlank(job.getJobName()), SysJob::getJobName, job.getJobName())
+                .eq(StringUtils.isNotBlank(job.getJobGroup()), SysJob::getJobGroup, job.getJobGroup())
+                .eq(StringUtils.isNotBlank(job.getStatus()), SysJob::getStatus, job.getStatus())
+                .like(StringUtils.isNotBlank(job.getInvokeTarget()), SysJob::getInvokeTarget, job.getInvokeTarget());
         return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
     }
 
@@ -64,10 +64,10 @@
     @Override
     public List<SysJob> selectJobList(SysJob job) {
         return list(new LambdaQueryWrapper<SysJob>()
-                .like(StrUtil.isNotBlank(job.getJobName()), SysJob::getJobName, job.getJobName())
-                .eq(StrUtil.isNotBlank(job.getJobGroup()), SysJob::getJobGroup, job.getJobGroup())
-                .eq(StrUtil.isNotBlank(job.getStatus()), SysJob::getStatus, job.getStatus())
-                .like(StrUtil.isNotBlank(job.getInvokeTarget()), SysJob::getInvokeTarget, job.getInvokeTarget()));
+                .like(StringUtils.isNotBlank(job.getJobName()), SysJob::getJobName, job.getJobName())
+                .eq(StringUtils.isNotBlank(job.getJobGroup()), SysJob::getJobGroup, job.getJobGroup())
+                .eq(StringUtils.isNotBlank(job.getStatus()), SysJob::getStatus, job.getStatus())
+                .like(StringUtils.isNotBlank(job.getInvokeTarget()), SysJob::getInvokeTarget, job.getInvokeTarget()));
     }
 
     /**
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
index 7f88a58..e5bfcb7 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -1,29 +1,29 @@
-package com.ruoyi.quartz.task;
-
-import cn.hutool.core.lang.Console;
-import cn.hutool.core.util.StrUtil;
-import org.springframework.stereotype.Component;
-
-/**
- * 瀹氭椂浠诲姟璋冨害娴嬭瘯
- * 
- * @author ruoyi
- */
-@Component("ryTask")
-public class RyTask
-{
-    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
-    {
-        Console.log(StrUtil.format("鎵ц澶氬弬鏂规硶锛� 瀛楃涓茬被鍨媨}锛屽竷灏旂被鍨媨}锛岄暱鏁村瀷{}锛屾诞鐐瑰瀷{}锛屾暣褰}", s, b, l, d, i));
-    }
-
-    public void ryParams(String params)
-    {
-        Console.log("鎵ц鏈夊弬鏂规硶锛�" + params);
-    }
-
-    public void ryNoParams()
-    {
-        Console.log("鎵ц鏃犲弬鏂规硶");
-    }
-}
+package com.ruoyi.quartz.task;
+
+import cn.hutool.core.lang.Console;
+import com.ruoyi.common.utils.StringUtils;
+import org.springframework.stereotype.Component;
+
+/**
+ * 瀹氭椂浠诲姟璋冨害娴嬭瘯
+ *
+ * @author ruoyi
+ */
+@Component("ryTask")
+public class RyTask
+{
+    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
+    {
+        Console.log(StringUtils.format("鎵ц澶氬弬鏂规硶锛� 瀛楃涓茬被鍨媨}锛屽竷灏旂被鍨媨}锛岄暱鏁村瀷{}锛屾诞鐐瑰瀷{}锛屾暣褰}", s, b, l, d, i));
+    }
+
+    public void ryParams(String params)
+    {
+        Console.log("鎵ц鏈夊弬鏂规硶锛�" + params);
+    }
+
+    public void ryNoParams()
+    {
+        Console.log("鎵ц鏃犲弬鏂规硶");
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
index ed4584e..95437a8 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
@@ -1,109 +1,108 @@
-package com.ruoyi.quartz.util;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.ScheduleConstants;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.quartz.domain.SysJob;
-import com.ruoyi.quartz.domain.SysJobLog;
-import com.ruoyi.quartz.service.ISysJobLogService;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Date;
-
-/**
- * 鎶借薄quartz璋冪敤
- *
- * @author ruoyi
- */
-public abstract class AbstractQuartzJob implements Job
-{
-    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
-
-    /**
-     * 绾跨▼鏈湴鍙橀噺
-     */
-    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
-
-    @Override
-    public void execute(JobExecutionContext context) throws JobExecutionException
-    {
-        SysJob sysJob = new SysJob();
-        BeanUtil.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob);
-        try
-        {
-            before(context, sysJob);
-            if (Validator.isNotNull(sysJob))
-            {
-                doExecute(context, sysJob);
-            }
-            after(context, sysJob, null);
-        }
-        catch (Exception e)
-        {
-            log.error("浠诲姟鎵ц寮傚父  - 锛�", e);
-            after(context, sysJob, e);
-        }
-    }
-
-    /**
-     * 鎵ц鍓�
-     *
-     * @param context 宸ヤ綔鎵ц涓婁笅鏂囧璞�
-     * @param sysJob 绯荤粺璁″垝浠诲姟
-     */
-    protected void before(JobExecutionContext context, SysJob sysJob)
-    {
-        threadLocal.set(new Date());
-    }
-
-    /**
-     * 鎵ц鍚�
-     *
-     * @param context 宸ヤ綔鎵ц涓婁笅鏂囧璞�
-     * @param sysJob 绯荤粺璁″垝浠诲姟
-     */
-    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
-    {
-        Date startTime = threadLocal.get();
-        threadLocal.remove();
-
-        final SysJobLog sysJobLog = new SysJobLog();
-        sysJobLog.setJobName(sysJob.getJobName());
-        sysJobLog.setJobGroup(sysJob.getJobGroup());
-        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
-        sysJobLog.setStartTime(startTime);
-        sysJobLog.setStopTime(new Date());
-        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
-        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 鎬诲叡鑰楁椂锛�" + runMs + "姣");
-        if (e != null)
-        {
-            sysJobLog.setStatus(Constants.FAIL);
-            String errorMsg = StrUtil.sub(ExceptionUtil.stacktraceToString(e), 0, 2000);
-            sysJobLog.setExceptionInfo(errorMsg);
-        }
-        else
-        {
-            sysJobLog.setStatus(Constants.SUCCESS);
-        }
-
-        // 鍐欏叆鏁版嵁搴撳綋涓�
-        SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
-    }
-
-    /**
-     * 鎵ц鏂规硶锛岀敱瀛愮被閲嶈浇
-     *
-     * @param context 宸ヤ綔鎵ц涓婁笅鏂囧璞�
-     * @param sysJob 绯荤粺璁″垝浠诲姟
-     * @throws Exception 鎵ц杩囩▼涓殑寮傚父
-     */
-    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
-}
+package com.ruoyi.quartz.util;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.exceptions.ExceptionUtil;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.constant.ScheduleConstants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.quartz.domain.SysJob;
+import com.ruoyi.quartz.domain.SysJobLog;
+import com.ruoyi.quartz.service.ISysJobLogService;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+/**
+ * 鎶借薄quartz璋冪敤
+ *
+ * @author ruoyi
+ */
+public abstract class AbstractQuartzJob implements Job
+{
+    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
+
+    /**
+     * 绾跨▼鏈湴鍙橀噺
+     */
+    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
+
+    @Override
+    public void execute(JobExecutionContext context) throws JobExecutionException
+    {
+        SysJob sysJob = new SysJob();
+        BeanUtil.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob);
+        try
+        {
+            before(context, sysJob);
+            if (StringUtils.isNotNull(sysJob))
+            {
+                doExecute(context, sysJob);
+            }
+            after(context, sysJob, null);
+        }
+        catch (Exception e)
+        {
+            log.error("浠诲姟鎵ц寮傚父  - 锛�", e);
+            after(context, sysJob, e);
+        }
+    }
+
+    /**
+     * 鎵ц鍓�
+     *
+     * @param context 宸ヤ綔鎵ц涓婁笅鏂囧璞�
+     * @param sysJob 绯荤粺璁″垝浠诲姟
+     */
+    protected void before(JobExecutionContext context, SysJob sysJob)
+    {
+        threadLocal.set(new Date());
+    }
+
+    /**
+     * 鎵ц鍚�
+     *
+     * @param context 宸ヤ綔鎵ц涓婁笅鏂囧璞�
+     * @param sysJob 绯荤粺璁″垝浠诲姟
+     */
+    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
+    {
+        Date startTime = threadLocal.get();
+        threadLocal.remove();
+
+        final SysJobLog sysJobLog = new SysJobLog();
+        sysJobLog.setJobName(sysJob.getJobName());
+        sysJobLog.setJobGroup(sysJob.getJobGroup());
+        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+        sysJobLog.setStartTime(startTime);
+        sysJobLog.setStopTime(new Date());
+        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
+        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 鎬诲叡鑰楁椂锛�" + runMs + "姣");
+        if (e != null)
+        {
+            sysJobLog.setStatus(Constants.FAIL);
+            String errorMsg = StringUtils.substring(ExceptionUtil.stacktraceToString(e), 0, 2000);
+            sysJobLog.setExceptionInfo(errorMsg);
+        }
+        else
+        {
+            sysJobLog.setStatus(Constants.SUCCESS);
+        }
+
+        // 鍐欏叆鏁版嵁搴撳綋涓�
+        SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
+    }
+
+    /**
+     * 鎵ц鏂规硶锛岀敱瀛愮被閲嶈浇
+     *
+     * @param context 宸ヤ綔鎵ц涓婁笅鏂囧璞�
+     * @param sysJob 绯荤粺璁″垝浠诲姟
+     * @throws Exception 鎵ц杩囩▼涓殑寮傚父
+     */
+    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
index f017e1b..ba55d2d 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
@@ -1,184 +1,183 @@
-package com.ruoyi.quartz.util;
-
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.quartz.domain.SysJob;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * 浠诲姟鎵ц宸ュ叿
- *
- * @author ruoyi
- */
-public class JobInvokeUtil
-{
-    /**
-     * 鎵ц鏂规硶
-     *
-     * @param sysJob 绯荤粺浠诲姟
-     */
-    public static void invokeMethod(SysJob sysJob) throws Exception
-    {
-        String invokeTarget = sysJob.getInvokeTarget();
-        String beanName = getBeanName(invokeTarget);
-        String methodName = getMethodName(invokeTarget);
-        List<Object[]> methodParams = getMethodParams(invokeTarget);
-
-        if (!isValidClassName(beanName))
-        {
-            Object bean = SpringUtils.getBean(beanName);
-            invokeMethod(bean, methodName, methodParams);
-        }
-        else
-        {
-            Object bean = Class.forName(beanName).newInstance();
-            invokeMethod(bean, methodName, methodParams);
-        }
-    }
-
-    /**
-     * 璋冪敤浠诲姟鏂规硶
-     *
-     * @param bean 鐩爣瀵硅薄
-     * @param methodName 鏂规硶鍚嶇О
-     * @param methodParams 鏂规硶鍙傛暟
-     */
-    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
-            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
-            InvocationTargetException
-    {
-        if (Validator.isNotNull(methodParams) && methodParams.size() > 0)
-        {
-            Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));
-            method.invoke(bean, getMethodParamsValue(methodParams));
-        }
-        else
-        {
-            Method method = bean.getClass().getDeclaredMethod(methodName);
-            method.invoke(bean);
-        }
-    }
-
-    /**
-     * 鏍¢獙鏄惁涓轰负class鍖呭悕
-     * 
-     * @param str 鍚嶇О
-     * @return true鏄� false鍚�
-     */
-    public static boolean isValidClassName(String invokeTarget)
-    {
-        return StrUtil.count(invokeTarget, ".") > 1;
-    }
-
-    /**
-     * 鑾峰彇bean鍚嶇О
-     * 
-     * @param invokeTarget 鐩爣瀛楃涓�
-     * @return bean鍚嶇О
-     */
-    public static String getBeanName(String invokeTarget)
-    {
-        String beanName = StrUtil.subBefore(invokeTarget, "(",false);
-        return StrUtil.subBefore(beanName, ".",true);
-    }
-
-    /**
-     * 鑾峰彇bean鏂规硶
-     * 
-     * @param invokeTarget 鐩爣瀛楃涓�
-     * @return method鏂规硶
-     */
-    public static String getMethodName(String invokeTarget)
-    {
-        String methodName = StrUtil.subBefore(invokeTarget, "(",false);
-        return StrUtil.subAfter(methodName, ".",true);
-    }
-
-    /**
-     * 鑾峰彇method鏂规硶鍙傛暟鐩稿叧鍒楄〃
-     * 
-     * @param invokeTarget 鐩爣瀛楃涓�
-     * @return method鏂规硶鐩稿叧鍙傛暟鍒楄〃
-     */
-    public static List<Object[]> getMethodParams(String invokeTarget)
-    {
-        String methodStr = StrUtil.subBetween(invokeTarget, "(", ")");
-        if (StrUtil.isEmpty(methodStr))
-        {
-            return null;
-        }
-        String[] methodParams = methodStr.split(",");
-        List<Object[]> classs = new LinkedList<>();
-        for (int i = 0; i < methodParams.length; i++)
-        {
-            String str = StrUtil.trimToEmpty(methodParams[i]);
-            // String瀛楃涓茬被鍨嬶紝鍖呭惈'
-            if (StrUtil.contains(str, "'"))
-            {
-                classs.add(new Object[] { StrUtil.replace(str, "'", ""), String.class });
-            }
-            // boolean甯冨皵绫诲瀷锛岀瓑浜巘rue鎴栬�協alse
-            else if (StrUtil.equals(str, "true") || StrUtil.equalsIgnoreCase(str, "false"))
-            {
-                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
-            }
-            // long闀挎暣褰紝鍖呭惈L
-            else if (StrUtil.containsIgnoreCase(str, "L"))
-            {
-                classs.add(new Object[] { Long.valueOf(StrUtil.replaceIgnoreCase(str, "L", "")), Long.class });
-            }
-            // double娴偣绫诲瀷锛屽寘鍚獶
-            else if (StrUtil.containsIgnoreCase(str, "D"))
-            {
-                classs.add(new Object[] { Double.valueOf(StrUtil.replaceIgnoreCase(str, "D", "")), Double.class });
-            }
-            // 鍏朵粬绫诲瀷褰掔被涓烘暣褰�
-            else
-            {
-                classs.add(new Object[] { Integer.valueOf(str), Integer.class });
-            }
-        }
-        return classs;
-    }
-
-    /**
-     * 鑾峰彇鍙傛暟绫诲瀷
-     * 
-     * @param methodParams 鍙傛暟鐩稿叧鍒楄〃
-     * @return 鍙傛暟绫诲瀷鍒楄〃
-     */
-    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)
-    {
-        Class<?>[] classs = new Class<?>[methodParams.size()];
-        int index = 0;
-        for (Object[] os : methodParams)
-        {
-            classs[index] = (Class<?>) os[1];
-            index++;
-        }
-        return classs;
-    }
-
-    /**
-     * 鑾峰彇鍙傛暟鍊�
-     * 
-     * @param methodParams 鍙傛暟鐩稿叧鍒楄〃
-     * @return 鍙傛暟鍊煎垪琛�
-     */
-    public static Object[] getMethodParamsValue(List<Object[]> methodParams)
-    {
-        Object[] classs = new Object[methodParams.size()];
-        int index = 0;
-        for (Object[] os : methodParams)
-        {
-            classs[index] = (Object) os[0];
-            index++;
-        }
-        return classs;
-    }
-}
+package com.ruoyi.quartz.util;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.quartz.domain.SysJob;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 浠诲姟鎵ц宸ュ叿
+ *
+ * @author ruoyi
+ */
+public class JobInvokeUtil
+{
+    /**
+     * 鎵ц鏂规硶
+     *
+     * @param sysJob 绯荤粺浠诲姟
+     */
+    public static void invokeMethod(SysJob sysJob) throws Exception
+    {
+        String invokeTarget = sysJob.getInvokeTarget();
+        String beanName = getBeanName(invokeTarget);
+        String methodName = getMethodName(invokeTarget);
+        List<Object[]> methodParams = getMethodParams(invokeTarget);
+
+        if (!isValidClassName(beanName))
+        {
+            Object bean = SpringUtils.getBean(beanName);
+            invokeMethod(bean, methodName, methodParams);
+        }
+        else
+        {
+            Object bean = Class.forName(beanName).newInstance();
+            invokeMethod(bean, methodName, methodParams);
+        }
+    }
+
+    /**
+     * 璋冪敤浠诲姟鏂规硶
+     *
+     * @param bean 鐩爣瀵硅薄
+     * @param methodName 鏂规硶鍚嶇О
+     * @param methodParams 鏂规硶鍙傛暟
+     */
+    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
+            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException
+    {
+        if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0)
+        {
+            Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));
+            method.invoke(bean, getMethodParamsValue(methodParams));
+        }
+        else
+        {
+            Method method = bean.getClass().getDeclaredMethod(methodName);
+            method.invoke(bean);
+        }
+    }
+
+    /**
+     * 鏍¢獙鏄惁涓轰负class鍖呭悕
+     *
+     * @param str 鍚嶇О
+     * @return true鏄� false鍚�
+     */
+    public static boolean isValidClassName(String invokeTarget)
+    {
+        return StringUtils.countMatches(invokeTarget, ".") > 1;
+    }
+
+    /**
+     * 鑾峰彇bean鍚嶇О
+     *
+     * @param invokeTarget 鐩爣瀛楃涓�
+     * @return bean鍚嶇О
+     */
+    public static String getBeanName(String invokeTarget)
+    {
+        String beanName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBefore(beanName, ".");
+    }
+
+    /**
+     * 鑾峰彇bean鏂规硶
+     *
+     * @param invokeTarget 鐩爣瀛楃涓�
+     * @return method鏂规硶
+     */
+    public static String getMethodName(String invokeTarget)
+    {
+        String methodName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBefore(methodName, ".");
+    }
+
+    /**
+     * 鑾峰彇method鏂规硶鍙傛暟鐩稿叧鍒楄〃
+     *
+     * @param invokeTarget 鐩爣瀛楃涓�
+     * @return method鏂规硶鐩稿叧鍙傛暟鍒楄〃
+     */
+    public static List<Object[]> getMethodParams(String invokeTarget)
+    {
+        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+        if (StringUtils.isEmpty(methodStr))
+        {
+            return null;
+        }
+        String[] methodParams = methodStr.split(",");
+        List<Object[]> classs = new LinkedList<>();
+        for (int i = 0; i < methodParams.length; i++)
+        {
+            String str = StringUtils.trimToEmpty(methodParams[i]);
+            // String瀛楃涓茬被鍨嬶紝鍖呭惈'
+            if (StringUtils.contains(str, "'"))
+            {
+                classs.add(new Object[] { StringUtils.replace(str, "'", ""), String.class });
+            }
+            // boolean甯冨皵绫诲瀷锛岀瓑浜巘rue鎴栬�協alse
+            else if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false"))
+            {
+                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
+            }
+            // long闀挎暣褰紝鍖呭惈L
+            else if (StringUtils.containsIgnoreCase(str, "L"))
+            {
+                classs.add(new Object[] { Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class });
+            }
+            // double娴偣绫诲瀷锛屽寘鍚獶
+            else if (StringUtils.containsIgnoreCase(str, "D"))
+            {
+                classs.add(new Object[] { Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), Double.class });
+            }
+            // 鍏朵粬绫诲瀷褰掔被涓烘暣褰�
+            else
+            {
+                classs.add(new Object[] { Integer.valueOf(str), Integer.class });
+            }
+        }
+        return classs;
+    }
+
+    /**
+     * 鑾峰彇鍙傛暟绫诲瀷
+     *
+     * @param methodParams 鍙傛暟鐩稿叧鍒楄〃
+     * @return 鍙傛暟绫诲瀷鍒楄〃
+     */
+    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)
+    {
+        Class<?>[] classs = new Class<?>[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams)
+        {
+            classs[index] = (Class<?>) os[1];
+            index++;
+        }
+        return classs;
+    }
+
+    /**
+     * 鑾峰彇鍙傛暟鍊�
+     *
+     * @param methodParams 鍙傛暟鐩稿叧鍒楄〃
+     * @return 鍙傛暟鍊煎垪琛�
+     */
+    public static Object[] getMethodParamsValue(List<Object[]> methodParams)
+    {
+        Object[] classs = new Object[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams)
+        {
+            classs[index] = (Object) os[0];
+            index++;
+        }
+        return classs;
+    }
+}
diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml
index 3665c80..ed08fe2 100644
--- a/ruoyi-system/pom.xml
+++ b/ruoyi-system/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>2.6.0</version>
+        <version>3.0.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -23,6 +23,12 @@
             <artifactId>ruoyi-common</artifactId>
         </dependency>
 
+        <!-- OSS鍔熻兘妯″潡 -->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-oss</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
index 66569b7..cdd7810 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
@@ -1,9 +1,10 @@
 package com.ruoyi.system.domain;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -25,20 +26,21 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_config")
+@ExcelIgnoreUnannotated
 public class SysConfig implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
      * 鍙傛暟涓婚敭
      */
-    @Excel(name = "鍙傛暟涓婚敭", cellType = ColumnType.NUMERIC)
+    @ExcelProperty(value = "鍙傛暟涓婚敭")
     @TableId(value = "config_id", type = IdType.AUTO)
     private Long configId;
 
     /**
      * 鍙傛暟鍚嶇О
      */
-    @Excel(name = "鍙傛暟鍚嶇О")
+    @ExcelProperty(value = "鍙傛暟鍚嶇О")
     @NotBlank(message = "鍙傛暟鍚嶇О涓嶈兘涓虹┖")
     @Size(min = 0, max = 100, message = "鍙傛暟鍚嶇О涓嶈兘瓒呰繃100涓瓧绗�")
     private String configName;
@@ -46,7 +48,7 @@
     /**
      * 鍙傛暟閿悕
      */
-    @Excel(name = "鍙傛暟閿悕")
+    @ExcelProperty(value = "鍙傛暟閿悕")
     @NotBlank(message = "鍙傛暟閿悕闀垮害涓嶈兘涓虹┖")
     @Size(min = 0, max = 100, message = "鍙傛暟閿悕闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
     private String configKey;
@@ -54,7 +56,7 @@
     /**
      * 鍙傛暟閿��
      */
-    @Excel(name = "鍙傛暟閿��")
+    @ExcelProperty(value = "鍙傛暟閿��")
     @NotBlank(message = "鍙傛暟閿�间笉鑳戒负绌�")
     @Size(min = 0, max = 500, message = "鍙傛暟閿�奸暱搴︿笉鑳借秴杩�500涓瓧绗�")
     private String configValue;
@@ -62,7 +64,8 @@
     /**
      * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
      */
-    @Excel(name = "绯荤粺鍐呯疆", readConverterExp = "Y=鏄�,N=鍚�")
+    @ExcelProperty(value = "绯荤粺鍐呯疆", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_yes_no")
     private String configType;
 
     /**
@@ -75,7 +78,6 @@
      * 鍒涘缓鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
 
     /**
@@ -88,7 +90,6 @@
      * 鏇存柊鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
index 3182bc4..898aa8a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
@@ -1,12 +1,13 @@
 package com.ruoyi.system.domain;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -26,63 +27,64 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_logininfor")
+@ExcelIgnoreUnannotated
 public class SysLogininfor implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
      * ID
      */
-    @Excel(name = "搴忓彿", cellType = ColumnType.NUMERIC)
+    @ExcelProperty(value = "搴忓彿")
     @TableId(value = "info_id", type = IdType.AUTO)
     private Long infoId;
 
     /**
      * 鐢ㄦ埛璐﹀彿
      */
-    @Excel(name = "鐢ㄦ埛璐﹀彿")
+    @ExcelProperty(value = "鐢ㄦ埛璐﹀彿")
     private String userName;
 
     /**
      * 鐧诲綍鐘舵�� 0鎴愬姛 1澶辫触
      */
-    @Excel(name = "鐧诲綍鐘舵��", readConverterExp = "0=鎴愬姛,1=澶辫触")
+    @ExcelProperty(value = "鐧诲綍鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
     private String status;
 
     /**
      * 鐧诲綍IP鍦板潃
      */
-    @Excel(name = "鐧诲綍鍦板潃")
+    @ExcelProperty(value = "鐧诲綍鍦板潃")
     private String ipaddr;
 
     /**
      * 鐧诲綍鍦扮偣
      */
-    @Excel(name = "鐧诲綍鍦扮偣")
+    @ExcelProperty(value = "鐧诲綍鍦扮偣")
     private String loginLocation;
 
     /**
      * 娴忚鍣ㄧ被鍨�
      */
-    @Excel(name = "娴忚鍣�")
+    @ExcelProperty(value = "娴忚鍣�")
     private String browser;
 
     /**
      * 鎿嶄綔绯荤粺
      */
-    @Excel(name = "鎿嶄綔绯荤粺")
+    @ExcelProperty(value = "鎿嶄綔绯荤粺")
     private String os;
 
     /**
      * 鎻愮ず娑堟伅
      */
-    @Excel(name = "鎻愮ず娑堟伅")
+    @ExcelProperty(value = "鎻愮ず娑堟伅")
     private String msg;
 
     /**
      * 璁块棶鏃堕棿
      */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Excel(name = "璁块棶鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @ExcelProperty(value = "璁块棶鏃堕棿")
     private Date loginTime;
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
index 03e5d26..20fc273 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
@@ -1,12 +1,13 @@
 package com.ruoyi.system.domain;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -26,26 +27,28 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_oper_log")
+@ExcelIgnoreUnannotated
 public class SysOperLog implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
      * 鏃ュ織涓婚敭
      */
-    @Excel(name = "鎿嶄綔搴忓彿", cellType = ColumnType.NUMERIC)
+    @ExcelProperty(value = "鎿嶄綔搴忓彿")
     @TableId(value = "oper_id", type = IdType.AUTO)
     private Long operId;
 
     /**
      * 鎿嶄綔妯″潡
      */
-    @Excel(name = "鎿嶄綔妯″潡")
+    @ExcelProperty(value = "鎿嶄綔妯″潡")
     private String title;
 
     /**
      * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
      */
-    @Excel(name = "涓氬姟绫诲瀷", readConverterExp = "0=鍏跺畠,1=鏂板,2=淇敼,3=鍒犻櫎,4=鎺堟潈,5=瀵煎嚭,6=瀵煎叆,7=寮洪��,8=鐢熸垚浠g爜,9=娓呯┖鏁版嵁")
+    @ExcelProperty(value = "涓氬姟绫诲瀷", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_oper_type")
     private Integer businessType;
 
     /**
@@ -57,80 +60,81 @@
     /**
      * 璇锋眰鏂规硶
      */
-    @Excel(name = "璇锋眰鏂规硶")
+    @ExcelProperty(value = "璇锋眰鏂规硶")
     private String method;
 
     /**
      * 璇锋眰鏂瑰紡
      */
-    @Excel(name = "璇锋眰鏂瑰紡")
+    @ExcelProperty(value = "璇锋眰鏂瑰紡")
     private String requestMethod;
 
     /**
      * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
      */
-    @Excel(name = "鎿嶄綔绫诲埆", readConverterExp = "0=鍏跺畠,1=鍚庡彴鐢ㄦ埛,2=鎵嬫満绔敤鎴�")
+    @ExcelProperty(value = "鎿嶄綔绫诲埆", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(readConverterExp = "0=鍏跺畠,1=鍚庡彴鐢ㄦ埛,2=鎵嬫満绔敤鎴�")
     private Integer operatorType;
 
     /**
      * 鎿嶄綔浜哄憳
      */
-    @Excel(name = "鎿嶄綔浜哄憳")
+    @ExcelProperty(value = "鎿嶄綔浜哄憳")
     private String operName;
 
     /**
      * 閮ㄩ棬鍚嶇О
      */
-    @Excel(name = "閮ㄩ棬鍚嶇О")
+    @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
     private String deptName;
 
     /**
      * 璇锋眰url
      */
-    @Excel(name = "璇锋眰鍦板潃")
+    @ExcelProperty(value = "璇锋眰鍦板潃")
     private String operUrl;
 
     /**
      * 鎿嶄綔鍦板潃
      */
-    @Excel(name = "鎿嶄綔鍦板潃")
+    @ExcelProperty(value = "鎿嶄綔鍦板潃")
     private String operIp;
 
     /**
      * 鎿嶄綔鍦扮偣
      */
-    @Excel(name = "鎿嶄綔鍦扮偣")
+    @ExcelProperty(value = "鎿嶄綔鍦扮偣")
     private String operLocation;
 
     /**
      * 璇锋眰鍙傛暟
      */
-    @Excel(name = "璇锋眰鍙傛暟")
+    @ExcelProperty(value = "璇锋眰鍙傛暟")
     private String operParam;
 
     /**
      * 杩斿洖鍙傛暟
      */
-    @Excel(name = "杩斿洖鍙傛暟")
+    @ExcelProperty(value = "杩斿洖鍙傛暟")
     private String jsonResult;
 
     /**
      * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
      */
-    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=寮傚父")
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
     private Integer status;
 
     /**
      * 閿欒娑堟伅
      */
-    @Excel(name = "閿欒娑堟伅")
+    @ExcelProperty(value = "閿欒娑堟伅")
     private String errorMsg;
 
     /**
      * 鎿嶄綔鏃堕棿
      */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Excel(name = "鎿嶄綔鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @ExcelProperty(value = "鎿嶄綔鏃堕棿")
     private Date operTime;
 
     /**
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/domain/SysOss.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOss.java
similarity index 100%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/domain/SysOss.java
rename to ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOss.java
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java
new file mode 100644
index 0000000..9f0e28e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java
@@ -0,0 +1,111 @@
+package com.ruoyi.system.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import java.io.Serializable;
+import java.util.Date;
+import java.math.BigDecimal;
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃璞� sys_oss_config
+ *
+ * @author ruoyi
+ * @date 2021-08-11
+ */
+@Data
+@NoArgsConstructor
+@Accessors(chain = true)
+@TableName("sys_oss_config")
+public class SysOssConfig implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+
+    /**
+     * 涓诲缓
+     */
+    @TableId(value = "oss_config_id")
+    private Integer ossConfigId;
+
+    /**
+     * 閰嶇疆key
+     */
+    private String configKey;
+
+    /**
+     * accessKey
+     */
+    private String accessKey;
+
+    /**
+     * 绉橀挜
+     */
+    private String secretKey;
+
+    /**
+     * 妗跺悕绉�
+     */
+    private String bucketName;
+
+    /**
+     * 鍓嶇紑
+     */
+    private String prefix;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+    private String endpoint;
+
+    /**
+     * 鏄惁https锛�0鍚� 1鏄級
+     */
+    private String isHttps;
+
+    /**
+     * 鍩�
+     */
+    private String region;
+
+    /**
+     * 鐘舵��(0姝e父 1鍋滅敤)
+     */
+    private String status;
+
+    /**
+     * 鎵╁睍瀛楁
+     */
+    private String ext1;
+
+    /**
+     * 鍒涘缓鑰�
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private String createBy;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /**
+     * 鏇存柊鑰�
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updateBy;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
index 5bde684..5672250 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
@@ -1,9 +1,10 @@
 package com.ruoyi.system.domain;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -25,20 +26,21 @@
 @NoArgsConstructor
 @Accessors(chain = true)
 @TableName("sys_post")
+@ExcelIgnoreUnannotated
 public class SysPost implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
      * 宀椾綅搴忓彿
      */
-    @Excel(name = "宀椾綅搴忓彿", cellType = ColumnType.NUMERIC)
+    @ExcelProperty(value = "宀椾綅搴忓彿")
     @TableId(value = "post_id", type = IdType.AUTO)
     private Long postId;
 
     /**
      * 宀椾綅缂栫爜
      */
-    @Excel(name = "宀椾綅缂栫爜")
+    @ExcelProperty(value = "宀椾綅缂栫爜")
     @NotBlank(message = "宀椾綅缂栫爜涓嶈兘涓虹┖")
     @Size(min = 0, max = 64, message = "宀椾綅缂栫爜闀垮害涓嶈兘瓒呰繃64涓瓧绗�")
     private String postCode;
@@ -46,7 +48,7 @@
     /**
      * 宀椾綅鍚嶇О
      */
-    @Excel(name = "宀椾綅鍚嶇О")
+    @ExcelProperty(value = "宀椾綅鍚嶇О")
     @NotBlank(message = "宀椾綅鍚嶇О涓嶈兘涓虹┖")
     @Size(min = 0, max = 50, message = "宀椾綅鍚嶇О闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
     private String postName;
@@ -54,14 +56,15 @@
     /**
      * 宀椾綅鎺掑簭
      */
-    @Excel(name = "宀椾綅鎺掑簭")
+    @ExcelProperty(value = "宀椾綅鎺掑簭")
     @NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
     private String postSort;
 
     /**
      * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
      */
-    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+	@ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
     private String status;
 
     /**
@@ -74,7 +77,6 @@
      * 鍒涘缓鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
 
     /**
@@ -87,7 +89,6 @@
      * 鏇存柊鏃堕棿
      */
     @TableField(fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
 
     /**
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java
similarity index 100%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java
rename to ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java
new file mode 100644
index 0000000..3e8defc
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java
@@ -0,0 +1,130 @@
+package com.ruoyi.system.domain.bo;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.common.core.validate.AddGroup;
+import com.ruoyi.common.core.validate.EditGroup;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃笟鍔″璞� sys_oss_config
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel("浜戝瓨鍌ㄩ厤缃笟鍔″璞�")
+public class SysOssConfigBo extends BaseEntity {
+
+	/**
+	 * 涓诲缓
+	 */
+	@ApiModelProperty(value = "涓诲缓", required = true)
+	@NotNull(message = "涓诲缓涓嶈兘涓虹┖", groups = { EditGroup.class })
+	private Long ossConfigId;
+
+    /**
+     * 閰嶇疆key
+     */
+    @ApiModelProperty(value = "configKey", required = true)
+    @NotBlank(message = "configKey涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+	@Size(min = 2, max = 100, message = "configKey闀垮害蹇呴』浠嬩簬2鍜�20 涔嬮棿")
+    private String configKey;
+
+    /**
+     * accessKey
+     */
+    @ApiModelProperty(value = "accessKey", required = true)
+	@NotBlank(message = "accessKey涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+	@Size(min = 2, max = 100, message = "accessKey闀垮害蹇呴』浠嬩簬2鍜�100 涔嬮棿")
+    private String accessKey;
+
+    /**
+     * 绉橀挜
+     */
+    @ApiModelProperty(value = "secretKey", required = true)
+	@NotBlank(message = "secretKey涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+	@Size(min = 2, max = 100, message = "secretKey闀垮害蹇呴』浠嬩簬2鍜�100 涔嬮棿")
+    private String secretKey;
+
+    /**
+     * 妗跺悕绉�
+     */
+    @ApiModelProperty(value = "bucketName", required = true)
+	@NotBlank(message = "bucketName涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+	@Size(min = 2, max = 100, message = "bucketName闀垮害蹇呴』浠嬩簬2鍜�100涔嬮棿")
+    private String bucketName;
+
+    /**
+     * 鍓嶇紑
+     */
+    @ApiModelProperty(value = "鍓嶇紑")
+    private String prefix;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+    @ApiModelProperty(value = "endpoint", required = true)
+	@NotBlank(message = "endpoint涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+	@Size(min = 2, max = 100, message = "endpoint闀垮害蹇呴』浠嬩簬2鍜�100涔嬮棿")
+    private String endpoint;
+
+	/**
+	 * 鏄惁https锛圷=鏄�,N=鍚︼級
+	 */
+	@ApiModelProperty("鏄惁https锛圷=鏄�,N=鍚︼級")
+	private String isHttps;
+
+	/**
+	 * 鐘舵�侊紙0=姝e父,1=鍋滅敤锛�
+	 */
+	@ApiModelProperty("鐘舵�侊紙0=姝e父,1=鍋滅敤锛�")
+	private String status;
+
+    /**
+     * 鍩�
+     */
+    @ApiModelProperty(value = "region")
+    private String region;
+
+    /**
+     * 鎵╁睍瀛楁
+     */
+    @ApiModelProperty(value = "鎵╁睍瀛楁")
+    private String ext1;
+
+
+    /**
+     * 鍒嗛〉澶у皬
+     */
+    @ApiModelProperty("鍒嗛〉澶у皬")
+    private Integer pageSize;
+
+    /**
+     * 褰撳墠椤垫暟
+     */
+    @ApiModelProperty("褰撳墠椤垫暟")
+    private Integer pageNum;
+
+    /**
+     * 鎺掑簭鍒�
+     */
+    @ApiModelProperty("鎺掑簭鍒�")
+    private String orderByColumn;
+
+    /**
+     * 鎺掑簭鐨勬柟鍚慸esc鎴栬�卆sc
+     */
+    @ApiModelProperty(value = "鎺掑簭鐨勬柟鍚�", example = "asc,desc")
+    private String isAsc;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
index dbe7a6e..495db54 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
@@ -1,6 +1,6 @@
 package com.ruoyi.system.domain.vo;
 
-import cn.hutool.core.lang.Validator;
+import com.ruoyi.common.utils.StringUtils;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
@@ -56,7 +56,7 @@
 		this.title = title;
 		this.icon = icon;
 		this.noCache = noCache;
-		if (Validator.isUrl(link)) {
+		if (StringUtils.ishttp(link)) {
 			this.link = link;
 		}
 	}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssConfigVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssConfigVo.java
new file mode 100644
index 0000000..58e3900
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssConfigVo.java
@@ -0,0 +1,96 @@
+package com.ruoyi.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃鍥惧璞� sys_oss_config
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Data
+@ApiModel("浜戝瓨鍌ㄩ厤缃鍥惧璞�")
+@ExcelIgnoreUnannotated
+public class SysOssConfigVo {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+     * 涓诲缓
+     */
+	@ApiModelProperty("涓诲缓")
+	private Long ossConfigId;
+
+    /**
+     * 閰嶇疆key
+     */
+	@ApiModelProperty("閰嶇疆key")
+	private String configKey;
+
+    /**
+     * accessKey
+     */
+	@ApiModelProperty("accessKey")
+	private String accessKey;
+
+    /**
+     * 绉橀挜
+     */
+	@ApiModelProperty("secretKey")
+	private String secretKey;
+
+    /**
+     * 妗跺悕绉�
+     */
+	@ApiModelProperty("妗跺悕绉�")
+	private String bucketName;
+
+    /**
+     * 鍓嶇紑
+     */
+	@ApiModelProperty("鍓嶇紑")
+	private String prefix;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+	@ApiModelProperty("璁块棶绔欑偣")
+	private String endpoint;
+
+    /**
+     * 鏄惁https锛圷=鏄�,N=鍚︼級
+     */
+	@ApiModelProperty("鏄惁https锛圷=鏄�,N=鍚︼級")
+	private String isHttps;
+
+    /**
+     * 鍩�
+     */
+	@ApiModelProperty("鍩�")
+	private String region;
+
+    /**
+     * 鐘舵�侊紙0=姝e父,1=鍋滅敤锛�
+     */
+	@ApiModelProperty("鐘舵�侊紙0=姝e父,1=鍋滅敤锛�")
+	private String status;
+
+    /**
+     * 鎵╁睍瀛楁
+     */
+	@ApiModelProperty("鎵╁睍瀛楁")
+	private String ext1;
+
+	/**
+	 * 澶囨敞
+	 */
+	@ApiModelProperty("澶囨敞")
+	private String remark;
+
+}
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/domain/vo/SysOssVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssVo.java
similarity index 100%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/domain/vo/SysOssVo.java
rename to ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOssVo.java
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java
new file mode 100644
index 0000000..6842f0a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java
@@ -0,0 +1,93 @@
+package com.ruoyi.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀵硅薄瀵煎嚭VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+@Accessors(chain = true)
+public class SysUserExportVo implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 鐢ㄦ埛ID
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛搴忓彿")
+	private Long userId;
+
+	/**
+	 * 鐢ㄦ埛璐﹀彿
+	 */
+	@ExcelProperty(value = "鐧诲綍鍚嶇О")
+	private String userName;
+
+	/**
+	 * 鐢ㄦ埛鏄电О
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛鍚嶇О")
+	private String nickName;
+
+	/**
+	 * 鐢ㄦ埛閭
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛閭")
+	private String email;
+
+	/**
+	 * 鎵嬫満鍙风爜
+	 */
+	@ExcelProperty(value = "鎵嬫満鍙风爜")
+	private String phonenumber;
+
+	/**
+	 * 鐢ㄦ埛鎬у埆
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛鎬у埆", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_user_sex")
+	private String sex;
+
+	/**
+	 * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+	 */
+	@ExcelProperty(value = "甯愬彿鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
+	private String status;
+
+	/**
+	 * 鏈�鍚庣櫥褰旾P
+	 */
+	@ExcelProperty(value = "鏈�鍚庣櫥褰旾P")
+	private String loginIp;
+
+	/**
+	 * 鏈�鍚庣櫥褰曟椂闂�
+	 */
+	@ExcelProperty(value = "鏈�鍚庣櫥褰曟椂闂�")
+	private Date loginDate;
+
+	/**
+	 * 閮ㄩ棬鍚嶇О
+	 */
+	@ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+	private String deptName;
+
+	/**
+	 * 璐熻矗浜�
+	 */
+	@ExcelProperty(value = "閮ㄩ棬璐熻矗浜�")
+	private String leader;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java
new file mode 100644
index 0000000..9c1a7d3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java
@@ -0,0 +1,73 @@
+package com.ruoyi.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.convert.ExcelDictConvert;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛瀵硅薄瀵煎叆VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+// @Accessors(chain = true) // 瀵煎叆涓嶅厑璁镐娇鐢� 浼氭壘涓嶅埌set鏂规硶
+public class SysUserImportVo implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 鐢ㄦ埛ID
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛搴忓彿")
+	private Long userId;
+
+	/**
+	 * 閮ㄩ棬ID
+	 */
+	@ExcelProperty(value = "閮ㄩ棬缂栧彿")
+	private Long deptId;
+
+	/**
+	 * 鐢ㄦ埛璐﹀彿
+	 */
+	@ExcelProperty(value = "鐧诲綍鍚嶇О")
+	private String userName;
+
+	/**
+	 * 鐢ㄦ埛鏄电О
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛鍚嶇О")
+	private String nickName;
+
+	/**
+	 * 鐢ㄦ埛閭
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛閭")
+	private String email;
+
+	/**
+	 * 鎵嬫満鍙风爜
+	 */
+	@ExcelProperty(value = "鎵嬫満鍙风爜")
+	private String phonenumber;
+
+	/**
+	 * 鐢ㄦ埛鎬у埆
+	 */
+	@ExcelProperty(value = "鐢ㄦ埛鎬у埆", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_user_sex")
+	private String sex;
+
+	/**
+	 * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+	 */
+	@ExcelProperty(value = "甯愬彿鐘舵��", converter = ExcelDictConvert.class)
+	@ExcelDictFormat(dictType = "sys_common_status")
+	private String status;
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssConfigMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssConfigMapper.java
new file mode 100644
index 0000000..9546e73
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssConfigMapper.java
@@ -0,0 +1,15 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
+import com.ruoyi.system.domain.SysOssConfig;
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃甅apper鎺ュ彛
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+public interface SysOssConfigMapper extends BaseMapperPlus<SysOssConfig> {
+
+}
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/mapper/SysOssMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssMapper.java
similarity index 100%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/mapper/SysOssMapper.java
rename to ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOssMapper.java
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java
new file mode 100644
index 0000000..f1ece65
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java
@@ -0,0 +1,58 @@
+package com.ruoyi.system.service;
+
+import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.system.domain.SysOssConfig;
+import com.ruoyi.system.domain.bo.SysOssConfigBo;
+import com.ruoyi.system.domain.vo.SysOssConfigVo;
+
+import java.util.Collection;
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃甋ervice鎺ュ彛
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+public interface ISysOssConfigService extends IServicePlus<SysOssConfig, SysOssConfigVo> {
+
+	/**
+	 * 鏌ヨ鍗曚釜
+	 */
+	SysOssConfigVo queryById(Integer ossConfigId);
+
+	/**
+	 * 鏌ヨ鍒楄〃
+	 */
+    TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo);
+
+
+	/**
+	 * 鏍规嵁鏂板涓氬姟瀵硅薄鎻掑叆浜戝瓨鍌ㄩ厤缃�
+	 * @param bo 浜戝瓨鍌ㄩ厤缃柊澧炰笟鍔″璞�
+	 * @return
+	 */
+	Boolean insertByBo(SysOssConfigBo bo);
+
+	/**
+	 * 鏍规嵁缂栬緫涓氬姟瀵硅薄淇敼浜戝瓨鍌ㄩ厤缃�
+	 * @param bo 浜戝瓨鍌ㄩ厤缃紪杈戜笟鍔″璞�
+	 * @return
+	 */
+	Boolean updateByBo(SysOssConfigBo bo);
+
+	/**
+	 * 鏍¢獙骞跺垹闄ゆ暟鎹�
+	 * @param ids 涓婚敭闆嗗悎
+	 * @param isValid 鏄惁鏍¢獙,true-鍒犻櫎鍓嶆牎楠�,false-涓嶆牎楠�
+	 * @return
+	 */
+	Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+	/**
+	 * 鍚敤鍋滅敤鐘舵��
+	 */
+	int updateOssConfigStatus(SysOssConfigBo bo);
+
+}
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/service/ISysOssService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java
similarity index 99%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/service/ISysOssService.java
rename to ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java
index 4f998e0..b5dc078 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/system/service/ISysOssService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java
@@ -2,8 +2,8 @@
 
 import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.system.domain.bo.SysOssBo;
 import com.ruoyi.system.domain.SysOss;
+import com.ruoyi.system.domain.bo.SysOssBo;
 import com.ruoyi.system.domain.vo.SysOssVo;
 import org.springframework.web.multipart.MultipartFile;
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
index ea1b89b..99a7442 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -112,6 +112,14 @@
     public int insertUser(SysUser user);
 
     /**
+     * 娉ㄥ唽鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public boolean registerUser(SysUser user);
+
+    /**
      * 淇敼鐢ㄦ埛淇℃伅
      *
      * @param user 鐢ㄦ埛淇℃伅
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
index 84b10db..6cc8958 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -1,8 +1,7 @@
 package com.ruoyi.system.service.impl;
 
 import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.annotation.DataSource;
 import com.ruoyi.common.constant.Constants;
@@ -11,7 +10,7 @@
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.enums.DataSourceType;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.PageUtils;
 import com.ruoyi.system.domain.SysConfig;
 import com.ruoyi.system.mapper.SysConfigMapper;
@@ -48,13 +47,13 @@
 	public TableDataInfo<SysConfig> selectPageConfigList(SysConfig config) {
 		Map<String, Object> params = config.getParams();
 		LambdaQueryWrapper<SysConfig> lqw = new LambdaQueryWrapper<SysConfig>()
-			.like(StrUtil.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName())
-			.eq(StrUtil.isNotBlank(config.getConfigType()), SysConfig::getConfigType, config.getConfigType())
-			.like(StrUtil.isNotBlank(config.getConfigKey()), SysConfig::getConfigKey, config.getConfigKey())
-			.apply(Validator.isNotEmpty(params.get("beginTime")),
+			.like(StringUtils.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName())
+			.eq(StringUtils.isNotBlank(config.getConfigType()), SysConfig::getConfigType, config.getConfigType())
+			.like(StringUtils.isNotBlank(config.getConfigKey()), SysConfig::getConfigKey, config.getConfigKey())
+			.apply(StringUtils.isNotEmpty(params.get("beginTime")),
 				"date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')",
 				params.get("beginTime"))
-			.apply(Validator.isNotEmpty(params.get("endTime")),
+			.apply(StringUtils.isNotEmpty(params.get("endTime")),
 				"date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
 				params.get("endTime"));
 		return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
@@ -81,16 +80,16 @@
 	@Override
 	public String selectConfigByKey(String configKey) {
 		String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
-		if (Validator.isNotEmpty(configValue)) {
+		if (StringUtils.isNotEmpty(configValue)) {
 			return configValue;
 		}
 		SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
 			.eq(SysConfig::getConfigKey, configKey));
-		if (Validator.isNotNull(retConfig)) {
+		if (StringUtils.isNotNull(retConfig)) {
 			redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
 			return retConfig.getConfigValue();
 		}
-		return StrUtil.EMPTY;
+		return StringUtils.EMPTY;
 	}
 
 	/**
@@ -101,7 +100,7 @@
 	@Override
 	public boolean selectCaptchaOnOff() {
 		String captchaOnOff = selectConfigByKey("sys.account.captchaOnOff");
-		if (StrUtil.isEmpty(captchaOnOff)) {
+		if (StringUtils.isEmpty(captchaOnOff)) {
 			return true;
 		}
 		return Convert.toBool(captchaOnOff);
@@ -117,13 +116,13 @@
 	public List<SysConfig> selectConfigList(SysConfig config) {
 		Map<String, Object> params = config.getParams();
 		LambdaQueryWrapper<SysConfig> lqw = new LambdaQueryWrapper<SysConfig>()
-			.like(StrUtil.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName())
-			.eq(StrUtil.isNotBlank(config.getConfigType()), SysConfig::getConfigType, config.getConfigType())
-			.like(StrUtil.isNotBlank(config.getConfigKey()), SysConfig::getConfigKey, config.getConfigKey())
-			.apply(Validator.isNotEmpty(params.get("beginTime")),
+			.like(StringUtils.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName())
+			.eq(StringUtils.isNotBlank(config.getConfigType()), SysConfig::getConfigType, config.getConfigType())
+			.like(StringUtils.isNotBlank(config.getConfigKey()), SysConfig::getConfigKey, config.getConfigKey())
+			.apply(StringUtils.isNotEmpty(params.get("beginTime")),
 				"date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')",
 				params.get("beginTime"))
-			.apply(Validator.isNotEmpty(params.get("endTime")),
+			.apply(StringUtils.isNotEmpty(params.get("endTime")),
 				"date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
 				params.get("endTime"));
 		return baseMapper.selectList(lqw);
@@ -169,8 +168,8 @@
 	public void deleteConfigByIds(Long[] configIds) {
 		for (Long configId : configIds) {
 			SysConfig config = selectConfigById(configId);
-			if (StrUtil.equals(UserConstants.YES, config.getConfigType())) {
-				throw new CustomException(String.format("鍐呯疆鍙傛暟銆�%1$s銆戜笉鑳藉垹闄� ", config.getConfigKey()));
+			if (StringUtils.equals(UserConstants.YES, config.getConfigType())) {
+				throw new ServiceException(String.format("鍐呯疆鍙傛暟銆�%1$s銆戜笉鑳藉垹闄� ", config.getConfigKey()));
 			}
 			redisCache.deleteObject(getCacheKey(config.getConfigKey()));
 		}
@@ -214,9 +213,9 @@
 	 */
 	@Override
 	public String checkConfigKeyUnique(SysConfig config) {
-		Long configId = Validator.isNull(config.getConfigId()) ? -1L : config.getConfigId();
+		Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();
 		SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, config.getConfigKey()));
-		if (Validator.isNotNull(info) && info.getConfigId().longValue() != configId.longValue()) {
+		if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue()) {
 			return UserConstants.NOT_UNIQUE;
 		}
 		return UserConstants.UNIQUE;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
index 03fd99b..4a88702 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -1,7 +1,6 @@
 package com.ruoyi.system.service.impl;
 
 import cn.hutool.core.convert.Convert;
-import cn.hutool.core.lang.Validator;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.ruoyi.common.annotation.DataScope;
@@ -11,7 +10,8 @@
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.mapper.SysDeptMapper;
 import com.ruoyi.system.mapper.SysRoleMapper;
 import com.ruoyi.system.mapper.SysUserMapper;
@@ -159,12 +159,12 @@
      */
     @Override
     public String checkDeptNameUnique(SysDept dept) {
-        Long deptId = Validator.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
+        Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
         SysDept info = getOne(new LambdaQueryWrapper<SysDept>()
                 .eq(SysDept::getDeptName, dept.getDeptName())
                 .eq(SysDept::getParentId, dept.getParentId())
                 .last("limit 1"));
-        if (Validator.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -181,7 +181,7 @@
         SysDept info = getById(dept.getParentId());
         // 濡傛灉鐖惰妭鐐逛笉涓烘甯哥姸鎬�,鍒欎笉鍏佽鏂板瀛愯妭鐐�
         if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
-            throw new CustomException("閮ㄩ棬鍋滅敤锛屼笉鍏佽鏂板");
+            throw new ServiceException("閮ㄩ棬鍋滅敤锛屼笉鍏佽鏂板");
         }
         dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
         return baseMapper.insert(dept);
@@ -197,14 +197,15 @@
     public int updateDept(SysDept dept) {
         SysDept newParentDept = getById(dept.getParentId());
         SysDept oldDept = getById(dept.getDeptId());
-        if (Validator.isNotNull(newParentDept) && Validator.isNotNull(oldDept)) {
+        if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) {
             String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
             String oldAncestors = oldDept.getAncestors();
             dept.setAncestors(newAncestors);
             updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
         }
         int result = baseMapper.updateById(dept);
-        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus())) {
+        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
+			&& !StringUtils.equals("0", dept.getAncestors())) {
             // 濡傛灉璇ラ儴闂ㄦ槸鍚敤鐘舵�侊紝鍒欏惎鐢ㄨ閮ㄩ棬鐨勬墍鏈変笂绾ч儴闂�
             updateParentDeptStatusNormal(dept);
         }
@@ -273,7 +274,7 @@
     private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
         List<SysDept> tlist = new ArrayList<SysDept>();
 		for (SysDept n : list) {
-			if (Validator.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
+			if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
 				tlist.add(n);
 			}
 		}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
index 9ccafc0..fdd436f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
@@ -1,6 +1,6 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.core.domain.entity.SysDictData;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
@@ -24,9 +24,9 @@
 	@Override
 	public TableDataInfo<SysDictData> selectPageDictDataList(SysDictData dictData) {
 		LambdaQueryWrapper<SysDictData> lqw = new LambdaQueryWrapper<SysDictData>()
-			.eq(StrUtil.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType())
-			.like(StrUtil.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel())
-			.eq(StrUtil.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus())
+			.eq(StringUtils.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType())
+			.like(StringUtils.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel())
+			.eq(StringUtils.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus())
 			.orderByAsc(SysDictData::getDictSort);
 		return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
 	}
@@ -40,9 +40,9 @@
 	@Override
 	public List<SysDictData> selectDictDataList(SysDictData dictData) {
 		return list(new LambdaQueryWrapper<SysDictData>()
-			.eq(StrUtil.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType())
-			.like(StrUtil.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel())
-			.eq(StrUtil.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus())
+			.eq(StringUtils.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType())
+			.like(StringUtils.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel())
+			.eq(StringUtils.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus())
 			.orderByAsc(SysDictData::getDictSort));
 	}
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
index 7e2644f..e334158 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
@@ -1,8 +1,7 @@
 package com.ruoyi.system.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.ruoyi.common.constant.UserConstants;
@@ -10,7 +9,7 @@
 import com.ruoyi.common.core.domain.entity.SysDictType;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.DictUtils;
 import com.ruoyi.common.utils.PageUtils;
 import com.ruoyi.system.mapper.SysDictDataMapper;
@@ -48,13 +47,13 @@
 	public TableDataInfo<SysDictType> selectPageDictTypeList(SysDictType dictType) {
 		Map<String, Object> params = dictType.getParams();
 		LambdaQueryWrapper<SysDictType> lqw = new LambdaQueryWrapper<SysDictType>()
-			.like(StrUtil.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName())
-			.eq(StrUtil.isNotBlank(dictType.getStatus()), SysDictType::getStatus, dictType.getStatus())
-			.like(StrUtil.isNotBlank(dictType.getDictType()), SysDictType::getDictType, dictType.getDictType())
-			.apply(Validator.isNotEmpty(params.get("beginTime")),
+			.like(StringUtils.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName())
+			.eq(StringUtils.isNotBlank(dictType.getStatus()), SysDictType::getStatus, dictType.getStatus())
+			.like(StringUtils.isNotBlank(dictType.getDictType()), SysDictType::getDictType, dictType.getDictType())
+			.apply(StringUtils.isNotEmpty(params.get("beginTime")),
 				"date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')",
 				params.get("beginTime"))
-			.apply(Validator.isNotEmpty(params.get("endTime")),
+			.apply(StringUtils.isNotEmpty(params.get("endTime")),
 				"date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
 				params.get("endTime"));
 		return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
@@ -70,13 +69,13 @@
 	public List<SysDictType> selectDictTypeList(SysDictType dictType) {
 		Map<String, Object> params = dictType.getParams();
 		return list(new LambdaQueryWrapper<SysDictType>()
-			.like(StrUtil.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName())
-			.eq(StrUtil.isNotBlank(dictType.getStatus()), SysDictType::getStatus, dictType.getStatus())
-			.like(StrUtil.isNotBlank(dictType.getDictType()), SysDictType::getDictType, dictType.getDictType())
-			.apply(Validator.isNotEmpty(params.get("beginTime")),
+			.like(StringUtils.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName())
+			.eq(StringUtils.isNotBlank(dictType.getStatus()), SysDictType::getStatus, dictType.getStatus())
+			.like(StringUtils.isNotBlank(dictType.getDictType()), SysDictType::getDictType, dictType.getDictType())
+			.apply(StringUtils.isNotEmpty(params.get("beginTime")),
 				"date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')",
 				params.get("beginTime"))
-			.apply(Validator.isNotEmpty(params.get("endTime")),
+			.apply(StringUtils.isNotEmpty(params.get("endTime")),
 				"date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
 				params.get("endTime")));
 	}
@@ -145,7 +144,7 @@
 			SysDictType dictType = selectDictTypeById(dictId);
 			if (dictDataMapper.selectCount(new LambdaQueryWrapper<SysDictData>()
 				.eq(SysDictData::getDictType, dictType.getDictType())) > 0) {
-				throw new CustomException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", dictType.getDictName()));
+				throw new ServiceException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", dictType.getDictName()));
 			}
 			DictUtils.removeDictCache(dictType.getDictType());
 		}
@@ -225,11 +224,11 @@
 	 */
 	@Override
 	public String checkDictTypeUnique(SysDictType dict) {
-		Long dictId = Validator.isNull(dict.getDictId()) ? -1L : dict.getDictId();
+		Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
 		SysDictType dictType = getOne(new LambdaQueryWrapper<SysDictType>()
 			.eq(SysDictType::getDictType, dict.getDictType())
 			.last("limit 1"));
-		if (Validator.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) {
+		if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) {
 			return UserConstants.NOT_UNIQUE;
 		}
 		return UserConstants.UNIQUE;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
index 45ed439..8b56619 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
@@ -1,11 +1,10 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysLogininfor;
 import com.ruoyi.system.mapper.SysLogininforMapper;
 import com.ruoyi.system.service.ISysLogininforService;
@@ -28,13 +27,13 @@
     public TableDataInfo<SysLogininfor> selectPageLogininforList(SysLogininfor logininfor) {
         Map<String, Object> params = logininfor.getParams();
         LambdaQueryWrapper<SysLogininfor> lqw = new LambdaQueryWrapper<SysLogininfor>()
-                .like(StrUtil.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
-                .eq(StrUtil.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus())
-                .like(StrUtil.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName())
-                .apply(Validator.isNotEmpty(params.get("beginTime")),
+                .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
+                .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus())
+                .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName())
+                .apply(StringUtils.isNotEmpty(params.get("beginTime")),
                         "date_format(login_time,'%y%m%d') >= date_format({0},'%y%m%d')",
                         params.get("beginTime"))
-                .apply(Validator.isNotEmpty(params.get("endTime")),
+                .apply(StringUtils.isNotEmpty(params.get("endTime")),
                         "date_format(login_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                         params.get("endTime"));
         return PageUtils.buildDataInfo(page(PageUtils.buildPage("info_id","desc"), lqw));
@@ -61,13 +60,13 @@
     public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor) {
         Map<String, Object> params = logininfor.getParams();
         return list(new LambdaQueryWrapper<SysLogininfor>()
-                .like(StrUtil.isNotBlank(logininfor.getIpaddr()),SysLogininfor::getIpaddr,logininfor.getIpaddr())
-                .eq(StrUtil.isNotBlank(logininfor.getStatus()),SysLogininfor::getStatus,logininfor.getStatus())
-                .like(StrUtil.isNotBlank(logininfor.getUserName()),SysLogininfor::getUserName,logininfor.getUserName())
-                .apply(Validator.isNotEmpty(params.get("beginTime")),
+                .like(StringUtils.isNotBlank(logininfor.getIpaddr()),SysLogininfor::getIpaddr,logininfor.getIpaddr())
+                .eq(StringUtils.isNotBlank(logininfor.getStatus()),SysLogininfor::getStatus,logininfor.getStatus())
+                .like(StringUtils.isNotBlank(logininfor.getUserName()),SysLogininfor::getUserName,logininfor.getUserName())
+                .apply(StringUtils.isNotEmpty(params.get("beginTime")),
                         "date_format(login_time,'%y%m%d') >= date_format({0},'%y%m%d')",
                         params.get("beginTime"))
-                .apply(Validator.isNotEmpty(params.get("endTime")),
+                .apply(StringUtils.isNotEmpty(params.get("endTime")),
                         "date_format(login_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                         params.get("endTime"))
                 .orderByDesc(SysLogininfor::getInfoId));
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
index 13d283b..a46d62c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -1,7 +1,5 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.constant.UserConstants;
@@ -11,6 +9,7 @@
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysRoleMenu;
 import com.ruoyi.system.domain.vo.MetaVo;
 import com.ruoyi.system.domain.vo.RouterVo;
@@ -18,7 +17,6 @@
 import com.ruoyi.system.mapper.SysRoleMapper;
 import com.ruoyi.system.mapper.SysRoleMenuMapper;
 import com.ruoyi.system.service.ISysMenuService;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -63,9 +61,9 @@
         // 绠$悊鍛樻樉绀烘墍鏈夎彍鍗曚俊鎭�
         if (SysUser.isAdmin(userId)) {
             menuList = list(new LambdaQueryWrapper<SysMenu>()
-                    .like(StrUtil.isNotBlank(menu.getMenuName()),SysMenu::getMenuName,menu.getMenuName())
-                    .eq(StrUtil.isNotBlank(menu.getVisible()),SysMenu::getVisible,menu.getVisible())
-                    .eq(StrUtil.isNotBlank(menu.getStatus()),SysMenu::getStatus,menu.getStatus())
+                    .like(StringUtils.isNotBlank(menu.getMenuName()),SysMenu::getMenuName,menu.getMenuName())
+                    .eq(StringUtils.isNotBlank(menu.getVisible()),SysMenu::getVisible,menu.getVisible())
+                    .eq(StringUtils.isNotBlank(menu.getStatus()),SysMenu::getStatus,menu.getStatus())
                     .orderByAsc(SysMenu::getParentId)
                     .orderByAsc(SysMenu::getOrderNum));
         } else {
@@ -86,7 +84,7 @@
         List<String> perms = baseMapper.selectMenuPermsByUserId(userId);
         Set<String> permsSet = new HashSet<>();
         for (String perm : perms) {
-            if (Validator.isNotEmpty(perm)) {
+            if (StringUtils.isNotEmpty(perm)) {
                 permsSet.addAll(Arrays.asList(perm.trim().split(",")));
             }
         }
@@ -137,7 +135,7 @@
             router.setName(getRouteName(menu));
             router.setPath(getRouterPath(menu));
             router.setComponent(getComponent(menu));
-            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()), menu.getPath()));
+            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
             List<SysMenu> cMenus = menu.getChildren();
             if (!cMenus.isEmpty() && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                 router.setAlwaysShow(true);
@@ -149,8 +147,8 @@
                 RouterVo children = new RouterVo();
                 children.setPath(menu.getPath());
                 children.setComponent(menu.getComponent());
-                children.setName(StrUtil.upperFirst(menu.getPath()));
-                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()), menu.getPath()));
+                children.setName(StringUtils.capitalize(menu.getPath()));
+                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
 				childrenList.add(children);
 				router.setChildren(childrenList);
 			} else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) {
@@ -161,7 +159,7 @@
 				String routerPath = StringUtils.replaceEach(menu.getPath(), new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" });
 				children.setPath(routerPath);
 				children.setComponent(UserConstants.INNER_LINK);
-				children.setName(StrUtil.upperFirst(routerPath));
+				children.setName(StringUtils.capitalize(routerPath));
 				children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                 childrenList.add(children);
                 router.setChildren(childrenList);
@@ -285,12 +283,12 @@
      */
     @Override
     public String checkMenuNameUnique(SysMenu menu) {
-        Long menuId = Validator.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
+        Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
         SysMenu info = getOne(new LambdaQueryWrapper<SysMenu>()
                 .eq(SysMenu::getMenuName,menu.getMenuName())
                 .eq(SysMenu::getParentId,menu.getParentId())
                 .last("limit 1"));
-        if (Validator.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -303,10 +301,10 @@
      * @return 璺敱鍚嶇О
      */
     public String getRouteName(SysMenu menu) {
-        String routerName = StrUtil.upperFirst(menu.getPath());
+        String routerName = StringUtils.capitalize(menu.getPath());
         // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
         if (isMenuFrame(menu)) {
-            routerName = StrUtil.EMPTY;
+            routerName = StringUtils.EMPTY;
         }
         return routerName;
     }
@@ -343,11 +341,11 @@
      */
     public String getComponent(SysMenu menu) {
         String component = UserConstants.LAYOUT;
-        if (StrUtil.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) {
+        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) {
             component = menu.getComponent();
-		} else if (StrUtil.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
+		} else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
 			component = UserConstants.INNER_LINK;
-		} else if (StrUtil.isEmpty(menu.getComponent()) && isParentView(menu)) {
+		} else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) {
             component = UserConstants.PARENT_VIEW;
         }
         return component;
@@ -371,7 +369,7 @@
      * @return 缁撴灉
      */
     public boolean isInnerLink(SysMenu menu) {
-        return menu.getIsFrame().equals(UserConstants.NO_FRAME) && Validator.isUrl(menu.getPath());
+        return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
     }
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
index 5c7f623..dd8fdbc 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
@@ -1,6 +1,6 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
@@ -24,9 +24,9 @@
     @Override
     public TableDataInfo<SysNotice> selectPageNoticeList(SysNotice notice) {
         LambdaQueryWrapper<SysNotice> lqw = new LambdaQueryWrapper<SysNotice>()
-                .like(StrUtil.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle())
-                .eq(StrUtil.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType())
-                .like(StrUtil.isNotBlank(notice.getCreateBy()), SysNotice::getCreateBy, notice.getCreateBy());
+                .like(StringUtils.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle())
+                .eq(StringUtils.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType())
+                .like(StringUtils.isNotBlank(notice.getCreateBy()), SysNotice::getCreateBy, notice.getCreateBy());
         return PageUtils.buildDataInfo(page(PageUtils.buildPage(),lqw));
     }
 
@@ -50,9 +50,9 @@
     @Override
     public List<SysNotice> selectNoticeList(SysNotice notice) {
         return list(new LambdaQueryWrapper<SysNotice>()
-                .like(StrUtil.isNotBlank(notice.getNoticeTitle()),SysNotice::getNoticeTitle,notice.getNoticeTitle())
-                .eq(StrUtil.isNotBlank(notice.getNoticeType()),SysNotice::getNoticeType,notice.getNoticeType())
-                .like(StrUtil.isNotBlank(notice.getCreateBy()),SysNotice::getCreateBy,notice.getCreateBy()));
+                .like(StringUtils.isNotBlank(notice.getNoticeTitle()),SysNotice::getNoticeTitle,notice.getNoticeTitle())
+                .eq(StringUtils.isNotBlank(notice.getNoticeType()),SysNotice::getNoticeType,notice.getNoticeType())
+                .like(StringUtils.isNotBlank(notice.getCreateBy()),SysNotice::getCreateBy,notice.getCreateBy()));
     }
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
index 4fd5313..ff518bd 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
@@ -1,8 +1,7 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
@@ -29,7 +28,7 @@
     public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog) {
         Map<String, Object> params = operLog.getParams();
         LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
-                .like(StrUtil.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
+                .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
                 .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                         SysOperLog::getBusinessType, operLog.getBusinessType())
                 .func(f -> {
@@ -37,13 +36,13 @@
                         f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
                     }
                 })
-                .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
+                .eq(operLog.getStatus() != null,
                         SysOperLog::getStatus, operLog.getStatus())
-                .like(StrUtil.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
-                .apply(Validator.isNotEmpty(params.get("beginTime")),
+                .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
+                .apply(StringUtils.isNotEmpty(params.get("beginTime")),
                         "date_format(oper_time,'%y%m%d') >= date_format({0},'%y%m%d')",
                         params.get("beginTime"))
-                .apply(Validator.isNotEmpty(params.get("endTime")),
+                .apply(StringUtils.isNotEmpty(params.get("endTime")),
                         "date_format(oper_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                         params.get("endTime"));
         return PageUtils.buildDataInfo(page(PageUtils.buildPage("oper_id","desc"), lqw));
@@ -70,7 +69,7 @@
     public List<SysOperLog> selectOperLogList(SysOperLog operLog) {
         Map<String, Object> params = operLog.getParams();
         return list(new LambdaQueryWrapper<SysOperLog>()
-                .like(StrUtil.isNotBlank(operLog.getTitle()),SysOperLog::getTitle,operLog.getTitle())
+                .like(StringUtils.isNotBlank(operLog.getTitle()),SysOperLog::getTitle,operLog.getTitle())
                 .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                         SysOperLog::getBusinessType,operLog.getBusinessType())
                 .func(f -> {
@@ -80,11 +79,11 @@
                 })
                 .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
                         SysOperLog::getStatus,operLog.getStatus())
-                .like(StrUtil.isNotBlank(operLog.getOperName()),SysOperLog::getOperName,operLog.getOperName())
-                .apply(Validator.isNotEmpty(params.get("beginTime")),
+                .like(StringUtils.isNotBlank(operLog.getOperName()),SysOperLog::getOperName,operLog.getOperName())
+                .apply(StringUtils.isNotEmpty(params.get("beginTime")),
                         "date_format(oper_time,'%y%m%d') >= date_format({0},'%y%m%d')",
                         params.get("beginTime"))
-                .apply(Validator.isNotEmpty(params.get("endTime")),
+                .apply(StringUtils.isNotEmpty(params.get("endTime")),
                         "date_format(oper_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                         params.get("endTime"))
                 .orderByDesc(SysOperLog::getOperId));
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java
new file mode 100644
index 0000000..5a6e8de
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java
@@ -0,0 +1,175 @@
+package com.ruoyi.system.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
+import com.ruoyi.common.core.page.PagePlus;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.oss.constant.CloudConstant;
+import com.ruoyi.system.domain.SysOssConfig;
+import com.ruoyi.system.domain.bo.SysOssConfigBo;
+import com.ruoyi.system.domain.vo.SysOssConfigVo;
+import com.ruoyi.system.mapper.SysOssConfigMapper;
+import com.ruoyi.system.service.ISysOssConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 浜戝瓨鍌ㄩ厤缃甋ervice涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@Service
+public class SysOssConfigServiceImpl extends ServicePlusImpl<SysOssConfigMapper, SysOssConfig, SysOssConfigVo> implements ISysOssConfigService {
+
+	private final RedisCache redisCache;
+
+	/**
+	 * 椤圭洰鍚姩鏃讹紝鍒濆鍖栧弬鏁板埌缂撳瓨锛屽姞杞介厤缃被
+	 */
+	@PostConstruct
+	public void init() {
+		List<SysOssConfig> list = list();
+		for (SysOssConfig config : list) {
+			String configKey = config.getConfigKey();
+			if ("0".equals(config.getStatus())) {
+				redisCache.setCacheObject(CloudConstant.CACHE_CONFIG_KEY, configKey);
+			}
+			setConfigCache(true, config);
+		}
+	}
+
+    @Override
+    public SysOssConfigVo queryById(Integer ossConfigId){
+        return getVoById(ossConfigId);
+    }
+
+    @Override
+    public TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo) {
+        PagePlus<SysOssConfig, SysOssConfigVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
+        return PageUtils.buildDataInfo(result);
+    }
+
+
+    private LambdaQueryWrapper<SysOssConfig> buildQueryWrapper(SysOssConfigBo bo) {
+        LambdaQueryWrapper<SysOssConfig> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getConfigKey()), SysOssConfig::getConfigKey, bo.getConfigKey());
+        lqw.like(StringUtils.isNotBlank(bo.getBucketName()), SysOssConfig::getBucketName, bo.getBucketName());
+		lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysOssConfig::getStatus, bo.getStatus());
+		return lqw;
+    }
+
+    @Override
+    public Boolean insertByBo(SysOssConfigBo bo) {
+        SysOssConfig config = BeanUtil.toBean(bo, SysOssConfig.class);
+        validEntityBeforeSave(config);
+		return setConfigCache(save(config), config);
+    }
+
+    @Override
+    public Boolean updateByBo(SysOssConfigBo bo) {
+        SysOssConfig config = BeanUtil.toBean(bo, SysOssConfig.class);
+        validEntityBeforeSave(config);
+		return setConfigCache(updateById(config), config);
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(SysOssConfig entity){
+		if (StringUtils.isNotEmpty(entity.getConfigKey())
+			&& UserConstants.NOT_UNIQUE.equals(checkConfigKeyUnique(entity))) {
+			throw new ServiceException("鎿嶄綔閰嶇疆'" + entity.getConfigKey() + "'澶辫触, 閰嶇疆key宸插瓨鍦�!");
+		}
+    }
+
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+    	if(isValid) {
+			if (CollUtil.containsAny(ids, CloudConstant.SYSTEM_DATA_IDS)) {
+				throw new ServiceException("绯荤粺鍐呯疆, 涓嶅彲鍒犻櫎!");
+			}
+		}
+        boolean flag = removeByIds(ids);
+    	if (flag) {
+			for (Long configId : ids) {
+				SysOssConfig config = getById(configId);
+				redisCache.deleteObject(getCacheKey(config.getConfigKey()));
+			}
+		}
+    	return flag;
+    }
+
+	/**
+	 * 鍒ゆ柇configKey鏄惁鍞竴
+	 */
+	private String checkConfigKeyUnique(SysOssConfig sysOssConfig) {
+		long ossConfigId = StringUtils.isNull(sysOssConfig.getOssConfigId()) ? -1L : sysOssConfig.getOssConfigId();
+		SysOssConfig info = getOne(new LambdaQueryWrapper<SysOssConfig>()
+			.select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey)
+			.eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey()));
+		if (StringUtils.isNotNull(info) && info.getOssConfigId() != ossConfigId) {
+			return UserConstants.NOT_UNIQUE;
+		}
+		return UserConstants.UNIQUE;
+	}
+
+	/**
+	 * 鍚敤绂佺敤鐘舵��
+	 */
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public int updateOssConfigStatus(SysOssConfigBo bo) {
+		SysOssConfig sysOssConfig = BeanUtil.toBean(bo, SysOssConfig.class);
+		int row = baseMapper.update(null, new LambdaUpdateWrapper<SysOssConfig>()
+			.set(SysOssConfig::getStatus, "1"));
+		row += baseMapper.updateById(sysOssConfig);
+		if (row > 0) {
+			redisCache.setCacheObject(CloudConstant.CACHE_CONFIG_KEY, sysOssConfig.getConfigKey());
+		}
+		return row;
+	}
+
+	/**
+	 * 璁剧疆cache key
+	 *
+	 * @param configKey 鍙傛暟閿�
+	 * @return 缂撳瓨閿甼ey
+	 */
+	private String getCacheKey(String configKey) {
+		return CloudConstant.SYS_OSS_KEY + configKey;
+	}
+
+	/**
+	 * 濡傛灉鎿嶄綔鎴愬姛 鍒欐洿鏂扮紦瀛�
+	 * @param flag 鎿嶄綔鐘舵��
+	 * @param config 閰嶇疆
+	 * @return 杩斿洖鎿嶄綔鐘舵��
+	 */
+	private boolean setConfigCache(boolean flag, SysOssConfig config) {
+		if (flag) {
+			redisCache.setCacheObject(
+				getCacheKey(config.getConfigKey()),
+				JsonUtils.toJsonString(config));
+		}
+		return flag;
+	}
+}
diff --git a/ruoyi-oss/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
similarity index 71%
rename from ruoyi-oss/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
rename to ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
index 5c34a5c..13a2220 100644
--- a/ruoyi-oss/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
@@ -1,21 +1,21 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.PagePlus;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.oss.entity.UploadResult;
 import com.ruoyi.oss.factory.OssFactory;
-import com.ruoyi.oss.service.ICloudStorageService;
-import com.ruoyi.system.domain.bo.SysOssBo;
+import com.ruoyi.oss.service.ICloudStorageStrategy;
 import com.ruoyi.system.domain.SysOss;
+import com.ruoyi.system.domain.bo.SysOssBo;
+import com.ruoyi.system.domain.vo.SysOssVo;
 import com.ruoyi.system.mapper.SysOssMapper;
 import com.ruoyi.system.service.ISysOssService;
-import com.ruoyi.system.domain.vo.SysOssVo;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -41,27 +41,27 @@
 	private LambdaQueryWrapper<SysOss> buildQueryWrapper(SysOssBo bo) {
 		Map<String, Object> params = bo.getParams();
 		LambdaQueryWrapper<SysOss> lqw = Wrappers.lambdaQuery();
-		lqw.like(StrUtil.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName());
-		lqw.like(StrUtil.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName());
-		lqw.eq(StrUtil.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix());
-		lqw.eq(StrUtil.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl());
+		lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName());
+		lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName());
+		lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix());
+		lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl());
 		lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
 			SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
-		lqw.eq(StrUtil.isNotBlank(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy());
-		lqw.eq(StrUtil.isNotBlank(bo.getService()), SysOss::getService, bo.getService());
+		lqw.eq(StringUtils.isNotBlank(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy());
+		lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService());
 		return lqw;
 	}
 
 	@Override
 	public SysOss upload(MultipartFile file) {
 		String originalfileName = file.getOriginalFilename();
-		String suffix = StrUtil.sub(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
-		ICloudStorageService storage = OssFactory.instance();
+		String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
+		ICloudStorageStrategy storage = OssFactory.instance();
 		UploadResult uploadResult;
 		try {
 			uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
 		} catch (IOException e) {
-			throw new CustomException("鏂囦欢璇诲彇寮傚父!!!", e);
+			throw new ServiceException(e.getMessage());
 		}
 		// 淇濆瓨鏂囦欢淇℃伅
 		SysOss oss = new SysOss()
@@ -81,7 +81,7 @@
 		}
 		List<SysOss> list = listByIds(ids);
 		for (SysOss sysOss : list) {
-			ICloudStorageService storage = OssFactory.instance(sysOss.getService());
+			ICloudStorageStrategy storage = OssFactory.instance(sysOss.getService());
 			storage.delete(sysOss.getUrl());
 		}
 		return removeByIds(ids);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
index 6660431..30d4075 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
@@ -1,13 +1,12 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysPost;
 import com.ruoyi.system.domain.SysUserPost;
 import com.ruoyi.system.mapper.SysPostMapper;
@@ -33,9 +32,9 @@
     @Override
     public TableDataInfo<SysPost> selectPagePostList(SysPost post) {
         LambdaQueryWrapper<SysPost> lqw = new LambdaQueryWrapper<SysPost>()
-                .like(StrUtil.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode())
-                .eq(StrUtil.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus())
-                .like(StrUtil.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName());
+                .like(StringUtils.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode())
+                .eq(StringUtils.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus())
+                .like(StringUtils.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName());
         return PageUtils.buildDataInfo(page(PageUtils.buildPage(),lqw));
     }
 
@@ -48,9 +47,9 @@
     @Override
     public List<SysPost> selectPostList(SysPost post) {
         return list(new LambdaQueryWrapper<SysPost>()
-                .like(StrUtil.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode())
-                .eq(StrUtil.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus())
-                .like(StrUtil.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName()));
+                .like(StringUtils.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode())
+                .eq(StringUtils.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus())
+                .like(StringUtils.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName()));
     }
 
     /**
@@ -93,10 +92,10 @@
      */
     @Override
     public String checkPostNameUnique(SysPost post) {
-        Long postId = Validator.isNull(post.getPostId()) ? -1L : post.getPostId();
+        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
         SysPost info = getOne(new LambdaQueryWrapper<SysPost>()
                 .eq(SysPost::getPostName, post.getPostName()).last("limit 1"));
-        if (Validator.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -110,10 +109,10 @@
      */
     @Override
     public String checkPostCodeUnique(SysPost post) {
-        Long postId = Validator.isNull(post.getPostId()) ? -1L : post.getPostId();
+        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
         SysPost info = getOne(new LambdaQueryWrapper<SysPost>()
                 .eq(SysPost::getPostCode, post.getPostCode()).last("limit 1"));
-        if (Validator.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -153,7 +152,7 @@
         for (Long postId : postIds) {
             SysPost post = selectPostById(postId);
             if (countUserPostById(postId) > 0) {
-                throw new CustomException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", post.getPostName()));
+                throw new ServiceException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", post.getPostName()));
             }
         }
         return baseMapper.deleteBatchIds(Arrays.asList(postIds));
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
index 70a33ee..bad0911 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -1,14 +1,14 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.annotation.DataScope;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.system.domain.SysRoleDept;
 import com.ruoyi.system.domain.SysRoleMenu;
@@ -91,7 +91,7 @@
         List<SysRole> perms = baseMapper.selectRolePermissionByUserId(userId);
         Set<String> permsSet = new HashSet<>();
         for (SysRole perm : perms) {
-            if (Validator.isNotNull(perm)) {
+            if (StringUtils.isNotNull(perm)) {
                 permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
             }
         }
@@ -138,10 +138,10 @@
      */
     @Override
     public String checkRoleNameUnique(SysRole role) {
-        Long roleId = Validator.isNull(role.getRoleId()) ? -1L : role.getRoleId();
+        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
         SysRole info = getOne(new LambdaQueryWrapper<SysRole>()
                 .eq(SysRole::getRoleName, role.getRoleName()).last("limit 1"));
-        if (Validator.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -155,10 +155,10 @@
      */
     @Override
     public String checkRoleKeyUnique(SysRole role) {
-        Long roleId = Validator.isNull(role.getRoleId()) ? -1L : role.getRoleId();
+        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
         SysRole info = getOne(new LambdaQueryWrapper<SysRole>()
                 .eq(SysRole::getRoleKey, role.getRoleKey()).last("limit 1"));
-        if (Validator.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -171,8 +171,8 @@
      */
     @Override
     public void checkRoleAllowed(SysRole role) {
-        if (Validator.isNotNull(role.getRoleId()) && role.isAdmin()) {
-            throw new CustomException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳瑙掕壊");
+        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) {
+            throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳瑙掕壊");
         }
     }
 
@@ -316,7 +316,7 @@
             checkRoleAllowed(new SysRole(roleId));
             SysRole role = selectRoleById(roleId);
             if (countUserRoleByRoleId(roleId) > 0) {
-                throw new CustomException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", role.getRoleName()));
+                throw new ServiceException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", role.getRoleName()));
             }
         }
         List<Long> ids = Arrays.asList(roleIds);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
index 1dec949..6a41cb6 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
@@ -1,8 +1,7 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
 import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysUserOnline;
 import com.ruoyi.system.service.ISysUserOnlineService;
 import org.springframework.stereotype.Service;
@@ -23,7 +22,7 @@
      */
     @Override
     public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user) {
-        if (StrUtil.equals(ipaddr, user.getIpaddr())) {
+        if (StringUtils.equals(ipaddr, user.getIpaddr())) {
             return loginUserToUserOnline(user);
         }
         return null;
@@ -38,7 +37,7 @@
      */
     @Override
     public SysUserOnline selectOnlineByUserName(String userName, LoginUser user) {
-        if (StrUtil.equals(userName, user.getUsername())) {
+        if (StringUtils.equals(userName, user.getUsername())) {
             return loginUserToUserOnline(user);
         }
         return null;
@@ -54,7 +53,7 @@
      */
     @Override
     public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user) {
-        if (StrUtil.equals(ipaddr, user.getIpaddr()) && StrUtil.equals(userName, user.getUsername())) {
+        if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) {
             return loginUserToUserOnline(user);
         }
         return null;
@@ -68,7 +67,7 @@
      */
     @Override
     public SysUserOnline loginUserToUserOnline(LoginUser user) {
-        if (Validator.isNull(user) || Validator.isNull(user.getUser())) {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUser())) {
             return null;
         }
         SysUserOnline sysUserOnline = new SysUserOnline();
@@ -79,7 +78,7 @@
         sysUserOnline.setBrowser(user.getBrowser());
         sysUserOnline.setOs(user.getOs());
         sysUserOnline.setLoginTime(user.getLoginTime());
-        if (Validator.isNotNull(user.getUser().getDept())) {
+        if (StringUtils.isNotNull(user.getUser().getDept())) {
             sysUserOnline.setDeptName(user.getUser().getDept().getDeptName());
         }
         return sysUserOnline;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
index ffaecd6..3ece47e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -1,6 +1,5 @@
 package com.ruoyi.system.service.impl;
 
-import cn.hutool.core.lang.Validator;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.ruoyi.common.annotation.DataScope;
@@ -9,9 +8,10 @@
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.PageUtils;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.SysPost;
 import com.ruoyi.system.domain.SysUserPost;
 import com.ruoyi.system.domain.SysUserRole;
@@ -128,7 +128,7 @@
         for (SysRole role : list) {
             idsStr.append(role.getRoleName()).append(",");
         }
-        if (Validator.isNotEmpty(idsStr.toString())) {
+        if (StringUtils.isNotEmpty(idsStr.toString())) {
             return idsStr.substring(0, idsStr.length() - 1);
         }
         return idsStr.toString();
@@ -147,7 +147,7 @@
         for (SysPost post : list) {
             idsStr.append(post.getPostName()).append(",");
         }
-        if (Validator.isNotEmpty(idsStr.toString())) {
+        if (StringUtils.isNotEmpty(idsStr.toString())) {
             return idsStr.substring(0, idsStr.length() - 1);
         }
         return idsStr.toString();
@@ -176,11 +176,11 @@
      */
     @Override
     public String checkPhoneUnique(SysUser user) {
-        Long userId = Validator.isNull(user.getUserId()) ? -1L : user.getUserId();
+        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
         SysUser info = getOne(new LambdaQueryWrapper<SysUser>()
                 .select(SysUser::getUserId, SysUser::getPhonenumber)
                 .eq(SysUser::getPhonenumber, user.getPhonenumber()).last("limit 1"));
-        if (Validator.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -194,11 +194,11 @@
      */
     @Override
     public String checkEmailUnique(SysUser user) {
-        Long userId = Validator.isNull(user.getUserId()) ? -1L : user.getUserId();
+        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
         SysUser info = getOne(new LambdaQueryWrapper<SysUser>()
                 .select(SysUser::getUserId, SysUser::getEmail)
                 .eq(SysUser::getEmail, user.getEmail()).last("limit 1"));
-        if (Validator.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
+        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
             return UserConstants.NOT_UNIQUE;
         }
         return UserConstants.UNIQUE;
@@ -211,8 +211,8 @@
      */
     @Override
     public void checkUserAllowed(SysUser user) {
-        if (Validator.isNotNull(user.getUserId()) && user.isAdmin()) {
-            throw new CustomException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳鐢ㄦ埛");
+        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
+            throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳鐢ㄦ埛");
         }
     }
 
@@ -232,6 +232,17 @@
         // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
         insertUserRole(user);
         return rows;
+    }
+
+    /**
+     * 娉ㄥ唽鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+	@Override
+    public boolean registerUser(SysUser user) {
+        return baseMapper.insert(user) > 0;
     }
 
     /**
@@ -340,7 +351,7 @@
      */
     public void insertUserRole(SysUser user) {
         Long[] roles = user.getRoleIds();
-        if (Validator.isNotNull(roles)) {
+        if (StringUtils.isNotNull(roles)) {
             // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
             List<SysUserRole> list = new ArrayList<SysUserRole>();
             for (Long roleId : roles) {
@@ -362,7 +373,7 @@
      */
     public void insertUserPost(SysUser user) {
         Long[] posts = user.getPostIds();
-        if (Validator.isNotNull(posts)) {
+        if (StringUtils.isNotNull(posts)) {
             // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
             List<SysUserPost> list = new ArrayList<SysUserPost>();
             for (Long postId : posts) {
@@ -384,7 +395,7 @@
      * @param roleIds 瑙掕壊缁�
      */
     public void insertUserRole(Long userId, Long[] roleIds) {
-        if (Validator.isNotNull(roleIds)) {
+        if (StringUtils.isNotNull(roleIds)) {
             // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
             List<SysUserRole> list = new ArrayList<SysUserRole>();
             for (Long roleId : roleIds) {
@@ -445,8 +456,8 @@
      */
     @Override
     public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
-        if (Validator.isNull(userList) || userList.size() == 0) {
-            throw new CustomException("瀵煎叆鐢ㄦ埛鏁版嵁涓嶈兘涓虹┖锛�");
+        if (StringUtils.isNull(userList) || userList.size() == 0) {
+            throw new ServiceException("瀵煎叆鐢ㄦ埛鏁版嵁涓嶈兘涓虹┖锛�");
         }
         int successNum = 0;
         int failureNum = 0;
@@ -457,7 +468,7 @@
             try {
                 // 楠岃瘉鏄惁瀛樺湪杩欎釜鐢ㄦ埛
                 SysUser u = baseMapper.selectUserByUserName(user.getUserName());
-                if (Validator.isNull(u)) {
+                if (StringUtils.isNull(u)) {
                     user.setPassword(SecurityUtils.encryptPassword(password));
                     user.setCreateBy(operName);
                     this.insertUser(user);
@@ -481,7 +492,7 @@
         }
         if (failureNum > 0) {
             failureMsg.insert(0, "寰堟姳姝夛紝瀵煎叆澶辫触锛佸叡 " + failureNum + " 鏉℃暟鎹牸寮忎笉姝g‘锛岄敊璇涓嬶細");
-            throw new CustomException(failureMsg.toString());
+            throw new ServiceException(failureMsg.toString());
         } else {
             successMsg.insert(0, "鎭枩鎮紝鏁版嵁宸插叏閮ㄥ鍏ユ垚鍔燂紒鍏� " + successNum + " 鏉★紝鏁版嵁濡備笅锛�");
         }
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml
new file mode 100644
index 0000000..77dc40e
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysOssConfigMapper">
+
+    <resultMap type="com.ruoyi.system.domain.SysOssConfig" id="SysOssConfigResult">
+        <result property="ossConfigId" column="oss_config_id"/>
+        <result property="configKey" column="config_key"/>
+        <result property="accessKey" column="access_key"/>
+        <result property="secretKey" column="secret_key"/>
+        <result property="bucketName" column="bucket_name"/>
+        <result property="prefix" column="prefix"/>
+        <result property="endpoint" column="endpoint"/>
+        <result property="isHttps" column="is_https"/>
+        <result property="region" column="region"/>
+        <result property="status" column="status"/>
+        <result property="ext1" column="ext1"/>
+        <result property="createBy" column="create_by"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="remark" column="remark"/>
+    </resultMap>
+
+
+</mapper>
diff --git a/ruoyi-oss/src/main/resources/mapper/system/SysOssMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml
similarity index 100%
rename from ruoyi-oss/src/main/resources/mapper/system/SysOssMapper.xml
rename to ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml
diff --git a/ruoyi-ui/bin/run-web.bat b/ruoyi-ui/bin/run-web.bat
index a938e89..3e209d7 100644
--- a/ruoyi-ui/bin/run-web.bat
+++ b/ruoyi-ui/bin/run-web.bat
@@ -1,6 +1,6 @@
 @echo off
 echo.
-echo [信息] 使用 Vue 运行 Web 工程。
+echo [锟斤拷息] 使锟斤拷 Vue CLI 锟斤拷锟斤拷锟斤拷锟斤拷 Web 锟斤拷锟教★拷
 echo.
 
 %~d0
@@ -9,4 +9,4 @@
 cd ..
 npm run dev
 
-pause
\ No newline at end of file
+pause
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index c980bab..604d964 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -1,6 +1,6 @@
 {
   "name": "ruoyi-vue-plus",
-  "version": "2.6.0",
+  "version": "3.0.0",
   "description": "RuoYi-Vue-Plus鍚庡彴绠$悊绯荤粺",
   "author": "LionLi",
   "license": "MIT",
@@ -41,7 +41,7 @@
     "clipboard": "2.0.6",
     "core-js": "3.8.1",
     "echarts": "4.9.0",
-    "element-ui": "2.15.3",
+    "element-ui": "2.15.5",
     "file-saver": "2.0.4",
     "fuse.js": "6.4.3",
     "highlight.js": "9.18.5",
diff --git a/ruoyi-ui/src/api/demo/demo.js b/ruoyi-ui/src/api/demo/demo.js
index c7195af..04d4025 100644
--- a/ruoyi-ui/src/api/demo/demo.js
+++ b/ruoyi-ui/src/api/demo/demo.js
@@ -52,11 +52,3 @@
   })
 }
 
-// 瀵煎嚭娴嬭瘯鍗曡〃
-export function exportDemo(query) {
-  return request({
-    url: '/demo/demo/export',
-    method: 'get',
-    params: query
-  })
-}
diff --git a/ruoyi-ui/src/api/demo/tree.js b/ruoyi-ui/src/api/demo/tree.js
index d597e72..4c7ebc0 100644
--- a/ruoyi-ui/src/api/demo/tree.js
+++ b/ruoyi-ui/src/api/demo/tree.js
@@ -42,12 +42,3 @@
     method: 'delete'
   })
 }
-
-// 瀵煎嚭娴嬭瘯鏍戣〃
-export function exportTree(query) {
-  return request({
-    url: '/demo/tree/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js
index 869cd9f..8b5b6cf 100644
--- a/ruoyi-ui/src/api/login.js
+++ b/ruoyi-ui/src/api/login.js
@@ -15,6 +15,18 @@
   })
 }
 
+// 娉ㄥ唽鏂规硶
+export function register(data) {
+  return request({
+    url: '/register',
+    headers: {
+      isToken: false
+    },
+    method: 'post',
+    data: data
+  })
+}
+
 // 鑾峰彇鐢ㄦ埛璇︾粏淇℃伅
 export function getInfo() {
   return request({
@@ -37,4 +49,4 @@
     url: '/captchaImage',
     method: 'get'
   })
-}
\ No newline at end of file
+}
diff --git a/ruoyi-ui/src/api/monitor/jobLog.js b/ruoyi-ui/src/api/monitor/jobLog.js
index be1fffd..6e0be61 100644
--- a/ruoyi-ui/src/api/monitor/jobLog.js
+++ b/ruoyi-ui/src/api/monitor/jobLog.js
@@ -24,12 +24,3 @@
     method: 'delete'
   })
 }
-
-// 瀵煎嚭璋冨害鏃ュ織
-export function exportJobLog(query) {
-  return request({
-    url: '/monitor/jobLog/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/logininfor.js b/ruoyi-ui/src/api/monitor/logininfor.js
index 383d61f..26a46eb 100644
--- a/ruoyi-ui/src/api/monitor/logininfor.js
+++ b/ruoyi-ui/src/api/monitor/logininfor.js
@@ -24,12 +24,3 @@
     method: 'delete'
   })
 }
-
-// 瀵煎嚭鐧诲綍鏃ュ織
-export function exportLogininfor(query) {
-  return request({
-    url: '/monitor/logininfor/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/operlog.js b/ruoyi-ui/src/api/monitor/operlog.js
index f09b8ed..a04bca8 100644
--- a/ruoyi-ui/src/api/monitor/operlog.js
+++ b/ruoyi-ui/src/api/monitor/operlog.js
@@ -24,12 +24,3 @@
     method: 'delete'
   })
 }
-
-// 瀵煎嚭鎿嶄綔鏃ュ織
-export function exportOperlog(query) {
-  return request({
-    url: '/monitor/operlog/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/config.js b/ruoyi-ui/src/api/system/config.js
index 4c5cb6b..c193284 100644
--- a/ruoyi-ui/src/api/system/config.js
+++ b/ruoyi-ui/src/api/system/config.js
@@ -59,11 +59,3 @@
   })
 }
 
-// 瀵煎嚭鍙傛暟
-export function exportConfig(query) {
-  return request({
-    url: '/system/config/export',
-    method: 'get',
-    params: query
-  })
-}
diff --git a/ruoyi-ui/src/api/system/dict/data.js b/ruoyi-ui/src/api/system/dict/data.js
index d7aca89..6c9eb79 100644
--- a/ruoyi-ui/src/api/system/dict/data.js
+++ b/ruoyi-ui/src/api/system/dict/data.js
@@ -50,12 +50,3 @@
     method: 'delete'
   })
 }
-
-// 瀵煎嚭瀛楀吀鏁版嵁
-export function exportData(query) {
-  return request({
-    url: '/system/dict/data/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/type.js b/ruoyi-ui/src/api/system/dict/type.js
index 2f0532d..a0254ba 100644
--- a/ruoyi-ui/src/api/system/dict/type.js
+++ b/ruoyi-ui/src/api/system/dict/type.js
@@ -51,15 +51,6 @@
   })
 }
 
-// 瀵煎嚭瀛楀吀绫诲瀷
-export function exportType(query) {
-  return request({
-    url: '/system/dict/type/export',
-    method: 'get',
-    params: query
-  })
-}
-
 // 鑾峰彇瀛楀吀閫夋嫨妗嗗垪琛�
 export function optionselect() {
   return request({
diff --git a/ruoyi-ui/src/api/system/oss.js b/ruoyi-ui/src/api/system/oss.js
index 39be597..965f137 100644
--- a/ruoyi-ui/src/api/system/oss.js
+++ b/ruoyi-ui/src/api/system/oss.js
@@ -16,3 +16,14 @@
     method: 'delete'
   })
 }
+
+export function changePreviewListResource(previewListResource) {
+  const data = {
+    previewListResource
+  }
+  return request({
+    url: '/system/oss/changePreviewListResource',
+    method: 'put',
+    data: data
+  })
+}
diff --git a/ruoyi-ui/src/api/system/ossConfig.js b/ruoyi-ui/src/api/system/ossConfig.js
new file mode 100644
index 0000000..2c6ae0c
--- /dev/null
+++ b/ruoyi-ui/src/api/system/ossConfig.js
@@ -0,0 +1,58 @@
+import request from '@/utils/request'
+
+// 鏌ヨ浜戝瓨鍌ㄩ厤缃垪琛�
+export function listOssConfig(query) {
+  return request({
+    url: '/system/oss/config/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ浜戝瓨鍌ㄩ厤缃缁�
+export function getOssConfig(ossConfigId) {
+  return request({
+    url: '/system/oss/config/' + ossConfigId,
+    method: 'get'
+  })
+}
+
+// 鏂板浜戝瓨鍌ㄩ厤缃�
+export function addOssConfig(data) {
+  return request({
+    url: '/system/oss/config',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼浜戝瓨鍌ㄩ厤缃�
+export function updateOssConfig(data) {
+  return request({
+    url: '/system/oss/config',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎浜戝瓨鍌ㄩ厤缃�
+export function delOssConfig(ossConfigId) {
+  return request({
+    url: '/system/oss/config/' + ossConfigId,
+    method: 'delete'
+  })
+}
+
+// 鐢ㄦ埛鐘舵�佷慨鏀�
+export function changeOssConfigStatus(ossConfigId, status, configKey) {
+  const data = {
+    ossConfigId,
+    status,
+    configKey
+  }
+  return request({
+    url: '/system/oss/config/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js
index c669ac4..888538e 100644
--- a/ruoyi-ui/src/api/system/role.js
+++ b/ruoyi-ui/src/api/system/role.js
@@ -65,16 +65,6 @@
   })
 }
 
-// 瀵煎嚭瑙掕壊
-export function exportRole(query) {
-  return request({
-    url: '/system/role/export',
-    method: 'get',
-    params: query
-  })
-}
-
-
 // 鏌ヨ瑙掕壊宸叉巿鏉冪敤鎴峰垪琛�
 export function allocatedUserList(query) {
   return request({
diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js
index 37f4eb3..204c26e 100644
--- a/ruoyi-ui/src/api/system/user.js
+++ b/ruoyi-ui/src/api/system/user.js
@@ -44,15 +44,6 @@
   })
 }
 
-// 瀵煎嚭鐢ㄦ埛
-export function exportUser(query) {
-  return request({
-    url: '/system/user/export',
-    method: 'get',
-    params: query
-  })
-}
-
 // 鐢ㄦ埛瀵嗙爜閲嶇疆
 export function resetUserPwd(userId, password) {
   const data = {
@@ -115,14 +106,6 @@
     url: '/system/user/profile/avatar',
     method: 'post',
     data: data
-  })
-}
-
-// 涓嬭浇鐢ㄦ埛瀵煎叆妯℃澘
-export function importTemplate() {
-  return request({
-    url: '/system/user/importTemplate',
-    method: 'get'
   })
 }
 
diff --git a/ruoyi-ui/src/components/Breadcrumb/index.vue b/ruoyi-ui/src/components/Breadcrumb/index.vue
index b313fdd..1fbae5f 100644
--- a/ruoyi-ui/src/components/Breadcrumb/index.vue
+++ b/ruoyi-ui/src/components/Breadcrumb/index.vue
@@ -45,7 +45,7 @@
       if (!name) {
         return false
       }
-      return name.trim() === '棣栭〉'
+      return name.trim() === 'Index'
     },
     handleLink(item) {
       const { redirect, path } = item
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index d07dead..5bc2b6c 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -16,7 +16,7 @@
 import './permission' // permission control
 import { getDicts } from "@/api/system/dict/data";
 import { getConfigKey } from "@/api/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
 import Pagination from "@/components/Pagination";
 // 鑷畾涔夎〃鏍煎伐鍏风粍浠�
 import RightToolbar from "@/components/RightToolbar"
@@ -39,7 +39,6 @@
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.selectDictLabel = selectDictLabel
 Vue.prototype.selectDictLabels = selectDictLabels
-Vue.prototype.download = download
 Vue.prototype.handleTree = handleTree
 
 Vue.prototype.msgSuccess = function (msg) {
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index 98f09ed..381264e 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -44,6 +44,11 @@
     hidden: true
   },
   {
+    path: '/register',
+    component: (resolve) => require(['@/views/register'], resolve),
+    hidden: true
+  },
+  {
     path: '/404',
     component: (resolve) => require(['@/views/error/404'], resolve),
     hidden: true
@@ -61,8 +66,8 @@
       {
         path: 'index',
         component: (resolve) => require(['@/views/index'], resolve),
-        name: '棣栭〉',
-        meta: { title: '棣栭〉', icon: 'dashboard', noCache: true, affix: true }
+        name: 'Index',
+        meta: { title: '棣栭〉', icon: 'dashboard', affix: true }
       }
     ]
   },
@@ -120,6 +125,19 @@
     ]
   },
   {
+    path: '/system/oss-config',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'index',
+        component: (resolve) => require(['@/views/system/oss/config'], resolve),
+        name: 'OssConfig',
+        meta: { title: '閰嶇疆绠$悊', activeMenu: '/system/oss'}
+      }
+    ]
+  },
+  {
     path: '/monitor/job-log',
     component: Layout,
     hidden: true,
diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js
index c6624e3..917f916 100644
--- a/ruoyi-ui/src/store/modules/user.js
+++ b/ruoyi-ui/src/store/modules/user.js
@@ -51,7 +51,7 @@
       return new Promise((resolve, reject) => {
         getInfo().then(res => {
           const user = res.data.user
-          const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
+          const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : user.avatar;
           if (res.data.roles && res.data.roles.length > 0) { // 楠岃瘉杩斿洖鐨剅oles鏄惁鏄竴涓潪绌烘暟缁�
             commit('SET_ROLES', res.data.roles)
             commit('SET_PERMISSIONS', res.data.permissions)
diff --git a/ruoyi-ui/src/utils/download.js b/ruoyi-ui/src/utils/download.js
new file mode 100644
index 0000000..52b07f7
--- /dev/null
+++ b/ruoyi-ui/src/utils/download.js
@@ -0,0 +1,91 @@
+import axios from 'axios'
+import { getToken } from '@/utils/auth'
+
+const mimeMap = {
+  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+  zip: 'application/zip',
+  oss: 'application/octet-stream'
+}
+
+const baseUrl = process.env.VUE_APP_BASE_API
+export function downLoadZip(str, filename) {
+  var url = baseUrl + str
+  axios({
+    method: 'get',
+    url: url,
+    responseType: 'blob',
+    headers: { 'Authorization': 'Bearer ' + getToken() }
+  }).then(res => {
+    resolveBlob(res, mimeMap.zip)
+  })
+}
+
+export function downLoadOss(ossId) {
+  var url = baseUrl + '/system/oss/download/' + ossId
+  axios({
+    method: 'get',
+    url: url,
+    responseType: 'blob',
+    headers: { 'Authorization': 'Bearer ' + getToken() }
+  }).then(res => {
+    resolveBlob(res, mimeMap.oss)
+  })
+}
+
+export function downLoadExcel(url, params) {
+  // get璇锋眰鏄犲皠params鍙傛暟
+  if (params) {
+    let urlparams = url + '?';
+    for (const propName of Object.keys(params)) {
+      const value = params[propName];
+      var part = encodeURIComponent(propName) + "=";
+      if (value !== null && typeof(value) !== "undefined") {
+        if (typeof value === 'object') {
+          for (const key of Object.keys(value)) {
+            if (value[key] !== null && typeof (value[key]) !== 'undefined') {
+              let params = propName + '[' + key + ']';
+              let subPart = encodeURIComponent(params) + '=';
+              urlparams += subPart + encodeURIComponent(value[key]) + '&';
+            }
+          }
+        } else {
+          urlparams += part + encodeURIComponent(value) + "&";
+        }
+      }
+    }
+    urlparams = urlparams.slice(0, -1);
+    url = urlparams;
+  }
+  url = baseUrl + url
+  axios({
+    method: 'get',
+    url: url,
+    responseType: 'blob',
+    headers: { 'Authorization': 'Bearer ' + getToken() }
+  }).then(res => {
+    resolveBlob(res, mimeMap.xlsx)
+  })
+}
+
+/**
+ * 瑙f瀽blob鍝嶅簲鍐呭骞朵笅杞�
+ * @param {*} res blob鍝嶅簲鍐呭
+ * @param {String} mimeType MIME绫诲瀷
+ */
+export function resolveBlob(res, mimeType) {
+  const aLink = document.createElement('a')
+  var blob = new Blob([res.data], { type: mimeType })
+  // //浠巖esponse鐨刪eaders涓幏鍙杅ilename, 鍚庣response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 璁剧疆鐨勬枃浠跺悕;
+  var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
+  var contentDisposition = decodeURI(res.headers['content-disposition'])
+  var result = patt.exec(contentDisposition)
+  var fileName = result[1]
+  fileName = fileName.replace(/\"/g, '')
+  aLink.style.display = 'none'
+  aLink.href = URL.createObjectURL(blob)
+  aLink.setAttribute('download', decodeURI(fileName)) // 璁剧疆涓嬭浇鏂囦欢鍚嶇О
+  document.body.appendChild(aLink)
+  aLink.click()
+  URL.revokeObjectURL(aLink.href);//娓呴櫎寮曠敤
+  document.body.removeChild(aLink);
+}
diff --git a/ruoyi-ui/src/utils/ossdownload.js b/ruoyi-ui/src/utils/ossdownload.js
deleted file mode 100644
index 0b9cf10..0000000
--- a/ruoyi-ui/src/utils/ossdownload.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import axios from 'axios'
-import { getToken } from '@/utils/auth'
-
-const mimeMap = {
-  oss: 'application/octet-stream'
-}
-
-const baseUrl = process.env.VUE_APP_BASE_API
-export function downLoadOss(ossId) {
-  var url = baseUrl + '/system/oss/download/' + ossId
-    axios({
-    method: 'get',
-    url: url,
-    responseType: 'blob',
-    headers: { 'Authorization': 'Bearer ' + getToken() }
-  }).then(res => {
-    resolveBlob(res, mimeMap.oss)
-  })
-}
-/**
- * 瑙f瀽blob鍝嶅簲鍐呭骞朵笅杞�
- * @param {*} res blob鍝嶅簲鍐呭
- * @param {String} mimeType MIME绫诲瀷
- */
-export function resolveBlob(res, mimeType) {
-  const aLink = document.createElement('a')
-  var blob = new Blob([res.data], { type: mimeType })
-  // 浠巖esponse鐨刪eaders涓幏鍙杅ilename, 鍚庣response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 璁剧疆鐨勬枃浠跺悕;
-  var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
-  var contentDisposition = decodeURI(res.headers['content-disposition'])
-  var result = patt.exec(contentDisposition)
-  var fileName = result[1]
-  fileName = fileName.replace(/\"/g, '')
-  aLink.href = URL.createObjectURL(blob)
-  aLink.setAttribute('download', decodeURI(fileName)) // 璁剧疆涓嬭浇鏂囦欢鍚嶇О
-  document.body.appendChild(aLink)
-  aLink.click()
-  document.body.removeChild(aLink);
-}
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index 6a7cbfa..e4418b1 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -28,9 +28,11 @@
       if (value !== null && typeof(value) !== "undefined") {
         if (typeof value === 'object') {
           for (const key of Object.keys(value)) {
-            let params = propName + '[' + key + ']';
-            var subPart = encodeURIComponent(params) + "=";
-            url += subPart + encodeURIComponent(value[key]) + "&";
+            if (value[key] !== null && typeof (value[key]) !== 'undefined') {
+              let params = propName + '[' + key + ']';
+              let subPart = encodeURIComponent(params) + '=';
+              url += subPart + encodeURIComponent(value[key]) + '&';
+            }
           }
         } else {
           url += part + encodeURIComponent(value) + "&";
@@ -64,7 +66,7 @@
           location.href = '/index';
         })
       }).catch(() => {});
-      return Promise.reject('error')
+      return Promise.reject('浠ょ墝楠岃瘉澶辫触')
     } else if (code === 500) {
       Message({
         message: msg,
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
index ac390f5..b426a31 100644
--- a/ruoyi-ui/src/utils/ruoyi.js
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -55,16 +55,15 @@
 
 // 娣诲姞鏃ユ湡鑼冨洿
 export function addDateRange(params, dateRange, propName) {
-	var search = params;
-	search.params = {};
-	if (null != dateRange && '' != dateRange) {
-		if (typeof (propName) === "undefined") {
-			search.params["beginTime"] = dateRange[0];
-			search.params["endTime"] = dateRange[1];
-		} else {
-			search.params["begin" + propName] = dateRange[0];
-			search.params["end" + propName] = dateRange[1];
-		}
+	let search = params;
+	search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
+	dateRange = Array.isArray(dateRange) ? dateRange : [];
+	if (typeof (propName) === 'undefined') {
+		search.params['beginTime'] = dateRange[0];
+		search.params['endTime'] = dateRange[1];
+	} else {
+		search.params['begin' + propName] = dateRange[0];
+		search.params['end' + propName] = dateRange[1];
 	}
 	return search;
 }
@@ -94,11 +93,6 @@
 		})
 	})
 	return actions.join('').substring(0, actions.join('').length - 1);
-}
-
-// 閫氱敤涓嬭浇鏂规硶
-export function download(fileName) {
-	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
 }
 
 // 瀛楃涓叉牸寮忓寲(%s )
diff --git a/ruoyi-ui/src/utils/zipdownload.js b/ruoyi-ui/src/utils/zipdownload.js
deleted file mode 100644
index fff4873..0000000
--- a/ruoyi-ui/src/utils/zipdownload.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import axios from 'axios'
-import { getToken } from '@/utils/auth'
-
-const mimeMap = {
-  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
-  zip: 'application/zip'
-}
-
-const baseUrl = process.env.VUE_APP_BASE_API
-export function downLoadZip(str, filename) {
-  var url = baseUrl + str
-  axios({
-    method: 'get',
-    url: url,
-    responseType: 'blob',
-    headers: { 'Authorization': 'Bearer ' + getToken() }
-  }).then(res => {
-    resolveBlob(res, mimeMap.zip)
-  })
-}
-/**
- * 瑙f瀽blob鍝嶅簲鍐呭骞朵笅杞�
- * @param {*} res blob鍝嶅簲鍐呭
- * @param {String} mimeType MIME绫诲瀷
- */
-export function resolveBlob(res, mimeType) {
-  const aLink = document.createElement('a')
-  var blob = new Blob([res.data], { type: mimeType })
-  // //浠巖esponse鐨刪eaders涓幏鍙杅ilename, 鍚庣response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 璁剧疆鐨勬枃浠跺悕;
-  var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
-  var contentDisposition = decodeURI(res.headers['content-disposition'])
-  var result = patt.exec(contentDisposition)
-  var fileName = result[1]
-  fileName = fileName.replace(/\"/g, '')
-  aLink.href = URL.createObjectURL(blob)
-  aLink.setAttribute('download', fileName) // 璁剧疆涓嬭浇鏂囦欢鍚嶇О
-  document.body.appendChild(aLink)
-  aLink.click()
-  document.body.removeChild(aLink);
-}
diff --git a/ruoyi-ui/src/views/demo/demo/index.vue b/ruoyi-ui/src/views/demo/demo/index.vue
index c2ef2e0..a0d9edc 100644
--- a/ruoyi-ui/src/views/demo/demo/index.vue
+++ b/ruoyi-ui/src/views/demo/demo/index.vue
@@ -169,7 +169,8 @@
 </template>
 
 <script>
-import { listDemo, pageDemo, getDemo, delDemo, addDemo, updateDemo, exportDemo } from "@/api/demo/demo";
+import { listDemo, pageDemo, getDemo, delDemo, addDemo, updateDemo } from "@/api/demo/demo";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Demo",
@@ -360,18 +361,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夋祴璇曞崟琛ㄦ暟鎹」?', "璀﹀憡", {
-        confirmButtonText: "纭畾",
-        cancelButtonText: "鍙栨秷",
-        type: "warning"
-      }).then(() => {
-        this.exportLoading = true;
-        return exportDemo(queryParams);
-      }).then(response => {
-        this.download(response.msg);
-        this.exportLoading = false;
-      })
+      downLoadExcel('/demo/demo/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/demo/tree/index.vue b/ruoyi-ui/src/views/demo/tree/index.vue
index 57b152f..ea54195 100644
--- a/ruoyi-ui/src/views/demo/tree/index.vue
+++ b/ruoyi-ui/src/views/demo/tree/index.vue
@@ -110,7 +110,7 @@
 </template>
 
 <script>
-import { listTree, getTree, delTree, addTree, updateTree, exportTree } from "@/api/demo/tree";
+import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index 31f3379..23c0e05 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -93,6 +93,54 @@
             <span>鏇存柊鏃ュ織</span>
           </div>
           <el-collapse accordion>
+            <el-collapse-item title="v3.0.0 - 2021-8-18">
+              <ol>
+                <li>add [閲嶅ぇ鏇存柊]閲嶅啓 OSS 妯″潡鐩稿叧瀹炵幇 鏀寔鍔ㄦ�侀厤缃�(椤甸潰閰嶇疆)<li>
+                <li>add [閲嶅ぇ鏇存柊]澧炲姞 jackson 瓒呭嚭 JS 鏈�澶ф暟鍊艰嚜鍔ㄨ浆瀛楃涓�(闆姳id搴忓垪鍖�)澶勭悊<li>
+                <li>add [閲嶅ぇ鏇存柊]閲嶅啓 闃查噸鎻愪氦鎷︽埅鍣� 鏀寔鍏ㄥ眬涓庢敞瑙h嚜瀹氫箟 鎷︽埅鏃堕棿閰嶇疆閰嶇疆 浼樺寲閫昏緫<li>
+                <li>add [閲嶅ぇ鏇存柊]鏂板鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�<li>
+                <li>add [閲嶅ぇ鏇存柊]澧炲姞 easyexcel 宸ュ叿绫�<li>
+                <li>add [閲嶅ぇ鏇存柊]闆嗘垚 鎬ц兘鍒嗘瀽鎻掍欢 p6spy 鏇村己鍔茬殑 SQL 鍒嗘瀽<li>
+                <li>add [閲嶅ぇ鏇存柊]澧炲姞 瀹屾暣鍥介檯鍖栬В鍐虫柟妗�<li>
+                <li>add [閲嶅ぇ鏇存柊]鏀寔鑷畾涔夋敞瑙e疄鐜版帴鍙i檺娴�<li>
+                <li>update feign-okhttp 11.0 => 11.2<li>
+                <li>update okhttp 3.19.4 => 4.9.1<li>
+                <li>update minio 8.2.0 => 8.3.0<li>
+                <li>update hutool 5.7.6 => 5.7.7<li>
+                <li>update element-ui 2.15.2 => 2.15.5<li>
+                <li>update springboot admin 2.4.3 => 2.5.0 (鏂板 Quartz 涓撳睘鐩戞帶椤�)<li>
+                <li>add 澧炲姞 admin 鐩戞帶瀹㈡埛绔紑鍏�<li>
+                <li>add 澧炲姞 鍥介檯鍖栨紨绀篸emo<li>
+                <li>update 鏇存柊杞欢鏋舵瀯鍥�<li>
+                <li>update 浼樺寲XSS璺ㄧ珯鑴氭湰杩囨护<li>
+                <li>update 浼樺寲BLOB涓嬭浇鏃舵竻闄RL瀵硅薄寮曠敤<li>
+                <li>update 鏇存柊 闃查噸鎻愪氦鎷︽埅鍣� demo婕旂ず妗堜緥<li>
+                <li>update 鏃ュ父瀛楃涓叉牎楠� 缁熶竴閲嶆瀯鍒� StringUtils 渚夸簬缁存姢鎵╁睍<li>
+                <li>update 淇敼 鑷姩娉ㄥ叆鍣� 鐢ㄦ埛鏈櫥褰曞紓甯告嫤鎴姏鍑鸿鍛� 杩斿洖Null<li>
+                <li>update 閲嶆瀯 缁熶竴浣跨敤 娴佸伐鍏蜂笅杞�<li>
+                <li>update 閲嶅啓 鎵�鏈変笟鍔″鍑� 閫傞厤easyexcel宸ュ叿<li>
+                <li>update 绉诲姩鏂囦欢瀛樺偍涓氬姟鍒� system 妯″潡<li>
+                <li>update 浠g爜鐢熸垚妯℃澘 閫傞厤鏂癳xcel瀵煎嚭<li>
+                <li>update 灏� Actuator 閰嶇疆 绉诲姩鍒板叏灞�閰嶇疆<li>
+                <li>update 缁熶竴闀滃儚鏃跺尯閰嶇疆 绉婚櫎涓绘満鏃堕棿鏄犲皠<li>
+                <li>update 鏇存敼澶氭暟鎹簮妗嗘灦鏇存竻鏅扮殑渚濊禆鍚�<li>
+                <li>update 鏇存柊 闃块噷浜� maven婧� 鏂板湴鍧�<li>
+                <li>update 琛ュ叏鍩虹瀹炰綋 鏂囨。娉ㄨВ<li>
+                <li>update 浠g爜鐢熸垚鏂囨。娉ㄨВ 澧炲姞蹇呭~鍒ゆ柇閰嶇疆<li>
+                <li>update 娉ㄥ叆鍣� insert 澧炲姞 update 瀛楁澶勭悊<li>
+                <li>update 榛樿棣栭〉浣跨敤keep-alive缂撳瓨<li>
+                <li>fix 鐢熶骇minio鍥炴樉闂<li>
+                <li>fix 淇瑙掕壊鍒嗛厤鐢ㄦ埛椤甸潰鎺ユ敹鍙傛暟涓庝紶閫掑弬鏁扮被鍨嬩笉涓�鑷村鑷寸殑閿欒<li>
+                <li>fix 淇浠g爜鐢熸垚 鍒犻櫎鎸夐挳鎶ラ敊 loading 涓嶅彇娑堥棶棰�<li>
+                <li>fix 瑙e喅鐧诲綍鍚庢祻瑙堝櫒鍚庡彴Breadcrumb缁勪欢鎶ラ敊<li>
+                <li>fix 淇DictUtils鏂规硶鎶ラ敊<li>
+                <li>fix 澶村儚涓婁紶 鏈蛋OSS瀛樺偍闂<li>
+                <li>fix oss鍒楄〃 jpeg 涓嶅洖鏄鹃棶棰�<li>
+                <li>fix 淇鎿嶄綔鏃ュ織鏍规嵁鐘舵�佹煡璇㈠紓甯搁棶棰�<li>
+                <li>remove 绉婚櫎鍘熺敓excel宸ュ叿<li>
+                <li>remove 绉婚櫎閫氱敤涓婁紶涓嬭浇鎺ュ彛涓庨厤缃�<li>
+              </ol>
+            </el-collapse-item>
             <el-collapse-item title="v2.6.0 - 2021-7-28">
               <ol>
                 <li>add [閲嶅ぇ鏂板] 澧炲姞 OSS 瀵硅薄瀛樺偍妯″潡</li>
@@ -336,7 +384,7 @@
 import config from '../../package.json'
 
 export default {
-  name: "index",
+  name: "Index",
   data() {
     return {
       // 鐗堟湰鍙�
diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue
index a87cb9d..6c35bd8 100644
--- a/ruoyi-ui/src/views/login.vue
+++ b/ruoyi-ui/src/views/login.vue
@@ -44,6 +44,9 @@
           <span v-if="!loading">鐧� 褰�</span>
           <span v-else>鐧� 褰� 涓�...</span>
         </el-button>
+        <div style="float: right;" v-if="register">
+          <router-link class="link-type" :to="'/register'">绔嬪嵆娉ㄥ唽</router-link>
+        </div>
       </el-form-item>
     </el-form>
     <!--  搴曢儴  -->
@@ -73,15 +76,18 @@
       },
       loginRules: {
         username: [
-          { required: true, trigger: "blur", message: "鐢ㄦ埛鍚嶄笉鑳戒负绌�" }
+          { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勮处鍙�" }
         ],
         password: [
-          { required: true, trigger: "blur", message: "瀵嗙爜涓嶈兘涓虹┖" }
+          { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勫瘑鐮�" }
         ],
-        code: [{ required: true, trigger: "change", message: "楠岃瘉鐮佷笉鑳戒负绌�" }]
+        code: [{ required: true, trigger: "change", message: "璇疯緭鍏ラ獙璇佺爜" }]
       },
       loading: false,
+      // 楠岃瘉鐮佸紑鍏�
       captchaOnOff: true,
+      // 娉ㄥ唽寮�鍏�
+      register: false,
       redirect: undefined
     };
   },
diff --git a/ruoyi-ui/src/views/monitor/job/index.vue b/ruoyi-ui/src/views/monitor/job/index.vue
index 0e0d943..d12e73e 100644
--- a/ruoyi-ui/src/views/monitor/job/index.vue
+++ b/ruoyi-ui/src/views/monitor/job/index.vue
@@ -280,7 +280,8 @@
 </template>
 
 <script>
-import { listJob, getJob, delJob, addJob, updateJob, exportJob, runJob, changeJobStatus } from "@/api/monitor/job";
+import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Job",
@@ -505,18 +506,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm("鏄惁纭瀵煎嚭鎵�鏈夊畾鏃朵换鍔℃暟鎹」?", "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportJob(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/monitor/job/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/monitor/job/log.vue b/ruoyi-ui/src/views/monitor/job/log.vue
index 25db43f..8ce0111 100644
--- a/ruoyi-ui/src/views/monitor/job/log.vue
+++ b/ruoyi-ui/src/views/monitor/job/log.vue
@@ -177,8 +177,9 @@
 </template>
 
 <script>
-import { getJob} from "@/api/monitor/job";
-import { listJobLog, delJobLog, exportJobLog, cleanJobLog } from "@/api/monitor/jobLog";
+import { getJob } from "@/api/monitor/job";
+import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "JobLog",
@@ -310,19 +311,8 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm("鏄惁纭瀵煎嚭鎵�鏈夎皟搴︽棩蹇楁暟鎹」?", "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportJobLog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/monitor/jobLog/export', this.queryParams);
     }
   }
 };
-</script>
\ No newline at end of file
+</script>
diff --git a/ruoyi-ui/src/views/monitor/logininfor/index.vue b/ruoyi-ui/src/views/monitor/logininfor/index.vue
index 07937b4..5d6c051 100644
--- a/ruoyi-ui/src/views/monitor/logininfor/index.vue
+++ b/ruoyi-ui/src/views/monitor/logininfor/index.vue
@@ -119,7 +119,8 @@
 </template>
 
 <script>
-import { list, delLogininfor, cleanLogininfor, exportLogininfor } from "@/api/monitor/logininfor";
+import { list, delLogininfor, cleanLogininfor } from "@/api/monitor/logininfor";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Logininfor",
@@ -228,18 +229,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夋搷浣滄棩蹇楁暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportLogininfor(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/monitor/logininfor/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/monitor/operlog/index.vue b/ruoyi-ui/src/views/monitor/operlog/index.vue
index ff6c798..6462cd2 100644
--- a/ruoyi-ui/src/views/monitor/operlog/index.vue
+++ b/ruoyi-ui/src/views/monitor/operlog/index.vue
@@ -188,7 +188,8 @@
 </template>
 
 <script>
-import { list, delOperlog, cleanOperlog, exportOperlog } from "@/api/monitor/operlog";
+import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Operlog",
@@ -316,18 +317,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夋搷浣滄棩蹇楁暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportOperlog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/monitor/operlog/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue
new file mode 100644
index 0000000..914fb74
--- /dev/null
+++ b/ruoyi-ui/src/views/register.vue
@@ -0,0 +1,208 @@
+<template>
+  <div class="register">
+    <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
+      <h3 class="title">鑻ヤ緷鍚庡彴绠$悊绯荤粺</h3>
+      <el-form-item prop="username">
+        <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="璐﹀彿">
+          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="password">
+        <el-input
+          v-model="registerForm.password"
+          type="password"
+          auto-complete="off"
+          placeholder="瀵嗙爜"
+          @keyup.enter.native="handleRegister"
+        >
+          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="confirmPassword">
+        <el-input
+          v-model="registerForm.confirmPassword"
+          type="password"
+          auto-complete="off"
+          placeholder="纭瀵嗙爜"
+          @keyup.enter.native="handleRegister"
+        >
+          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="code" v-if="captchaOnOff">
+        <el-input
+          v-model="registerForm.code"
+          auto-complete="off"
+          placeholder="楠岃瘉鐮�"
+          style="width: 63%"
+          @keyup.enter.native="handleRegister"
+        >
+          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+        </el-input>
+        <div class="register-code">
+          <img :src="codeUrl" @click="getCode" class="register-code-img"/>
+        </div>
+      </el-form-item>
+      <el-form-item style="width:100%;">
+        <el-button
+          :loading="loading"
+          size="medium"
+          type="primary"
+          style="width:100%;"
+          @click.native.prevent="handleRegister"
+        >
+          <span v-if="!loading">娉� 鍐�</span>
+          <span v-else>娉� 鍐� 涓�...</span>
+        </el-button>
+        <div style="float: right;">
+          <router-link class="link-type" :to="'/login'">浣跨敤宸叉湁璐︽埛鐧诲綍</router-link>
+        </div>
+      </el-form-item>
+    </el-form>
+    <!--  搴曢儴  -->
+    <div class="el-register-footer">
+      <span>Copyright 漏 2018-2021 ruoyi.vip All Rights Reserved.</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getCodeImg, register } from "@/api/login";
+
+export default {
+  name: "Register",
+  data() {
+    const equalToPassword = (rule, value, callback) => {
+      if (this.registerForm.password !== value) {
+        callback(new Error("涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�"));
+      } else {
+        callback();
+      }
+    };
+    return {
+      codeUrl: "",
+      registerForm: {
+        username: "",
+        password: "",
+        confirmPassword: "",
+        code: "",
+        uuid: ""
+      },
+      registerRules: {
+        username: [
+          { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勮处鍙�" },
+          { min: 2, max: 20, message: '鐢ㄦ埛璐﹀彿闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿', trigger: 'blur' }
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勫瘑鐮�" },
+          { min: 5, max: 20, message: '鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿', trigger: 'blur' }
+        ],
+        confirmPassword: [
+          { required: true, trigger: "blur", message: "璇峰啀娆¤緭鍏ユ偍鐨勫瘑鐮�" },
+          { required: true, validator: equalToPassword, trigger: "blur" }
+        ],
+        code: [{ required: true, trigger: "change", message: "璇疯緭鍏ラ獙璇佺爜" }]
+      },
+      loading: false,
+      captchaOnOff: true
+    };
+  },
+  created() {
+    this.getCode();
+  },
+  methods: {
+    getCode() {
+      getCodeImg().then(res => {
+        this.captchaOnOff = res.data.captchaOnOff === undefined ? true : res.data.captchaOnOff;
+        if (this.captchaOnOff) {
+          this.codeUrl = "data:image/gif;base64," + res.data.img;
+          this.registerForm.uuid = res.data.uuid;
+        }
+      });
+    },
+    handleRegister() {
+      this.$refs.registerForm.validate(valid => {
+        if (valid) {
+          this.loading = true;
+          register(this.registerForm).then(res => {
+            const username = this.registerForm.username;
+            this.$alert("<font color='red'>鎭枩浣狅紝鎮ㄧ殑璐﹀彿 " + username + " 娉ㄥ唽鎴愬姛锛�</font>", '绯荤粺鎻愮ず', {
+              dangerouslyUseHTMLString: true
+            }).then(() => {
+              this.$router.push("/login");
+            }).catch(() => {});
+          }).catch(() => {
+            this.loading = false;
+            if (this.captchaOnOff) {
+              this.getCode();
+            }
+          })
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+.register {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  background-image: url("../assets/images/login-background.jpg");
+  background-size: cover;
+}
+.title {
+  margin: 0px auto 30px auto;
+  text-align: center;
+  color: #707070;
+}
+
+.register-form {
+  border-radius: 6px;
+  background: #ffffff;
+  width: 400px;
+  padding: 25px 25px 5px 25px;
+  .el-input {
+    height: 38px;
+    input {
+      height: 38px;
+    }
+  }
+  .input-icon {
+    height: 39px;
+    width: 14px;
+    margin-left: 2px;
+  }
+}
+.register-tip {
+  font-size: 13px;
+  text-align: center;
+  color: #bfbfbf;
+}
+.register-code {
+  width: 33%;
+  height: 38px;
+  float: right;
+  img {
+    cursor: pointer;
+    vertical-align: middle;
+  }
+}
+.el-register-footer {
+  height: 40px;
+  line-height: 40px;
+  position: fixed;
+  bottom: 0;
+  width: 100%;
+  text-align: center;
+  color: #fff;
+  font-family: Arial;
+  font-size: 12px;
+  letter-spacing: 1px;
+}
+.register-code-img {
+  height: 38px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/system/config/index.vue b/ruoyi-ui/src/views/system/config/index.vue
index 25086a9..69d8564 100644
--- a/ruoyi-ui/src/views/system/config/index.vue
+++ b/ruoyi-ui/src/views/system/config/index.vue
@@ -181,7 +181,8 @@
 </template>
 
 <script>
-import { listConfig, getConfig, delConfig, addConfig, updateConfig, exportConfig, refreshCache } from "@/api/system/config";
+import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Config",
@@ -342,18 +343,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夊弬鏁版暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportConfig(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/system/config/export', this.queryParams);
     },
     /** 鍒锋柊缂撳瓨鎸夐挳鎿嶄綔 */
     handleRefreshCache() {
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
index bd46d8b..cd86963 100644
--- a/ruoyi-ui/src/views/system/dict/data.vue
+++ b/ruoyi-ui/src/views/system/dict/data.vue
@@ -183,8 +183,9 @@
 </template>
 
 <script>
-import { listData, getData, delData, addData, updateData, exportData } from "@/api/system/dict/data";
+import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
 import { listType, getType } from "@/api/system/dict/type";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Data",
@@ -388,18 +389,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夋暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportData(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/system/dict/data/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/dict/index.vue b/ruoyi-ui/src/views/system/dict/index.vue
index b80dd37..d7a0b00 100644
--- a/ruoyi-ui/src/views/system/dict/index.vue
+++ b/ruoyi-ui/src/views/system/dict/index.vue
@@ -193,7 +193,8 @@
 </template>
 
 <script>
-import { listType, getType, delType, addType, updateType, exportType, refreshCache } from "@/api/system/dict/type";
+import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Dict",
@@ -346,18 +347,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夌被鍨嬫暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportType(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/system/dict/type/export', this.queryParams);
     },
     /** 鍒锋柊缂撳瓨鎸夐挳鎿嶄綔 */
     handleRefreshCache() {
diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
index 0558718..5e8187a 100644
--- a/ruoyi-ui/src/views/system/menu/index.vue
+++ b/ruoyi-ui/src/views/system/menu/index.vue
@@ -88,7 +88,7 @@
     </el-table>
 
     <!-- 娣诲姞鎴栦慨鏀硅彍鍗曞璇濇 -->
-    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="680px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="100px">
         <el-row>
           <el-col :span="24">
diff --git a/ruoyi-ui/src/views/system/oss/config.vue b/ruoyi-ui/src/views/system/oss/config.vue
new file mode 100644
index 0000000..c6ea3a6
--- /dev/null
+++ b/ruoyi-ui/src/views/system/oss/config.vue
@@ -0,0 +1,414 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="閰嶇疆key" prop="configKey">
+        <el-select v-model="queryParams.configKey" placeholder="璇烽�夋嫨閰嶇疆key" clearable size="small">
+          <el-option
+            v-for="configKey in configKeyOptions"
+            :key="configKey.configKey"
+            :label="configKey.label"
+            :value="configKey.configKey"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="妗跺悕绉�" prop="bucketName">
+        <el-input
+          v-model="queryParams.bucketName"
+          placeholder="璇疯緭鍏ユ《鍚嶇О"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:oss:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:oss:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:oss:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="涓诲缓" align="center" prop="ossConfigId" v-if="false"/>
+      <el-table-column label="閰嶇疆key" align="center" prop="configKey" />
+      <el-table-column label="璁块棶绔欑偣" align="center" prop="endpoint" width="200" />
+      <el-table-column label="妗跺悕绉�" align="center" prop="bucketName" />
+      <el-table-column label="鍓嶇紑" align="center" prop="prefix" />
+      <el-table-column label="鍩�" align="center" prop="region" />
+      <el-table-column label="鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            active-value="0"
+            inactive-value="1"
+            @change="handleStatusChange(scope.row)"
+          ></el-switch>
+        </template>
+      </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="['system:oss:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:oss:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀逛簯瀛樺偍閰嶇疆瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="閰嶇疆key" prop="configKey">
+          <el-select v-model="form.configKey" placeholder="璇烽�夋嫨閰嶇疆key">
+            <el-option
+              v-for="configKey in configKeyOptions"
+              :key="configKey.configKey"
+              :label="configKey.label"
+              :value="configKey.configKey"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="璁块棶绔欑偣" prop="endpoint">
+          <el-input v-model="form.endpoint" placeholder="璇疯緭鍏ヨ闂珯鐐�" />
+        </el-form-item>
+        <el-form-item label="accessKey" prop="accessKey">
+          <el-input v-model="form.accessKey" placeholder="璇疯緭鍏ccessKey" />
+        </el-form-item>
+        <el-form-item label="secretKey" prop="secretKey">
+          <el-input v-model="form.secretKey" placeholder="璇疯緭鍏ョ閽�" />
+        </el-form-item>
+        <el-form-item label="妗跺悕绉�" prop="bucketName">
+          <el-input v-model="form.bucketName" placeholder="璇疯緭鍏ユ《鍚嶇О" />
+        </el-form-item>
+        <el-form-item label="鍓嶇紑" prop="prefix">
+          <el-input v-model="form.prefix" placeholder="璇疯緭鍏ュ墠缂�" />
+        </el-form-item>
+        <el-form-item label="鏄惁HTTPS">
+          <el-radio-group v-model="form.isHttps">
+            <el-radio
+              v-for="dict in isHttpsOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="鍩�" prop="region">
+          <el-input v-model="form.region" placeholder="璇疯緭鍏ュ煙" />
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+
+import {
+  listOssConfig,
+  getOssConfig,
+  delOssConfig,
+  addOssConfig,
+  updateOssConfig,
+  changeOssConfigStatus
+} from "@/api/system/ossConfig";
+
+export default {
+  name: "OssConfig",
+  data() {
+    return {
+      // 鎸夐挳loading
+      buttonLoading: false,
+      // 閬僵灞�
+      loading: true,
+      // 瀵煎嚭閬僵灞�
+      exportLoading: false,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 浜戝瓨鍌ㄩ厤缃〃鏍兼暟鎹�
+      ossConfigList: [],
+      // configKeyOptions
+      configKeyOptions: [],
+      configKeyDatas: [
+        { configKey: "minio", label: "Minio" },
+        { configKey: "qiniu", label: "涓冪墰浜�" },
+        { configKey: "aliyun", label: "闃块噷浜�" },
+        { configKey: "qcloud", label: "鑵捐浜�" },
+      ],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁https瀛楀吀
+      isHttpsOptions: [],
+      // 鐘舵��(0姝e父 1鍋滅敤)瀛楀吀
+      statusOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        configKey: undefined,
+        bucketName: undefined,
+        status: undefined,
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        configKey: [
+          { required: true, message: "configKey涓嶈兘涓虹┖", trigger: "blur" },
+        ],
+        accessKey: [
+          { required: true, message: "accessKey涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 200,
+            message: "accessKey闀垮害蹇呴』浠嬩簬 2 鍜� 100 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        secretKey: [
+          { required: true, message: "secretKey涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 100,
+            message: "secretKey闀垮害蹇呴』浠嬩簬 2 鍜� 100 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        bucketName: [
+          { required: true, message: "bucketName涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 100,
+            message: "bucketName闀垮害蹇呴』浠嬩簬 2 鍜� 100 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+        endpoint: [
+          { required: true, message: "endpoint涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            min: 2,
+            max: 100,
+            message: "endpoint鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 100 涔嬮棿",
+            trigger: "blur",
+          },
+        ],
+      },
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_yes_no").then(response => {
+      this.isHttpsOptions = response.data;
+    });
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.configKeyOptions = this.configKeyDatas;
+  },
+  methods: {
+    /** 鏌ヨ浜戝瓨鍌ㄩ厤缃垪琛� */
+    getList() {
+      this.loading = true;
+      listOssConfig(this.queryParams).then((response) => {
+        this.ossConfigList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        ossConfigId: undefined,
+        configKey: undefined,
+        accessKey: undefined,
+        secretKey: undefined,
+        bucketName: undefined,
+        prefix: undefined,
+        endpoint: undefined,
+        isHttps: "N",
+        region: undefined,
+        status: "1",
+        remark: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.ossConfigId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞浜戝瓨鍌ㄩ厤缃�";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.loading = true;
+      this.reset();
+      const ossConfigId = row.ossConfigId || this.ids;
+      getOssConfig(ossConfigId).then((response) => {
+        this.loading = false;
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼浜戝瓨鍌ㄩ厤缃�";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.buttonLoading = true;
+          if (this.form.ossConfigId != null) {
+            updateOssConfig(this.form).then(response => {
+              this.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          } else {
+            addOssConfig(this.form).then(response => {
+              this.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const ossConfigIds = row.ossConfigId || this.ids;
+      this.$confirm('鏄惁纭鍒犻櫎浜戝瓨鍌ㄩ厤缃紪鍙蜂负"' + ossConfigIds + '"鐨勬暟鎹」?', "璀﹀憡", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning"
+      }).then(() => {
+        this.loading = true;
+        return delOssConfig(ossConfigIds);
+      }).then(() => {
+        this.loading = false;
+        this.getList();
+        this.msgSuccess("鍒犻櫎鎴愬姛");
+      }).finally(() => {
+        this.loading = false;
+      });
+    },
+    // 浜戝瓨鍌ㄩ厤缃姸鎬佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$confirm(
+        '纭瑕�"' + text + '""' + row.configKey + '"閰嶇疆鍚�?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning",
+      }).then(() => {
+        return changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
+      }).then(() => {
+        this.getList()
+        this.msgSuccess(text + "鎴愬姛");
+      }).catch(() => {
+        row.status = row.status === "0" ? "1" : "0";
+      })
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/oss/index.vue b/ruoyi-ui/src/views/system/oss/index.vue
index 1171cc9..2bbbba0 100644
--- a/ruoyi-ui/src/views/system/oss/index.vue
+++ b/ruoyi-ui/src/views/system/oss/index.vue
@@ -96,7 +96,25 @@
           v-hasPermi="['system:oss:remove']"
         >鍒犻櫎</el-button>
       </el-col>
-
+      <el-col :span="1.5">
+        <el-button
+          :type="previewListResource ? 'danger' : 'warning'"
+          plain
+          size="mini"
+          @click="handlePreviewListResource(!previewListResource)"
+          v-hasPermi="['system:oss:edit']"
+        >棰勮寮�鍏� : {{previewListResource ? "绂佺敤" : "鍚敤"}}</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="el-icon-s-operation"
+          size="mini"
+          @click="handleOssConfig"
+          v-hasPermi="['system:oss:list']"
+        >閰嶇疆绠$悊</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -109,12 +127,12 @@
       <el-table-column label="鏂囦欢灞曠ず" align="center" prop="url">
         <template slot-scope="scope">
           <el-image
-            v-if="previewListResource && scope.row.fileSuffix.indexOf('png','jpg','jpeg') > 0"
+            v-if="previewListResource && checkFileSuffix(scope.row.fileSuffix)"
             style="width: 100px; height: 100px;"
             :src="scope.row.url"
             :preview-src-list="[scope.row.url]"/>
           <span v-text="scope.row.url"
-                v-if="scope.row.fileSuffix.indexOf('png','jpg','jpeg') < 0 || !previewListResource"/>
+                v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource"/>
         </template>
       </el-table-column>
       <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
@@ -169,10 +187,8 @@
 </template>
 
 <script>
-import { listOss, delOss } from "@/api/system/oss";
-import { downLoadOss } from "@/utils/ossdownload";
-import { updateConfig } from "@/api/system/config";
-
+import { listOss, delOss, changePreviewListResource } from "@/api/system/oss";
+import { downLoadOss } from "@/utils/download";
 
 export default {
   name: "Oss",
@@ -249,6 +265,12 @@
         this.loading = false;
       });
     },
+    checkFileSuffix(fileSuffix) {
+      let arr = ["png", "jpg", "jpeg"];
+      return arr.some(type => {
+        return fileSuffix.indexOf(type) > -1;
+      });
+    },
     // 鍙栨秷鎸夐挳
     cancel() {
       this.open = false;
@@ -277,6 +299,10 @@
       this.ids = selection.map(item => item.ossId)
       this.single = selection.length!==1
       this.multiple = !selection.length
+    },
+    /** 浠诲姟鏃ュ織鍒楄〃鏌ヨ */
+    handleOssConfig() {
+      this.$router.push({ path: '/system/oss-config/index'})
     },
     /** 鏂囦欢鎸夐挳鎿嶄綔 */
     handleFile() {
@@ -308,14 +334,33 @@
           confirmButtonText: "纭畾",
           cancelButtonText: "鍙栨秷",
           type: "warning"
-        }).then(() => {
-          this.loading = true;
-          return delOss(ossIds);
-        }).then(() => {
-          this.loading = false;
-          this.getList();
-          this.msgSuccess("鍒犻櫎鎴愬姛");
-        }).catch(() => {});
+      }).then(() => {
+        this.loading = true;
+        return delOss(ossIds);
+      }).then(() => {
+        this.loading = false;
+        this.getList();
+        this.msgSuccess("鍒犻櫎鎴愬姛");
+      }).finally(() => {
+        this.loading = false;
+      });
+    },
+    // 棰勮鍒楄〃鍥剧墖鐘舵�佷慨鏀�
+    handlePreviewListResource(previewListResource) {
+      let text = previewListResource ? "鍚敤" : "鍋滅敤";
+      this.$confirm(
+        '纭瑕�"' + text + '""棰勮鍒楄〃鍥剧墖"閰嶇疆鍚�?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning",
+      }).then(() => {
+        return changePreviewListResource(previewListResource);
+      }).then(() => {
+        this.getList()
+        this.msgSuccess(text + "鎴愬姛");
+      }).catch(() => {
+        this.previewListResource = previewListResource !== true;
+      })
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/post/index.vue b/ruoyi-ui/src/views/system/post/index.vue
index 9d15938..f5b77c7 100644
--- a/ruoyi-ui/src/views/system/post/index.vue
+++ b/ruoyi-ui/src/views/system/post/index.vue
@@ -156,7 +156,8 @@
 </template>
 
 <script>
-import { listPost, getPost, delPost, addPost, updatePost, exportPost } from "@/api/system/post";
+import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Post",
@@ -313,18 +314,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夊矖浣嶆暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportPost(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/system/post/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
index 53d4f8d..0057413 100644
--- a/ruoyi-ui/src/views/system/role/index.vue
+++ b/ruoyi-ui/src/views/system/role/index.vue
@@ -259,9 +259,10 @@
 </template>
 
 <script>
-import { listRole, getRole, delRole, addRole, updateRole, exportRole, dataScope, changeRoleStatus } from "@/api/system/role";
+import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus } from "@/api/system/role";
 import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
 import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/dept";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "Role",
@@ -625,18 +626,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夎鑹叉暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportRole(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/system/role/export', this.queryParams);
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/role/selectUser.vue b/ruoyi-ui/src/views/system/role/selectUser.vue
index 14ae0bb..5a97095 100644
--- a/ruoyi-ui/src/views/system/role/selectUser.vue
+++ b/ruoyi-ui/src/views/system/role/selectUser.vue
@@ -64,7 +64,7 @@
   props: {
     // 瑙掕壊缂栧彿
     roleId: {
-      type: Number
+      type: [Number, String]
     }
   },
   data() {
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index 1b97220..3214a72 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -346,11 +346,12 @@
 </template>
 
 <script>
-import { listUser, getUser, delUser, addUser, updateUser, exportUser, resetUserPwd, changeUserStatus, importTemplate } from "@/api/system/user";
+import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/system/user";
 import { getToken } from "@/utils/auth";
 import { treeselect } from "@/api/system/dept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { downLoadExcel } from "@/utils/download";
 
 export default {
   name: "User",
@@ -436,7 +437,8 @@
       // 琛ㄥ崟鏍¢獙
       rules: {
         userName: [
-          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          { min: 2, max: 20, message: '鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿', trigger: 'blur' }
         ],
         nickName: [
           { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" }
@@ -659,18 +661,7 @@
     },
     /** 瀵煎嚭鎸夐挳鎿嶄綔 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('鏄惁纭瀵煎嚭鎵�鏈夌敤鎴锋暟鎹」?', "璀﹀憡", {
-          confirmButtonText: "纭畾",
-          cancelButtonText: "鍙栨秷",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportUser(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      downLoadExcel('/system/user/export', this.queryParams);
     },
     /** 瀵煎叆鎸夐挳鎿嶄綔 */
     handleImport() {
@@ -679,9 +670,7 @@
     },
     /** 涓嬭浇妯℃澘鎿嶄綔 */
     importTemplate() {
-      importTemplate().then(response => {
-        this.download(response.msg);
-      });
+      downLoadExcel('/system/user/importTemplate');
     },
     // 鏂囦欢涓婁紶涓鐞�
     handleFileUploadProgress(event, file, fileList) {
diff --git a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
index 6ed6314..3d1b9ef 100644
--- a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
+++ b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
@@ -77,7 +77,8 @@
         autoCrop: true, // 鏄惁榛樿鐢熸垚鎴浘妗�
         autoCropWidth: 200, // 榛樿鐢熸垚鎴浘妗嗗搴�
         autoCropHeight: 200, // 榛樿鐢熸垚鎴浘妗嗛珮搴�
-        fixedBox: true // 鍥哄畾鎴浘妗嗗ぇ灏� 涓嶅厑璁告敼鍙�
+        fixedBox: true, // 鍥哄畾鎴浘妗嗗ぇ灏� 涓嶅厑璁告敼鍙�
+        filename: ''
       },
       previews: {}
     };
@@ -116,6 +117,7 @@
         reader.readAsDataURL(file);
         reader.onload = () => {
           this.options.img = reader.result;
+          this.options.filename = file.name;
         };
       }
     },
@@ -123,10 +125,11 @@
     uploadImg() {
       this.$refs.cropper.getCropBlob(data => {
         let formData = new FormData();
-        formData.append("avatarfile", data);
+        console.log(this.options.filename)
+        formData.append("avatarfile", data, this.options.filename);
         uploadAvatar(formData).then(response => {
           this.open = false;
-          this.options.img = process.env.VUE_APP_BASE_API + response.data.imgUrl;
+          this.options.img = response.data.imgUrl;
           store.commit('SET_AVATAR', this.options.img);
           this.msgSuccess("淇敼鎴愬姛");
           this.visible = false;
diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/ruoyi-ui/src/views/tool/gen/index.vue
index 28074fe..1b69e21 100644
--- a/ruoyi-ui/src/views/tool/gen/index.vue
+++ b/ruoyi-ui/src/views/tool/gen/index.vue
@@ -180,7 +180,7 @@
 <script>
 import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
 import importTable from "./importTable";
-import { downLoadZip } from "@/utils/zipdownload";
+import { downLoadZip } from "@/utils/download";
 import hljs from "highlight.js/lib/highlight";
 import "highlight.js/styles/github-gist.css";
 hljs.registerLanguage("java", require("highlight.js/lib/languages/java"));
diff --git a/sql/oss.sql b/sql/oss.sql
index 3b20c07..2ecfacf 100644
--- a/sql/oss.sql
+++ b/sql/oss.sql
@@ -16,7 +16,30 @@
     primary key (oss_id)
 ) engine=innodb comment ='OSS浜戝瓨鍌ㄨ〃';
 
-insert into sys_config values(10, 'OSS浜戝瓨鍌ㄦ湇鍔″晢',       'sys.oss.cloudStorageService',      'minio',          'Y', 'admin', sysdate(), '', null, 'OSS浜戝瓨鍌ㄦ湇鍔″晢(qiniu:涓冪墰浜�, aliyun:闃块噷浜�, qcloud:鑵捐浜�, minio: Minio)');
+-- ----------------------------
+-- OSS浜戝瓨鍌ㄥ姩鎬侀厤缃〃
+-- ----------------------------
+drop table if exists sys_oss_config;
+create table sys_oss_config (
+    oss_config_id   bigint(20)   not null auto_increment comment '涓诲缓',
+    config_key      varchar(255)  not null default ''     comment '閰嶇疆key',
+    access_key      varchar(255)            default ''    comment 'accessKey',
+    secret_key      varchar(255)            default ''    comment '绉橀挜',
+    bucket_name     varchar(255)            default ''    comment '妗跺悕绉�',
+    prefix           varchar(255)           default ''     comment '鍓嶇紑',
+    endpoint         varchar(255)           default ''     comment '璁块棶绔欑偣',
+    is_https         char(1)                default 'N'    comment '鏄惁https锛圷=鏄�,N=鍚︼級',
+    region           varchar(255)           default ''     comment '鍩�',
+    status           char(1)                default '1'    comment '鐘舵�侊紙0=姝e父,1=鍋滅敤锛�',
+    ext1             varchar(255)           default ''      comment '鎵╁睍瀛楁',
+    create_by       varchar(64)             default ''     comment '鍒涘缓鑰�',
+    create_time     datetime                default null   comment '鍒涘缓鏃堕棿',
+    update_by       varchar(64)             default ''      comment '鏇存柊鑰�',
+    update_time     datetime                default null    comment '鏇存柊鏃堕棿',
+    remark           varchar(500)           default null    comment '澶囨敞',
+    primary key (oss_config_id)
+) engine=innodb comment='浜戝瓨鍌ㄩ厤缃〃';
+
 insert into sys_config values(11, 'OSS棰勮鍒楄〃璧勬簮寮�鍏�',   'sys.oss.previewListResource',      'true',           'Y', 'admin', sysdate(), '', null, 'true:寮�鍚�, false:鍏抽棴');
 
 insert into sys_menu values('118',  '鏂囦欢绠$悊', '1',   '10', 'oss',     'system/oss/index',      1, 0, 'C', '0', '0', 'system:oss:list',      'upload',       'admin', sysdate(), '', null, '鏂囦欢绠$悊鑿滃崟');
@@ -25,3 +48,10 @@
 insert into sys_menu values('1601', '鏂囦欢涓婁紶', '118', '2', '#', '', 1, 0, 'F', '0', '0', 'system:oss:upload',       '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1602', '鏂囦欢涓嬭浇', '118', '3', '#', '', 1, 0, 'F', '0', '0', 'system:oss:download',     '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1603', '鏂囦欢鍒犻櫎', '118', '4', '#', '', 1, 0, 'F', '0', '0', 'system:oss:remove',       '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1604', '閰嶇疆娣诲姞', '118', '5', '#', '', 1, 0, 'F', '0', '0', 'system:oss:add',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1605', '閰嶇疆缂栬緫', '118', '6', '#', '', 1, 0, 'F', '0', '0', 'system:oss:edit',         '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_oss_config values (1, 'minio',  'ruoyi',            'ruoyi123',        'ruoyi',             '', 'http://localhost:9000',                'N', '',            '0', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
+insert into sys_oss_config values (2, 'qiniu',  'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'http://XXX.XXXX.com',                  'N', 'z0',          '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
+insert into sys_oss_config values (3, 'aliyun', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'http://oss-cn-beijing.aliyuncs.com',   'N', '',            '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
+insert into sys_oss_config values (4, 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1250000000',  '', 'http://cos.ap-beijing.myqcloud.com',   'N', 'ap-beijing',  '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
diff --git a/sql/ry_20210713.sql b/sql/ry_20210731.sql
similarity index 98%
rename from sql/ry_20210713.sql
rename to sql/ry_20210731.sql
index 088960e..d48552e 100644
--- a/sql/ry_20210713.sql
+++ b/sql/ry_20210731.sql
@@ -537,10 +537,11 @@
   primary key (config_id)
 ) engine=innodb auto_increment=100 comment = '鍙傛暟閰嶇疆琛�';
 
-insert into sys_config values(1, '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О', 'sys.index.skinName',            'skin-blue',     'Y', 'admin', sysdate(), '', null, '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
-insert into sys_config values(2, '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',     'sys.user.initPassword',         '123456',        'Y', 'admin', sysdate(), '', null, '鍒濆鍖栧瘑鐮� 123456' );
-insert into sys_config values(3, '涓绘鏋堕〉-渚ц竟鏍忎富棰�',       'sys.index.sideTheme',           'theme-dark',    'Y', 'admin', sysdate(), '', null, '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
-insert into sys_config values(4, '璐﹀彿鑷姪-楠岃瘉鐮佸紑鍏�',       'sys.account.captchaOnOff',      'true',          'Y', 'admin', sysdate(), '', null, '鏄惁寮�鍚櫥褰曢獙璇佺爜鍔熻兘锛坱rue寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(1, '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О',     'sys.index.skinName',            'skin-blue',     'Y', 'admin', sysdate(), '', null, '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
+insert into sys_config values(2, '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',         'sys.user.initPassword',         '123456',        'Y', 'admin', sysdate(), '', null, '鍒濆鍖栧瘑鐮� 123456' );
+insert into sys_config values(3, '涓绘鏋堕〉-渚ц竟鏍忎富棰�',           'sys.index.sideTheme',           'theme-dark',    'Y', 'admin', sysdate(), '', null, '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
+insert into sys_config values(4, '璐﹀彿鑷姪-楠岃瘉鐮佸紑鍏�',           'sys.account.captchaOnOff',      'true',          'Y', 'admin', sysdate(), '', null, '鏄惁寮�鍚獙璇佺爜鍔熻兘锛坱rue寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(5, '璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�', 'sys.account.registerUser',      'false',         'Y', 'admin', sysdate(), '', null, '鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�');
 
 
 -- ----------------------------

--
Gitblit v1.9.3