疯狂的狮子li
2021-11-29 42295ef2ac0a5e78674cf24b62d6834138f0ffdc
Merge remote-tracking branch 'origin/dev' into satoken

# Conflicts:
# pom.xml
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
# ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
# ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
# ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RepeatSubmitAspect.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
# ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
# ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/PermissionService.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java
已添加18个文件
已重命名8个文件
已删除41个文件
已修改140个文件
6994 ■■■■■ 文件已修改
README.md 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/Dockerfile 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-prod.yml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/logback.xml 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/spy.properties 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/pom.xml 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/service/ConfigService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/service/DictService.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/service/LogininforService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/service/OperLogService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/excel/DefautExcelResult.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/excel/ExcelListener.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/excel/ExcelResult.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java 244 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/FeignTestController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java 134 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisPubSubController.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisRateLimiterController.java 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/Swagger3DemoController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/FeignTestService.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/constant/FeignTestConstant.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/package-info.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/package-info.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/resources/mapper/demo/package-info.md 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/resources/mapper/package-info.md 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-monitor-admin/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-dev.yml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-prod.yml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application.yml 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RepeatSubmitAspect.java 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/TLogConfig.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ValidatorConfig.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/mapper/package-info.md 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/java/controller.java.vm 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/constant/OssConstant.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/OssEnumd.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/properties/OssProperties.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/service/IOssStrategy.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractOssStrategy.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunOssStrategy.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioOssStrategy.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudOssStrategy.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuOssStrategy.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java 100 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java 149 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/package-info.md 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/.env.development 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/.env.production 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/.env.staging 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/package.json 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/login.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/monitor/job.js 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/monitor/jobLog.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/monitor/server.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/system/post.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Breadcrumb/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/RightToolbar/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/RuoYi/Doc/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/RuoYi/Git/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/SizeSelect/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/layout/components/Navbar.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/layout/components/Sidebar/Logo.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/layout/components/TagsView/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/layout/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/main.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/plugins/download.js 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/plugins/index.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/plugins/tab.js 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/router/index.js 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/store/modules/permission.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/store/modules/settings.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/store/modules/tagsView.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/utils/dict/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/utils/index.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/utils/request.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/utils/ruoyi.js 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/demo/demo/index.vue 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/index.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/login.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/monitor/job/index.vue 517 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/monitor/job/log.vue 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/monitor/logininfor/index.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/monitor/operlog/index.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/register.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/config/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/dept/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/dict/data.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/dict/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/menu/index.vue 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/post/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/role/authUser.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/role/index.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/role/selectUser.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/authRole.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/index.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/profile/resetPwd.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/profile/userAvatar.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/profile/userInfo.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/tool/gen/editTable.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/vue.config.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/bin/ry.bat 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/docker/docker-compose.yml 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/docker/redis/redis.conf 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/quartz.sql 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/sql/ry_20210908.sql 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -10,12 +10,14 @@
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
RuoYi-Vue-Plus æ˜¯åŸºäºŽ RuoYi-Vue é’ˆå¯¹ `分布式集群` åœºæ™¯å‡çº§(不兼容原框架)
> RuoYi-Vue-Plus æ˜¯åŸºäºŽ RuoYi-Vue é’ˆå¯¹ `分布式集群` åœºæ™¯å‡çº§(不兼容原框架)
> ç³»ç»Ÿæ¼”示: [传送门](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/系统演示?sort_id=4836388)
| åŠŸèƒ½ä»‹ç» | ä½¿ç”¨æŠ€æœ¯ | æ–‡æ¡£åœ°å€ | ç‰¹æ€§æ³¨æ„äº‹é¡¹ |
|---|---|---|---|
| å½“前框架 | RuoYi-Vue-Plus | [RuoYi-Vue-Plus文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) | é‡å†™RuoYi-Vue全方位升级(不兼容原框架) |
| satoken分支 | RuoYi-Vue-Plus-satoken | [satoken分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/) | ä½¿ç”¨satoken重构权限鉴权(仅供学习不推荐上生产) |
| satoken分支 | RuoYi-Vue-Plus-satoken | [satoken分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/) | ä½¿ç”¨satoken重构权限鉴权(公测 å¯å°è¯•上生产) |
| å•体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | å•体应用结构 |
| åŽŸæ¡†æž¶ | RuoYi-Vue | [RuoYi-Vue官网](http://ruoyi.vip/) | å®šæœŸåŒæ­¥éœ€è¦çš„功能 |
| å‰ç«¯å¼€å‘框架 | Vue、Element UI | [Element UI官网](https://element.eleme.cn/#/zh-CN) | |
@@ -28,17 +30,16 @@
| æ•°æ®åº“框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | æ›´å¼ºåŠ²çš„ SQL åˆ†æž |
| å¤šæ•°æ®æºæ¡†æž¶ | dynamic-datasource | [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/content) | æ”¯æŒä¸»ä»Žä¸Žå¤šç§ç±»æ•°æ®åº“异构 |
| åºåˆ—化框架 | Jackson | [Jackson官网](https://github.com/FasterXML/jackson) | ç»Ÿä¸€ä½¿ç”¨ jackson é«˜æ•ˆå¯é  |
| ç½‘络框架 | Feign、OkHttp3 | [Feign官网](https://github.com/OpenFeign/feign) | æŽ¥å£åŒ–管理 HTTP è¯·æ±‚ |
| Redis客户端 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | æ”¯æŒå•机、集群配置 |
| åˆ†å¸ƒå¼é™æµ | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | å…¨å±€ã€è¯·æ±‚IP、集群ID å¤šç§é™æµ |
| åˆ†å¸ƒå¼é” | Lock4j | [Lock4j官网](https://gitee.com/baomidou/lock4j) | æ³¨è§£é”ã€å·¥å…·é” å¤šç§å¤šæ · |
| åˆ†å¸ƒå¼å¹‚ç­‰ | Lock4j | [Lock4j文档](https://gitee.com/baomidou/lock4j) | åŸºäºŽåˆ†å¸ƒå¼é”å®žçް |
| åˆ†å¸ƒå¼å¹‚ç­‰ | Redisson | [Lock4j文档](https://gitee.com/baomidou/lock4j) | æ‹¦æˆªé‡å¤æäº¤ |
| åˆ†å¸ƒå¼æ—¥å¿— | TLog | [TLog文档](https://yomahub.com/tlog/docs) | æ”¯æŒè·Ÿè¸ªé“¾è·¯æ—¥å¿—记录、性能分析、链路排查 |
| åˆ†å¸ƒå¼ä»»åŠ¡è°ƒåº¦ | Xxl-Job | [Xxl-Job官网](https://www.xuxueli.com/xxl-job/) | é«˜æ€§èƒ½ é«˜å¯é  æ˜“扩展 |
| æ–‡ä»¶å­˜å‚¨ | Minio | [Minio文档](https://docs.min.io/) | æœ¬åœ°å­˜å‚¨ |
| æ–‡ä»¶å­˜å‚¨ | ä¸ƒç‰›ã€é˜¿é‡Œã€è…¾è®¯ | [OSS使用文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4359146&doc_id=1469725) | äº‘存储 |
| ç›‘控框架 | SpringBoot-Admin | [SpringBoot-Admin文档](https://codecentric.github.io/spring-boot-admin/current/) | å…¨æ–¹ä½æœåŠ¡ç›‘æŽ§ |
| æ ¡éªŒæ¡†æž¶ | Validation | [Validation文档](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/) | å¢žå¼ºæŽ¥å£å®‰å…¨æ€§ã€ä¸¥è°¨æ€§ |
| æ ¡éªŒæ¡†æž¶ | Validation | [Validation文档](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/) | å¢žå¼ºæŽ¥å£å®‰å…¨æ€§ã€ä¸¥è°¨æ€§ æ”¯æŒå›½é™…化 |
| Excel框架 | Alibaba EasyExcel | [EasyExcel文档](https://www.yuque.com/easyexcel/doc/easyexcel) | æ€§èƒ½ä¼˜å¼‚ æ‰©å±•性强 |
| æ–‡æ¡£æ¡†æž¶ | Knife4j | [Knife4j文档](https://doc.xiaominfo.com/knife4j/documentation/) | ç¾ŽåŒ–接口文档 |
| å·¥å…·ç±»æ¡†æž¶ | Hutool、Lombok | [Hutool文档](https://www.hutool.cn/docs/) | å‡å°‘代码冗余 å¢žåŠ å®‰å…¨æ€§ |
@@ -61,8 +62,7 @@
## è½¯ä»¶æž¶æž„图
![Plus部署架构图](https://images.gitee.com/uploads/images/2021/0729/112230_4295e5ce_1766278.png "Plus部署架构图.png")
![Plus部署架构图](https://images.gitee.com/uploads/images/2021/1112/202137_673ac5d2_1766278.png "Plus部署架构图.png")
## è´¡çŒ®ä»£ç 
欢迎各路英雄豪杰 `PR` ä»£ç  è¯·æäº¤åˆ° `dev` å¼€å‘分支 ç»Ÿä¸€æµ‹è¯•发版
pom.xml
@@ -14,7 +14,7 @@
    <properties>
        <ruoyi-vue-plus.version>3.3.0</ruoyi-vue-plus.version>
        <spring-boot.version>2.5.6</spring-boot.version>
        <spring-boot.version>2.5.7</spring-boot.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
@@ -24,19 +24,17 @@
        <swagger-annotations.version>1.5.22</swagger-annotations.version>
        <poi.version>4.1.2</poi.version>
        <easyexcel.version>2.2.11</easyexcel.version>
        <velocity.version>1.7</velocity.version>
        <velocity.version>2.3</velocity.version>
        <satoken.version>1.28.0</satoken.version>
        <mybatis-plus.version>3.4.3.4</mybatis-plus.version>
        <p6spy.version>3.9.1</p6spy.version>
        <hutool.version>5.7.15</hutool.version>
        <feign.version>3.0.3</feign.version>
        <feign-okhttp.version>11.6</feign-okhttp.version>
        <okhttp.version>4.9.1</okhttp.version>
        <spring-boot-admin.version>2.5.2</spring-boot-admin.version>
        <redisson.version>3.16.3</redisson.version>
        <hutool.version>5.7.16</hutool.version>
        <okhttp.version>4.9.2</okhttp.version>
        <spring-boot-admin.version>2.5.4</spring-boot-admin.version>
        <redisson.version>3.16.4</redisson.version>
        <lock4j.version>2.2.1</lock4j.version>
        <dynamic-ds.version>3.4.1</dynamic-ds.version>
        <tlog.version>1.3.3</tlog.version>
        <tlog.version>1.3.4</tlog.version>
        <xxl-job.version>2.3.0</xxl-job.version>
        <!-- jdk11 ç¼ºå¤±ä¾èµ– jaxb-->
@@ -120,7 +118,7 @@
            <!-- velocity代码生成使用模板 -->
            <dependency>
                <groupId>org.apache.velocity</groupId>
                <artifactId>velocity</artifactId>
                <artifactId>velocity-engine-core</artifactId>
                <version>${velocity.version}</version>
            </dependency>
@@ -172,25 +170,6 @@
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <!-- @deprecated ç”±äºŽä½¿ç”¨äººæ•°è¾ƒå°‘ å†³å®šä¸Ž 3.4.0 ç‰ˆæœ¬ç§»é™¤ -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
                <version>${feign.version}</version>
                <exclusions>
                    <exclusion>
                        <artifactId>feign-core</artifactId>
                        <groupId>io.github.openfeign</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- @deprecated ç”±äºŽä½¿ç”¨äººæ•°è¾ƒå°‘ å†³å®šä¸Ž 3.4.0 ç‰ˆæœ¬ç§»é™¤ -->
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-okhttp</artifactId>
                <version>${feign-okhttp.version}</version>
            </dependency>
            <dependency>
@@ -253,21 +232,8 @@
            <dependency>
                <groupId>com.yomahub</groupId>
                <artifactId>tlog-feign</artifactId>
                <version>${tlog.version}</version>
            </dependency>
            <dependency>
                <groupId>com.yomahub</groupId>
                <artifactId>tlog-xxl-job</artifactId>
                <version>${tlog.version}</version>
            </dependency>
            <!-- å®šæ—¶ä»»åŠ¡ @deprecated 3.4.0删除 è¿ç§»è‡³xxl-job -->
            <dependency>
                <groupId>com.ruoyi</groupId>
                <artifactId>ruoyi-quartz</artifactId>
                <version>${ruoyi-vue-plus.version}</version>
            </dependency>
            <!-- å®šæ—¶ä»»åŠ¡ -->
@@ -326,7 +292,6 @@
        <module>ruoyi-admin</module>
        <module>ruoyi-framework</module>
        <module>ruoyi-system</module>
        <module>ruoyi-quartz</module>
        <module>ruoyi-job</module>
        <module>ruoyi-generator</module>
        <module>ruoyi-common</module>
@@ -391,6 +356,7 @@
                <!-- çŽ¯å¢ƒæ ‡è¯†ï¼Œéœ€è¦ä¸Žé…ç½®æ–‡ä»¶çš„åç§°ç›¸å¯¹åº” -->
                <profiles.active>local</profiles.active>
                <logging.level>debug</logging.level>
                <knife4j.production>false</knife4j.production>
                <endpoints.include>'*'</endpoints.include>
            </properties>
        </profile>
@@ -400,6 +366,7 @@
                <!-- çŽ¯å¢ƒæ ‡è¯†ï¼Œéœ€è¦ä¸Žé…ç½®æ–‡ä»¶çš„åç§°ç›¸å¯¹åº” -->
                <profiles.active>dev</profiles.active>
                <logging.level>debug</logging.level>
                <knife4j.production>false</knife4j.production>
                <endpoints.include>'*'</endpoints.include>
            </properties>
            <activation>
@@ -412,6 +379,7 @@
            <properties>
                <profiles.active>prod</profiles.active>
                <logging.level>warn</logging.level>
                <knife4j.production>true</knife4j.production>
                <endpoints.include>health, info, logfile</endpoints.include>
            </properties>
        </profile>
ruoyi-admin/Dockerfile
@@ -4,6 +4,7 @@
RUN mkdir -p /ruoyi/server
RUN mkdir -p /ruoyi/server/logs
RUN mkdir -p /ruoyi/server/temp
WORKDIR /ruoyi/server
ruoyi-admin/pom.xml
@@ -41,12 +41,6 @@
            <artifactId>ruoyi-system</artifactId>
        </dependency>
        <!-- å®šæ—¶ä»»åŠ¡ @deprecated 3.4.0删除 è¿ç§»è‡³xxl-job -->
<!--        <dependency>-->
<!--            <groupId>com.ruoyi</groupId>-->
<!--            <artifactId>ruoyi-quartz</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-job</artifactId>
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -2,6 +2,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
/**
 * å¯åŠ¨ç¨‹åº
@@ -14,7 +15,9 @@
    public static void main(String[] args) {
        System.setProperty("spring.devtools.restart.enabled", "false");
        SpringApplication.run(RuoYiApplication.class, args);
        SpringApplication application = new SpringApplication(RuoYiApplication.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
        System.out.println("(♥◠‿◠)ノ゙  RuoYi-Vue-Plus启动成功   áƒš(´ڡ`ლ)゙");
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
@@ -43,7 +43,7 @@
    @ApiOperation("导出系统访问记录列表")
    @Log(title = "登录日志", businessType = BusinessType.EXPORT)
    @SaCheckPermission("monitor:logininfor:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysLogininfor logininfor, HttpServletResponse response) {
        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
        ExcelUtil.exportExcel(list, "登录日志", SysLogininfor.class, response);
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
@@ -43,7 +43,7 @@
    @ApiOperation("导出操作日志记录列表")
    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
    @SaCheckPermission("monitor:operlog:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysOperLog operLog, HttpServletResponse response) {
        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
        ExcelUtil.exportExcel(list, "操作日志", SysOperLog.class, response);
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
@@ -2,7 +2,6 @@
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@@ -13,6 +12,7 @@
import com.ruoyi.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -48,7 +48,7 @@
    @ApiOperation("导出参数配置列表")
    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:config:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysConfig config, HttpServletResponse response) {
        List<SysConfig> list = configService.selectConfigList(config);
        ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response);
@@ -60,7 +60,7 @@
    @ApiOperation("根据参数编号获取详细信息")
    @SaCheckPermission("system:config:query")
    @GetMapping(value = "/{configId}")
    public AjaxResult<SysConfig> getInfo(@PathVariable Long configId) {
    public AjaxResult<SysConfig> getInfo(@ApiParam("参数ID") @PathVariable Long configId) {
        return AjaxResult.success(configService.selectConfigById(configId));
    }
@@ -69,7 +69,7 @@
     */
    @ApiOperation("根据参数键名查询参数值")
    @GetMapping(value = "/configKey/{configKey}")
    public AjaxResult<Void> getConfigKey(@PathVariable String configKey) {
    public AjaxResult<Void> getConfigKey(@ApiParam("参数Key") @PathVariable String configKey) {
        return AjaxResult.success(configService.selectConfigByKey(configKey));
    }
@@ -80,7 +80,6 @@
    @SaCheckPermission("system:config:add")
    @Log(title = "参数管理", businessType = BusinessType.INSERT)
    @PostMapping
    @RepeatSubmit
    public AjaxResult<Void> add(@Validated @RequestBody SysConfig config) {
        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
            return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
@@ -109,7 +108,7 @@
    @SaCheckPermission("system:config:remove")
    @Log(title = "参数管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{configIds}")
    public AjaxResult<Void> remove(@PathVariable Long[] configIds) {
    public AjaxResult<Void> remove(@ApiParam("参数ID串") @PathVariable Long[] configIds) {
        configService.deleteConfigByIds(configIds);
        return success();
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
@@ -1,18 +1,19 @@
package com.ruoyi.web.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
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.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysDeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -53,7 +54,7 @@
    @ApiOperation("查询部门列表(排除节点)")
    @SaCheckPermission("system:dept:list")
    @GetMapping("/list/exclude/{deptId}")
    public AjaxResult<List<SysDept>> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) {
    public AjaxResult<List<SysDept>> excludeChild(@ApiParam("部门ID") @PathVariable(value = "deptId", required = false) Long deptId) {
        List<SysDept> depts = deptService.selectDeptList(new SysDept());
        depts.removeIf(d -> d.getDeptId().equals(deptId)
                || ArrayUtil.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
@@ -66,7 +67,7 @@
    @ApiOperation("根据部门编号获取详细信息")
    @SaCheckPermission("system:dept:query")
    @GetMapping(value = "/{deptId}")
    public AjaxResult<SysDept> getInfo(@PathVariable Long deptId) {
    public AjaxResult<SysDept> getInfo(@ApiParam("部门ID") @PathVariable Long deptId) {
        deptService.checkDeptDataScope(deptId);
        return AjaxResult.success(deptService.selectDeptById(deptId));
    }
@@ -76,7 +77,7 @@
     */
    @ApiOperation("获取部门下拉树列表")
    @GetMapping("/treeselect")
    public AjaxResult<List<TreeSelect>> treeselect(SysDept dept) {
    public AjaxResult<List<Tree<Long>>> treeselect(SysDept dept) {
        List<SysDept> depts = deptService.selectDeptList(dept);
        return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
    }
@@ -86,7 +87,7 @@
     */
    @ApiOperation("加载对应角色部门列表树")
    @GetMapping(value = "/roleDeptTreeselect/{roleId}")
    public AjaxResult<Map<String, Object>> roleDeptTreeselect(@PathVariable("roleId") Long roleId) {
    public AjaxResult<Map<String, Object>> roleDeptTreeselect(@ApiParam("角色ID") @PathVariable("roleId") Long roleId) {
        List<SysDept> depts = deptService.selectDeptList(new SysDept());
        Map<String, Object> ajax = new HashMap<>();
        ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
@@ -134,7 +135,7 @@
    @SaCheckPermission("system:dept:remove")
    @Log(title = "部门管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{deptId}")
    public AjaxResult<Void> remove(@PathVariable Long deptId) {
    public AjaxResult<Void> remove(@ApiParam("部门ID串") @PathVariable Long deptId) {
        if (deptService.hasChildByDeptId(deptId)) {
            return AjaxResult.error("存在下级部门,不允许删除");
        }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
@@ -13,6 +13,7 @@
import com.ruoyi.system.service.ISysDictTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -47,7 +48,7 @@
    @ApiOperation("导出字典数据列表")
    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:dict:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysDictData dictData, HttpServletResponse response) {
        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
        ExcelUtil.exportExcel(list, "字典数据", SysDictData.class, response);
@@ -59,7 +60,7 @@
    @ApiOperation("查询字典数据详细")
    @SaCheckPermission("system:dict:query")
    @GetMapping(value = "/{dictCode}")
    public AjaxResult<SysDictData> getInfo(@PathVariable Long dictCode) {
    public AjaxResult<SysDictData> getInfo(@ApiParam("字典code") @PathVariable Long dictCode) {
        return AjaxResult.success(dictDataService.selectDictDataById(dictCode));
    }
@@ -68,7 +69,7 @@
     */
    @ApiOperation("根据字典类型查询字典数据信息")
    @GetMapping(value = "/type/{dictType}")
    public AjaxResult<List<SysDictData>> dictType(@PathVariable String dictType) {
    public AjaxResult<List<SysDictData>> dictType(@ApiParam("字典类型") @PathVariable String dictType) {
        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
        if (StringUtils.isNull(data)) {
            data = new ArrayList<>();
@@ -105,7 +106,7 @@
    @SaCheckPermission("system:dict:remove")
    @Log(title = "字典类型", businessType = BusinessType.DELETE)
    @DeleteMapping("/{dictCodes}")
    public AjaxResult<Void> remove(@PathVariable Long[] dictCodes) {
    public AjaxResult<Void> remove(@ApiParam("字典code串") @PathVariable Long[] dictCodes) {
        dictDataService.deleteDictDataByIds(dictCodes);
        return success();
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
@@ -12,6 +12,7 @@
import com.ruoyi.system.service.ISysDictTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -44,7 +45,7 @@
    @ApiOperation("导出字典类型列表")
    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:dict:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysDictType dictType, HttpServletResponse response) {
        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
        ExcelUtil.exportExcel(list, "字典类型", SysDictType.class, response);
@@ -56,7 +57,7 @@
    @ApiOperation("查询字典类型详细")
    @SaCheckPermission("system:dict:query")
    @GetMapping(value = "/{dictId}")
    public AjaxResult<SysDictType> getInfo(@PathVariable Long dictId) {
    public AjaxResult<SysDictType> getInfo(@ApiParam("字典ID") @PathVariable Long dictId) {
        return AjaxResult.success(dictTypeService.selectDictTypeById(dictId));
    }
@@ -95,7 +96,7 @@
    @SaCheckPermission("system:dict:remove")
    @Log(title = "字典类型", businessType = BusinessType.DELETE)
    @DeleteMapping("/{dictIds}")
    public AjaxResult<Void> remove(@PathVariable Long[] dictIds) {
    public AjaxResult<Void> remove(@ApiParam("字典ID串") @PathVariable Long[] dictIds) {
        dictTypeService.deleteDictTypeByIds(dictIds);
        return success();
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -10,6 +10,7 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysLoginService;
import com.ruoyi.system.service.SysPermissionService;
import io.swagger.annotations.Api;
@@ -33,13 +34,14 @@
 * @author Lion Li
 */
@Validated
@Api(value = "数据字典信息控制器", tags = {"数据字典信息管理"})
@Api(value = "登录验证控制器", tags = {"登录验证管理"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
public class SysLoginController {
    private final SysLoginService loginService;
    private final ISysMenuService menuService;
    private final ISysUserService userService;
    private final SysPermissionService permissionService;
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
@@ -1,17 +1,18 @@
package com.ruoyi.web.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
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.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysMenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -52,7 +53,7 @@
    @ApiOperation("根据菜单编号获取详细信息")
    @SaCheckPermission("system:menu:query")
    @GetMapping(value = "/{menuId}")
    public AjaxResult<SysMenu> getInfo(@PathVariable Long menuId) {
    public AjaxResult<SysMenu> getInfo(@ApiParam("菜单ID") @PathVariable Long menuId) {
        return AjaxResult.success(menuService.selectMenuById(menuId));
    }
@@ -61,7 +62,7 @@
     */
    @ApiOperation("获取菜单下拉树列表")
    @GetMapping("/treeselect")
    public AjaxResult<List<TreeSelect>> treeselect(SysMenu menu) {
    public AjaxResult<List<Tree<Long>>> treeselect(SysMenu menu) {
        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
        return AjaxResult.success(menuService.buildMenuTreeSelect(menus));
    }
@@ -71,7 +72,7 @@
     */
    @ApiOperation("加载对应角色菜单列表树")
    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
    public AjaxResult<Map<String, Object>> roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
    public AjaxResult<Map<String, Object>> roleMenuTreeselect(@ApiParam("角色ID") @PathVariable("roleId") Long roleId) {
        List<SysMenu> menus = menuService.selectMenuList(getUserId());
        Map<String, Object> ajax = new HashMap<>();
        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
@@ -120,7 +121,7 @@
    @SaCheckPermission("system:menu:remove")
    @Log(title = "菜单管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{menuId}")
    public AjaxResult<Void> remove(@PathVariable("menuId") Long menuId) {
    public AjaxResult<Void> remove(@ApiParam("菜单ID") @PathVariable("menuId") Long menuId) {
        if (menuService.hasChildByMenuId(menuId)) {
            return AjaxResult.error("存在子菜单,不允许删除");
        }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
@@ -13,6 +13,7 @@
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
/**
@@ -45,7 +46,7 @@
    @ApiOperation("根据通知公告编号获取详细信息")
    @SaCheckPermission("system:notice:query")
    @GetMapping(value = "/{noticeId}")
    public AjaxResult<SysNotice> getInfo(@PathVariable Long noticeId) {
    public AjaxResult<SysNotice> getInfo(@ApiParam("公告ID") @PathVariable Long noticeId) {
        return AjaxResult.success(noticeService.selectNoticeById(noticeId));
    }
@@ -78,7 +79,7 @@
    @SaCheckPermission("system:notice:remove")
    @Log(title = "通知公告", businessType = BusinessType.DELETE)
    @DeleteMapping("/{noticeIds}")
    public AjaxResult<Void> remove(@PathVariable Long[] noticeIds) {
    public AjaxResult<Void> remove(@ApiParam("公告ID串") @PathVariable Long[] noticeIds) {
        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java
@@ -15,6 +15,7 @@
import com.ruoyi.system.service.ISysOssConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -56,7 +57,8 @@
    @ApiOperation("获取对象存储配置详细信息")
    @SaCheckPermission("system:oss:query")
    @GetMapping("/{ossConfigId}")
    public AjaxResult<SysOssConfigVo> getInfo(@NotNull(message = "主键不能为空")
    public AjaxResult<SysOssConfigVo> getInfo(@ApiParam("OSS配置ID")
                                              @NotNull(message = "主键不能为空")
                                              @PathVariable("ossConfigId") Integer ossConfigId) {
        return AjaxResult.success(iSysOssConfigService.queryById(ossConfigId));
    }
@@ -92,7 +94,8 @@
    @SaCheckPermission("system:oss:remove")
    @Log(title = "对象存储配置", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ossConfigIds}")
    public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空")
    public AjaxResult<Void> remove(@ApiParam("OSS配置ID串")
                                   @NotEmpty(message = "主键不能为空")
                                   @PathVariable Long[] ossConfigIds) {
        return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true) ? 1 : 0);
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
@@ -17,17 +17,14 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.oss.constant.CloudConstant;
import com.ruoyi.oss.constant.OssConstant;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.domain.SysOss;
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;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@@ -37,6 +34,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
@@ -72,7 +70,7 @@
     */
    @ApiOperation("上传OSS对象存储")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件", dataType = "java.io.File", required = true),
        @ApiImplicitParam(name = "file", value = "文件", dataTypeClass = File.class, required = true),
    })
    @SaCheckPermission("system:oss:upload")
    @Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
@@ -92,7 +90,7 @@
    @ApiOperation("下载OSS对象存储")
    @SaCheckPermission("system:oss:download")
    @GetMapping("/download/{ossId}")
    public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
    public void download(@ApiParam("OSS对象ID") @PathVariable Long ossId, HttpServletResponse response) throws IOException {
        SysOss sysOss = iSysOssService.getById(ossId);
        if (ObjectUtil.isNull(sysOss)) {
            throw new ServiceException("文件数据不存在!");
@@ -120,7 +118,8 @@
    @SaCheckPermission("system:oss:remove")
    @Log(title = "OSS对象存储", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ossIds}")
    public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空")
    public AjaxResult<Void> remove(@ApiParam("OSS对象ID串")
                                   @NotEmpty(message = "主键不能为空")
                                   @PathVariable Long[] ossIds) {
        return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true) ? 1 : 0);
    }
@@ -135,7 +134,7 @@
    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));
            .eq(SysConfig::getConfigKey, OssConstant.PEREVIEW_LIST_RESOURCE_KEY));
        config.setConfigValue(map.get("previewListResource").toString());
        return toAjax(iSysConfigService.updateConfig(config));
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -12,6 +12,7 @@
import com.ruoyi.system.service.ISysPostService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -47,7 +48,7 @@
    @ApiOperation("导出岗位列表")
    @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:post:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysPost post, HttpServletResponse response) {
        List<SysPost> list = postService.selectPostList(post);
        ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response);
@@ -59,7 +60,7 @@
    @ApiOperation("根据岗位编号获取详细信息")
    @SaCheckPermission("system:post:query")
    @GetMapping(value = "/{postId}")
    public AjaxResult<SysPost> getInfo(@PathVariable Long postId) {
    public AjaxResult<SysPost> getInfo(@ApiParam("岗位ID") @PathVariable Long postId) {
        return AjaxResult.success(postService.selectPostById(postId));
    }
@@ -102,7 +103,7 @@
    @SaCheckPermission("system:post:remove")
    @Log(title = "岗位管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{postIds}")
    public AjaxResult<Void> remove(@PathVariable Long[] postIds) {
    public AjaxResult<Void> remove(@ApiParam("岗位ID串") @PathVariable Long[] postIds) {
        return toAjax(postService.deletePostByIds(postIds));
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -18,6 +18,7 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@@ -43,7 +44,7 @@
    @GetMapping
    public AjaxResult<Map<String, Object>> profile() {
        SysUser user = userService.getById(getUserId());
        Map<String,Object> ajax = new HashMap<>();
        Map<String, Object> ajax = new HashMap<>();
        ajax.put("user", user);
        ajax.put("roleGroup", userService.selectUserRoleGroup(user.getUserName()));
        ajax.put("postGroup", userService.selectUserPostGroup(user.getUserName()));
@@ -66,6 +67,7 @@
            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
        }
        user.setUserId(getUserId());
        user.setUserName(null);
        user.setPassword(null);
        if (userService.updateUserProfile(user) > 0) {
            return AjaxResult.success();
@@ -77,6 +79,10 @@
     * é‡ç½®å¯†ç 
     */
    @ApiOperation("重置密码")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "oldPassword", value = "旧密码", paramType = "query", dataTypeClass = String.class),
        @ApiImplicitParam(name = "newPassword", value = "新密码", paramType = "query", dataTypeClass = String.class)
    })
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
    @PutMapping("/updatePwd")
    public AjaxResult<Void> updatePwd(String oldPassword, String newPassword) {
@@ -100,7 +106,7 @@
     */
    @ApiOperation("头像上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "用户头像", dataType = "java.io.File", required = true),
        @ApiImplicitParam(name = "avatarfile", value = "用户头像", dataTypeClass = File.class, required = true),
    })
    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
    @PostMapping("/avatar")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -13,8 +13,7 @@
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -48,7 +47,7 @@
    @ApiOperation("导出角色信息列表")
    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:role:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysRole role, HttpServletResponse response) {
        List<SysRole> list = roleService.selectRoleList(role);
        ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response);
@@ -60,7 +59,7 @@
    @ApiOperation("根据角色编号获取详细信息")
    @SaCheckPermission("system:role:query")
    @GetMapping(value = "/{roleId}")
    public AjaxResult<SysRole> getInfo(@PathVariable Long roleId) {
    public AjaxResult<SysRole> getInfo(@ApiParam("角色ID") @PathVariable Long roleId) {
        roleService.checkRoleDataScope(roleId);
        return AjaxResult.success(roleService.selectRoleById(roleId));
    }
@@ -134,7 +133,7 @@
    @SaCheckPermission("system:role:remove")
    @Log(title = "角色管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{roleIds}")
    public AjaxResult<Void> remove(@PathVariable Long[] roleIds) {
    public AjaxResult<Void> remove(@ApiParam("岗位ID串") @PathVariable Long[] roleIds) {
        return toAjax(roleService.deleteRoleByIds(roleIds));
    }
@@ -183,6 +182,10 @@
     * æ‰¹é‡å–消授权用户
     */
    @ApiOperation("批量取消授权用户")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "roleId", value = "角色ID", paramType = "query", dataTypeClass = String.class),
        @ApiImplicitParam(name = "userIds", value = "用户ID串", paramType = "query", dataTypeClass = String.class)
    })
    @SaCheckPermission("system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/cancelAll")
@@ -194,6 +197,10 @@
     * æ‰¹é‡é€‰æ‹©ç”¨æˆ·æŽˆæƒ
     */
    @ApiOperation("批量选择用户授权")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "roleId", value = "角色ID", paramType = "query", dataTypeClass = String.class),
        @ApiImplicitParam(name = "userIds", value = "用户ID串", paramType = "query", dataTypeClass = String.class)
    })
    @SaCheckPermission("system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/selectAll")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -13,18 +13,17 @@
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.vo.SysUserExportVo;
import com.ruoyi.system.domain.vo.SysUserImportVo;
import com.ruoyi.system.listener.SysUserImportListener;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -67,7 +66,7 @@
    @ApiOperation("导出用户列表")
    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:user:export")
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(SysUser user, HttpServletResponse response) {
        List<SysUser> list = userService.selectUserList(user);
        List<SysUserExportVo> listVo = BeanUtil.copyToList(list, SysUserExportVo.class);
@@ -90,15 +89,12 @@
    @SaCheckPermission("system:user:import")
    @PostMapping("/importData")
    public AjaxResult<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
        List<SysUserImportVo> userListVo = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class);
        List<SysUser> userList = BeanUtil.copyToList(userListVo, SysUser.class);
        String operName = userService.getById(getUserId()).getUserName();
        String message = userService.importUser(userList, updateSupport, operName);
        return AjaxResult.success(message);
        ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
        return AjaxResult.success(result.getAnalysis());
    }
    @ApiOperation("下载导入模板")
    @GetMapping("/importTemplate")
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response);
    }
@@ -109,7 +105,7 @@
    @ApiOperation("根据用户编号获取详细信息")
    @SaCheckPermission("system:user:query")
    @GetMapping(value = {"/", "/{userId}" })
    public AjaxResult<Map<String, Object>> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
    public AjaxResult<Map<String, Object>> getInfo(@ApiParam("用户ID") @PathVariable(value = "userId", required = false) Long userId) {
        userService.checkUserDataScope(userId);
        Map<String, Object> ajax = new HashMap<>();
        List<SysRole> roles = roleService.selectRoleAll();
@@ -170,7 +166,7 @@
    @SaCheckPermission("system:user:remove")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult<Void> remove(@PathVariable Long[] userIds) {
    public AjaxResult<Void> remove(@ApiParam("角色ID串") @PathVariable Long[] userIds) {
        if (ArrayUtil.contains(userIds, getUserId())) {
            return error("当前用户不能删除");
        }
@@ -208,7 +204,7 @@
    @ApiOperation("根据用户编号获取授权角色")
    @SaCheckPermission("system:user:query")
    @GetMapping("/authRole/{userId}")
    public AjaxResult<Map<String, Object>> authRole(@PathVariable("userId") Long userId) {
    public AjaxResult<Map<String, Object>> authRole(@ApiParam("用户ID") @PathVariable("userId") Long userId) {
        SysUser user = userService.selectUserById(userId);
        List<SysRole> roles = roleService.selectRolesByUserId(userId);
        Map<String, Object> ajax = new HashMap<>();
@@ -221,6 +217,10 @@
     * ç”¨æˆ·æŽˆæƒè§’色
     */
    @ApiOperation("用户授权角色")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "userId", value = "用户Id", paramType = "query", dataTypeClass = String.class),
        @ApiImplicitParam(name = "roleIds", value = "角色ID串", paramType = "query", dataTypeClass = String.class)
    })
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.GRANT)
    @PutMapping("/authRole")
ruoyi-admin/src/main/resources/application-prod.yml
@@ -1,3 +1,10 @@
--- # é…ç½®ä¸´æ—¶è·¯å¾„存储
spring:
  servlet:
    multipart:
      # ä¸´æ—¶æ–‡ä»¶å­˜å‚¨ä½ç½® é¿å…ä¸´æ—¶æ–‡ä»¶è¢«ç³»ç»Ÿæ¸…理报错
      location: /ruoyi/server/temp
--- # ç›‘控配置
spring:
  boot:
ruoyi-admin/src/main/resources/application.yml
@@ -10,6 +10,8 @@
  demoEnabled: true
  # èŽ·å–ip地址开关
  addressEnabled: true
  # ç¼“存懒加载
  cacheLazy: true
captcha:
  # é¡µé¢ <参数设置> å¯å¼€å¯å…³é—­ éªŒè¯ç æ ¡éªŒ
@@ -234,6 +236,22 @@
    - name: 3.代码生成模块
      basePackage: com.ruoyi.generator
knife4j:
  # æ˜¯å¦å¼€å¯Knife4j增强模式
  enable: true
  # æ˜¯å¦å¼€å¯ç”Ÿäº§çŽ¯å¢ƒä¿æŠ¤ç­–ç•¥
  production: @knife4j.production@
  # å‰ç«¯Ui的个性化配置属性
  setting:
    # é»˜è®¤è¯­è¨€
    language: zh-CN
    # æ˜¯å¦æ˜¾ç¤ºFooter
    enableFooter: false
    # æ˜¯å¦å¼€å¯åŠ¨æ€å‚æ•°è°ƒè¯•åŠŸèƒ½
    enableDynamicParameter: true
    # æ˜¯å¦åœ¨æ¯ä¸ªDebug调试栏后显示刷新变量按钮
    enableReloadCacheParameter: true
# é˜²æ­¢XSS攻击
xss:
  # è¿‡æ»¤å¼€å…³
@@ -261,22 +279,6 @@
  # DISCARD_POLICY ä¸¢å¼ƒ
  # ABORT_POLICY ä¸­æ­¢
  rejectedExecutionHandler: CALLER_RUNS_POLICY
# feign ç›¸å…³é…ç½®
feign:
  # ä¸æ”¯æŒå¤šåŒ…, å¦‚有需要可在注解配置 æˆ– æå‡æ‰«åŒ…等级
  # ä¾‹å¦‚ com.**.**.feign
  package: com.ruoyi.**.feign
  # å¼€å¯åŽ‹ç¼©
  compression:
    request:
      enabled: true
    response:
      enabled: true
  okhttp:
    enabled: true
  circuitbreaker:
    enabled: true
--- # redisson ç¼“存配置
redisson:
@@ -313,34 +315,3 @@
  endpoint:
    logfile:
      external-file: ./logs/sys-console.log
--- # å®šæ—¶ä»»åŠ¡é…ç½®
spring:
  quartz:
    scheduler-name: RuoyiScheduler
    startup-delay: 1s
    overwrite-existing-jobs: true
    auto-startup: true
    job-store-type: jdbc
    properties:
      org:
        quartz:
          # Scheduler ç›¸å…³é…ç½®
          scheduler:
            instanceName: RuoyiScheduler
            instanceId: AUTO
          # çº¿ç¨‹æ± ç›¸å…³é…ç½®
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 20
            threadPriority: 5
          # JobStore é›†ç¾¤é…ç½®
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            isClustered: true
            clusterCheckinInterval: 15000
            txIsolationLevelSerializable: true
            misfireThreshold: 60000
            tablePrefix: QRTZ_
            # sqlserver å¯ç”¨
            # selectWithLockSQL: SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?
ruoyi-admin/src/main/resources/logback.xml
@@ -31,7 +31,7 @@
            <level>INFO</level>
        </filter>
    </appender>
    <!-- ç³»ç»Ÿæ—¥å¿—输出 -->
    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-info.log</file>
@@ -54,7 +54,7 @@
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-error.log</file>
        <!-- å¾ªçŽ¯æ”¿ç­–ï¼šåŸºäºŽæ—¶é—´åˆ›å»ºæ—¥å¿—æ–‡ä»¶ -->
@@ -76,21 +76,7 @@
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- ç”¨æˆ·è®¿é—®æ—¥å¿—输出  -->
    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/sys-user.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- æŒ‰å¤©å›žæ»š daily -->
            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- æ—¥å¿—最大的历史 60天 -->
            <maxHistory>60</maxHistory>
        </rollingPolicy>
        <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder">
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>
    <!-- ç³»ç»Ÿæ¨¡å—日志级别控制  -->
    <logger name="com.ruoyi" level="info" />
    <!-- Spring日志级别控制  -->
@@ -99,16 +85,12 @@
    <root level="info">
        <appender-ref ref="console" />
    </root>
    <!--系统操作日志-->
    <root level="info">
        <appender-ref ref="file_info" />
        <appender-ref ref="file_error" />
        <appender-ref ref="file_console" />
    </root>
    <!--系统用户操作日志-->
    <logger name="sys-user" level="info">
        <appender-ref ref="sys-user"/>
    </logger>
</configuration>
</configuration>
ruoyi-admin/src/main/resources/spy.properties
@@ -22,5 +22,3 @@
outagedetectioninterval=2
# æ˜¯å¦è¿‡æ»¤ Log
filter=true
# è¿‡æ»¤ Log æ—¶æ‰€æŽ’除的表名列表,以逗号分隔
exclude=QRTZ_
ruoyi-common/pom.xml
@@ -87,18 +87,6 @@
            <artifactId>jaxb-impl</artifactId>
        </dependency>
        <!-- redis ç¼“存操作 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- pool å¯¹è±¡æ±  -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!-- servlet包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
@@ -120,18 +108,6 @@
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- @deprecated ç”±äºŽä½¿ç”¨äººæ•°è¾ƒå°‘ å†³å®šä¸Ž 3.4.0 ç‰ˆæœ¬ç§»é™¤ -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- @deprecated ç”±äºŽä½¿ç”¨äººæ•°è¾ƒå°‘ å†³å®šä¸Ž 3.4.0 ç‰ˆæœ¬ç§»é™¤ -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
        <dependency>
@@ -180,10 +156,6 @@
            <artifactId>tlog-webroot</artifactId>
        </dependency>
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-feign</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -39,6 +39,11 @@
    private boolean demoEnabled;
    /**
     * ç¼“存懒加载
     */
    private boolean cacheLazy;
    /**
     * èŽ·å–åœ°å€å¼€å…³
     */
    @Getter
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -106,13 +106,4 @@
     */
    public static final String SYS_DICT_KEY = "sys_dict:";
    /**
     * RMI è¿œç¨‹æ–¹æ³•调用
     */
    public static final String LOOKUP_RMI = "rmi://";
    /**
     * LDAP è¿œç¨‹æ–¹æ³•调用
     */
    public static final String LOOKUP_LDAP = "ldap://";
}
ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/convert/ExcelDictConvert.java
@@ -8,8 +8,10 @@
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.core.service.DictService;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
@@ -41,7 +43,7 @@
        if (StringUtils.isBlank(type)) {
            value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator());
        } else {
            value = ExcelUtil.reverseDictByExp(label, type, anno.separator());
            value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator());
        }
        return Convert.convert(contentProperty.getField().getType(), value);
    }
@@ -58,7 +60,7 @@
        if (StringUtils.isBlank(type)) {
            label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator());
        } else {
            label = ExcelUtil.convertDictByExp(value, type, anno.separator());
            label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator());
        }
        return new CellData<>(label);
    }
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/core/service/ConfigService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.common.core.service;
/**
 * é€šç”¨ å‚数配置服务
 *
 * @author Lion Li
 */
public interface ConfigService {
    /**
     * æ ¹æ®å‚æ•° key èŽ·å–å‚æ•°å€¼
     *
     * @param configKey å‚æ•° key
     * @return å‚数值
     */
    String getConfigValue(String configKey);
}
ruoyi-common/src/main/java/com/ruoyi/common/core/service/DictService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package com.ruoyi.common.core.service;
/**
 * é€šç”¨ å­—典服务
 *
 * @author Lion Li
 */
public interface DictService {
    /**
     * åˆ†éš”符
     */
    String SEPARATOR = ",";
    /**
     * æ ¹æ®å­—典类型和字典值获取字典标签
     *
     * @param dictType  å­—典类型
     * @param dictValue å­—典值
     * @return å­—典标签
     */
    default String getDictLabel(String dictType, String dictValue) {
        return getDictLabel(dictType, dictValue, SEPARATOR);
    }
    /**
     * æ ¹æ®å­—典类型和字典标签获取字典值
     *
     * @param dictType  å­—典类型
     * @param dictLabel å­—典标签
     * @return å­—典值
     */
    default String getDictValue(String dictType, String dictLabel) {
        return getDictValue(dictType, dictLabel, SEPARATOR);
    }
    /**
     * æ ¹æ®å­—典类型和字典值获取字典标签
     *
     * @param dictType  å­—典类型
     * @param dictValue å­—典值
     * @param separator åˆ†éš”符
     * @return å­—典标签
     */
    String getDictLabel(String dictType, String dictValue, String separator);
    /**
     * æ ¹æ®å­—典类型和字典标签获取字典值
     *
     * @param dictType  å­—典类型
     * @param dictLabel å­—典标签
     * @param separator åˆ†éš”符
     * @return å­—典值
     */
    String getDictValue(String dictType, String dictLabel, String separator);
}
ruoyi-common/src/main/java/com/ruoyi/common/core/service/LogininforService.java
@@ -2,6 +2,11 @@
import javax.servlet.http.HttpServletRequest;
/**
 * é€šç”¨ ç³»ç»Ÿè®¿é—®æ—¥å¿—
 *
 * @author Lion Li
 */
public interface LogininforService {
    void recordLogininfor(String username, String status, String message,
ruoyi-common/src/main/java/com/ruoyi/common/core/service/OperLogService.java
@@ -3,7 +3,13 @@
import com.ruoyi.common.core.domain.dto.OperLogDTO;
import org.springframework.scheduling.annotation.Async;
/**
 * é€šç”¨ æ“ä½œæ—¥å¿—
 *
 * @author Lion Li
 */
public interface OperLogService {
    @Async
    void recordOper(OperLogDTO operLogDTO);
}
ruoyi-common/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
package com.ruoyi.common.excel;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.utils.ValidatorUtils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
 * Excel å¯¼å…¥ç›‘听
 *
 * @author Yjoioooo
 * @author Lion Li
 */
@Slf4j
@NoArgsConstructor
public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> {
    /**
     * æ˜¯å¦Validator检验,默认为是
     */
    private Boolean isValidate = Boolean.TRUE;
    /**
     * excel è¡¨å¤´æ•°æ®
     */
    private Map<Integer, String> headMap;
    /**
     * å¯¼å…¥å›žæ‰§
     */
    private ExcelResult<T> excelResult;
    public DefaultExcelListener(boolean isValidate) {
        this.excelResult = new DefautExcelResult<>();
        this.isValidate = isValidate;
    }
    /**
     * å¤„理异常
     *
     * @param exception ExcelDataConvertException
     * @param context   Excel ä¸Šä¸‹æ–‡
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        String errMsg = null;
        if (exception instanceof ExcelDataConvertException) {
            // å¦‚果是某一个单元格的转换异常 èƒ½èŽ·å–åˆ°å…·ä½“è¡Œå·
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            Integer rowIndex = excelDataConvertException.getRowIndex();
            Integer columnIndex = excelDataConvertException.getColumnIndex();
            errMsg = StrUtil.format("第{}行-第{}列-表头{}: è§£æžå¼‚常<br/>",
                rowIndex + 1, columnIndex + 1, headMap.get(columnIndex));
            if (log.isDebugEnabled()) {
                log.error(errMsg);
            }
        }
        if (exception instanceof ConstraintViolationException) {
            ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception;
            Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations();
            String constraintViolationsMsg = constraintViolations.stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(", "));
            errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg);
            if (log.isDebugEnabled()) {
                log.error(errMsg);
            }
        }
        excelResult.getErrorList().add(errMsg);
        throw new ExcelAnalysisException(errMsg);
    }
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap = headMap;
        log.debug("解析到一条表头数据: {}", JSON.toJSONString(headMap));
    }
    @Override
    public void invoke(T data, AnalysisContext context) {
        if (isValidate) {
            ValidatorUtils.validate(data);
        }
        excelResult.getList().add(data);
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.debug("所有数据解析完成!");
    }
    @Override
    public ExcelResult<T> getExcelResult() {
        return excelResult;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/excel/DefautExcelResult.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
package com.ruoyi.common.excel;
import cn.hutool.core.util.StrUtil;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
/**
 * é»˜è®¤excel返回对象
 *
 * @author Yjoioooo
 * @author Lion Li
 */
public class DefautExcelResult<T> implements ExcelResult<T> {
    /**
     * æ•°æ®å¯¹è±¡list
     */
    @Setter
    private List<T> list;
    /**
     * é”™è¯¯ä¿¡æ¯åˆ—表
     */
    @Setter
    private List<String> errorList;
    public DefautExcelResult() {
        this.list = new ArrayList<>();
        this.errorList = new ArrayList<>();
    }
    public DefautExcelResult(List<T> list, List<String> errorList) {
        this.list = list;
        this.errorList = errorList;
    }
    public DefautExcelResult(ExcelResult<T> excelResult) {
        this.list = excelResult.getList();
        this.errorList = excelResult.getErrorList();
    }
    @Override
    public List<T> getList() {
        return list;
    }
    @Override
    public List<String> getErrorList() {
        return errorList;
    }
    /**
     * èŽ·å–å¯¼å…¥å›žæ‰§
     *
     * @return å¯¼å…¥å›žæ‰§
     */
    @Override
    public String getAnalysis() {
        int successCount = list.size();
        int errorCount = errorList.size();
        if (successCount == 0) {
            return "读取失败,未解析到数据";
        } else {
            if (errorCount == 0) {
                return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount);
            } else {
                return "";
            }
        }
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/excel/ExcelListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.ruoyi.common.excel;
import com.alibaba.excel.read.listener.ReadListener;
/**
 * Excel å¯¼å…¥ç›‘听
 *
 * @author Lion Li
 */
public interface ExcelListener<T> extends ReadListener<T> {
    ExcelResult<T> getExcelResult();
}
ruoyi-common/src/main/java/com/ruoyi/common/excel/ExcelResult.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.ruoyi.common.excel;
import java.util.List;
/**
 * excel返回对象
 *
 * @author Lion Li
 */
public interface ExcelResult<T> {
    /**
     * å¯¹è±¡åˆ—表
     */
    List<T> getList();
    /**
     * é”™è¯¯åˆ—表
     */
    List<String> getErrorList();
    /**
     * å¯¼å…¥å›žæ‰§
     */
    String getAnalysis();
}
ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
@@ -11,7 +11,9 @@
 * å­—典工具类
 *
 * @author ruoyi
 * @deprecated 3.5.0 ç‰ˆæœ¬åˆ é™¤ è¿ç§»è‡³ {@link com.ruoyi.common.core.service.DictService}
 */
@Deprecated
public class DictUtils {
    /**
@@ -36,9 +38,8 @@
     * @return dictDatas å­—典数据列表
     */
    public static List<SysDictData> getDictCache(String key) {
        Object cacheObj = RedisUtils.getCacheObject(getCacheKey(key));
        if (StringUtils.isNotNull(cacheObj)) {
            List<SysDictData> dictDatas = (List<SysDictData>) cacheObj;
        List<SysDictData> dictDatas = RedisUtils.getCacheObject(getCacheKey(key));
        if (StringUtils.isNotNull(dictDatas)) {
            return dictDatas;
        }
        return null;
ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.utils;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -63,7 +64,9 @@
        }
        PagePlus<T, K> page = new PagePlus<>(pageNum, pageSize);
        OrderItem orderItem = buildOrderItem(orderByColumn, isAsc);
        page.addOrder(orderItem);
        if (ObjectUtil.isNotNull(orderItem)) {
            page.addOrder(orderItem);
        }
        return page;
    }
@@ -87,7 +90,9 @@
        }
        Page<T> page = new Page<>(pageNum, pageSize);
        OrderItem orderItem = buildOrderItem(orderByColumn, isAsc);
        page.addOrder(orderItem);
        if (ObjectUtil.isNotNull(orderItem)) {
            page.addOrder(orderItem);
        }
        return page;
    }
ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java
@@ -88,7 +88,30 @@
     * @param value ç¼“存的值
     */
    public static <T> void setCacheObject(final String key, final T value) {
        client.getBucket(key).set(value);
        setCacheObject(key, value, false);
    }
    /**
     * ç¼“存基本的对象,保留当前对象 TTL æœ‰æ•ˆæœŸ
     *
     * @param key   ç¼“存的键值
     * @param value ç¼“存的值
     * @param isSaveTtl æ˜¯å¦ä¿ç•™TTL有效期(例如: set之前ttl剩余90 set之后还是为90)
     * @since Redis 6.X ä»¥ä¸Šä½¿ç”¨ setAndKeepTTL å…¼å®¹ 5.X æ–¹æ¡ˆ
     */
    public static <T> void setCacheObject(final String key, final T value, final boolean isSaveTtl) {
        RBucket<Object> bucket = client.getBucket(key);
        if (isSaveTtl) {
            try {
                bucket.setAndKeepTTL(value);
            } catch (Exception e) {
                long timeToLive = bucket.remainTimeToLive();
                bucket.set(value);
                bucket.expire(timeToLive, TimeUnit.MILLISECONDS);
            }
        } else {
            bucket.set(value);
        }
    }
    /**
ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.common.utils;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.lang.tree.parser.NodeParser;
import java.util.List;
/**
 * æ‰©å±• hutool TreeUtil å°è£…系统树构建
 *
 * @author Lion Li
 */
public class TreeBuildUtils extends TreeUtil {
    /**
     * æ ¹æ®å‰ç«¯å®šåˆ¶å·®å¼‚化字段
     */
    public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label");
    /**
     * é»˜è®¤æ ‘父节点id
     */
    public static final Long DEFAULT_PARENT_ID = 0L;
    public static <T> List<Tree<Long>> build(List<T> list, NodeParser<T, Long> nodeParser) {
        return TreeUtil.build(list, DEFAULT_PARENT_ID, DEFAULT_CONFIG, nodeParser);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.ruoyi.common.utils;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
/**
 * Validator æ ¡éªŒæ¡†æž¶å·¥å…·
 *
 * @author Lion Li
 */
public class ValidatorUtils {
    private static final Validator VALID = Validation.buildDefaultValidatorFactory().getValidator();
    public static <T> void validate(T object, Class<?>... groups) {
        Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
        if (!validate.isEmpty()) {
            throw new ConstraintViolationException("参数校验异常", validate);
        }
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -4,7 +4,9 @@
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.ruoyi.common.convert.ExcelBigNumberConvert;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.excel.DefaultExcelListener;
import com.ruoyi.common.excel.ExcelListener;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
@@ -21,129 +23,133 @@
 */
public class ExcelUtil {
    /**
     * å¯¹excel表单默认第一个索引名转换成list(EasyExcel)
     *
     * @param is è¾“入流
     * @return è½¬æ¢åŽé›†åˆ
     */
    public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
        return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
    }
    /**
     * åŒæ­¥å¯¼å…¥(适用于小数据量)
     *
     * @param is è¾“入流
     * @return è½¬æ¢åŽé›†åˆ
     */
    public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
        return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
    }
    /**
     * å¯¹list数据源将其里面的数据导入到excel表单(EasyExcel)
     *
     * @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();
            FileUtils.setAttachmentResponseHeader(response, filename);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
            ServletOutputStream os = response.getOutputStream();
            EasyExcel.write(os, clazz)
                .autoCloseStream(false)
                // è‡ªåŠ¨é€‚é…
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                // å¤§æ•°å€¼è‡ªåŠ¨è½¬æ¢ é˜²æ­¢å¤±çœŸ
                .registerConverter(new ExcelBigNumberConvert())
                .sheet(sheetName).doWrite(list);
        } catch (IOException e) {
            throw new RuntimeException("导出Excel异常");
        }
    }
    /**
     * è§£æžå¯¼å‡ºå€¼ 0=男,1=女,2=未知
     *
     * @param propertyValue å‚数值
     * @param converterExp  ç¿»è¯‘注解
     * @param separator     åˆ†éš”符
     * @return è§£æžåŽå€¼
     */
    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);
    }
    /**
     * ä½¿ç”¨æ ¡éªŒç›‘听器 å¼‚步导入 åŒæ­¥è¿”回
     *
     * @param is         è¾“入流
     * @param clazz      å¯¹è±¡ç±»åž‹
     * @param isValidate æ˜¯å¦ Validator æ£€éªŒ é»˜è®¤ä¸ºæ˜¯
     * @return è½¬æ¢åŽé›†åˆ
     */
    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {
        DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
        EasyExcel.read(is, clazz, listener).sheet().doRead();
        return listener.getExcelResult();
    }
    /**
     * åå‘解析值 ç”·=0,女=1,未知=2
     *
     * @param propertyValue å‚数值
     * @param converterExp  ç¿»è¯‘注解
     * @param separator     åˆ†éš”符
     * @return è§£æžåŽå€¼
     */
    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);
    }
    /**
     * ä½¿ç”¨è‡ªå®šä¹‰ç›‘听器 å¼‚步导入 è‡ªå®šä¹‰è¿”回
     *
     * @param is       è¾“入流
     * @param clazz    å¯¹è±¡ç±»åž‹
     * @param listener è‡ªå®šä¹‰ç›‘听器
     * @return è½¬æ¢åŽé›†åˆ
     */
    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {
        EasyExcel.read(is, clazz, listener).sheet().doRead();
        return listener.getExcelResult();
    }
    /**
     * è§£æžå­—典值
     *
     * @param dictValue å­—典值
     * @param dictType  å­—典类型
     * @param separator åˆ†éš”符
     * @return å­—典标签
     */
    public static String convertDictByExp(String dictValue, String dictType, String separator) {
        return DictUtils.getDictLabel(dictType, dictValue, separator);
    }
    /**
     * å¯¼å‡ºexcel
     *
     * @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();
            FileUtils.setAttachmentResponseHeader(response, filename);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
            ServletOutputStream os = response.getOutputStream();
            EasyExcel.write(os, clazz)
                .autoCloseStream(false)
                // è‡ªåŠ¨é€‚é…
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                // å¤§æ•°å€¼è‡ªåŠ¨è½¬æ¢ é˜²æ­¢å¤±çœŸ
                .registerConverter(new ExcelBigNumberConvert())
                .sheet(sheetName).doWrite(list);
        } catch (IOException e) {
            throw new RuntimeException("导出Excel异常");
        }
    }
    /**
     * åå‘解析值字典值
     *
     * @param dictLabel å­—典标签
     * @param dictType  å­—典类型
     * @param separator åˆ†éš”符
     * @return å­—典值
     */
    public static String reverseDictByExp(String dictLabel, String dictType, String separator) {
        return DictUtils.getDictValue(dictType, dictLabel, separator);
    }
    /**
     * è§£æžå¯¼å‡ºå€¼ 0=男,1=女,2=未知
     *
     * @param propertyValue å‚数值
     * @param converterExp  ç¿»è¯‘注解
     * @param separator     åˆ†éš”符
     * @return è§£æžåŽå€¼
     */
    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);
    }
    /**
     * ç¼–码文件名
     */
    public static String encodingFilename(String filename) {
        return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
    }
    /**
     * åå‘解析值 ç”·=0,女=1,未知=2
     *
     * @param propertyValue å‚数值
     * @param converterExp  ç¿»è¯‘注解
     * @param separator     åˆ†éš”符
     * @return è§£æžåŽå€¼
     */
    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);
    }
    /**
     * ç¼–码文件名
     */
    public static String encodingFilename(String filename) {
        return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/FeignTestController.java
ÎļþÒÑɾ³ý
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
@@ -28,75 +28,75 @@
@RequestMapping("/demo/cache")
public class RedisCacheController {
    /**
     * æµ‹è¯• @Cacheable
     *
     * è¡¨ç¤ºè¿™ä¸ªæ–¹æ³•有了缓存的功能,方法的返回值会被缓存下来
     * ä¸‹ä¸€æ¬¡è°ƒç”¨è¯¥æ–¹æ³•前,会去检查是否缓存中已经有值
     * å¦‚果有就直接返回,不调用方法
     * å¦‚果没有,就调用方法,然后把结果缓存起来
     * è¿™ä¸ªæ³¨è§£ã€Œä¸€èˆ¬ç”¨åœ¨æŸ¥è¯¢æ–¹æ³•上」
     *
     * é‡ç‚¹è¯´æ˜Ž: ç¼“存注解严谨与其他筛选数据功能一起使用
     * ä¾‹å¦‚: æ•°æ®æƒé™æ³¨è§£ ä¼šé€ æˆ ç¼“存击穿 ä¸Ž æ•°æ®ä¸ä¸€è‡´é—®é¢˜
     *
     * cacheNames ä¸ºé…ç½®æ–‡ä»¶å†… groupId
     */
    @ApiOperation("测试 @Cacheable")
    @Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
    @GetMapping("/test1")
    public AjaxResult<String> test1(String key, String value){
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯• @Cacheable
     * <p>
     * è¡¨ç¤ºè¿™ä¸ªæ–¹æ³•有了缓存的功能,方法的返回值会被缓存下来
     * ä¸‹ä¸€æ¬¡è°ƒç”¨è¯¥æ–¹æ³•前,会去检查是否缓存中已经有值
     * å¦‚果有就直接返回,不调用方法
     * å¦‚果没有,就调用方法,然后把结果缓存起来
     * è¿™ä¸ªæ³¨è§£ã€Œä¸€èˆ¬ç”¨åœ¨æŸ¥è¯¢æ–¹æ³•上」
     * <p>
     * é‡ç‚¹è¯´æ˜Ž: ç¼“存注解严谨与其他筛选数据功能一起使用
     * ä¾‹å¦‚: æ•°æ®æƒé™æ³¨è§£ ä¼šé€ æˆ ç¼“存击穿 ä¸Ž æ•°æ®ä¸ä¸€è‡´é—®é¢˜
     * <p>
     * cacheNames ä¸ºé…ç½®æ–‡ä»¶å†… groupId
     */
    @ApiOperation("测试 @Cacheable")
    @Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
    @GetMapping("/test1")
    public AjaxResult<String> test1(String key, String value) {
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯• @CachePut
     *
     * åŠ äº†@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
     * å®ƒã€Œé€šå¸¸ç”¨åœ¨æ–°å¢žæ–¹æ³•上」
     *
     * cacheNames ä¸º é…ç½®æ–‡ä»¶å†… groupId
     */
    @ApiOperation("测试 @CachePut")
    @CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
    @GetMapping("/test2")
    public AjaxResult<String> test2(String key, String value){
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯• @CachePut
     * <p>
     * åŠ äº†@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用
     * å®ƒã€Œé€šå¸¸ç”¨åœ¨æ–°å¢žæ–¹æ³•上」
     * <p>
     * cacheNames ä¸º é…ç½®æ–‡ä»¶å†… groupId
     */
    @ApiOperation("测试 @CachePut")
    @CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
    @GetMapping("/test2")
    public AjaxResult<String> test2(String key, String value) {
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯• @CacheEvict
     *
     * ä½¿ç”¨äº†CacheEvict注解的方法,会清空指定缓存
     * ã€Œä¸€èˆ¬ç”¨åœ¨æ›´æ–°æˆ–者删除的方法上」
     *
     * cacheNames ä¸º é…ç½®æ–‡ä»¶å†… groupId
     */
    @ApiOperation("测试 @CacheEvict")
    @CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
    @GetMapping("/test3")
    public AjaxResult<String> test3(String key, String value){
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯• @CacheEvict
     * <p>
     * ä½¿ç”¨äº†CacheEvict注解的方法,会清空指定缓存
     * ã€Œä¸€èˆ¬ç”¨åœ¨æ›´æ–°æˆ–者删除的方法上」
     * <p>
     * cacheNames ä¸º é…ç½®æ–‡ä»¶å†… groupId
     */
    @ApiOperation("测试 @CacheEvict")
    @CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null")
    @GetMapping("/test3")
    public AjaxResult<String> test3(String key, String value) {
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯•设置过期时间
     * æ‰‹åŠ¨è®¾ç½®è¿‡æœŸæ—¶é—´10秒
     * 11秒后获取 åˆ¤æ–­æ˜¯å¦ç›¸ç­‰
     */
    @ApiOperation("测试设置过期时间")
    @GetMapping("/test6")
    public AjaxResult<Boolean> test6(String key, String value){
        RedisUtils.setCacheObject(key, value);
        boolean flag = RedisUtils.expire(key, 10, TimeUnit.SECONDS);
        System.out.println("***********" + flag);
        try {
            Thread.sleep(11 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object obj = RedisUtils.getCacheObject(key);
        return AjaxResult.success("操作成功", value.equals(obj));
    }
    /**
     * æµ‹è¯•设置过期时间
     * æ‰‹åŠ¨è®¾ç½®è¿‡æœŸæ—¶é—´10秒
     * 11秒后获取 åˆ¤æ–­æ˜¯å¦ç›¸ç­‰
     */
    @ApiOperation("测试设置过期时间")
    @GetMapping("/test6")
    public AjaxResult<Boolean> test6(String key, String value) {
        RedisUtils.setCacheObject(key, value);
        boolean flag = RedisUtils.expire(key, 10, TimeUnit.SECONDS);
        System.out.println("***********" + flag);
        try {
            Thread.sleep(11 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object obj = RedisUtils.getCacheObject(key);
        return AjaxResult.success("操作成功", value.equals(obj));
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisLockController.java
@@ -9,7 +9,6 @@
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -28,59 +27,50 @@
@RequestMapping("/demo/redisLock")
public class RedisLockController {
    @Autowired
    private LockTemplate lockTemplate;
    @Autowired
    private LockTemplate lockTemplate;
    /**
     * æµ‹è¯•lock4j æ³¨è§£
     */
    @ApiOperation("测试lock4j æ³¨è§£")
    @Lock4j(keys = {"#key"})
    @GetMapping("/testLock4j")
    public  AjaxResult<String> testLock4j(String key,String value){
        System.out.println("start:"+key+",time:"+ LocalTime.now().toString());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end :"+key+",time:"+LocalTime.now().toString());
        return AjaxResult.success("操作成功",value);
    }
    /**
     * æµ‹è¯•lock4j æ³¨è§£
     */
    @ApiOperation("测试lock4j æ³¨è§£")
    @Lock4j(keys = {"#key"})
    @GetMapping("/testLock4j")
    public AjaxResult<String> testLock4j(String key, String value) {
        System.out.println("start:" + key + ",time:" + LocalTime.now().toString());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end :" + key + ",time:" + LocalTime.now().toString());
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯•lock4j å·¥å…·
     */
    @ApiOperation("测试lock4j å·¥å…·")
    @GetMapping("/testLock4jLockTemaplate")
    public  AjaxResult<String> testLock4jLockTemaplate(String key,String value){
        final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        // èŽ·å–é”æˆåŠŸï¼Œå¤„ç†ä¸šåŠ¡
        try {
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                //
            }
            System.out.println("执行简单方法1 , å½“前线程:" + Thread.currentThread().getName());
        } finally {
            //释放锁
            lockTemplate.releaseLock(lockInfo);
        }
        //结束
        return AjaxResult.success("操作成功",value);
    }
    /**
     * æµ‹è¯•lock4j å·¥å…·
     */
    @ApiOperation("测试lock4j å·¥å…·")
    @GetMapping("/testLock4jLockTemaplate")
    public AjaxResult<String> testLock4jLockTemaplate(String key, String value) {
        final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        // èŽ·å–é”æˆåŠŸï¼Œå¤„ç†ä¸šåŠ¡
        try {
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                //
            }
            System.out.println("执行简单方法1 , å½“前线程:" + Thread.currentThread().getName());
        } finally {
            //释放锁
            lockTemplate.releaseLock(lockInfo);
        }
        //结束
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯•spring-cache注解
     */
    @ApiOperation("测试spring-cache注解")
    @Cacheable(value = "test", key = "#key")
    @GetMapping("/testCache")
    public AjaxResult<String> testCache(String key) {
        return AjaxResult.success("操作成功", key);
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisPubSubController.java
@@ -4,6 +4,7 @@
import com.ruoyi.common.utils.RedisUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -21,22 +22,22 @@
@RequestMapping("/demo/redis/pubsub")
public class RedisPubSubController {
    @ApiOperation("发布消息")
    @GetMapping("/pub")
    public AjaxResult<Void> pub(String key, String value){
        RedisUtils.publish(key, value, consumer -> {
            System.out.println("发布通道 => " + key + ", å‘送值 => " + value);
        });
        return AjaxResult.success("操作成功");
    }
    @ApiOperation("发布消息")
    @GetMapping("/pub")
    public AjaxResult<Void> pub(@ApiParam("通道Key") String key, @ApiParam("发送内容") String value) {
        RedisUtils.publish(key, value, consumer -> {
            System.out.println("发布通道 => " + key + ", å‘送值 => " + value);
        });
        return AjaxResult.success("操作成功");
    }
    @ApiOperation("订阅消息")
    @GetMapping("/sub")
    public AjaxResult<Void> sub(String key){
        RedisUtils.subscribe(key, String.class, msg -> {
            System.out.println("订阅通道 => " + key + ", æŽ¥æ”¶å€¼ => " + msg);
        });
        return AjaxResult.success("操作成功");
    }
    @ApiOperation("订阅消息")
    @GetMapping("/sub")
    public AjaxResult<Void> sub(@ApiParam("通道Key") String key) {
        RedisUtils.subscribe(key, String.class, msg -> {
            System.out.println("订阅通道 => " + key + ", æŽ¥æ”¶å€¼ => " + msg);
        });
        return AjaxResult.success("操作成功");
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisRateLimiterController.java
@@ -22,37 +22,37 @@
@RequestMapping("/demo/rateLimiter")
public class RedisRateLimiterController {
    /**
     * æµ‹è¯•全局限流
     * å…¨å±€å½±å“
     */
    @ApiOperation("测试全局限流")
    @RateLimiter(count = 2, time = 10)
    @GetMapping("/test")
    public  AjaxResult<String> test(String value){
        return AjaxResult.success("操作成功",value);
    }
    /**
     * æµ‹è¯•全局限流
     * å…¨å±€å½±å“
     */
    @ApiOperation("测试全局限流")
    @RateLimiter(count = 2, time = 10)
    @GetMapping("/test")
    public AjaxResult<String> test(String value) {
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯•请求IP限流
     * åŒä¸€IP请求受影响
     */
    @ApiOperation("测试请求IP限流")
    @RateLimiter(count = 2, time = 10, limitType = LimitType.IP)
    @GetMapping("/testip")
    public  AjaxResult<String> testip(String value){
        return AjaxResult.success("操作成功",value);
    }
    /**
     * æµ‹è¯•请求IP限流
     * åŒä¸€IP请求受影响
     */
    @ApiOperation("测试请求IP限流")
    @RateLimiter(count = 2, time = 10, limitType = LimitType.IP)
    @GetMapping("/testip")
    public AjaxResult<String> testip(String value) {
        return AjaxResult.success("操作成功", value);
    }
    /**
     * æµ‹è¯•集群实例限流
     * å¯åŠ¨ä¸¤ä¸ªåŽç«¯æœåŠ¡äº’ä¸å½±å“
     */
    @ApiOperation("测试集群实例限流")
    @RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER)
    @GetMapping("/testcluster")
    public  AjaxResult<String> testcluster(String value){
        return AjaxResult.success("操作成功",value);
    }
    /**
     * æµ‹è¯•集群实例限流
     * å¯åŠ¨ä¸¤ä¸ªåŽç«¯æœåŠ¡äº’ä¸å½±å“
     */
    @ApiOperation("测试集群实例限流")
    @RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER)
    @GetMapping("/testcluster")
    public AjaxResult<String> testcluster(String value) {
        return AjaxResult.success("操作成功", value);
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/Swagger3DemoController.java
@@ -21,18 +21,18 @@
@RequestMapping("/swagger/demo")
public class Swagger3DemoController {
    /**
     * ä¸Šä¼ è¯·æ±‚
     * å¿…须使用 @RequestPart æ³¨è§£æ ‡æ³¨ä¸ºæ–‡ä»¶
     * dataType å¿…须为 "java.io.File"
     */
    @ApiOperation(value = "通用上传请求")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "文件", dataType = "java.io.File", required = true),
    })
    @PostMapping(value = "/upload")
    public AjaxResult<String> upload(@RequestPart("file") MultipartFile file) {
        return AjaxResult.success("操作成功", file.getOriginalFilename());
    }
    /**
     * ä¸Šä¼ è¯·æ±‚
     * å¿…须使用 @RequestPart æ³¨è§£æ ‡æ³¨ä¸ºæ–‡ä»¶
     * dataType å¿…须为 "java.io.File"
     */
    @ApiOperation(value = "通用上传请求")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "文件", dataType = "java.io.File", required = true),
    })
    @PostMapping(value = "/upload")
    public AjaxResult<String> upload(@RequestPart("file") MultipartFile file) {
        return AjaxResult.success("操作成功", file.getOriginalFilename());
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java
@@ -34,48 +34,48 @@
    /**
     * æ–°å¢žæ‰¹é‡æ–¹æ³• å¯å®Œç¾Žæ›¿ä»£ saveBatch ç§’级插入上万数据 (对mysql负荷较大)
     */
    @ApiOperation(value = "新增批量方法")
    @ApiOperation(value = "新增批量方法")
    @PostMapping("/add")
//    @DataSource(DataSourceType.SLAVE)
    public AjaxResult<Void> add() {
        List<TestDemo> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
        }
        List<TestDemo> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
        }
        return toAjax(iTestDemoService.saveAll(list) ? 1 : 0);
    }
    /**
     * æ–°å¢žæˆ–æ›´æ–° å¯å®Œç¾Žæ›¿ä»£ saveOrUpdateBatch é«˜æ€§èƒ½
     */
    @ApiOperation(value = "新增或更新批量方法")
    @PostMapping("/addOrUpdate")
    /**
     * æ–°å¢žæˆ–æ›´æ–° å¯å®Œç¾Žæ›¿ä»£ saveOrUpdateBatch é«˜æ€§èƒ½
     */
    @ApiOperation(value = "新增或更新批量方法")
    @PostMapping("/addOrUpdate")
//    @DataSource(DataSourceType.SLAVE)
    public AjaxResult<Void> addOrUpdate() {
        List<TestDemo> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
        }
        iTestDemoService.saveAll(list);
        for (int i = 0; i < list.size(); i++) {
            TestDemo testDemo = list.get(i);
            testDemo.setTestKey("批量新增或修改").setValue("批量新增或修改");
            if (i % 2 == 0) {
                testDemo.setId(null);
            }
        }
        return toAjax(iTestDemoService.saveOrUpdateAll(list) ? 1 : 0);
    }
    public AjaxResult<Void> addOrUpdate() {
        List<TestDemo> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
        }
        iTestDemoService.saveAll(list);
        for (int i = 0; i < list.size(); i++) {
            TestDemo testDemo = list.get(i);
            testDemo.setTestKey("批量新增或修改").setValue("批量新增或修改");
            if (i % 2 == 0) {
                testDemo.setId(null);
            }
        }
        return toAjax(iTestDemoService.saveOrUpdateAll(list) ? 1 : 0);
    }
    /**
     * åˆ é™¤æ‰¹é‡æ–¹æ³•
     */
    @ApiOperation(value = "删除批量方法")
    @ApiOperation(value = "删除批量方法")
    @DeleteMapping()
//    @DataSource(DataSourceType.SLAVE)
    public AjaxResult<Void> remove() {
        return toAjax(iTestDemoService.remove(new LambdaQueryWrapper<TestDemo>()
            .eq(TestDemo::getOrderNum, -1L)) ? 1 : 0);
            .eq(TestDemo::getOrderNum, -1L)) ? 1 : 0);
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
@@ -1,6 +1,7 @@
package com.ruoyi.demo.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
@@ -10,16 +11,20 @@
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ValidatorUtils;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.demo.domain.bo.TestDemoImportVo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import com.ruoyi.demo.service.ITestDemoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
@@ -63,20 +68,35 @@
        return iTestDemoService.customPageList(bo);
    }
    /**
    @ApiOperation("导入测试-校验")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "导入文件", dataType = "java.io.File", required = true),
    })
    @Log(title = "测试单表", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('demo:demo:import')")
    @PostMapping("/importData")
    public AjaxResult<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {
        ExcelResult<TestDemoImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true);
        List<TestDemoImportVo> volist = excelResult.getList();
        List<TestDemo> list = BeanUtil.copyToList(volist, TestDemo.class);
        iTestDemoService.saveAll(list);
        return AjaxResult.success(excelResult.getAnalysis());
    }
    /**
     * å¯¼å‡ºæµ‹è¯•单表列表
     */
    @ApiOperation("导出测试单表列表")
    @SaCheckPermission("demo:demo:export")
    @Log(title = "测试单表", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    @PostMapping("/export")
    public void export(@Validated TestDemoBo bo, HttpServletResponse response) {
        List<TestDemoVo> list = iTestDemoService.queryList(bo);
        // æµ‹è¯•雪花id导出
        // æµ‹è¯•雪花id导出
//        for (TestDemoVo vo : list) {
//            vo.setId(1234567891234567893L);
//        }
        ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response);
        ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response);
    }
    /**
@@ -85,8 +105,9 @@
    @ApiOperation("获取测试单表详细信息")
    @SaCheckPermission("demo:demo:query")
    @GetMapping("/{id}")
    public AjaxResult<TestDemoVo> getInfo(@NotNull(message = "主键不能为空")
                                                  @PathVariable("id") Long id) {
    public AjaxResult<TestDemoVo> getInfo(@ApiParam("测试ID")
                                          @NotNull(message = "主键不能为空")
                                          @PathVariable("id") Long id) {
        return AjaxResult.success(iTestDemoService.queryById(id));
    }
@@ -98,7 +119,10 @@
    @Log(title = "测试单表", businessType = BusinessType.INSERT)
    @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "不允许重复提交")
    @PostMapping()
    public AjaxResult<Void> add(@Validated(AddGroup.class) @RequestBody TestDemoBo bo) {
    public AjaxResult<Void> add(@RequestBody TestDemoBo bo) {
        // ä½¿ç”¨æ ¡éªŒå·¥å…·å¯¹æ ‡ @Validated(AddGroup.class) æ³¨è§£
        // ç”¨äºŽåœ¨éž Controller çš„地方校验对象
        ValidatorUtils.validate(bo, AddGroup.class);
        return toAjax(iTestDemoService.insertByBo(bo) ? 1 : 0);
    }
@@ -121,8 +145,9 @@
    @SaCheckPermission("demo:demo:remove")
    @Log(title = "测试单表" , businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空")
                                       @PathVariable Long[] ids) {
    public AjaxResult<Void> remove(@ApiParam("测试ID串")
                                   @NotEmpty(message = "主键不能为空")
                                   @PathVariable Long[] ids) {
        return toAjax(iTestDemoService.deleteWithValidByIds(Arrays.asList(ids), true) ? 1 : 0);
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestI18nController.java
@@ -4,9 +4,16 @@
import com.ruoyi.common.utils.MessageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
@@ -14,6 +21,7 @@
 *
 * @author Lion Li
 */
@Validated
@Api(value = "测试国际化控制器", tags = {"测试国际化管理"})
@RestController
@RequestMapping("/demo/i18n")
@@ -27,7 +35,42 @@
     */
    @ApiOperation("通过code获取国际化内容")
    @GetMapping()
    public AjaxResult<Void> get(String code) {
    public AjaxResult<Void> get(@ApiParam("国际化code") String code) {
        return AjaxResult.success(MessageUtils.message(code));
    }
    /**
     * Validator æ ¡éªŒå›½é™…化
     * ä¸ä¼ å€¼ åˆ†åˆ«æŸ¥çœ‹å¼‚常返回
     *
     * æµ‹è¯•使用 not.null
     */
    @ApiOperation("Validator æ ¡éªŒå›½é™…化")
    @GetMapping("/test1")
    public AjaxResult<Void> test1(@NotBlank(message = "{not.null}") String str) {
        return AjaxResult.success(str);
    }
    /**
     * Bean æ ¡éªŒå›½é™…化
     * ä¸ä¼ å€¼ åˆ†åˆ«æŸ¥çœ‹å¼‚常返回
     *
     * æµ‹è¯•使用 not.null
     */
    @ApiOperation("Bean æ ¡éªŒå›½é™…化")
    @GetMapping("/test2")
    public AjaxResult<TestI18nBo> test2(@Validated TestI18nBo bo) {
        return AjaxResult.success(bo);
    }
    @Data
    public static class TestI18nBo {
        @NotBlank(message = "{not.null}")
        private String name;
        @NotNull(message = "{not.null}")
        @Range(min = 0, max = 100, message = "{length.not.valid}")
        private Integer age;
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestTreeController.java
@@ -15,6 +15,7 @@
import com.ruoyi.demo.service.ITestTreeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@@ -61,7 +62,7 @@
    @GetMapping("/export")
    public void export(@Validated TestTreeBo bo, HttpServletResponse response) {
        List<TestTreeVo> list = iTestTreeService.queryList(bo);
        ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response);
        ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response);
    }
    /**
@@ -70,8 +71,9 @@
    @ApiOperation("获取测试树表详细信息")
    @SaCheckPermission("demo:tree:query")
    @GetMapping("/{id}")
    public AjaxResult<TestTreeVo> getInfo(@NotNull(message = "主键不能为空")
                                                  @PathVariable("id") Long id) {
    public AjaxResult<TestTreeVo> getInfo(@ApiParam("测试树ID")
                                          @NotNull(message = "主键不能为空")
                                          @PathVariable("id") Long id) {
        return AjaxResult.success(iTestTreeService.queryById(id));
    }
@@ -106,8 +108,9 @@
    @SaCheckPermission("demo:tree:remove")
    @Log(title = "测试树表" , businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空")
                                       @PathVariable Long[] ids) {
    public AjaxResult<Void> remove(@ApiParam("测试树ID串")
                                   @NotEmpty(message = "主键不能为空")
                                   @PathVariable Long[] ids) {
        return toAjax(iTestTreeService.deleteWithValidByIds(Arrays.asList(ids), true) ? 1 : 0);
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoImportVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package com.ruoyi.demo.domain.bo;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
 * æµ‹è¯•单表业务对象 test_demo
 *
 * @author Lion Li
 * @date 2021-07-26
 */
@Data
@ApiModel("测试单表业务对象")
public class TestDemoImportVo {
    /**
     * éƒ¨é—¨id
     */
    @ApiModelProperty("部门id")
    @NotNull(message = "部门id不能为空")
    @ExcelProperty(value = "部门id")
    private Long deptId;
    /**
     * ç”¨æˆ·id
     */
    @ApiModelProperty("用户id")
    @NotNull(message = "用户id不能为空")
    @ExcelProperty(value = "用户id")
    private Long userId;
    /**
     * æŽ’序号
     */
    @ApiModelProperty("排序号")
    @NotNull(message = "排序号不能为空")
    @ExcelProperty(value = "排序号")
    private Long orderNum;
    /**
     * key键
     */
    @ApiModelProperty("key键")
    @NotBlank(message = "key键不能为空")
    @ExcelProperty(value = "key键")
    private String testKey;
    /**
     * å€¼
     */
    @ApiModelProperty("值")
    @NotBlank(message = "值不能为空")
    @ExcelProperty(value = "值")
    private String value;
}
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/FeignTestService.java
ÎļþÒÑɾ³ý
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/constant/FeignTestConstant.java
ÎļþÒÑɾ³ý
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java
ÎļþÒÑɾ³ý
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/package-info.java
ÎļþÒÑɾ³ý
ruoyi-demo/src/main/java/com/ruoyi/demo/feign/package-info.java
ÎļþÒÑɾ³ý
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java
@@ -2,11 +2,9 @@
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.mybatisplus.cache.MybatisPlusRedisCache;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Param;
/**
@@ -15,8 +13,6 @@
 * @author Lion Li
 * @date 2021-07-26
 */
// å¦‚使需切换数据源 è¯·å‹¿ä½¿ç”¨ç¼“å­˜ ä¼šé€ æˆæ•°æ®ä¸ä¸€è‡´çŽ°è±¡
@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
public interface TestDemoMapper extends BaseMapperPlus<TestDemo> {
    Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
ruoyi-demo/src/main/resources/mapper/demo/package-info.md
ruoyi-demo/src/main/resources/mapper/package-info.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
java包使用 `.` åˆ†å‰² resource ç›®å½•使用 `/` åˆ†å‰²
<br>
此文件目的 é˜²æ­¢æ–‡ä»¶å¤¹ç²˜è¿žæ‰¾ä¸åˆ° `xml` æ–‡ä»¶
ruoyi-extend/ruoyi-monitor-admin/pom.xml
@@ -28,6 +28,12 @@
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
    </dependencies>
    <build>
ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java
@@ -34,6 +34,8 @@
            //授予对所有静态资产和登录页面的公共访问权限。
            .antMatchers(adminContextPath + "/assets/**").permitAll()
            .antMatchers(adminContextPath + "/login").permitAll()
            .antMatchers("/actuator").anonymous()
            .antMatchers("/actuator/**").anonymous()
            //必须对每个其他请求进行身份验证
            .anyRequest().authenticated().and()
            //配置登录和注销
ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
--- # ç›‘控配置
spring:
  boot:
    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
ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
--- # ç›‘控配置
spring:
  boot:
    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
ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
@@ -1,6 +1,12 @@
server:
  port: 9090
spring:
  application:
    name: ruoyi-monitor-admin
  profiles:
    active: @profiles.active@
--- # ç›‘控中心服务端配置
spring:
  security:
    user:
@@ -9,3 +15,17 @@
  boot:
    admin:
      context-path: /admin
--- # Actuator ç›‘控端点的配置项
management:
  endpoints:
    web:
      # Actuator æä¾›çš„ API æŽ¥å£çš„æ ¹ç›®å½•。默认为 /actuator
      base-path: /actuator
      exposure:
        # éœ€è¦å¼€æ”¾çš„端点。默认值只打开 health å’Œ info ä¸¤ä¸ªç«¯ç‚¹ã€‚通过设置 * ï¼Œå¯ä»¥å¼€æ”¾æ‰€æœ‰ç«¯ç‚¹ã€‚
        # ç”Ÿäº§çŽ¯å¢ƒä¸å»ºè®®æ”¾å¼€æ‰€æœ‰ æ ¹æ®é¡¹ç›®éœ€æ±‚放开即可
        include: @endpoints.include@
  endpoint:
    logfile:
      external-file: ./logs/ruoyi-monitor-admin.log
ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
@@ -71,6 +71,11 @@
            <version>${mysql-connector-java.version}</version>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!-- xxl-job-core -->
        <dependency>
            <groupId>com.xuxueli</groupId>
ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-dev.yml
@@ -1,3 +1,18 @@
--- # ç›‘控配置
spring:
  boot:
    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
--- # æ•°æ®åº“配置
spring:
  datasource:
ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-prod.yml
@@ -1,3 +1,18 @@
--- # ç›‘控配置
spring:
  boot:
    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
--- # æ•°æ®åº“配置
spring:
  datasource:
ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application.yml
@@ -4,6 +4,8 @@
  servlet:
    context-path: /xxl-job-admin
spring:
  application:
    name: ruoyi-xxl-job-admin
  profiles:
    active: @profiles.active@
  mvc:
@@ -28,13 +30,22 @@
    suffix: .ftl
    templateLoaderPath: classpath:/templates/
--- # ç›‘控配置
--- # Actuator ç›‘控端点的配置项
management:
  health:
    mail:
      enabled: false
  server:
    base-path: /actuator
  endpoints:
    web:
      # Actuator æä¾›çš„ API æŽ¥å£çš„æ ¹ç›®å½•。默认为 /actuator
      base-path: /actuator
      exposure:
        # éœ€è¦å¼€æ”¾çš„端点。默认值只打开 health å’Œ info ä¸¤ä¸ªç«¯ç‚¹ã€‚通过设置 * ï¼Œå¯ä»¥å¼€æ”¾æ‰€æœ‰ç«¯ç‚¹ã€‚
        # ç”Ÿäº§çŽ¯å¢ƒä¸å»ºè®®æ”¾å¼€æ‰€æœ‰ æ ¹æ®é¡¹ç›®éœ€æ±‚放开即可
        include: @endpoints.include@
  endpoint:
    logfile:
      external-file: ./logs/ruoyi-xxl-job-admin.log
--- # xxljob系统配置
xxl:
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
@@ -7,6 +7,7 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RepeatSubmitAspect.java
@@ -1,13 +1,12 @@
package com.ruoyi.framework.aspectj;
import cn.dev33.satoken.SaManager;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.RepeatSubmitProperties;
@@ -18,8 +17,14 @@
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * é˜²æ­¢é‡å¤æäº¤
@@ -33,7 +38,6 @@
public class RepeatSubmitAspect {
    private final RepeatSubmitProperties repeatSubmitProperties;
    private final LockTemplate lockTemplate;
    @Before("@annotation(repeatSubmit)")
    public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
@@ -46,7 +50,7 @@
            throw new ServiceException("重复提交间隔时间不能小于'1'秒");
        }
        HttpServletRequest request = ServletUtils.getRequest();
        String nowParams = StrUtil.join(",", point.getArgs());
        String nowParams = argsArrayToString(point.getArgs());
        // è¯·æ±‚地址(作为存放cache的key值)
        String url = request.getRequestURI();
@@ -59,10 +63,58 @@
        submitKey = SecureUtil.md5(submitKey + ":" + nowParams);
        // å”¯ä¸€æ ‡è¯†ï¼ˆæŒ‡å®škey + æ¶ˆæ¯å¤´ï¼‰
        String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
        LockInfo lock = lockTemplate.lock(cacheRepeatKey, interval, interval / 2);
        if (lock == null) {
        String key = RedisUtils.getCacheObject(cacheRepeatKey);
        if (key == null) {
            RedisUtils.setCacheObject(cacheRepeatKey, "", interval, TimeUnit.MILLISECONDS);
        } else {
            throw new ServiceException(repeatSubmit.message());
        }
    }
    /**
     * å‚数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        StringBuilder params = new StringBuilder();
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
                    try {
                        params.append(JsonUtils.toJsonString(o)).append(" ");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return params.toString().trim();
    }
    /**
     * åˆ¤æ–­æ˜¯å¦éœ€è¦è¿‡æ»¤çš„对象。
     *
     * @param o å¯¹è±¡ä¿¡æ¯ã€‚
     * @return å¦‚果是需要过滤的对象,则返回true;否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
            || o instanceof BindingResult;
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java
ÎļþÒÑɾ³ý
ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
@@ -20,7 +20,6 @@
 * @author Lion Li
 */
@Configuration
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
public class FilterConfig {
    @Autowired
@@ -28,6 +27,7 @@
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Bean
    @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
    public FilterRegistrationBean xssFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
@@ -1,7 +1,6 @@
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;
@@ -28,7 +27,6 @@
     */
    static class I18nLocaleResolver implements LocaleResolver {
        @NotNull
        @Override
        public Locale resolveLocale(HttpServletRequest httpServletRequest) {
            String language = httpServletRequest.getHeader("content-language");
@@ -41,7 +39,7 @@
        }
        @Override
        public void setLocale(@NotNull HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
        public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
        }
    }
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java
@@ -2,6 +2,7 @@
import cn.dev33.satoken.config.SaTokenConfig;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.SwaggerProperties;
@@ -34,6 +35,9 @@
    @Autowired
    private SaTokenConfig saTokenConfig;
    @Autowired
    private OpenApiExtensionResolver openApiExtensionResolver;
    /**
     * åˆ›å»ºAPI
     */
@@ -58,6 +62,7 @@
                    // è®¾ç½®å®‰å…¨æ¨¡å¼ï¼Œswagger可以设置访问token
                    .securitySchemes(securitySchemes())
                    .securityContexts(securityContexts())
                    .extensions(openApiExtensionResolver.buildExtensions(group.getName()))
                    .pathMapping(swaggerProperties.getPathMapping());
            String beanName = StringUtils.substringAfterLast(basePackage, ".") + "Docket";
            SpringUtils.registerBean(beanName, docket);
ruoyi-framework/src/main/java/com/ruoyi/framework/config/TLogConfig.java
@@ -1,7 +1,6 @@
package com.ruoyi.framework.config;
import com.yomahub.tlog.core.aop.AspectLogAop;
import com.yomahub.tlog.feign.filter.TLogFeignFilter;
import com.yomahub.tlog.spring.TLogPropertyInit;
import com.yomahub.tlog.spring.TLogSpringAware;
import com.yomahub.tlog.springboot.property.TLogProperty;
@@ -39,11 +38,6 @@
    @Bean
    public AspectLogAop aspectLogAop() {
        return new AspectLogAop();
    }
    @Bean
    public TLogFeignFilter tLogFeignFilter() {
        return new TLogFeignFilter();
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ValidatorConfig.java
@@ -1,12 +1,14 @@
package com.ruoyi.framework.config;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Properties;
/**
 * æ ¡éªŒæ¡†æž¶é…ç½®ç±»
@@ -16,16 +18,26 @@
@Configuration
public class ValidatorConfig {
    @Autowired
    private MessageSource messageSource;
    /**
     * é…ç½®æ ¡éªŒæ¡†æž¶ å¿«é€Ÿè¿”回模式
     */
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true)
                .buildValidatorFactory();
        return validatorFactory.getValidator();
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        // å›½é™…化
        factoryBean.setValidationMessageSource(messageSource);
        // è®¾ç½®ä½¿ç”¨ HibernateValidator æ ¡éªŒå™¨
        factoryBean.setProviderClass(HibernateValidator.class);
        Properties properties = new Properties();
        // è®¾ç½® å¿«é€Ÿå¼‚常返回
        properties.setProperty("hibernate.validator.fail_fast", "true");
        factoryBean.setValidationProperties(properties);
        // åŠ è½½é…ç½®
        factoryBean.afterPropertiesSet();
        return factoryBean.getValidator();
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
@@ -14,7 +14,7 @@
 *
 * @author Lion Li
 */
@Slf4j(topic = "sys-user")
@Slf4j
@Component
public class ShutdownManager {
ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
@@ -16,7 +16,9 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
/**
 * å…¨å±€å¼‚常处理器
@@ -104,7 +106,9 @@
    @ExceptionHandler(BindException.class)
    public AjaxResult<Void> handleBindException(BindException e) {
        log.error(e.getMessage(), e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        String message = e.getAllErrors().stream()
            .map(DefaultMessageSourceResolvable::getDefaultMessage)
            .collect(Collectors.joining(", "));
        return AjaxResult.error(message);
    }
@@ -114,7 +118,9 @@
    @ExceptionHandler(ConstraintViolationException.class)
    public AjaxResult<Void> constraintViolationException(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        String message = e.getConstraintViolations().iterator().next().getMessage();
        String message = e.getConstraintViolations().stream()
            .map(ConstraintViolation::getMessage)
            .collect(Collectors.joining(", "));
        return AjaxResult.error(message);
    }
ruoyi-generator/pom.xml
@@ -20,7 +20,7 @@
        <!--velocity代码生成使用模板 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <artifactId>velocity-engine-core</artifactId>
        </dependency>
        <!-- é€šç”¨å·¥å…·-->
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
@@ -2,6 +2,7 @@
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
@@ -14,7 +15,6 @@
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -201,6 +201,6 @@
        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(data, response.getOutputStream());
        IoUtil.write(response.getOutputStream(), false, data);
    }
}
ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
@@ -2,6 +2,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants;
@@ -21,7 +22,7 @@
import com.ruoyi.generator.util.VelocityInitializer;
import com.ruoyi.generator.util.VelocityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.poi.util.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
@@ -33,6 +34,7 @@
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
@@ -341,8 +343,8 @@
            try {
                // æ·»åŠ åˆ°zip
                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
                IOUtils.write(sw.toString(), zip, Constants.UTF8);
                IOUtils.closeQuietly(sw);
                IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
                IoUtil.close(sw);
                zip.flush();
                zip.closeEntry();
            } catch (IOException e) {
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
@@ -19,10 +19,9 @@
        Properties p = new Properties();
        try {
            // åŠ è½½classpath目录下的vm文件
            p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            // å®šä¹‰å­—符集
            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
            p.setProperty(Velocity.OUTPUT_ENCODING, Constants.UTF8);
            // åˆå§‹åŒ–Velocity引擎,指定配置Properties
            Velocity.init(p);
        } catch (Exception e) {
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
@@ -247,7 +247,8 @@
        List<String> dicts = new ArrayList<String>();
        for (GenTableColumn column : columns) {
            if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
                    column.getHtmlType(), new String[]{GenConstants.HTML_SELECT, GenConstants.HTML_RADIO})) {
                    column.getHtmlType(),
                new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) {
                dicts.add("'" + column.getDictType() + "'");
            }
        }
ruoyi-generator/src/main/resources/mapper/package-info.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
java包使用 `.` åˆ†å‰² resource ç›®å½•使用 `/` åˆ†å‰²
<br>
此文件目的 é˜²æ­¢æ–‡ä»¶å¤¹ç²˜è¿žæ‰¾ä¸åˆ° `xml` æ–‡ä»¶
ruoyi-generator/src/main/resources/vm/java/controller.java.vm
@@ -28,6 +28,7 @@
#elseif($table.tree)
#end
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiOperation;
/**
@@ -80,7 +81,8 @@
    @ApiOperation("获取${functionName}详细信息")
    @SaCheckPermission("${permissionPrefix}:query")
    @GetMapping("/{${pkColumn.javaField}}")
    public AjaxResult<${ClassName}Vo> getInfo(@NotNull(message = "主键不能为空")
    public AjaxResult<${ClassName}Vo> getInfo(@ApiParam("主键")
                                                  @NotNull(message = "主键不能为空")
                                                  @PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) {
        return AjaxResult.success(i${ClassName}Service.queryById(${pkColumn.javaField}));
    }
@@ -116,7 +118,8 @@
    @SaCheckPermission("${permissionPrefix}:remove")
    @Log(title = "${functionName}" , businessType = BusinessType.DELETE)
    @DeleteMapping("/{${pkColumn.javaField}s}")
    public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空")
    public AjaxResult<Void> remove(@ApiParam("主键串")
                                       @NotEmpty(message = "主键不能为空")
                                       @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) {
        return toAjax(i${ClassName}Service.deleteWithValidByIds(Arrays.asList(${pkColumn.javaField}s), true) ? 1 : 0);
    }
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -108,7 +108,11 @@
#elseif($column.list && $column.dictType && "" != $column.dictType)
      <el-table-column label="${comment}" align="center" prop="${javaField}">
        <template slot-scope="scope">
#if($column.htmlType == "checkbox")
          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
#end
        </template>
      </el-table-column>
#elseif($column.list && "" != $javaField)
@@ -296,8 +300,7 @@
      queryParams: {
#foreach ($column in $columns)
#if($column.query)
        $column.javaField: null#if($velocityCount != $columns.size()),#end
        $column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
      },
@@ -315,8 +318,7 @@
#end
        $column.javaField: [
          { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
        ]#if($velocityCount != $columns.size()),#end
        ]#if($foreach.count != $columns.size()),#end
#end
#end
      }
@@ -379,14 +381,12 @@
      this.form = {
#foreach ($column in $columns)
#if($column.htmlType == "radio")
        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
        $column.javaField: []#if($velocityCount != $columns.size()),#end
        $column.javaField: []#if($foreach.count != $columns.size()),#end
#else
        $column.javaField: null#if($velocityCount != $columns.size()),#end
        $column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
      };
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -108,7 +108,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['${moduleName}:${businessName}:export']"
        >导出</el-button>
@@ -137,7 +136,11 @@
#elseif($column.list && $column.dictType && "" != $column.dictType)
      <el-table-column label="${comment}" align="center" prop="${javaField}">
        <template slot-scope="scope">
#if($column.htmlType == "checkbox")
          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
#end
        </template>
      </el-table-column>
#elseif($column.list && "" != $javaField)
@@ -324,8 +327,6 @@
      buttonLoading: false,
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
#if($table.sub)
@@ -363,8 +364,7 @@
        pageSize: 10,
#foreach ($column in $columns)
#if($column.query)
        $column.javaField: undefined#if($velocityCount != $columns.size()),#end
        $column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
      },
@@ -382,8 +382,7 @@
#end
        $column.javaField: [
          { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
        ]#if($velocityCount != $columns.size()),#end
        ]#if($foreach.count != $columns.size()),#end
#end
#end
      }
@@ -427,14 +426,11 @@
      this.form = {
#foreach ($column in $columns)
#if($column.htmlType == "radio")
        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
        $column.javaField: []#if($velocityCount != $columns.size()),#end
        $column.javaField: []#if($foreach.count != $columns.size()),#end
#else
        $column.javaField: undefined#if($velocityCount != $columns.size()),#end
        $column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
      };
@@ -573,7 +569,9 @@
#end
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
        this.#[[$download]]#.excel('/${moduleName}/${businessName}/export', this.queryParams);
      this.download('${moduleName}/${businessName}/export', {
        ...this.queryParams
      }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
    }
  }
};
ruoyi-oss/src/main/java/com/ruoyi/oss/constant/OssConstant.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/constant/CloudConstant.java ÐÞ¸Ä
@@ -8,7 +8,7 @@
 *
 * @author Lion Li
 */
public class CloudConstant {
public class OssConstant {
    /**
     * OSS模块KEY
@@ -18,12 +18,12 @@
    /**
     * å¯¹è±¡å­˜å‚¨é…ç½®KEY
     */
    public static final String CLOUD_STORAGE_CONFIG_KEY = "CloudStorageConfig";
    public static final String OSS_CONFIG_KEY = "OssConfig";
    /**
     * ç¼“存配置KEY
     */
    public static final String CACHE_CONFIG_KEY = SYS_OSS_KEY + CLOUD_STORAGE_CONFIG_KEY;
    public static final String CACHE_CONFIG_KEY = SYS_OSS_KEY + OSS_CONFIG_KEY;
    /**
     * é¢„览列表资源开关Key
ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/CloudServiceEnumd.java
ÎļþÒÑɾ³ý
ruoyi-oss/src/main/java/com/ruoyi/oss/enumd/OssEnumd.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
package com.ruoyi.oss.enumd;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.service.impl.AliyunOssStrategy;
import com.ruoyi.oss.service.impl.MinioOssStrategy;
import com.ruoyi.oss.service.impl.QcloudOssStrategy;
import com.ruoyi.oss.service.impl.QiniuOssStrategy;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * å¯¹è±¡å­˜å‚¨æœåŠ¡å•†æžšä¸¾
 *
 * @author Lion Li
 */
@Getter
@AllArgsConstructor
public enum OssEnumd {
    /**
     * ä¸ƒç‰›äº‘
     */
    QINIU("qiniu", QiniuOssStrategy.class),
    /**
     * é˜¿é‡Œäº‘
     */
    ALIYUN("aliyun", AliyunOssStrategy.class),
    /**
     * è…¾è®¯äº‘
     */
    QCLOUD("qcloud", QcloudOssStrategy.class),
    /**
     * minio
     */
    MINIO("minio", MinioOssStrategy.class);
    private final String value;
    private final Class<?> serviceClass;
    public static Class<?> getServiceClass(String value) {
        for (OssEnumd clazz : values()) {
            if (clazz.getValue().equals(value)) {
                return clazz.getServiceClass();
            }
        }
        return null;
    }
    public static String getServiceName(String value) {
        for (OssEnumd clazz : values()) {
            if (clazz.getValue().equals(value)) {
                return StringUtils.uncapitalize(clazz.getServiceClass().getSimpleName());
            }
        }
        return null;
    }
}
ruoyi-oss/src/main/java/com/ruoyi/oss/factory/OssFactory.java
@@ -1,16 +1,15 @@
package com.ruoyi.oss.factory;
import cn.hutool.core.convert.Convert;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.oss.constant.CloudConstant;
import com.ruoyi.oss.enumd.CloudServiceEnumd;
import com.ruoyi.oss.constant.OssConstant;
import com.ruoyi.oss.enumd.OssEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.ICloudStorageStrategy;
import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.IOssStrategy;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
@@ -24,24 +23,31 @@
@Slf4j
public class OssFactory {
    static {
        RedisUtils.subscribe(CloudConstant.CACHE_CONFIG_KEY, String.class, msg -> {
            refreshService(msg);
            log.info("订阅刷新OSS配置 => " + msg);
        });
    }
    /**
     * æœåŠ¡å®žä¾‹ç¼“å­˜
     */
    private static final Map<String, ICloudStorageStrategy> SERVICES = new ConcurrentHashMap<>();
    private static final Map<String, IOssStrategy> SERVICES = new ConcurrentHashMap<>();
    /**
     * åˆå§‹åŒ–工厂
     */
    public static void init() {
        log.info("初始化OSS工厂");
        RedisUtils.subscribe(OssConstant.CACHE_CONFIG_KEY, String.class, type -> {
            // æ²¡æœ‰çš„实例不处理
            if (SERVICES.containsKey(type)) {
                refreshService(type);
                log.info("订阅刷新OSS配置 => " + type);
            }
        });
    }
    /**
     * èŽ·å–é»˜è®¤å®žä¾‹
     */
    public static ICloudStorageStrategy instance() {
    public static IOssStrategy instance() {
        // èŽ·å–redis é»˜è®¤ç±»åž‹
        String type = Convert.toStr(RedisUtils.getCacheObject(CloudConstant.CACHE_CONFIG_KEY));
        String type = RedisUtils.getCacheObject(OssConstant.CACHE_CONFIG_KEY);
        if (StringUtils.isEmpty(type)) {
            throw new OssException("文件存储服务类型无法找到!");
        }
@@ -51,8 +57,8 @@
    /**
     * æ ¹æ®ç±»åž‹èŽ·å–å®žä¾‹
     */
    public static ICloudStorageStrategy instance(String type) {
        ICloudStorageStrategy service = SERVICES.get(type);
    public static IOssStrategy instance(String type) {
        IOssStrategy service = SERVICES.get(type);
        if (service == null) {
            refreshService(type);
            service = SERVICES.get(type);
@@ -61,14 +67,14 @@
    }
    private static void refreshService(String type) {
        Object json = RedisUtils.getCacheObject(CloudConstant.SYS_OSS_KEY + type);
        CloudStorageProperties properties = JsonUtils.parseObject(json.toString(), CloudStorageProperties.class);
        Object json = RedisUtils.getCacheObject(OssConstant.SYS_OSS_KEY + type);
        OssProperties properties = JsonUtils.parseObject(json.toString(), OssProperties.class);
        if (properties == null) {
            throw new OssException("系统异常, '" + type + "'配置信息不存在!");
        }
        // èŽ·å–redis配置信息 åˆ›å»ºå¯¹è±¡ å¹¶ç¼“å­˜
        ICloudStorageStrategy service = (ICloudStorageStrategy) ReflectUtils.newInstance(CloudServiceEnumd.getServiceClass(type));
        ((AbstractCloudStorageStrategy)service).init(properties);
        IOssStrategy service = (IOssStrategy) ReflectUtils.newInstance(OssEnumd.getServiceClass(type));
        ((AbstractOssStrategy)service).init(properties);
        SERVICES.put(type, service);
    }
ruoyi-oss/src/main/java/com/ruoyi/oss/properties/OssProperties.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/properties/CloudStorageProperties.java ÐÞ¸Ä
@@ -2,15 +2,13 @@
import lombok.Data;
import java.util.Date;
/**
 * OSS对象存储 é…ç½®å±žæ€§
 *
 * @author Lion Li
 */
@Data
public class CloudStorageProperties {
public class OssProperties {
    /**
     * åŸŸå
@@ -46,10 +44,5 @@
     * æ˜¯å¦https(Y=是,N=否)
     */
    private String isHttps;
    /**
     * æ›´æ–°æ—¶é—´
     */
    private Date updateTime;
}
ruoyi-oss/src/main/java/com/ruoyi/oss/service/IOssStrategy.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/service/ICloudStorageStrategy.java ÐÞ¸Ä
@@ -9,7 +9,7 @@
 *
 * @author Lion Li
 */
public interface ICloudStorageStrategy {
public interface IOssStrategy {
    void createBucket();
@@ -17,15 +17,6 @@
     * èŽ·å–æœåŠ¡å•†ç±»åž‹
     */
    String getServiceType();
    /**
     * æ–‡ä»¶è·¯å¾„
     *
     * @param prefix å‰ç¼€
     * @param suffix åŽç¼€
     * @return è¿”回上传路径
     */
    String getPath(String prefix, String suffix);
    /**
     * æ–‡ä»¶ä¸Šä¼ 
@@ -70,5 +61,4 @@
     */
    UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
    String getEndpointLink();
}
ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractOssStrategy.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/service/abstractd/AbstractCloudStorageStrategy.java ÐÞ¸Ä
@@ -5,8 +5,8 @@
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.ICloudStorageStrategy;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.IOssStrategy;
import java.io.InputStream;
@@ -15,11 +15,11 @@
 *
 * @author Lion Li
 */
public abstract class AbstractCloudStorageStrategy implements ICloudStorageStrategy {
public abstract class AbstractOssStrategy implements IOssStrategy {
    protected CloudStorageProperties properties;
    protected OssProperties properties;
    public abstract void init(CloudStorageProperties properties);
    public abstract void init(OssProperties properties);
    @Override
    public abstract void createBucket();
@@ -27,7 +27,6 @@
    @Override
    public abstract String getServiceType();
    @Override
    public String getPath(String prefix, String suffix) {
        // ç”Ÿæˆuuid
        String uuid = IdUtil.fastSimpleUUID();
@@ -57,6 +56,5 @@
    @Override
    public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
    @Override
    public abstract String getEndpointLink();
}
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunOssStrategy.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/AliyunCloudStorageStrategy.java ÐÞ¸Ä
@@ -9,10 +9,10 @@
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.enumd.OssEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -22,12 +22,12 @@
 *
 * @author Lion Li
 */
public class AliyunCloudStorageStrategy extends AbstractCloudStorageStrategy {
public class AliyunOssStrategy extends AbstractOssStrategy {
    private OSSClient client;
    @Override
    public void init(CloudStorageProperties cloudStorageProperties) {
    public void init(OssProperties cloudStorageProperties) {
        properties = cloudStorageProperties;
        try {
            ClientConfiguration configuration = new ClientConfiguration();
@@ -57,7 +57,7 @@
    @Override
    public String getServiceType() {
        return CloudServiceEnumd.ALIYUN.getValue();
        return OssEnumd.ALIYUN.getValue();
    }
    @Override
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioOssStrategy.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/MinioCloudStorageStrategy.java ÐÞ¸Ä
@@ -2,11 +2,11 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.enumd.CloudServiceEnumd;
import com.ruoyi.oss.enumd.OssEnumd;
import com.ruoyi.oss.enumd.PolicyType;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import io.minio.*;
import org.springframework.http.MediaType;
@@ -18,12 +18,12 @@
 *
 * @author Lion Li
 */
public class MinioCloudStorageStrategy extends AbstractCloudStorageStrategy {
public class MinioOssStrategy extends AbstractOssStrategy {
    private MinioClient minioClient;
    @Override
    public void init(CloudStorageProperties cloudStorageProperties) {
    public void init(OssProperties cloudStorageProperties) {
        properties = cloudStorageProperties;
        try {
            minioClient = MinioClient.builder()
@@ -57,7 +57,7 @@
    @Override
    public String getServiceType() {
        return CloudServiceEnumd.MINIO.getValue();
        return OssEnumd.MINIO.getValue();
    }
    @Override
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudOssStrategy.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QcloudCloudStorageStrategy.java ÐÞ¸Ä
@@ -9,10 +9,10 @@
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.enumd.OssEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -22,12 +22,12 @@
 *
 * @author Lion Li
 */
public class QcloudCloudStorageStrategy extends AbstractCloudStorageStrategy {
public class QcloudOssStrategy extends AbstractOssStrategy {
    private COSClient client;
    @Override
    public void init(CloudStorageProperties cloudStorageProperties) {
    public void init(OssProperties cloudStorageProperties) {
        properties = cloudStorageProperties;
        try {
            COSCredentials credentials = new BasicCOSCredentials(
@@ -65,7 +65,7 @@
    @Override
    public String getServiceType() {
        return CloudServiceEnumd.QCLOUD.getValue();
        return OssEnumd.QCLOUD.getValue();
    }
    @Override
ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuOssStrategy.java
ÎļþÃû´Ó ruoyi-oss/src/main/java/com/ruoyi/oss/service/impl/QiniuCloudStorageStrategy.java ÐÞ¸Ä
@@ -8,10 +8,10 @@
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.enumd.CloudServiceEnumd;
import com.ruoyi.oss.enumd.OssEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.CloudStorageProperties;
import com.ruoyi.oss.service.abstractd.AbstractCloudStorageStrategy;
import com.ruoyi.oss.properties.OssProperties;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import java.io.InputStream;
@@ -20,14 +20,14 @@
 *
 * @author Lion Li
 */
public class QiniuCloudStorageStrategy extends AbstractCloudStorageStrategy {
public class QiniuOssStrategy extends AbstractOssStrategy {
    private UploadManager uploadManager;
    private BucketManager bucketManager;
    private String token;
    private Auth auth;
    @Override
    public void init(CloudStorageProperties cloudStorageProperties) {
    public void init(OssProperties cloudStorageProperties) {
        properties = cloudStorageProperties;
        try {
            Configuration config = new Configuration(getRegion(properties.getRegion()));
@@ -35,9 +35,8 @@
            config.useHttpsDomains = false;
            config.useHttpsDomains = "Y".equals(properties.getIsHttps());
            uploadManager = new UploadManager(config);
            Auth auth = Auth.create(properties.getAccessKey(), properties.getSecretKey());
            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)) {
@@ -63,15 +62,16 @@
    @Override
    public String getServiceType() {
        return CloudServiceEnumd.QINIU.getValue();
        return OssEnumd.QINIU.getValue();
    }
    @Override
    public UploadResult upload(byte[] data, String path, String contentType) {
        try {
            Response res = uploadManager.put(data, path, token, null, contentType, false);
            String token = auth.uploadToken(properties.getBucketName());
            Response res = uploadManager.put(data, path, token, null, contentType, false);
            if (!res.isOK()) {
                throw new RuntimeException("上传七牛出错:" + res.toString());
                throw new RuntimeException("上传七牛出错:" + res.error);
            }
        } catch (Exception e) {
            throw new OssException("上传文件失败,请核对七牛配置信息:[" + e.getMessage() + "]");
@@ -85,7 +85,7 @@
            path = path.replace(getEndpointLink() + "/", "");
            Response res = bucketManager.delete(properties.getBucketName(), path);
            if (!res.isOK()) {
                throw new RuntimeException("删除七牛文件出错:" + res.toString());
                throw new RuntimeException("删除七牛文件出错:" + res.error);
            }
        } catch (Exception e) {
            throw new OssException(e.getMessage());
ruoyi-quartz/pom.xml
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
ÎļþÒÑɾ³ý
ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
ÎļþÒÑɾ³ý
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java
@@ -67,7 +67,7 @@
     * å¸å·çŠ¶æ€ï¼ˆ0正常 1停用)
     */
    @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "sys_common_status")
    @ExcelDictFormat(dictType = "sys_normal_disable")
    private String status;
}
ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
package com.ruoyi.system.listener;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.excel.ExcelListener;
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.vo.SysUserImportVo;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
/**
 * ç³»ç»Ÿç”¨æˆ·è‡ªå®šä¹‰å¯¼å…¥
 *
 * @author Lion Li
 */
@Slf4j
public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo> implements ExcelListener<SysUserImportVo> {
    private final ISysUserService userService;
    private final String password;
    private final Boolean isUpdateSupport;
    private final String operName;
    private int successNum = 0;
    private int failureNum = 0;
    private final StringBuilder successMsg = new StringBuilder();
    private final StringBuilder failureMsg = new StringBuilder();
    public SysUserImportListener(Boolean isUpdateSupport) {
        this.userService = SpringUtils.getBean(ISysUserService.class);
        this.password = SpringUtils.getBean(ISysConfigService.class)
            .selectConfigByKey("sys.user.initPassword");
        this.isUpdateSupport = isUpdateSupport;
        this.operName = SecurityUtils.getUsername();
    }
    @Override
    public void invoke(SysUserImportVo userVo, AnalysisContext context) {
        SysUser user = this.userService.selectUserByUserName(userVo.getUserName());
        try {
            // éªŒè¯æ˜¯å¦å­˜åœ¨è¿™ä¸ªç”¨æˆ·
            if (StringUtils.isNull(user)) {
                user = BeanUtil.toBean(userVo, SysUser.class);
                user.setPassword(SecurityUtils.encryptPassword(password));
                user.setCreateBy(operName);
                userService.insertUser(user);
                successNum++;
                successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" å¯¼å…¥æˆåŠŸ");
            } else if (isUpdateSupport) {
                user.setUpdateBy(operName);
                userService.updateUser(user);
                successNum++;
                successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" æ›´æ–°æˆåŠŸ");
            } else {
                failureNum++;
                failureMsg.append("<br/>").append(failureNum).append("、账号 ").append(user.getUserName()).append(" å·²å­˜åœ¨");
            }
        } catch (Exception e) {
            failureNum++;
            String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " å¯¼å…¥å¤±è´¥ï¼š";
            failureMsg.append(msg).append(e.getMessage());
            log.error(msg, e);
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
    }
    @Override
    public ExcelResult<SysUserImportVo> getExcelResult() {
        return new ExcelResult<SysUserImportVo>() {
            @Override
            public String getAnalysis() {
                if (failureNum > 0) {
                    failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " æ¡æ•°æ®æ ¼å¼ä¸æ­£ç¡®ï¼Œé”™è¯¯å¦‚下:");
                    throw new ServiceException(failureMsg.toString());
                } else {
                    successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " æ¡ï¼Œæ•°æ®å¦‚下:");
                }
                return successMsg.toString();
            }
            @Override
            public List<SysUserImportVo> getList() {
                return null;
            }
            @Override
            public List<String> getErrorList() {
                return null;
            }
        };
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
@@ -58,6 +58,6 @@
     * @param menuCheckStrictly èœå•树选择项是否关联显示
     * @return é€‰ä¸­èœå•列表
     */
    List<Integer> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
    List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
}
ruoyi-system/src/main/java/com/ruoyi/system/runner/SystemApplicationRunner.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.system.runner;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDictTypeService;
import com.ruoyi.system.service.ISysOssConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
 * åˆå§‹åŒ– system æ¨¡å—对应业务数据
 *
 * @author Lion Li
 */
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Component
public class SystemApplicationRunner implements ApplicationRunner {
    private final RuoYiConfig ruoyiConfig;
    private final ISysConfigService configService;
    private final ISysDictTypeService dictTypeService;
    private final ISysOssConfigService ossConfigService;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        ossConfigService.init();
        log.info("初始化OSS配置成功");
        if (ruoyiConfig.isCacheLazy()){
            return;
        }
        configService.loadingConfigCache();
        log.info("加载参数缓存数据成功");
        dictTypeService.loadingDictCache();
        log.info("加载字典缓存数据成功");
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
@@ -1,7 +1,7 @@
package com.ruoyi.system.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysDept;
import java.util.List;
@@ -21,20 +21,12 @@
    List<SysDept> selectDeptList(SysDept dept);
    /**
     * æž„建前端所需要树结构
     *
     * @param depts éƒ¨é—¨åˆ—表
     * @return æ ‘结构列表
     */
    List<SysDept> buildDeptTree(List<SysDept> depts);
    /**
     * æž„建前端所需要下拉树结构
     *
     * @param depts éƒ¨é—¨åˆ—表
     * @return ä¸‹æ‹‰æ ‘结构列表
     */
    List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts);
    List<Tree<Long>> buildDeptTreeSelect(List<SysDept> depts);
    /**
     * æ ¹æ®è§’色ID查询部门树信息
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
@@ -1,7 +1,7 @@
package com.ruoyi.system.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.system.domain.vo.RouterVo;
@@ -54,7 +54,7 @@
     * @param roleId è§’色ID
     * @return é€‰ä¸­èœå•列表
     */
    List<Integer> selectMenuListByRoleId(Long roleId);
    List<Long> selectMenuListByRoleId(Long roleId);
    /**
     * æž„建前端路由所需要的菜单
@@ -65,20 +65,12 @@
    List<RouterVo> buildMenus(List<SysMenu> menus);
    /**
     * æž„建前端所需要树结构
     *
     * @param menus èœå•列表
     * @return æ ‘结构列表
     */
    List<SysMenu> buildMenuTree(List<SysMenu> menus);
    /**
     * æž„建前端所需要下拉树结构
     *
     * @param menus èœå•列表
     * @return ä¸‹æ‹‰æ ‘结构列表
     */
    List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus);
    List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus);
    /**
     * æ ¹æ®èœå•ID查询信息
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java
@@ -18,6 +18,11 @@
public interface ISysOssConfigService extends IServicePlus<SysOssConfig, SysOssConfigVo> {
    /**
     * åˆå§‹åŒ–OSS配置
     */
    void init();
    /**
     * æŸ¥è¯¢å•个
     */
    SysOssConfigVo queryById(Integer ossConfigId);
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -7,6 +7,7 @@
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.core.service.ConfigService;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
@@ -17,7 +18,6 @@
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -29,29 +29,17 @@
 * @author Lion Li
 */
@Service
public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysConfig, SysConfig> implements ISysConfigService {
    /**
     * é¡¹ç›®å¯åŠ¨æ—¶ï¼Œåˆå§‹åŒ–å‚æ•°åˆ°ç¼“å­˜
     */
    @PostConstruct
    public void init() {
        loadingConfigCache();
    }
public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysConfig, SysConfig> implements ISysConfigService, ConfigService {
    @Override
    public TableDataInfo<SysConfig> selectPageConfigList(SysConfig config) {
        Map<String, Object> params = config.getParams();
        LambdaQueryWrapper<SysConfig> lqw = new LambdaQueryWrapper<SysConfig>()
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime"));
            .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())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime"));
        return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
    }
@@ -75,12 +63,12 @@
     */
    @Override
    public String selectConfigByKey(String configKey) {
        String configValue = Convert.toStr(RedisUtils.getCacheObject(getCacheKey(configKey)));
        String configValue = RedisUtils.getCacheObject(getCacheKey(configKey));
        if (StringUtils.isNotEmpty(configValue)) {
            return configValue;
        }
        SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
                .eq(SysConfig::getConfigKey, configKey));
            .eq(SysConfig::getConfigKey, configKey));
        if (StringUtils.isNotNull(retConfig)) {
            RedisUtils.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
            return retConfig.getConfigValue();
@@ -112,15 +100,11 @@
    public List<SysConfig> selectConfigList(SysConfig config) {
        Map<String, Object> params = config.getParams();
        LambdaQueryWrapper<SysConfig> lqw = new LambdaQueryWrapper<SysConfig>()
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime"));
            .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())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime"));
        return baseMapper.selectList(lqw);
    }
@@ -218,6 +202,17 @@
    }
    /**
     * æ ¹æ®å‚æ•° key èŽ·å–å‚æ•°å€¼
     *
     * @param configKey å‚æ•° key
     * @return å‚数值
     */
    @Override
    public String getConfigValue(String configKey) {
        return selectConfigByKey(configKey);
    }
    /**
     * è®¾ç½®cache key
     *
     * @param configKey å‚æ•°é”®
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -1,11 +1,11 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
@@ -13,6 +13,7 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TreeBuildUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
@@ -21,10 +22,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
 * éƒ¨é—¨ç®¡ç† æœåŠ¡å®žçŽ°
@@ -53,41 +52,18 @@
    }
    /**
     * æž„建前端所需要树结构
     *
     * @param depts éƒ¨é—¨åˆ—表
     * @return æ ‘结构列表
     */
    @Override
    public List<SysDept> buildDeptTree(List<SysDept> depts) {
        List<SysDept> returnList = new ArrayList<SysDept>();
        List<Long> tempList = new ArrayList<Long>();
        for (SysDept dept : depts) {
            tempList.add(dept.getDeptId());
        }
        for (SysDept dept : depts) {
            // å¦‚果是顶级节点, éåŽ†è¯¥çˆ¶èŠ‚ç‚¹çš„æ‰€æœ‰å­èŠ‚ç‚¹
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }
    /**
     * æž„建前端所需要下拉树结构
     *
     * @param depts éƒ¨é—¨åˆ—表
     * @return ä¸‹æ‹‰æ ‘结构列表
     */
    @Override
    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {
        List<SysDept> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    public List<Tree<Long>> buildDeptTreeSelect(List<SysDept> depts) {
        return TreeBuildUtils.build(depts, (dept, tree) ->
            tree.setId(dept.getDeptId())
                .setParentId(dept.getParentId())
                .setName(dept.getDeptName())
                .setWeight(dept.getOrderNum()));
    }
    /**
@@ -122,8 +98,8 @@
    @Override
    public long selectNormalChildrenDeptById(Long deptId) {
        return count(new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getStatus, 0)
                .apply("find_in_set({0}, ancestors)", deptId));
            .eq(SysDept::getStatus, 0)
            .apply("find_in_set({0}, ancestors)", deptId));
    }
    /**
@@ -135,8 +111,7 @@
    @Override
    public boolean hasChildByDeptId(Long deptId) {
        long result = count(new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getParentId, deptId)
                .last("limit 1"));
            .eq(SysDept::getParentId, deptId));
        return result > 0;
    }
@@ -149,7 +124,7 @@
    @Override
    public boolean checkDeptExistUser(Long deptId) {
        long result = userMapper.selectCount(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getDeptId, deptId));
            .eq(SysUser::getDeptId, deptId));
        return result > 0;
    }
@@ -162,11 +137,11 @@
    @Override
    public String checkDeptNameUnique(SysDept dept) {
        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 (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysDept>()
            .eq(SysDept::getDeptName, dept.getDeptName())
            .eq(SysDept::getParentId, dept.getParentId())
            .ne(SysDept::getDeptId, deptId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -224,7 +199,7 @@
        }
        int result = baseMapper.updateById(dept);
        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
                && !StringUtils.equals("0", dept.getAncestors())) {
            && !StringUtils.equals("0", dept.getAncestors())) {
            // å¦‚果该部门是启用状态,则启用该部门的所有上级部门
            updateParentDeptStatusNormal(dept);
        }
@@ -240,8 +215,8 @@
        String ancestors = dept.getAncestors();
        Long[] deptIds = Convert.toLongArray(ancestors);
        update(null, new LambdaUpdateWrapper<SysDept>()
                .set(SysDept::getStatus, "0")
                .in(SysDept::getDeptId, Arrays.asList(deptIds)));
            .set(SysDept::getStatus, "0")
            .in(SysDept::getDeptId, Arrays.asList(deptIds)));
    }
    /**
@@ -253,7 +228,7 @@
     */
    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
        List<SysDept> children = list(new LambdaQueryWrapper<SysDept>()
                .apply("find_in_set({0},ancestors)", deptId));
            .apply("find_in_set({0},ancestors)", deptId));
        for (SysDept child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }
@@ -273,37 +248,4 @@
        return baseMapper.deleteById(deptId);
    }
    /**
     * é€’归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t) {
        // å¾—到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }
    /**
     * å¾—到子节点列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
        List<SysDept> tlist = new ArrayList<SysDept>();
        for (SysDept n : list) {
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦æœ‰å­èŠ‚ç‚¹
     */
    private boolean hasChild(List<SysDept> list, SysDept t) {
        return getChildList(list, t).size() > 0;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
@@ -1,11 +1,12 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.service.ISysDictDataService;
@@ -85,7 +86,7 @@
            SysDictData data = selectDictDataById(dictCode);
            removeById(dictCode);
            List<SysDictData> dictDatas = baseMapper.selectDictDataByType(data.getDictType());
            DictUtils.setDictCache(data.getDictType(), dictDatas);
            RedisUtils.setCacheObject(getCacheKey(data.getDictType()), dictDatas);
        }
    }
@@ -100,7 +101,7 @@
        int row = baseMapper.insert(data);
        if (row > 0) {
            List<SysDictData> dictDatas = baseMapper.selectDictDataByType(data.getDictType());
            DictUtils.setDictCache(data.getDictType(), dictDatas);
            RedisUtils.setCacheObject(getCacheKey(data.getDictType()), dictDatas);
        }
        return row;
    }
@@ -116,8 +117,18 @@
        int row = baseMapper.updateById(data);
        if (row > 0) {
            List<SysDictData> dictDatas = baseMapper.selectDictDataByType(data.getDictType());
            DictUtils.setDictCache(data.getDictType(), dictDatas);
            RedisUtils.setCacheObject(getCacheKey(data.getDictType()), dictDatas);
        }
        return row;
    }
    /**
     * è®¾ç½®cache key
     *
     * @param configKey å‚æ•°é”®
     * @return ç¼“存键key
     */
    String getCacheKey(String configKey) {
        return Constants.SYS_DICT_KEY + configKey;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
@@ -3,14 +3,16 @@
import cn.hutool.core.collection.CollUtil;
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.UserConstants;
import com.ruoyi.common.core.domain.entity.SysDictData;
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.core.service.DictService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.mapper.SysDictTypeMapper;
@@ -19,8 +21,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -30,32 +32,20 @@
 * @author Lion Li
 */
@Service
public class SysDictTypeServiceImpl extends ServicePlusImpl<SysDictTypeMapper, SysDictType, SysDictType> implements ISysDictTypeService {
public class SysDictTypeServiceImpl extends ServicePlusImpl<SysDictTypeMapper, SysDictType, SysDictType> implements ISysDictTypeService, DictService {
    @Autowired
    private SysDictDataMapper dictDataMapper;
    /**
     * é¡¹ç›®å¯åŠ¨æ—¶ï¼Œåˆå§‹åŒ–å­—å…¸åˆ°ç¼“å­˜
     */
    @PostConstruct
    public void init() {
        loadingDictCache();
    }
    @Override
    public TableDataInfo<SysDictType> selectPageDictTypeList(SysDictType dictType) {
        Map<String, Object> params = dictType.getParams();
        LambdaQueryWrapper<SysDictType> lqw = new LambdaQueryWrapper<SysDictType>()
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime"));
            .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())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime"));
        return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
    }
@@ -69,15 +59,11 @@
    public List<SysDictType> selectDictTypeList(SysDictType dictType) {
        Map<String, Object> params = dictType.getParams();
        return list(new LambdaQueryWrapper<SysDictType>()
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime")));
            .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())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime")));
    }
    /**
@@ -98,13 +84,13 @@
     */
    @Override
    public List<SysDictData> selectDictDataByType(String dictType) {
        List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
        if (CollUtil.isNotEmpty(dictDatas)) {
        List<SysDictData> dictDatas = RedisUtils.getCacheObject(getCacheKey(dictType));
        if (StringUtils.isNotEmpty(dictDatas)) {
            return dictDatas;
        }
        dictDatas = dictDataMapper.selectDictDataByType(dictType);
        if (CollUtil.isNotEmpty(dictDatas)) {
            DictUtils.setDictCache(dictType, dictDatas);
            RedisUtils.setCacheObject(getCacheKey(dictType), dictDatas);
            return dictDatas;
        }
        return null;
@@ -143,10 +129,10 @@
        for (Long dictId : dictIds) {
            SysDictType dictType = selectDictTypeById(dictId);
            if (dictDataMapper.selectCount(new LambdaQueryWrapper<SysDictData>()
                    .eq(SysDictData::getDictType, dictType.getDictType())) > 0) {
                .eq(SysDictData::getDictType, dictType.getDictType())) > 0) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
            }
            DictUtils.removeDictCache(dictType.getDictType());
            RedisUtils.deleteObject(getCacheKey(dictType.getDictType()));
        }
        baseMapper.deleteBatchIds(Arrays.asList(dictIds));
    }
@@ -159,7 +145,7 @@
        List<SysDictType> dictTypeList = list();
        for (SysDictType dictType : dictTypeList) {
            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dictType.getDictType());
            DictUtils.setDictCache(dictType.getDictType(), dictDatas);
            RedisUtils.setCacheObject(getCacheKey(dictType.getDictType()), dictDatas);
        }
    }
@@ -168,7 +154,8 @@
     */
    @Override
    public void clearDictCache() {
        DictUtils.clearDictCache();
        Collection<String> keys = RedisUtils.keys(Constants.SYS_DICT_KEY + "*");
        RedisUtils.deleteObject(keys);
    }
    /**
@@ -190,7 +177,7 @@
    public int insertDictType(SysDictType dict) {
        int row = baseMapper.insert(dict);
        if (row > 0) {
            DictUtils.setDictCache(dict.getDictType(), null);
            RedisUtils.setCacheObject(getCacheKey(dict.getDictType()), null);
        }
        return row;
    }
@@ -206,12 +193,12 @@
    public int updateDictType(SysDictType dict) {
        SysDictType oldDict = getById(dict.getDictId());
        dictDataMapper.update(null, new LambdaUpdateWrapper<SysDictData>()
                .set(SysDictData::getDictType, dict.getDictType())
                .eq(SysDictData::getDictType, oldDict.getDictType()));
            .set(SysDictData::getDictType, dict.getDictType())
            .eq(SysDictData::getDictType, oldDict.getDictType()));
        int row = baseMapper.updateById(dict);
        if (row > 0) {
            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());
            DictUtils.setDictCache(dict.getDictType(), dictDatas);
            RedisUtils.setCacheObject(getCacheKey(dict.getDictType()), dictDatas);
        }
        return row;
    }
@@ -225,12 +212,86 @@
    @Override
    public String checkDictTypeUnique(SysDictType dict) {
        Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
        SysDictType dictType = getOne(new LambdaQueryWrapper<SysDictType>()
                .eq(SysDictType::getDictType, dict.getDictType())
                .last("limit 1"));
        if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysDictType>()
            .eq(SysDictType::getDictType, dict.getDictType())
            .ne(SysDictType::getDictId, dictId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }
    /**
     * æ ¹æ®å­—典类型和字典值获取字典标签
     *
     * @param dictType  å­—典类型
     * @param dictValue å­—典值
     * @param separator åˆ†éš”符
     * @return å­—典标签
     */
    @Override
    public String getDictLabel(String dictType, String dictValue, String separator) {
        StringBuilder propertyString = new StringBuilder();
        List<SysDictData> datas = selectDictDataByType(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 å­—典值
     */
    @Override
    public String getDictValue(String dictType, String dictLabel, String separator) {
        StringBuilder propertyString = new StringBuilder();
        List<SysDictData> datas = selectDictDataByType(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);
    }
    /**
     * è®¾ç½®cache key
     *
     * @param configKey å‚æ•°é”®
     * @return ç¼“存键key
     */
    String getCacheKey(String configKey) {
        return Constants.SYS_DICT_KEY + configKey;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
@@ -90,16 +90,12 @@
    public TableDataInfo<SysLogininfor> selectPageLogininforList(SysLogininfor logininfor) {
        Map<String, Object> params = logininfor.getParams();
        LambdaQueryWrapper<SysLogininfor> lqw = new LambdaQueryWrapper<SysLogininfor>()
                .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(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));
            .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())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"));
        return PageUtils.buildDataInfo(page(PageUtils.buildPage("info_id", "desc"), lqw));
    }
    /**
@@ -123,16 +119,12 @@
    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor) {
        Map<String, Object> params = logininfor.getParams();
        return list(new LambdaQueryWrapper<SysLogininfor>()
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(login_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime"))
                .orderByDesc(SysLogininfor::getInfoId));
            .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())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"))
            .orderByDesc(SysLogininfor::getInfoId));
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -1,15 +1,16 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
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.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TreeBuildUtils;
import com.ruoyi.system.domain.SysRoleMenu;
import com.ruoyi.system.domain.vo.MetaVo;
import com.ruoyi.system.domain.vo.RouterVo;
@@ -21,7 +22,6 @@
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
 * èœå• ä¸šåŠ¡å±‚å¤„ç†
@@ -60,11 +60,11 @@
        // ç®¡ç†å‘˜æ˜¾ç¤ºæ‰€æœ‰èœå•信息
        if (SysUser.isAdmin(userId)) {
            menuList = list(new LambdaQueryWrapper<SysMenu>()
                    .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));
                .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 {
            menu.getParams().put("userId", userId);
            menuList = baseMapper.selectMenuListByUserId(menu);
@@ -114,7 +114,7 @@
     * @return é€‰ä¸­èœå•列表
     */
    @Override
    public List<Integer> selectMenuListByRoleId(Long roleId) {
    public List<Long> selectMenuListByRoleId(Long roleId) {
        SysRole role = roleMapper.selectById(roleId);
        return baseMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
    }
@@ -171,41 +171,18 @@
    }
    /**
     * æž„建前端所需要树结构
     *
     * @param menus èœå•列表
     * @return æ ‘结构列表
     */
    @Override
    public List<SysMenu> buildMenuTree(List<SysMenu> menus) {
        List<SysMenu> returnList = new ArrayList<SysMenu>();
        List<Long> tempList = new ArrayList<Long>();
        for (SysMenu dept : menus) {
            tempList.add(dept.getMenuId());
        }
        for (SysMenu menu : menus) {
            // å¦‚果是顶级节点, éåŽ†è¯¥çˆ¶èŠ‚ç‚¹çš„æ‰€æœ‰å­èŠ‚ç‚¹
            if (!tempList.contains(menu.getParentId())) {
                recursionFn(menus, menu);
                returnList.add(menu);
            }
        }
        if (returnList.isEmpty()) {
            returnList = menus;
        }
        return returnList;
    }
    /**
     * æž„建前端所需要下拉树结构
     *
     * @param menus èœå•列表
     * @return ä¸‹æ‹‰æ ‘结构列表
     */
    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus) {
        List<SysMenu> menuTrees = buildMenuTree(menus);
        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    public List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus) {
        return TreeBuildUtils.build(menus, (menu, tree) ->
            tree.setId(menu.getMenuId())
                .setParentId(menu.getParentId())
                .setName(menu.getMenuName())
                .setWeight(menu.getOrderNum()));
    }
    /**
@@ -285,11 +262,11 @@
    @Override
    public String checkMenuNameUnique(SysMenu menu) {
        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 (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysMenu>()
            .eq(SysMenu::getMenuName, menu.getMenuName())
            .eq(SysMenu::getParentId, menu.getParentId())
            .ne(SysMenu::getMenuId, menuId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -324,7 +301,7 @@
        }
        // éžå¤–链并且是一级目录(类型为目录)
        if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
                && UserConstants.NO_FRAME.equals(menu.getIsFrame())) {
            && UserConstants.NO_FRAME.equals(menu.getIsFrame())) {
            routerPath = "/" + menu.getPath();
        }
        // éžå¤–链并且是一级目录(类型为菜单)
@@ -360,7 +337,7 @@
     */
    public boolean isMenuFrame(SysMenu menu) {
        return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType())
                && menu.getIsFrame().equals(UserConstants.NO_FRAME);
            && menu.getIsFrame().equals(UserConstants.NO_FRAME);
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
@@ -47,23 +47,19 @@
    public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog) {
        Map<String, Object> params = operLog.getParams();
        LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
                .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
                .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                        SysOperLog::getBusinessType, operLog.getBusinessType())
                .func(f -> {
                    if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
                        f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
                    }
                })
                .eq(operLog.getStatus() != null,
                        SysOperLog::getStatus, operLog.getStatus())
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(oper_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime"));
            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
            .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                SysOperLog::getBusinessType, operLog.getBusinessType())
            .func(f -> {
                if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
                    f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
                }
            })
            .eq(operLog.getStatus() != null,
                SysOperLog::getStatus, operLog.getStatus())
            .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
        return PageUtils.buildDataInfo(page(PageUtils.buildPage("oper_id", "desc"), lqw));
    }
@@ -88,24 +84,20 @@
    public List<SysOperLog> selectOperLogList(SysOperLog operLog) {
        Map<String, Object> params = operLog.getParams();
        return list(new LambdaQueryWrapper<SysOperLog>()
                .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
                .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                        SysOperLog::getBusinessType, operLog.getBusinessType())
                .func(f -> {
                    if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
                        f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
                    }
                })
                .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
                        SysOperLog::getStatus, operLog.getStatus())
                .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(StringUtils.isNotEmpty(params.get("endTime")),
                        "date_format(oper_time,'%y%m%d') <= date_format({0},'%y%m%d')",
                        params.get("endTime"))
                .orderByDesc(SysOperLog::getOperId));
            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
            .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
                SysOperLog::getBusinessType, operLog.getBusinessType())
            .func(f -> {
                if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
                    f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
                }
            })
            .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
                SysOperLog::getStatus, operLog.getStatus())
            .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"))
            .orderByDesc(SysOperLog::getOperId));
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java
@@ -15,7 +15,8 @@
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.constant.CloudConstant;
import com.ruoyi.oss.constant.OssConstant;
import com.ruoyi.oss.factory.OssFactory;
import com.ruoyi.system.domain.SysOssConfig;
import com.ruoyi.system.domain.bo.SysOssConfigBo;
import com.ruoyi.system.domain.vo.SysOssConfigVo;
@@ -27,7 +28,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
@@ -46,16 +46,19 @@
    /**
     * é¡¹ç›®å¯åŠ¨æ—¶ï¼Œåˆå§‹åŒ–å‚æ•°åˆ°ç¼“å­˜ï¼ŒåŠ è½½é…ç½®ç±»
     */
    @PostConstruct
    @Override
    public void init() {
        List<SysOssConfig> list = list();
        // åŠ è½½OSS初始化配置
        for (SysOssConfig config : list) {
            String configKey = config.getConfigKey();
            if ("0".equals(config.getStatus())) {
                RedisUtils.setCacheObject(CloudConstant.CACHE_CONFIG_KEY, configKey);
                RedisUtils.setCacheObject(OssConstant.CACHE_CONFIG_KEY, configKey);
            }
            setConfigCache(true, config);
        }
        // åˆå§‹åŒ–OSS工厂
        OssFactory.init();
    }
    @Override
@@ -110,7 +113,7 @@
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            if (CollUtil.containsAny(ids, CloudConstant.SYSTEM_DATA_IDS)) {
            if (CollUtil.containsAny(ids, OssConstant.SYSTEM_DATA_IDS)) {
                throw new ServiceException("系统内置, ä¸å¯åˆ é™¤!");
            }
        }
@@ -153,7 +156,7 @@
                .set(SysOssConfig::getStatus, "1"));
        row += baseMapper.updateById(sysOssConfig);
        if (row > 0) {
            RedisUtils.setCacheObject(CloudConstant.CACHE_CONFIG_KEY, sysOssConfig.getConfigKey());
            RedisUtils.setCacheObject(OssConstant.CACHE_CONFIG_KEY, sysOssConfig.getConfigKey());
        }
        return row;
    }
@@ -165,7 +168,7 @@
     * @return ç¼“存键key
     */
    private String getCacheKey(String configKey) {
        return CloudConstant.SYS_OSS_KEY + configKey;
        return OssConstant.SYS_OSS_KEY + configKey;
    }
    /**
@@ -180,7 +183,7 @@
            RedisUtils.setCacheObject(
                    getCacheKey(config.getConfigKey()),
                    JsonUtils.toJsonString(config));
            RedisUtils.publish(CloudConstant.CACHE_CONFIG_KEY, config.getConfigKey(), msg -> {
            RedisUtils.publish(OssConstant.CACHE_CONFIG_KEY, config.getConfigKey(), msg -> {
                log.info("发布刷新OSS配置 => " + msg);
            });
        }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
@@ -10,7 +10,7 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.factory.OssFactory;
import com.ruoyi.oss.service.ICloudStorageStrategy;
import com.ruoyi.oss.service.IOssStrategy;
import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.domain.bo.SysOssBo;
import com.ruoyi.system.domain.vo.SysOssVo;
@@ -56,7 +56,7 @@
    public SysOss upload(MultipartFile file) {
        String originalfileName = file.getOriginalFilename();
        String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
        ICloudStorageStrategy storage = OssFactory.instance();
        IOssStrategy storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
@@ -81,7 +81,7 @@
        }
        List<SysOss> list = listByIds(ids);
        for (SysOss sysOss : list) {
            ICloudStorageStrategy storage = OssFactory.instance(sysOss.getService());
            IOssStrategy storage = OssFactory.instance(sysOss.getService());
            storage.delete(sysOss.getUrl());
        }
        return removeByIds(ids);
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
@@ -93,9 +93,10 @@
    @Override
    public String checkPostNameUnique(SysPost post) {
        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
        SysPost info = getOne(new LambdaQueryWrapper<SysPost>()
                .eq(SysPost::getPostName, post.getPostName()).last("limit 1"));
        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysPost>()
                .eq(SysPost::getPostName, post.getPostName())
                .ne(SysPost::getPostId, postId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -110,9 +111,10 @@
    @Override
    public String checkPostCodeUnique(SysPost post) {
        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
        SysPost info = getOne(new LambdaQueryWrapper<SysPost>()
                .eq(SysPost::getPostCode, post.getPostCode()).last("limit 1"));
        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysPost>()
                .eq(SysPost::getPostCode, post.getPostCode())
                .ne(SysPost::getPostId, postId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -141,9 +141,10 @@
    @Override
    public String checkRoleNameUnique(SysRole role) {
        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = getOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleName, role.getRoleName()).last("limit 1"));
        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleName, role.getRoleName())
                .ne(SysRole::getRoleId, roleId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -158,9 +159,10 @@
    @Override
    public String checkRoleKeyUnique(SysRole role) {
        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = getOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleKey, role.getRoleKey()).last("limit 1"));
        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
        long count = count(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleKey, role.getRoleKey())
                .ne(SysRole::getRoleId, roleId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -8,6 +8,7 @@
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.core.service.UserService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
@@ -35,7 +36,7 @@
 */
@Slf4j
@Service
public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser, SysUser> implements ISysUserService {
public class SysUserServiceImpl extends ServicePlusImpl<SysUserMapper, SysUser, SysUser> implements ISysUserService, UserService {
    @Autowired
    private SysRoleMapper roleMapper;
@@ -162,7 +163,7 @@
     */
    @Override
    public String checkUserNameUnique(String userName) {
        long count = count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName).last("limit 1"));
        long count = count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
@@ -178,10 +179,11 @@
    @Override
    public String checkPhoneUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = getOne(new LambdaQueryWrapper<SysUser>()
        long count = count(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserId, SysUser::getPhonenumber)
                .eq(SysUser::getPhonenumber, user.getPhonenumber()).last("limit 1"));
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
                .eq(SysUser::getPhonenumber, user.getPhonenumber())
                .ne(SysUser::getUserId, userId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
@@ -196,10 +198,11 @@
    @Override
    public String checkEmailUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = getOne(new LambdaQueryWrapper<SysUser>()
        long count = count(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserId, SysUser::getEmail)
                .eq(SysUser::getEmail, user.getEmail()).last("limit 1"));
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
                .eq(SysUser::getEmail, user.getEmail())
                .ne(SysUser::getUserId, userId));
        if (count > 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
ruoyi-system/src/main/resources/mapper/package-info.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
java包使用 `.` åˆ†å‰² resource ç›®å½•使用 `/` åˆ†å‰²
<br>
此文件目的 é˜²æ­¢æ–‡ä»¶å¤¹ç²˜è¿žæ‰¾ä¸åˆ° `xml` æ–‡ä»¶
ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -117,7 +117,7 @@
        order by m.parent_id, m.order_num
    </select>
    <select id="selectMenuListByRoleId" resultType="Integer">
    <select id="selectMenuListByRoleId" resultType="Long">
        select m.menu_id
        from sys_menu m
        left join sys_role_menu rm on m.menu_id = rm.menu_id
@@ -147,4 +147,4 @@
          and ur.user_id = #{userId}
    </select>
</mapper>
</mapper>
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -189,12 +189,12 @@
    <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
        <include refid="selectUserVo"/>
        where u.user_name = #{userName}
        where u.del_flag = '0' and u.user_name = #{userName}
    </select>
    <select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
        <include refid="selectUserVo"/>
        where u.user_id = #{userId}
        where u.del_flag = '0' and u.user_id = #{userId}
    </select>
ruoyi-ui/.env.development
@@ -7,6 +7,9 @@
# è‹¥ä¾ç®¡ç†ç³»ç»Ÿ/开发环境
VUE_APP_BASE_API = '/dev-api'
# åº”用访问路径 ä¾‹å¦‚使用前缀 /admin/
VUE_APP_CONTEXT_PATH = '/'
# ç›‘控地址
VUE_APP_MONITRO_ADMIN = 'http://localhost:9090/admin/login'
ruoyi-ui/.env.production
@@ -4,6 +4,9 @@
# ç”Ÿäº§çŽ¯å¢ƒé…ç½®
ENV = 'production'
# åº”用访问路径 ä¾‹å¦‚使用前缀 /admin/
VUE_APP_CONTEXT_PATH = '/'
# ç›‘控地址
VUE_APP_MONITRO_ADMIN = '/admin/login'
ruoyi-ui/.env.staging
@@ -6,6 +6,9 @@
# æµ‹è¯•环境配置
ENV = 'staging'
# åº”用访问路径 ä¾‹å¦‚使用前缀 /admin/
VUE_APP_CONTEXT_PATH = '/'
# ç›‘控地址
VUE_APP_MONITRO_ADMIN = '/admin/login'
ruoyi-ui/package.json
@@ -37,17 +37,17 @@
  },
  "dependencies": {
    "@riophae/vue-treeselect": "0.4.0",
    "axios": "0.21.0",
    "axios": "0.24.0",
    "clipboard": "2.0.6",
    "core-js": "3.8.1",
    "core-js": "3.19.1",
    "echarts": "4.9.0",
    "element-ui": "2.15.6",
    "file-saver": "2.0.5",
    "fuse.js": "6.4.3",
    "highlight.js": "9.18.5",
    "js-beautify": "1.13.0",
    "js-cookie": "2.2.1",
    "jsencrypt": "3.0.0-rc.1",
    "js-cookie": "3.0.1",
    "jsencrypt": "3.2.1",
    "nprogress": "0.2.0",
    "quill": "1.3.7",
    "screenfull": "5.0.2",
@@ -55,7 +55,7 @@
    "vue": "2.6.12",
    "vue-count-to": "1.0.13",
    "vue-cropper": "0.5.5",
    "vue-meta": "^2.4.0",
    "vue-meta": "2.4.0",
    "vue-router": "3.4.9",
    "vuedraggable": "2.24.3",
    "vuex": "3.6.0"
ruoyi-ui/src/api/login.js
@@ -10,6 +10,9 @@
  }
  return request({
    url: '/login',
    headers: {
      isToken: false
    },
    method: 'post',
    data: data
  })
@@ -47,7 +50,10 @@
export function getCodeImg() {
  return request({
    url: '/captchaImage',
    headers: {
      isToken: false
    },
    method: 'get',
    timeout: 20000
  })
}
}
ruoyi-ui/src/api/monitor/job.js
ÎļþÒÑɾ³ý
ruoyi-ui/src/api/monitor/jobLog.js
ÎļþÒÑɾ³ý
ruoyi-ui/src/api/monitor/server.js
ÎļþÒÑɾ³ý
ruoyi-ui/src/api/system/post.js
@@ -42,12 +42,3 @@
    method: 'delete'
  })
}
// å¯¼å‡ºå²—位
export function exportPost(query) {
  return request({
    url: '/system/post/export',
    method: 'get',
    params: query
  })
}
ruoyi-ui/src/components/Breadcrumb/index.vue
@@ -2,7 +2,7 @@
  <el-breadcrumb class="app-breadcrumb" separator="/">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
      </el-breadcrumb-item>
    </transition-group>
ruoyi-ui/src/components/RightToolbar/index.vue
@@ -62,7 +62,7 @@
    },
    // å³ä¾§åˆ—表元素变化
    dataChange(data) {
      for (var item in this.columns) {
      for (let item in this.columns) {
        const key = this.columns[item].key;
        this.columns[item].visible = !data.includes(key);
      }
ruoyi-ui/src/components/RuoYi/Doc/index.vue
@@ -1,6 +1,6 @@
<template>
  <div>
    <svg-icon icon-class="question" @click="goto"/>
    <svg-icon icon-class="question" @click="goto" />
  </div>
</template>
ruoyi-ui/src/components/RuoYi/Git/index.vue
@@ -1,6 +1,6 @@
<template>
  <div>
    <svg-icon icon-class="github" @click="goto"/>
    <svg-icon icon-class="github" @click="goto" />
  </div>
</template>
ruoyi-ui/src/components/SizeSelect/index.vue
@@ -5,8 +5,7 @@
    </div>
    <el-dropdown-menu slot="dropdown">
      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
        {{
          item.label }}
        {{ item.label }}
      </el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
ruoyi-ui/src/layout/components/Navbar.vue
@@ -102,7 +102,7 @@
        type: 'warning'
      }).then(() => {
        this.$store.dispatch('LogOut').then(() => {
          location.href = this.$router.options.base + '/index';
          location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
        })
      }).catch(() => {});
    }
ruoyi-ui/src/layout/components/Sidebar/Logo.vue
@@ -29,7 +29,7 @@
    variables() {
      return variables;
    },
    sideTheme() {
    sideTheme() {
      return this.$store.state.settings.sideTheme
    }
  },
ruoyi-ui/src/layout/components/TagsView/index.vue
@@ -152,31 +152,24 @@
      })
    },
    refreshSelectedTag(view) {
      this.$store.dispatch('tagsView/delCachedView', view).then(() => {
        const { fullPath } = view
        this.$nextTick(() => {
          this.$router.replace({
            path: '/redirect' + fullPath
          })
        })
      })
      this.$tab.refreshPage(view);
    },
    closeSelectedTag(view) {
      this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
      this.$tab.closePage(view).then(({ visitedViews }) => {
        if (this.isActive(view)) {
          this.toLastView(visitedViews, view)
        }
      })
    },
    closeRightTags() {
      this.$store.dispatch('tagsView/delRightTags', this.selectedTag).then(visitedViews => {
      this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
        if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
          this.toLastView(visitedViews)
        }
      })
    },
    closeLeftTags() {
      this.$store.dispatch('tagsView/delLeftTags', this.selectedTag).then(visitedViews => {
      this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
        if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
          this.toLastView(visitedViews)
        }
@@ -184,12 +177,12 @@
    },
    closeOthersTags() {
      this.$router.push(this.selectedTag).catch(()=>{});
      this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
      this.$tab.closeOtherPage(this.selectedTag).then(() => {
        this.moveToCurrentTag()
      })
    },
    closeAllTags(view) {
      this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
      this.$tab.closeAllPage().then(({ visitedViews }) => {
        if (this.affixTags.some(tag => tag.path === this.$route.path)) {
          return
        }
ruoyi-ui/src/layout/index.vue
@@ -98,7 +98,7 @@
  }
  .hideSidebar .fixed-header {
    width: calc(100% - 54px)
    width: calc(100% - 54px);
  }
  .mobile .fixed-header {
ruoyi-ui/src/main.js
@@ -10,8 +10,9 @@
import App from './App'
import store from './store'
import router from './router'
import directive from './directive' //directive
import directive from './directive' // directive
import plugins from './plugins' // plugins
import { download } from '@/utils/request'
import './assets/icons' // icon
import './permission' // permission control
@@ -43,6 +44,7 @@
Vue.prototype.addDateRange = addDateRange
Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
// å…¨å±€ç»„件挂载
ruoyi-ui/src/plugins/download.js
@@ -1,51 +1,12 @@
import { saveAs } from 'file-saver'
import axios from 'axios'
import { getToken } from '@/utils/auth'
import { Message } from 'element-ui'
import { saveAs } from 'file-saver'
import { getToken } from '@/utils/auth'
import { blobValidate } from "@/utils/ruoyi";
const baseURL = process.env.VUE_APP_BASE_API
export default {
  excel(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(async (res) => {
      const isLogin = await this.blobValidate(res.data);
      if (isLogin) {
        const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
        this.saveAs(blob, decodeURI(res.headers['download-filename']))
      } else {
          Message.error('无效的会话,或者会话已过期,请重新登录。');
      }
    })
  },
  oss(ossId) {
    var url = baseURL + '/system/oss/download/' + ossId
    axios({
@@ -54,7 +15,7 @@
      responseType: 'blob',
      headers: { 'Authorization': 'Bearer ' + getToken() }
    }).then(async (res) => {
      const isLogin = await this.blobValidate(res.data);
      const isLogin = await blobValidate(res.data);
      if (isLogin) {
        const blob = new Blob([res.data], { type: 'application/octet-stream' })
        this.saveAs(blob, decodeURI(res.headers['download-filename']))
@@ -71,7 +32,7 @@
      responseType: 'blob',
      headers: { 'Authorization': 'Bearer ' + getToken() }
    }).then(async (res) => {
      const isLogin = await this.blobValidate(res.data);
      const isLogin = await blobValidate(res.data);
      if (isLogin) {
        const blob = new Blob([res.data], { type: 'application/zip' })
        this.saveAs(blob, name)
@@ -82,15 +43,6 @@
  },
  saveAs(text, name, opts) {
    saveAs(text, name, opts);
  },
  async blobValidate(data) {
    try {
      const text = await data.text();
      JSON.parse(text);
      return false;
    } catch (error) {
      return true;
    }
  },
  }
}
ruoyi-ui/src/plugins/index.js
@@ -1,3 +1,4 @@
import tab from './tab'
import auth from './auth'
import cache from './cache'
import modal from './modal'
@@ -5,6 +6,8 @@
export default {
  install(Vue) {
    // é¡µç­¾æ“ä½œ
    Vue.prototype.$tab = tab
    // è®¤è¯å¯¹è±¡
    Vue.prototype.$auth = auth
    // ç¼“存对象
ruoyi-ui/src/plugins/tab.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
import store from '@/store'
import router from '@/router';
export default {
  // åˆ·æ–°å½“前tab页签
  refreshPage(obj) {
    const { path, matched } = router.currentRoute;
    if (obj === undefined) {
      matched.forEach((m) => {
        if (m.components && m.components.default && m.components.default.name) {
          if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
            obj = { name: m.components.default.name, path: path };
          }
        }
      });
    }
    return store.dispatch('tagsView/delCachedView', obj).then(() => {
      const { path } = obj
      router.replace({
        path: '/redirect' + path
      })
    })
  },
  // å…³é—­å½“前tab页签,打开新页签
  closeOpenPage(obj) {
    store.dispatch("tagsView/delView", router.currentRoute);
    if (obj !== undefined) {
      return router.push(obj);
    }
  },
  // å…³é—­æŒ‡å®štab页签
  closePage(obj) {
    if (obj === undefined) {
      return store.dispatch('tagsView/delView', router.currentRoute).then(({ lastPath }) => {
        return router.push(lastPath || '/');
      });
    }
    return store.dispatch('tagsView/delView', obj);
  },
  // å…³é—­æ‰€æœ‰tab页签
  closeAllPage() {
    return store.dispatch('tagsView/delAllViews');
  },
  // å…³é—­å·¦ä¾§tab页签
  closeLeftPage(obj) {
    return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute);
  },
  // å…³é—­å³ä¾§tab页签
  closeRightPage(obj) {
    return store.dispatch('tagsView/delRightTags', obj || router.currentRoute);
  },
  // å…³é—­å…¶ä»–tab页签
  closeOtherPage(obj) {
    return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
  },
  // æ·»åŠ tab页签
  openPage(title, url) {
    var obj = { path: url, meta: { title: title } }
    store.dispatch('tagsView/addView', obj);
    return router.push(url);
  },
  // ä¿®æ”¹tab页签
  updatePage(obj) {
    return store.dispatch('tagsView/updateVisitedView', obj);
  }
}
ruoyi-ui/src/router/index.js
@@ -95,7 +95,7 @@
        path: 'role/:userId(\\d+)',
        component: (resolve) => require(['@/views/system/user/authRole'], resolve),
        name: 'AuthRole',
        meta: { title: '分配角色', activeMenu: '/system/user'}
        meta: { title: '分配角色', activeMenu: '/system/user' }
      }
    ]
  },
@@ -108,7 +108,7 @@
        path: 'user/:roleId(\\d+)',
        component: (resolve) => require(['@/views/system/role/authUser'], resolve),
        name: 'AuthUser',
        meta: { title: '分配用户', activeMenu: '/system/role'}
        meta: { title: '分配用户', activeMenu: '/system/role' }
      }
    ]
  },
@@ -121,7 +121,7 @@
        path: 'index/:dictId(\\d+)',
        component: (resolve) => require(['@/views/system/dict/data'], resolve),
        name: 'Data',
        meta: { title: '字典数据', activeMenu: '/system/dict'}
        meta: { title: '字典数据', activeMenu: '/system/dict' }
      }
    ]
  },
@@ -139,19 +139,6 @@
    ]
  },
  {
    path: '/monitor/job-log',
    component: Layout,
    hidden: true,
    children: [
      {
        path: 'index',
        component: (resolve) => require(['@/views/monitor/job/log'], resolve),
        name: 'JobLog',
        meta: { title: '调度日志', activeMenu: '/monitor/job'}
      }
    ]
  },
  {
    path: '/tool/gen-edit',
    component: Layout,
    hidden: true,
@@ -160,14 +147,13 @@
        path: 'index',
        component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
        name: 'GenEdit',
        meta: { title: '修改生成配置', activeMenu: '/tool/gen'}
        meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
      }
    ]
  }
]
export default new Router({
  base: "", // é¡¹ç›®å‰ç¼€ ä¸Ž publicPath åŒæ­¥ ä¾‹å¦‚ /api
  mode: 'history', // åŽ»æŽ‰url中的#
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
ruoyi-ui/src/store/modules/permission.js
@@ -1,7 +1,7 @@
import { constantRoutes } from '@/router'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView';
import ParentView from '@/components/ParentView'
import InnerLink from '@/layout/components/InnerLink'
const permission = {
@@ -24,7 +24,7 @@
      // é¡¶éƒ¨å¯¼èˆªèœå•默认添加统计报表栏指向首页
      const index = [{
        path: 'index',
        meta: { title: '统计报表', icon: 'dashboard'}
        meta: { title: '统计报表', icon: 'dashboard' }
      }]
      state.topbarRouters = routes.concat(index);
    },
ruoyi-ui/src/store/modules/settings.js
@@ -8,7 +8,7 @@
  theme: storageSetting.theme || '#409EFF',
  sideTheme: storageSetting.sideTheme || sideTheme,
  showSettings: showSettings,
  topNav:  storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
  topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
  tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
  fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
  sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
ruoyi-ui/src/store/modules/tagsView.js
@@ -14,7 +14,7 @@
  },
  ADD_CACHED_VIEW: (state, view) => {
    if (state.cachedViews.includes(view.name)) return
    if (!view.meta.noCache) {
    if (view.meta && !view.meta.noCache) {
      state.cachedViews.push(view.name)
    }
  },
@@ -63,7 +63,7 @@
      }
    }
  },
  DEL_RIGHT_VIEWS: (state, view) => {
    const index = state.visitedViews.findIndex(v => v.path === view.path)
    if (index === -1) {
ruoyi-ui/src/utils/dict/index.js
@@ -5,7 +5,7 @@
  mergeOptions(options)
  Vue.mixin({
    data() {
      if (this.$options.dicts === undefined || this.$options.dicts === null) {
      if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
        return {}
      }
      const dict = new Dict()
ruoyi-ui/src/utils/index.js
@@ -5,12 +5,12 @@
 */
export function formatDate(cellValue) {
  if (cellValue == null || cellValue == "") return "";
  var date = new Date(cellValue)
  var date = new Date(cellValue)
  var year = date.getFullYear()
  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
  var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
  return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
}
@@ -330,7 +330,7 @@
    ? val => map[val.toLowerCase()]
    : val => map[val]
}
export const exportDefault = 'export default '
export const beautifierConf = {
@@ -381,10 +381,10 @@
// ä¸‹åˆ’转驼峰
export function camelCase(str) {
  return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
  return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}
export function isNumberStr(str) {
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}
ruoyi-ui/src/utils/request.js
@@ -1,8 +1,12 @@
import axios from 'axios'
import { Notification, MessageBox, Message } from 'element-ui'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi";
import { saveAs } from 'file-saver'
let downloadLoadingInstance;
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// å¯¹åº”国际化资源文件后缀
@@ -14,6 +18,7 @@
  // è¶…æ—¶
  timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
  // æ˜¯å¦éœ€è¦è®¾ç½® token
@@ -23,24 +28,7 @@
  }
  // get请求映射params参数
  if (config.method === 'get' && config.params) {
    let url = config.url + '?';
    for (const propName of Object.keys(config.params)) {
      const value = config.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) + '=';
              url += subPart + encodeURIComponent(value[key]) + '&';
            }
          }
        } else {
          url += part + encodeURIComponent(value) + "&";
        }
      }
    }
    let url = config.url + '?' + tansParams(config.params);
    url = url.slice(0, -1);
    config.params = {};
    config.url = url;
@@ -57,6 +45,10 @@
    const code = res.data.code || 200;
    // èŽ·å–é”™è¯¯ä¿¡æ¯
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    // äºŒè¿›åˆ¶æ•°æ®åˆ™ç›´æŽ¥è¿”回
    if(res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer'){
      return res.data
    }
    if (code === 401) {
      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
          confirmButtonText: '重新登录',
@@ -65,7 +57,7 @@
        }
      ).then(() => {
        store.dispatch('LogOut').then(() => {
          location.href = this.$router.options.base + '/index';
          location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
        })
      }).catch(() => {});
      return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
@@ -105,4 +97,27 @@
  }
)
// é€šç”¨ä¸‹è½½æ–¹æ³•
export function download(url, params, filename) {
  downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
  return service.post(url, params, {
    transformRequest: [(params) => { return tansParams(params) }],
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    responseType: 'blob'
  }).then(async (data) => {
    const isLogin = await blobValidate(data);
    if (isLogin) {
      const blob = new Blob([data])
      saveAs(blob, filename)
    } else {
      Message.error('无效的会话,或者会话已过期,请重新登录。');
    }
    downloadLoadingInstance.close();
  }).catch((r) => {
    console.error(r)
    Message.error('下载文件出现错误,请联系管理员!')
    downloadLoadingInstance.close();
  })
}
export default service
ruoyi-ui/src/utils/ruoyi.js
@@ -85,8 +85,8 @@
    var temp = value.split(currentSeparator);
    Object.keys(value.split(currentSeparator)).some((val) => {
        Object.keys(datas).some((key) => {
            if (datas[key].dictValue == ('' + temp[val])) {
                actions.push(datas[key].dictLabel + currentSeparator);
            if (datas[key].value == ('' + temp[val])) {
                actions.push(datas[key].label + currentSeparator);
            }
        })
    })
@@ -181,3 +181,40 @@
    }
    return tree;
}
/**
* å‚数处理
* @param {*} params  å‚æ•°
*/
export function tansParams(params) {
    let result = ''
    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 + ']';
                        var subPart = encodeURIComponent(params) + "=";
                        result += subPart + encodeURIComponent(value[key]) + "&";
                    }
                }
            } else {
                result += part + encodeURIComponent(value) + "&";
            }
        }
    }
    return result
}
// éªŒè¯æ˜¯å¦ä¸ºblob格式
export async function blobValidate(data) {
    try {
      const text = await data.text();
      JSON.parse(text);
      return false;
    } catch (error) {
      return true;
    }
}
ruoyi-ui/src/views/demo/demo/index.vue
@@ -73,11 +73,20 @@
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="info"
          plain
          icon="el-icon-upload2"
          size="mini"
          @click="handleImport"
          v-hasPermi="['demo:demo:import']"
        >导入(校验)</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['demo:demo:export']"
        >导出</el-button>
@@ -165,11 +174,34 @@
        <el-button @click="cancel">取 æ¶ˆ</el-button>
      </div>
    </el-dialog>
    <!-- ç”¨æˆ·å¯¼å…¥å¯¹è¯æ¡† -->
    <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
      <el-upload
        ref="upload"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        drag
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
      </el-upload>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitFileForm">ç¡® å®š</el-button>
        <el-button @click="upload.open = false">取 æ¶ˆ</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { listDemo, pageDemo, getDemo, delDemo, addDemo, updateDemo } from "@/api/demo/demo";
import {getToken} from "@/utils/auth";
export default {
  name: "Demo",
@@ -181,8 +213,6 @@
      buttonLoading: false,
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -201,6 +231,19 @@
      open: false,
      // åˆ›å»ºæ—¶é—´æ—¶é—´èŒƒå›´
      daterangeCreateTime: [],
      // ç”¨æˆ·å¯¼å…¥å‚æ•°
      upload: {
        // æ˜¯å¦æ˜¾ç¤ºå¼¹å‡ºå±‚(用户导入)
        open: false,
        // å¼¹å‡ºå±‚标题(用户导入)
        title: "",
        // æ˜¯å¦ç¦ç”¨ä¸Šä¼ 
        isUploading: false,
        // è®¾ç½®ä¸Šä¼ çš„请求头部
        headers: { Authorization: "Bearer " + getToken() },
        // ä¸Šä¼ çš„地址
        url: process.env.VUE_APP_BASE_API + "/demo/demo/importData"
      },
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        pageNum: 1,
@@ -356,9 +399,32 @@
        this.loading = false;
      });
    },
    /** å¯¼å…¥æŒ‰é’®æ“ä½œ */
    handleImport() {
      this.upload.title = "用户导入";
      this.upload.open = true;
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/demo/demo/export', this.queryParams);
      this.download('demo/demo/export', {
        ...this.queryParams
      }, `demo_${new Date().getTime()}.xlsx`)
    },
    // æ–‡ä»¶ä¸Šä¼ ä¸­å¤„理
    handleFileUploadProgress(event, file, fileList) {
      this.upload.isUploading = true;
    },
    // æ–‡ä»¶ä¸Šä¼ æˆåŠŸå¤„ç†
    handleFileSuccess(response, file, fileList) {
      this.upload.open = false;
      this.upload.isUploading = false;
      this.$refs.upload.clearFiles();
      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
      this.getList();
    },
    // æäº¤ä¸Šä¼ æ–‡ä»¶
    submitFileForm() {
      this.$refs.upload.submit();
    }
  }
};
ruoyi-ui/src/views/index.vue
@@ -4,26 +4,34 @@
      <el-col :sm="24" :lg="12" style="padding-left: 20px">
        <h2>RuoYi-Vue-Plus后台管理框架</h2>
        <p>
          åŸºäºŽ RuoYi-Vue é›†æˆ Mybatis-Plus Lombok Hutool ç­‰ä¾¿æ·å¼€å‘工具 é€‚配重写相关业务 ä¾¿äºŽå¼€å‘ å®šæœŸä¸Ž RuoYi-Vue åŒæ­¥
          RuoYi-Vue-Plus æ˜¯åŸºäºŽ RuoYi-Vue é’ˆå¯¹ åˆ†å¸ƒå¼é›†ç¾¤ åœºæ™¯å‡çº§(不兼容原框架)
          <br/>
          * å‰ç«¯å¼€å‘框架 Vue、Element UI<br/>
          * åŽç«¯å¼€å‘框架 Spring Boot、Redis<br/>
          * åŽç«¯å¼€å‘框架 Spring Boot<br/>
          * å®¹å™¨æ¡†æž¶ Undertow åŸºäºŽ Netty çš„高性能容器<br/>
          * æƒé™è®¤è¯æ¡†æž¶ Spring Security、Jwt,支持多终端认证系统<br/>
          * å…³ç³»æ•°æ®åº“ MySQL é€‚配 8.X<br/>
          * ç¼“存数据库 Redis é€‚配 6.X<br/>
          * æ•°æ®åº“开发框架 Mybatis-Plus å¿«é€Ÿ CRUD å¢žåŠ å¼€å‘æ•ˆçŽ‡ æ’件化支持各类需求<br/>
          * ç½‘络框架 Feign、OkHttp3 æŽ¥å£åŒ–管理 HTTP è¯·æ±‚<br/>
          * å·¥å…·ç±»æ¡†æž¶ Hutool、Lombok å‡å°‘代码冗余 å¢žåŠ å®‰å…¨æ€§<br/>
          * ç›‘控框架 spring-boot-admin å…¨æ–¹ä½æœåŠ¡ç›‘æŽ§<br/>
          * æ ¡éªŒæ¡†æž¶ validation å¢žå¼ºæŽ¥å£å®‰å…¨æ€§ ä¸¥è°¨æ€§<br/>
          * æ–‡æ¡£æ¡†æž¶ knife4j ç¾ŽåŒ–接口文档<br/>
          * ä»£ç ç”Ÿæˆå™¨ ä¸€é”®ç”Ÿæˆå‰åŽç«¯ä»£ç <br/>
          * æƒé™è®¤è¯æ¡†æž¶ Spring Security、Jwt æ”¯æŒå¤šç»ˆç«¯è®¤è¯ç³»ç»Ÿ<br/>
          * å…³ç³»æ•°æ®åº“ MySQL é€‚配 8.X æœ€ä½Ž 5.7<br/>
          * ç¼“存数据库 Redis é€‚配 6.X æœ€ä½Ž 4.X<br/>
          * æ•°æ®åº“框架 Mybatis-Plus å¿«é€Ÿ CRUD å¢žåŠ å¼€å‘æ•ˆçŽ‡<br/>
          * æ•°æ®åº“框架 p6spy æ›´å¼ºåŠ²çš„ SQL åˆ†æž<br/>
          * å¤šæ•°æ®æºæ¡†æž¶ dynamic-datasource æ”¯æŒä¸»ä»Žä¸Žå¤šç§ç±»æ•°æ®åº“异构<br/>
          * Redis客户端 é‡‡ç”¨ Redisson æ€§èƒ½æ›´å¼º<br/>
          * åºåˆ—化框架 Jackson ç»Ÿä¸€ä½¿ç”¨ jackson é«˜æ•ˆå¯é <br/>
          * Redis客户端 Redisson æ€§èƒ½å¼ºåŠ²ã€API丰富<br/>
          * åˆ†å¸ƒå¼é™æµ Redisson å…¨å±€ã€è¯·æ±‚IP、集群ID å¤šç§é™æµ<br/>
          * åˆ†å¸ƒå¼é” Lock4j æ³¨è§£é”ã€å·¥å…·é” å¤šç§å¤šæ ·<br/>
          * åˆ†å¸ƒå¼å¹‚ç­‰ Lock4j åŸºäºŽåˆ†å¸ƒå¼é”å®žçް<br/>
          * åˆ†å¸ƒå¼æ—¥å¿— TLog æ”¯æŒè·Ÿè¸ªé“¾è·¯æ—¥å¿—记录、性能分析、链路排查<br/>
          * åˆ†å¸ƒå¼ä»»åŠ¡è°ƒåº¦ Xxl-Job é«˜æ€§èƒ½ é«˜å¯é  æ˜“扩展<br/>
          * æ–‡ä»¶å­˜å‚¨ Minio æœ¬åœ°å­˜å‚¨<br/>
          * æ–‡ä»¶å­˜å‚¨ ä¸ƒç‰›ã€é˜¿é‡Œã€è…¾è®¯    äº‘存储<br/>
          * ç›‘控框架 SpringBoot-Admin å…¨æ–¹ä½æœåŠ¡ç›‘æŽ§<br/>
          * æ ¡éªŒæ¡†æž¶ Validation å¢žå¼ºæŽ¥å£å®‰å…¨æ€§ ä¸¥è°¨æ€§<br/>
          * Excel框架 Alibaba EasyExcel æ€§èƒ½ä¼˜å¼‚ æ‰©å±•性强<br/>
          * æ–‡æ¡£æ¡†æž¶ knife4j ç¾ŽåŒ–接口文档<br/>
          * å·¥å…·ç±»æ¡†æž¶ Hutool、Lombok å‡å°‘代码冗余 å¢žåŠ å®‰å…¨æ€§<br/>
          * ä»£ç ç”Ÿæˆå™¨ é€‚配MP、Knife4j规范化代码 ä¸€é”®ç”Ÿæˆå‰åŽç«¯ä»£ç <br/>
          * éƒ¨ç½²æ–¹å¼ Docker å®¹å™¨ç¼–排 ä¸€é”®éƒ¨ç½²ä¸šåŠ¡é›†ç¾¤<br/>
          * æ–‡ä»¶å­˜å‚¨ OSS å¯¹è±¡å­˜å‚¨æ¨¡å— æ”¯æŒ(Minio、七牛、阿里、腾讯)<br/>
          * å›½é™…化 SpringMessage Spring标准国际化方案<br/>
        </p>
        <p>
          <b>当前版本:</b> <span>v{{ version }}</span>
ruoyi-ui/src/views/login.vue
@@ -3,7 +3,12 @@
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
      <h3 class="title">RuoYi-Vue-Plus后台管理系统</h3>
      <el-form-item prop="username">
        <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
        <el-input
          v-model="loginForm.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>
@@ -66,7 +71,6 @@
  data() {
    return {
      codeUrl: "",
      cookiePassword: "",
      loginForm: {
        username: "admin",
        password: "admin123",
ruoyi-ui/src/views/monitor/job/index.vue
ÎļþÒÑɾ³ý
ruoyi-ui/src/views/monitor/job/log.vue
ÎļþÒÑɾ³ý
ruoyi-ui/src/views/monitor/logininfor/index.vue
@@ -6,8 +6,8 @@
          v-model="queryParams.ipaddr"
          placeholder="请输入登录地址"
          clearable
          size="small"
          style="width: 240px;"
          size="small"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
@@ -16,8 +16,8 @@
          v-model="queryParams.userName"
          placeholder="请输入用户名称"
          clearable
          size="small"
          style="width: 240px;"
          size="small"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
@@ -83,7 +83,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['monitor:logininfor:export']"
        >导出</el-button>
@@ -132,8 +131,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå¤šä¸ªç¦ç”¨
@@ -216,7 +213,9 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/monitor/logininfor/export', this.queryParams);
      this.download('monitor/logininfor/export', {
        ...this.queryParams
      }, `logininfor_${new Date().getTime()}.xlsx`)
    }
  }
};
ruoyi-ui/src/views/monitor/operlog/index.vue
@@ -6,8 +6,8 @@
          v-model="queryParams.title"
          placeholder="请输入系统模块"
          clearable
          style="width: 240px;"
          size="small"
          style="width: 240px;"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
@@ -16,8 +16,8 @@
          v-model="queryParams.operName"
          placeholder="请输入操作人员"
          clearable
          style="width: 240px;"
          size="small"
          style="width: 240px;"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
@@ -99,7 +99,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['monitor:operlog:export']"
        >导出</el-button>
@@ -205,8 +204,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå¤šä¸ªç¦ç”¨
@@ -303,7 +300,9 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/monitor/operlog/export', this.queryParams);
      this.download('monitor/operlog/export', {
        ...this.queryParams
      }, `operlog_${new Date().getTime()}.xlsx`)
    }
  }
};
ruoyi-ui/src/views/register.vue
@@ -127,7 +127,8 @@
          register(this.registerForm).then(res => {
            const username = this.registerForm.username;
            this.$alert("<font color='red'>恭喜你,您的账号 " + username + " æ³¨å†ŒæˆåŠŸï¼</font>", '系统提示', {
              dangerouslyUseHTMLString: true
              dangerouslyUseHTMLString: true,
              type: 'success'
            }).then(() => {
              this.$router.push("/login");
            }).catch(() => {});
ruoyi-ui/src/views/system/config/index.vue
@@ -88,7 +88,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['system:config:export']"
        >导出</el-button>
@@ -194,8 +193,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -334,7 +331,9 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/system/config/export', this.queryParams);
      this.download('system/config/export', {
        ...this.queryParams
      }, `config_${new Date().getTime()}.xlsx`)
    },
    /** åˆ·æ–°ç¼“存按钮操作 */
    handleRefreshCache() {
ruoyi-ui/src/views/system/dept/index.vue
@@ -179,8 +179,6 @@
      isExpandAll: true,
      // é‡æ–°æ¸²æŸ“表格状态
      refreshTable: true,
      // æ˜¯å¦å±•å¼€
      expand: false,
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        deptName: undefined,
@@ -276,7 +274,7 @@
      this.open = true;
      this.title = "添加部门";
      listDept().then(response => {
            this.deptOptions = this.handleTree(response.data, "deptId");
        this.deptOptions = this.handleTree(response.data, "deptId");
      });
    },
    /** å±•å¼€/折叠操作 */
@@ -296,7 +294,7 @@
        this.title = "修改部门";
      });
      listDeptExcludeChild(row.deptId).then(response => {
            this.deptOptions = this.handleTree(response.data, "deptId");
        this.deptOptions = this.handleTree(response.data, "deptId");
      });
    },
    /** æäº¤æŒ‰é’® */
ruoyi-ui/src/views/system/dict/data.vue
@@ -75,10 +75,18 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['system:dict:export']"
        >导出</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="el-icon-close"
          size="mini"
          @click="handleClose"
        >关闭</el-button>
      </el-col>
      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>
@@ -193,8 +201,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -319,6 +325,11 @@
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** è¿”回按钮操作 */
    handleClose() {
      const obj = { path: "/system/dict" };
      this.$tab.closeOpenPage(obj);
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.resetForm("queryForm");
@@ -380,8 +391,10 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/system/dict/data/export', this.queryParams);
      this.download('system/dict/data/export', {
        ...this.queryParams
      }, `data_${new Date().getTime()}.xlsx`)
    }
  }
};
</script>
</script>
ruoyi-ui/src/views/system/dict/index.vue
@@ -94,7 +94,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['system:dict:export']"
        >导出</el-button>
@@ -202,8 +201,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -338,7 +335,9 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/system/dict/type/export', this.queryParams);
      this.download('system/dict/type/export', {
        ...this.queryParams
      }, `type_${new Date().getTime()}.xlsx`)
    },
    /** åˆ·æ–°ç¼“存按钮操作 */
    handleRefreshCache() {
@@ -348,4 +347,4 @@
    }
  }
};
</script>
</script>
ruoyi-ui/src/views/system/menu/index.vue
@@ -78,7 +78,8 @@
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button size="mini"
          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
@@ -126,8 +127,8 @@
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item v-if="form.menuType != 'F'" label="菜单图标">
          <el-col :span="24" v-if="form.menuType != 'F'">
            <el-form-item label="菜单图标">
              <el-popover
                placement="bottom-start"
                width="460"
@@ -158,8 +159,8 @@
              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType != 'F'">
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item>
              <span slot="label">
                <el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
                <i class="el-icon-question"></i>
@@ -172,8 +173,8 @@
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType != 'F'" prop="path">
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="path">
              <span slot="label">
                <el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
                <i class="el-icon-question"></i>
@@ -194,8 +195,8 @@
              <el-input v-model="form.component" placeholder="请输入组件路径" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType != 'M'">
          <el-col :span="12" v-if="form.menuType != 'M'">
            <el-form-item>
              <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
              <span slot="label">
                <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
@@ -205,8 +206,8 @@
              </span>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType == 'C'">
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item>
              <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
              <span slot="label">
                <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
@@ -216,8 +217,8 @@
              </span>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType == 'C'">
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item>
              <span slot="label">
                <el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
                <i class="el-icon-question"></i>
@@ -230,8 +231,8 @@
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType != 'F'">
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item>
              <span slot="label">
                <el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
                <i class="el-icon-question"></i>
@@ -247,8 +248,8 @@
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item v-if="form.menuType != 'F'">
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item>
              <span slot="label">
                <el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
                <i class="el-icon-question"></i>
ruoyi-ui/src/views/system/post/index.vue
@@ -74,7 +74,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['system:post:export']"
        >导出</el-button>
@@ -169,8 +168,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -305,7 +302,9 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/system/post/export', this.queryParams);
      this.download('system/post/export', {
        ...this.queryParams
      }, `post_${new Date().getTime()}.xlsx`)
    }
  }
};
ruoyi-ui/src/views/system/role/authUser.vue
@@ -153,8 +153,8 @@
    },
    // è¿”回按钮
    handleClose() {
      this.$store.dispatch("tagsView/delView", this.$route);
      this.$router.push({ path: "/system/role" });
      const obj = { path: "/system/role" };
      this.$tab.closeOpenPage(obj);
    },
    /** æœç´¢æŒ‰é’®æ“ä½œ */
    handleQuery() {
ruoyi-ui/src/views/system/role/index.vue
@@ -94,7 +94,6 @@
          plain
          icon="el-icon-download"
          size="mini"
          :loading="exportLoading"
          @click="handleExport"
          v-hasPermi="['system:role:export']"
        >导出</el-button>
@@ -270,8 +269,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -358,8 +355,7 @@
    /** æŸ¥è¯¢è§’色列表 */
    getList() {
      this.loading = true;
      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
        response => {
      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
          this.roleList = response.rows;
          this.total = response.total;
          this.loading = false;
@@ -613,8 +609,10 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/system/role/export', this.queryParams);
      this.download('system/role/export', {
        ...this.queryParams
      }, `role_${new Date().getTime()}.xlsx`)
    }
  }
};
</script>
</script>
ruoyi-ui/src/views/system/role/selectUser.vue
@@ -123,6 +123,10 @@
    handleSelectUser() {
      const roleId = this.queryParams.roleId;
      const userIds = this.userIds.join(",");
      if (userIds == "") {
        this.$modal.msgError("请选择要分配的用户");
        return;
      }
      authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => {
        this.$modal.msgSuccess(res.msg);
        if (res.code === 200) {
ruoyi-ui/src/views/system/user/authRole.vue
@@ -33,7 +33,7 @@
        </template>
      </el-table-column>
    </el-table>
    <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
    <el-form label-width="100px">
@@ -109,9 +109,9 @@
    },
    /** å…³é—­æŒ‰é’® */
    close() {
      this.$store.dispatch("tagsView/delView", this.$route);
      this.$router.push({ path: "/system/user" });
      const obj = { path: "/system/user" };
      this.$tab.closeOpenPage(obj);
    },
  },
};
</script>
</script>
ruoyi-ui/src/views/system/user/index.vue
@@ -131,7 +131,6 @@
              plain
              icon="el-icon-download"
              size="mini"
              :loading="exportLoading"
              @click="handleExport"
              v-hasPermi="['system:user:export']"
            >导出</el-button>
@@ -207,7 +206,7 @@
      </el-col>
    </el-row>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹å‚æ•°é…ç½®å¯¹è¯æ¡† -->
    <!-- æ·»åŠ æˆ–ä¿®æ”¹ç”¨æˆ·é…ç½®å¯¹è¯æ¡† -->
    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-row>
@@ -360,8 +359,6 @@
    return {
      // é®ç½©å±‚
      loading: true,
      // å¯¼å‡ºé®ç½©å±‚
      exportLoading: false,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
@@ -643,7 +640,9 @@
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      this.$download.excel('/system/user/export', this.queryParams);
      this.download('system/user/export', {
        ...this.queryParams
      }, `user_${new Date().getTime()}.xlsx`)
    },
    /** å¯¼å…¥æŒ‰é’®æ“ä½œ */
    handleImport() {
@@ -652,7 +651,8 @@
    },
    /** ä¸‹è½½æ¨¡æ¿æ“ä½œ */
    importTemplate() {
      this.$download.excel('/system/user/importTemplate');
      this.download('system/user/importTemplate', {
      }, `user_template_${new Date().getTime()}.xlsx`)
    },
    // æ–‡ä»¶ä¸Šä¼ ä¸­å¤„理
    handleFileUploadProgress(event, file, fileList) {
@@ -672,4 +672,4 @@
    }
  }
};
</script>
</script>
ruoyi-ui/src/views/system/user/profile/resetPwd.vue
@@ -29,7 +29,6 @@
      }
    };
    return {
      test: "1test",
      user: {
        oldPassword: undefined,
        newPassword: undefined,
@@ -55,17 +54,14 @@
    submit() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          updateUserPwd(this.user.oldPassword, this.user.newPassword).then(
            response => {
              this.$modal.msgSuccess("修改成功");
            }
          );
          updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
            this.$modal.msgSuccess("修改成功");
          });
        }
      });
    },
    close() {
      this.$store.dispatch("tagsView/delView", this.$route);
      this.$router.push({ path: "/index" });
      this.$tab.closePage();
    }
  }
};
ruoyi-ui/src/views/system/user/profile/userAvatar.vue
@@ -1,7 +1,7 @@
<template>
  <div>
    <div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened"  @close="closeDialog()">
    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened"  @close="closeDialog">
      <el-row>
        <el-col :xs="24" :md="12" :style="{height: '350px'}">
          <vue-cropper
@@ -143,7 +143,7 @@
    // å…³é—­çª—口
    closeDialog() {
      this.options.img = store.getters.avatar
      this.visible = false;
      this.visible = false;
    }
  }
};
@@ -172,4 +172,4 @@
  line-height: 110px;
  border-radius: 50%;
}
</style>
</style>
ruoyi-ui/src/views/system/user/profile/userInfo.vue
@@ -2,7 +2,7 @@
  <el-form ref="form" :model="user" :rules="rules" label-width="80px">
    <el-form-item label="用户昵称" prop="nickName">
      <el-input v-model="user.nickName" maxlength="30" />
    </el-form-item>
    </el-form-item>
    <el-form-item label="手机号码" prop="phonenumber">
      <el-input v-model="user.phonenumber" maxlength="11" />
    </el-form-item>
@@ -68,8 +68,7 @@
      });
    },
    close() {
      this.$store.dispatch("tagsView/delView", this.$route);
      this.$router.push({ path: "/index" });
      this.$tab.closePage();
    }
  }
};
ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -211,8 +211,8 @@
    },
    /** å…³é—­æŒ‰é’® */
    close() {
      this.$store.dispatch("tagsView/delView", this.$route);
      this.$router.push({ path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } })
      const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } };
      this.$tab.closeOpenPage(obj);
    }
  },
  mounted() {
ruoyi-ui/vue.config.js
@@ -16,8 +16,7 @@
  // éƒ¨ç½²ç”Ÿäº§çŽ¯å¢ƒå’Œå¼€å‘çŽ¯å¢ƒä¸‹çš„URL。
  // é»˜è®¤æƒ…况下,Vue CLI ä¼šå‡è®¾ä½ çš„应用是被部署在一个域名的根路径上
  // ä¾‹å¦‚ https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl ä¸º /admin/。
  // è®¾ç½®åŸºè·¯å¾„参考文档: http://doc.ruoyi.vip/ruoyi-vue/document/qdsc.html#应用路径
  publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
  publicPath: process.env.VUE_APP_CONTEXT_PATH,
  // åœ¨npm run build æˆ– yarn build æ—¶ ï¼Œç”Ÿæˆæ–‡ä»¶çš„目录名称(要和baseUrl的生产环境路径一致)(默认dist)
  outputDir: 'dist',
  // ç”¨äºŽæ”¾ç½®ç”Ÿæˆçš„静态资源 (js、css、img、fonts) çš„;(项目打包之后,静态资源会放在这个文件夹下)
script/bin/ry.bat
@@ -1,21 +1,21 @@
@echo off
rem jarƽ��Ŀ¼
rem jar平级目录
set AppName=ruoyi-admin.jar
rem JVM����
rem JVM参数
set JVM_OPTS="-Dname=%AppName%  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
ECHO.
    ECHO.  [1] ï¿½ï¿½ï¿½ï¿½%AppName%
    ECHO.  [2] ï¿½Ø±ï¿½%AppName%
    ECHO.  [3] ï¿½ï¿½ï¿½ï¿½%AppName%
    ECHO.  [4] ï¿½ï¿½ï¿½ï¿½×´Ì¬ %AppName%
    ECHO.  [5] ï¿½ï¿½ ï¿½ï¿½
    ECHO.  [1] å¯åЍ%AppName%
    ECHO.  [2] å…³é—­%AppName%
    ECHO.  [3] é‡å¯%AppName%
    ECHO.  [4] å¯åŠ¨çŠ¶æ€ %AppName%
    ECHO.  [5] é€€ å‡º
ECHO.
ECHO.������ѡ����Ŀ�����:
ECHO.请输入选择项目的序号:
set /p ID=
    IF "%id%"=="1" GOTO start
    IF "%id%"=="2" GOTO stop
@@ -35,11 +35,11 @@
start javaw %JAVA_OPTS% -jar %AppName%
echo  starting����
echo  starting……
echo  Start %AppName% success...
goto:eof
rem ï¿½ï¿½ï¿½ï¿½stopͨ��jps�������pid����������
rem å‡½æ•°stop通过jps命令查找pid并结束进程
:stop
    for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do (
        set pid=%%a
@@ -48,7 +48,7 @@
    if not defined pid (echo process %AppName% does not exists) else (
        echo prepare to kill %image_name%
        echo start kill %pid% ...
        rem ï¿½ï¿½ï¿½Ý½ï¿½ï¿½ï¿½ID��kill����
        rem æ ¹æ®è¿›ç¨‹ID,kill进程
        taskkill /f /pid %pid%
    )
goto:eof
script/docker/docker-compose.yml
@@ -2,7 +2,7 @@
services:
  mysql:
    image: mysql:8.0.24
    image: mysql:8.0.27
    container_name: mysql
    environment:
      # æ—¶åŒºä¸Šæµ·
@@ -32,8 +32,7 @@
        ipv4_address: 172.30.0.36
  nginx-web:
    # å¦‚果需要指定版本 å°±æŠŠ latest æ¢æˆç‰ˆæœ¬å·
    image: nginx:latest
    image: nginx:1.21.3
    container_name: nginx-web
    environment:
      # æ—¶åŒºä¸Šæµ·
@@ -56,7 +55,7 @@
      - ruoyi_net
  redis:
    image: redis:6.2.1
    image: redis:6.2.6
    container_name: redis
    ports:
      - 6379:6379
@@ -67,8 +66,8 @@
      # é…ç½®æ–‡ä»¶
      - /docker/redis/conf:/redis/config:rw
      # æ•°æ®æ–‡ä»¶
      - /docker/redis/data:/redis/data:rw
    command: "redis-server /redis/config/redis.conf --appendonly yes"
      - /docker/redis/data/:/redis/data/:rw
    command: "redis-server /redis/config/redis.conf"
    privileged: true
    restart: always
    networks:
@@ -76,7 +75,7 @@
        ipv4_address: 172.30.0.48
  minio:
    image: minio/minio:RELEASE.2021-07-08T01-15-01Z
    image: minio/minio:RELEASE.2021-10-27T16-29-42Z
    container_name: minio
    ports:
      # api ç«¯å£
script/docker/redis/redis.conf
@@ -1,2 +1,25 @@
# redis å¯†ç 
# requirepass 123456
# requirepass ruoyi123
# é…ç½®æŒä¹…化文件存储路径
dir /redis/data
# é…ç½®rdb
# 15分钟内有至少1个key被更改则进行快照
save 900 1
# 5分钟内有至少10个key被更改则进行快照
save 300 10
# 1分钟内有至少10000个key被更改则进行快照
save 60 10000
# å¼€å¯åŽ‹ç¼©
rdbcompression yes
# rdb文件名 ç”¨é»˜è®¤çš„即可
dbfilename dump.rdb
# å¼€å¯aof
appendonly yes
# æ–‡ä»¶å
appendfilename "appendonly.aof"
# æŒä¹…化策略,no:不同步,everysec:每秒一次,always:总是同步,速度比较慢
# appendfsync always
appendfsync everysec
# appendfsync no
script/sql/quartz.sql
ÎļþÒÑɾ³ý
script/sql/ry_20210908.sql
@@ -172,9 +172,7 @@
insert into sys_menu values('107',  '通知公告', '1',   '8', 'notice',     'system/notice/index',      '', 1, 0, 'C', '0', '0', 'system:notice:list',      'message',       'admin', sysdate(), '', null, '通知公告菜单');
insert into sys_menu values('108',  '日志管理', '1',   '9', 'log',        '',                         '', 1, 0, 'M', '0', '0', '',                        'log',           'admin', sysdate(), '', null, '日志管理菜单');
insert into sys_menu values('109',  '在线用户', '2',   '1', 'online',     'monitor/online/index',     '', 1, 0, 'C', '0', '0', 'monitor:online:list',     'online',        'admin', sysdate(), '', null, '在线用户菜单');
# insert into sys_menu values('110',  '定时任务', '2',   '2', 'job',        'monitor/job/index',        '', 1, 0, 'C', '0', '0', 'monitor:job:list',        'job',           'admin', sysdate(), '', null, '定时任务菜单');
insert into sys_menu values('111',  '数据监控', '2',   '3', 'druid',      'monitor/druid/index',      '', 1, 0, 'C', '0', '0', 'monitor:druid:list',      'druid',         'admin', sysdate(), '', null, '数据监控菜单');
# insert into sys_menu values('112',  '服务监控', '2',   '4', 'server',     'monitor/server/index',     '', 1, 0, 'C', '0', '0', 'monitor:server:list',     'server',        'admin', sysdate(), '', null, '服务监控菜单');
insert into sys_menu values('113',  '缓存监控', '2',   '5', 'cache',      'monitor/cache/index',      '', 1, 0, 'C', '0', '0', 'monitor:cache:list',      'redis',         'admin', sysdate(), '', null, '缓存监控菜单');
insert into sys_menu values('114',  '表单构建', '3',   '1', 'build',      'tool/build/index',         '', 1, 0, 'C', '0', '0', 'tool:build:list',         'build',         'admin', sysdate(), '', null, '表单构建菜单');
insert into sys_menu values('115',  '代码生成', '3',   '2', 'gen',        'tool/gen/index',           '', 1, 0, 'C', '0', '0', 'tool:gen:list',           'code',          'admin', sysdate(), '', null, '代码生成菜单');
@@ -248,13 +246,6 @@
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query',       '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, '');
-- å®šæ—¶ä»»åŠ¡æŒ‰é’®
# insert into sys_menu values('1049', '任务查询', '110', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query',          '#', 'admin', sysdate(), '', null, '');
# insert into sys_menu values('1050', '任务新增', '110', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add',            '#', 'admin', sysdate(), '', null, '');
# insert into sys_menu values('1051', '任务修改', '110', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit',           '#', 'admin', sysdate(), '', null, '');
# insert into sys_menu values('1052', '任务删除', '110', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove',         '#', 'admin', sysdate(), '', null, '');
# insert into sys_menu values('1053', '状态修改', '110', '5', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus',   '#', 'admin', sysdate(), '', null, '');
# insert into sys_menu values('1054', '任务导出', '110', '7', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export',         '#', 'admin', sysdate(), '', null, '');
-- ä»£ç ç”ŸæˆæŒ‰é’®
insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query',             '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit',              '#', 'admin', sysdate(), '', null, '');
@@ -373,12 +364,6 @@
insert into sys_role_menu values ('2', '1046');
insert into sys_role_menu values ('2', '1047');
insert into sys_role_menu values ('2', '1048');
insert into sys_role_menu values ('2', '1049');
insert into sys_role_menu values ('2', '1050');
insert into sys_role_menu values ('2', '1051');
insert into sys_role_menu values ('2', '1052');
insert into sys_role_menu values ('2', '1053');
insert into sys_role_menu values ('2', '1054');
insert into sys_role_menu values ('2', '1055');
insert into sys_role_menu values ('2', '1056');
insert into sys_role_menu values ('2', '1057');
@@ -469,8 +454,6 @@
insert into sys_dict_type values(1,  '用户性别', 'sys_user_sex',        '0', 'admin', sysdate(), '', null, '用户性别列表');
insert into sys_dict_type values(2,  '菜单状态', 'sys_show_hide',       '0', 'admin', sysdate(), '', null, '菜单状态列表');
insert into sys_dict_type values(3,  '系统开关', 'sys_normal_disable',  '0', 'admin', sysdate(), '', null, '系统开关列表');
insert into sys_dict_type values(4,  '任务状态', 'sys_job_status',      '0', 'admin', sysdate(), '', null, '任务状态列表');
insert into sys_dict_type values(5,  '任务分组', 'sys_job_group',       '0', 'admin', sysdate(), '', null, '任务分组列表');
insert into sys_dict_type values(6,  '系统是否', 'sys_yes_no',          '0', 'admin', sysdate(), '', null, '系统是否列表');
insert into sys_dict_type values(7,  '通知类型', 'sys_notice_type',     '0', 'admin', sysdate(), '', null, '通知类型列表');
insert into sys_dict_type values(8,  '通知状态', 'sys_notice_status',   '0', 'admin', sysdate(), '', null, '通知状态列表');
@@ -508,10 +491,6 @@
insert into sys_dict_data values(5,  2,  '隐藏',     '1',       'sys_show_hide',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '隐藏菜单');
insert into sys_dict_data values(6,  1,  '正常',     '0',       'sys_normal_disable',  '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
insert into sys_dict_data values(7,  2,  '停用',     '1',       'sys_normal_disable',  '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '停用状态');
insert into sys_dict_data values(8,  1,  '正常',     '0',       'sys_job_status',      '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
insert into sys_dict_data values(9,  2,  '暂停',     '1',       'sys_job_status',      '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '停用状态');
insert into sys_dict_data values(10, 1,  '默认',     'DEFAULT', 'sys_job_group',       '',   '',        'Y', '0', 'admin', sysdate(), '', null, '默认分组');
insert into sys_dict_data values(11, 2,  '系统',     'SYSTEM',  'sys_job_group',       '',   '',        'N', '0', 'admin', sysdate(), '', null, '系统分组');
insert into sys_dict_data values(12, 1,  '是',       'Y',       'sys_yes_no',          '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是');
insert into sys_dict_data values(13, 2,  '否',       'N',       'sys_yes_no',          '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '系统默认否');
insert into sys_dict_data values(14, 1,  '通知',     '1',       'sys_notice_type',     '',   'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知');
@@ -576,49 +555,6 @@
-- ----------------------------
-- 15、定时任务调度表
-- ----------------------------
drop table if exists sys_job;
create table sys_job (
  job_id              bigint(20)    not null auto_increment    comment '任务ID',
  job_name            varchar(64)   default ''                 comment '任务名称',
  job_group           varchar(64)   default 'DEFAULT'          comment '任务组名',
  invoke_target       varchar(500)  not null                   comment '调用目标字符串',
  cron_expression     varchar(255)  default ''                 comment 'cron执行表达式',
  misfire_policy      varchar(20)   default '3'                comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
  concurrent          char(1)       default '1'                comment '是否并发执行(0允许 1禁止)',
  status              char(1)       default '0'                comment '状态(0正常 1暂停)',
  create_by           varchar(64)   default ''                 comment '创建者',
  create_time         datetime                                 comment '创建时间',
  update_by           varchar(64)   default ''                 comment '更新者',
  update_time         datetime                                 comment '更新时间',
  remark              varchar(500)  default ''                 comment '备注信息',
  primary key (job_id, job_name, job_group)
) engine=innodb auto_increment=100 comment = '定时任务调度表';
insert into sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams',        '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
insert into sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')',  '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)',  '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
-- ----------------------------
-- 16、定时任务调度日志表
-- ----------------------------
drop table if exists sys_job_log;
create table sys_job_log (
  job_log_id          bigint(20)     not null auto_increment    comment '任务日志ID',
  job_name            varchar(64)    not null                   comment '任务名称',
  job_group           varchar(64)    not null                   comment '任务组名',
  invoke_target       varchar(500)   not null                   comment '调用目标字符串',
  job_message         varchar(500)                              comment '日志信息',
  status              char(1)        default '0'                comment '执行状态(0正常 1失败)',
  exception_info      varchar(2000)  default ''                 comment '异常信息',
  create_time         datetime                                  comment '创建时间',
  primary key (job_log_id)
) engine=innodb comment = '定时任务调度日志表';
-- ----------------------------
-- 17、通知公告表
-- ----------------------------
drop table if exists sys_notice;
@@ -639,8 +575,8 @@
-- ----------------------------
-- åˆå§‹åŒ–-公告信息表数据
-- ----------------------------
insert into sys_notice values('1', '温馨提醒:2018-07-01 è‹¥ä¾æ–°ç‰ˆæœ¬å‘布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员');
insert into sys_notice values('2', '维护通知:2018-07-01 è‹¥ä¾ç³»ç»Ÿå‡Œæ™¨ç»´æŠ¤', '1', '维护内容',   '0', 'admin', sysdate(), '', null, '管理员');
insert into sys_notice values('1', '温馨提醒:2018-07-01 æ–°ç‰ˆæœ¬å‘布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员');
insert into sys_notice values('2', '维护通知:2018-07-01 ç³»ç»Ÿå‡Œæ™¨ç»´æŠ¤', '1', '维护内容',   '0', 'admin', sysdate(), '', null, '管理员');
-- ----------------------------