疯狂的狮子li
2021-12-27 dd37247e65374dd4ef7e8e8b9212d8f29023e301
Merge remote-tracking branch 'origin/dev' into satoken

# Conflicts:
# pom.xml
# ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.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-common/pom.xml
# ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
# ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
# ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
# ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
# ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
# ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TokenServiceImpl.java
# ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserDetailsServiceImpl.java
已修改158个文件
已添加17个文件
已删除2个文件
5076 ■■■■ 文件已修改
README.md 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | 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 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-dev.yml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-prod.yml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/i18n/messages.properties 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/i18n/messages_en_US.properties 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/pom.xml 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataColumn.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataPermission.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/PageQuery.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/core/BaseMapperPlus.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/core/IServicePlus.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/core/ServicePlusImpl.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/page/PagePlus.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataScopeType.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/helper/DataPermissionHelper.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/BeanCopyUtils.java 98 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoBo.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestTreeBo.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/service/ITestDemoService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/pom.xml 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/Interceptor/PlusWebInvokeTimeInterceptor.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java 301 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/TLogConfig.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusDataPermissionInterceptor.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusWebInvokeTimeInterceptor.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/java/bo.java.vm 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/java/controller.java.vm 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/java/service.java.vm 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm 476 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm 577 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-job/pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-job/src/main/java/com/ruoyi/job/config/XxlJobConfig.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/SysDataScopeService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDataScopeServiceImpl.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 111 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/package.json 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/day.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/hour.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/min.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/month.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/result.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/second.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/week.vue 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/Crontab/year.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/components/ImagePreview/index.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/directive/index.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/directive/module/clipboard.js 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/main.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/plugins/download.js 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/plugins/modal.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/router/index.js 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/store/modules/permission.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/utils/request.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/monitor/online/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/menu/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/authRole.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/user/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/tool/gen/basicInfoForm.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/tool/gen/editTable.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/tool/gen/genInfoForm.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/tool/gen/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/vue.config.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/docker/nginx/nginx.conf 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
script/docker/redis/redis.conf 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -8,21 +8,21 @@
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]()
[![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
[![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/) | é«˜å¯è¯»æ€§ æ‰©å±•性(推荐使用) |
| å•体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | å•体应用结构 |
| Vue3分支 | RuoYi-Vue-Plus-UI | [UI地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus-UI) | ç”±äºŽç»„件还未完善 ä»…供学习 |
| åŽŸæ¡†æž¶ | RuoYi-Vue | [RuoYi-Vue官网](http://ruoyi.vip/) | å®šæœŸåŒæ­¥éœ€è¦çš„功能 |
| å‰ç«¯å¼€å‘框架 | Vue、Element UI | [Element UI官网](https://element.eleme.cn/#/zh-CN) | |
| åŽç«¯å¼€å‘框架 | SpringBoot | [SpringBoot官网](https://spring.io/projects/spring-boot/#learn) | |
| å®¹å™¨æ¡†æž¶ | Undertow | [Undertow官网](https://undertow.io/) | åŸºäºŽ Netty çš„高性能容器 |
| å®¹å™¨æ¡†æž¶ | Undertow | [Undertow官网](https://undertow.io/) | åŸºäºŽ XNIO çš„高性能容器 |
| æƒé™è®¤è¯æ¡†æž¶ | Spring Security、Jwt | [SpringSecurity官网](https://spring.io/projects/spring-security#learn) | æ”¯æŒå¤šç»ˆç«¯è®¤è¯ç³»ç»Ÿ |
| å…³ç³»æ•°æ®åº“ | MySQL | [MySQL官网](https://dev.mysql.com/) | é€‚配 8.X æœ€ä½Ž 5.7 |
| ç¼“存数据库 | Redis | [Redis官网](https://redis.io/) | é€‚配 6.X æœ€ä½Ž 4.X |
pom.xml
@@ -14,7 +14,7 @@
    <properties>
        <ruoyi-vue-plus.version>3.4.0</ruoyi-vue-plus.version>
        <spring-boot.version>2.5.7</spring-boot.version>
        <spring-boot.version>2.5.8</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,27 +24,28 @@
        <swagger-annotations.version>1.5.22</swagger-annotations.version>
        <poi.version>4.1.2</poi.version>
        <easyexcel.version>2.2.11</easyexcel.version>
        <cglib.version>3.3.0</cglib.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.16</hutool.version>
        <hutool.version>5.7.17</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>
        <spring-boot-admin.version>2.5.5</spring-boot-admin.version>
        <redisson.version>3.16.6</redisson.version>
        <lock4j.version>2.2.1</lock4j.version>
        <dynamic-ds.version>3.4.1</dynamic-ds.version>
        <tlog.version>1.3.4</tlog.version>
        <dynamic-ds.version>3.5.0</dynamic-ds.version>
        <tlog.version>1.3.6</tlog.version>
        <xxl-job.version>2.3.0</xxl-job.version>
        <!-- jdk11 ç¼ºå¤±ä¾èµ– jaxb-->
        <jaxb.version>3.0.1</jaxb.version>
        <!-- OSS é…ç½® -->
        <qiniu.version>7.8.0</qiniu.version>
        <qiniu.version>7.9.0</qiniu.version>
        <aliyun.oss.version>3.13.1</aliyun.oss.version>
        <qcloud.cos.version>5.6.58</qcloud.cos.version>
        <minio.version>8.3.3</minio.version>
        <minio.version>8.3.4</minio.version>
        <!-- docker é…ç½® -->
        <docker.registry.url>localhost</docker.registry.url>
@@ -115,6 +116,12 @@
                </exclusions>
            </dependency>
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>${cglib.version}</version>
            </dependency>
            <!-- velocity代码生成使用模板 -->
            <dependency>
                <groupId>org.apache.velocity</groupId>
@@ -168,7 +175,31 @@
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <artifactId>hutool-core</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-http</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-captcha</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-extra</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-jwt</artifactId>
                <version>${hutool.version}</version>
            </dependency>
@@ -210,29 +241,13 @@
            <dependency>
                <groupId>com.yomahub</groupId>
                <artifactId>tlog-spring-boot-configuration</artifactId>
                <artifactId>tlog-web-spring-boot-starter</artifactId>
                <version>${tlog.version}</version>
            </dependency>
            <dependency>
                <groupId>com.yomahub</groupId>
                <artifactId>tlog-webroot</artifactId>
                <version>${tlog.version}</version>
                <exclusions>
                    <exclusion>
                        <artifactId>javassist</artifactId>
                        <groupId>org.javassist</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>guava</artifactId>
                        <groupId>com.google.guava</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>com.yomahub</groupId>
                <artifactId>tlog-xxl-job</artifactId>
                <artifactId>tlog-xxljob-spring-boot-starter</artifactId>
                <version>${tlog.version}</version>
            </dependency>
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
@@ -4,6 +4,7 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -36,8 +37,8 @@
    @ApiOperation("查询系统访问记录列表")
    @SaCheckPermission("monitor:logininfor:list")
    @GetMapping("/list")
    public TableDataInfo<SysLogininfor> list(SysLogininfor logininfor) {
        return logininforService.selectPageLogininforList(logininfor);
    public TableDataInfo<SysLogininfor> list(SysLogininfor logininfor, PageQuery pageQuery) {
        return logininforService.selectPageLogininforList(logininfor, pageQuery);
    }
    @ApiOperation("导出系统访问记录列表")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
@@ -4,6 +4,7 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -36,8 +37,8 @@
    @ApiOperation("查询操作日志记录列表")
    @SaCheckPermission("monitor:operlog:list")
    @GetMapping("/list")
    public TableDataInfo<SysOperLog> list(SysOperLog operLog) {
        return operLogService.selectPageOperLogList(operLog);
    public TableDataInfo<SysOperLog> list(SysOperLog operLog, PageQuery pageQuery) {
        return operLogService.selectPageOperLogList(operLog, pageQuery);
    }
    @ApiOperation("导出操作日志记录列表")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
@@ -12,7 +12,6 @@
import com.ruoyi.common.core.domain.dto.UserOnlineDTO;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysUserOnline;
@@ -70,7 +69,7 @@
        Collections.reverse(userOnlineDTOList);
        userOnlineDTOList.removeAll(Collections.singleton(null));
        List<SysUserOnline> userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class);
        return PageUtils.buildDataInfo(userOnlineList);
        return TableDataInfo.build(userOnlineList);
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
@@ -5,6 +5,7 @@
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.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -41,8 +42,8 @@
    @ApiOperation("获取参数配置列表")
    @SaCheckPermission("system:config:list")
    @GetMapping("/list")
    public TableDataInfo<SysConfig> list(SysConfig config) {
        return configService.selectPageConfigList(config);
    public TableDataInfo<SysConfig> list(SysConfig config, PageQuery pageQuery) {
        return configService.selectPageConfigList(config, pageQuery);
    }
    @ApiOperation("导出参数配置列表")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
@@ -4,6 +4,7 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
@@ -41,8 +42,8 @@
    @ApiOperation("查询字典数据列表")
    @SaCheckPermission("system:dict:list")
    @GetMapping("/list")
    public TableDataInfo<SysDictData> list(SysDictData dictData) {
        return dictDataService.selectPageDictDataList(dictData);
    public TableDataInfo<SysDictData> list(SysDictData dictData, PageQuery pageQuery) {
        return dictDataService.selectPageDictDataList(dictData, pageQuery);
    }
    @ApiOperation("导出字典数据列表")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
@@ -5,6 +5,7 @@
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.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictType;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
@@ -38,8 +39,8 @@
    @ApiOperation("查询字典类型列表")
    @SaCheckPermission("system:dict:list")
    @GetMapping("/list")
    public TableDataInfo<SysDictType> list(SysDictType dictType) {
        return dictTypeService.selectPageDictTypeList(dictType);
    public TableDataInfo<SysDictType> list(SysDictType dictType, PageQuery pageQuery) {
        return dictTypeService.selectPageDictTypeList(dictType, pageQuery);
    }
    @ApiOperation("导出字典类型列表")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
@@ -4,6 +4,7 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.SysNotice;
@@ -36,8 +37,8 @@
    @ApiOperation("获取通知公告列表")
    @SaCheckPermission("system:notice:list")
    @GetMapping("/list")
    public TableDataInfo<SysNotice> list(SysNotice notice) {
        return noticeService.selectPageNoticeList(notice);
    public TableDataInfo<SysNotice> list(SysNotice notice, PageQuery pageQuery) {
        return noticeService.selectPageNoticeList(notice, pageQuery);
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssConfigController.java
@@ -5,6 +5,7 @@
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
@@ -47,8 +48,8 @@
    @ApiOperation("查询对象存储配置列表")
    @SaCheckPermission("system:oss:list")
    @GetMapping("/list")
    public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo) {
        return iSysOssConfigService.queryPageList(bo);
    public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) {
        return iSysOssConfigService.queryPageList(bo, pageQuery);
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
@@ -11,6 +11,7 @@
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
@@ -61,8 +62,8 @@
    @ApiOperation("查询OSS对象存储列表")
    @SaCheckPermission("system:oss:list")
    @GetMapping("/list")
    public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo) {
        return iSysOssService.queryPageList(bo);
    public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) {
        return iSysOssService.queryPageList(bo, pageQuery);
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -5,6 +5,7 @@
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.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -41,8 +42,8 @@
    @ApiOperation("获取岗位列表")
    @SaCheckPermission("system:post:list")
    @GetMapping("/list")
    public TableDataInfo<SysPost> list(SysPost post) {
        return postService.selectPagePostList(post);
    public TableDataInfo<SysPost> list(SysPost post, PageQuery pageQuery) {
        return postService.selectPagePostList(post, pageQuery);
    }
    @ApiOperation("导出岗位列表")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -11,7 +11,10 @@
import com.ruoyi.system.domain.SysOss;
import com.ruoyi.system.service.ISysOssService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -5,6 +5,7 @@
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.PageQuery;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
@@ -45,8 +46,8 @@
    @ApiOperation("查询角色信息列表")
    @SaCheckPermission("system:role:list")
    @GetMapping("/list")
    public TableDataInfo<SysRole> list(SysRole role) {
        return roleService.selectPageRoleList(role);
    public TableDataInfo<SysRole> list(SysRole role, PageQuery pageQuery) {
        return roleService.selectPageRoleList(role, pageQuery);
    }
    @ApiOperation("导出角色信息列表")
@@ -165,8 +166,8 @@
    @ApiOperation("查询已分配用户角色列表")
    @SaCheckPermission("system:role:list")
    @GetMapping("/authUser/allocatedList")
    public TableDataInfo<SysUser> allocatedList(SysUser user) {
        return userService.selectAllocatedList(user);
    public TableDataInfo<SysUser> allocatedList(SysUser user, PageQuery pageQuery) {
        return userService.selectAllocatedList(user, pageQuery);
    }
    /**
@@ -175,8 +176,8 @@
    @ApiOperation("查询未分配用户角色列表")
    @SaCheckPermission("system:role:list")
    @GetMapping("/authUser/unallocatedList")
    public TableDataInfo<SysUser> unallocatedList(SysUser user) {
        return userService.selectUnallocatedList(user);
    public TableDataInfo<SysUser> unallocatedList(SysUser user, PageQuery pageQuery) {
        return userService.selectUnallocatedList(user, pageQuery);
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -8,6 +8,7 @@
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.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
@@ -59,8 +60,8 @@
    @ApiOperation("获取用户列表")
    @SaCheckPermission("system:user:list")
    @GetMapping("/list")
    public TableDataInfo<SysUser> list(SysUser user) {
        return userService.selectPageUserList(user);
    public TableDataInfo<SysUser> list(SysUser user, PageQuery pageQuery) {
        return userService.selectPageUserList(user, pageQuery);
    }
    @ApiOperation("导出用户列表")
ruoyi-admin/src/main/resources/application-dev.yml
@@ -51,7 +51,9 @@
        # ä¸»åº“数据源
        master:
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true
          # jdbc æ‰€æœ‰å‚数配置参考 https://lionli.blog.csdn.net/article/details/122018562
          # rewriteBatchedStatements=true æ‰¹å¤„理优化 å¤§å¹…提升批量插入更新删除性能(对数据库有性能损耗 ä½¿ç”¨æ‰¹é‡æ“ä½œåº”考虑性能问题)
          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
          username: root
          password: root
        # ä»Žåº“数据源
ruoyi-admin/src/main/resources/application-prod.yml
@@ -58,7 +58,9 @@
        # ä¸»åº“数据源
        master:
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true
          # jdbc æ‰€æœ‰å‚数配置参考 https://lionli.blog.csdn.net/article/details/122018562
          # rewriteBatchedStatements=true æ‰¹å¤„理优化 å¤§å¹…提升批量插入更新删除性能(对数据库有性能损耗 ä½¿ç”¨æ‰¹é‡æ“ä½œåº”考虑性能问题)
          url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
          username: root
          password: root
        # ä»Žåº“数据源
ruoyi-admin/src/main/resources/application.yml
@@ -11,7 +11,7 @@
  # èŽ·å–ip地址开关
  addressEnabled: true
  # ç¼“存懒加载
  cacheLazy: true
  cacheLazy: false
captcha:
  # é¡µé¢ <参数设置> å¯å¼€å¯å…³é—­ éªŒè¯ç æ ¡éªŒ
@@ -52,10 +52,6 @@
    com.ruoyi: @logging.level@
    org.springframework: warn
  config: classpath:logback.xml
# tlog å…¨å±€è®¿é—®æ€§èƒ½æ‹¦æˆª
tlog:
  enable-invoke-time-print: true
# Spring配置
spring:
@@ -142,6 +138,8 @@
    - /*/api-docs
    # druid ç›‘控配置
    - /druid/**
  # ç”¨æˆ·æ”¾è¡Œ
  permit-all:
    # actuator ç›‘控配置
    - /actuator
    - /actuator/**
ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -2,12 +2,12 @@
not.null=* å¿…须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.not.exists=对不起, æ‚¨çš„账号:{0} ä¸å­˜åœ¨.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
user.password.retry.limit.exceed=密码错误次数过多,帐户锁定{0}分钟
user.password.delete=对不起,您的账号:{0} å·²è¢«åˆ é™¤
user.blocked=对不起,您的账号:{0} å·²ç¦ç”¨ï¼Œè¯·è”系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -2,12 +2,12 @@
not.null=* Required fill in
user.jcaptcha.error=Captcha error
user.jcaptcha.expire=Captcha invalid
user.not.exists=User does not exist/Password error
user.not.exists=Sorry, your account: {0} does not exist
user.password.not.match=User does not exist/Password error
user.password.retry.limit.count=Password input error {0} times
user.password.retry.limit.exceed=Password input error {0} times, account locked for 10 minutes
user.password.delete=Sorry, your account has been deleted
user.blocked=User disabled,please contact administrators
user.password.retry.limit.exceed=Too many password errors, account locked for {0} minutes
user.password.delete=Sorry, your account:{0} has been deleted
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
role.blocked=Role disabled,please contact administrators
user.logout.success=Exit successful
length.not.valid=The length must be between {min} and {max} characters
ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -2,12 +2,12 @@
not.null=* å¿…须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.not.exists=对不起, æ‚¨çš„账号:{0} ä¸å­˜åœ¨.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
user.password.retry.limit.exceed=密码错误次数过多,帐户锁定{0}分钟
user.password.delete=对不起,您的账号:{0} å·²è¢«åˆ é™¤
user.blocked=对不起,您的账号:{0} å·²ç¦ç”¨ï¼Œè¯·è”系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
ruoyi-common/pom.xml
@@ -74,17 +74,16 @@
            <artifactId>easyexcel</artifactId>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
        </dependency>
        <!-- yml解析器 -->
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
        </dependency>
<!--        &lt;!&ndash;Token生成与解析&ndash;&gt;-->
<!--        <dependency>-->
<!--            <groupId>io.jsonwebtoken</groupId>-->
<!--            <artifactId>jjwt</artifactId>-->
<!--        </dependency>-->
        <!-- jdk11 ç¼ºå¤±ä¾èµ– jaxb-->
        <dependency>
@@ -106,18 +105,41 @@
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
        </dependency>
        <!-- dynamic-datasource å¤šæ•°æ®æº-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-http</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-captcha</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-extra</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
@@ -130,10 +152,6 @@
            <artifactId>swagger-annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--  è‡ªåŠ¨ç”ŸæˆYML配置关联JSON文件  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
@@ -149,16 +167,6 @@
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-spring-boot-configuration</artifactId>
        </dependency>
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-webroot</artifactId>
        </dependency>
    </dependencies>
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataColumn.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.ruoyi.common.annotation;
import java.lang.annotation.*;
/**
 * æ•°æ®æƒé™
 *
 * @author Lion Li
 * @version 3.5.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataColumn {
    /**
     * å ä½ç¬¦å…³é”®å­—
     */
    String key() default "deptName";
    /**
     * å ä½ç¬¦æ›¿æ¢å€¼
     */
    String value() default "dept_id";
}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataPermission.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.common.annotation;
import java.lang.annotation.*;
/**
 * æ•°æ®æƒé™ç»„
 *
 * @author Lion Li
 * @version 3.5.0
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermission {
    DataColumn[] value();
}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
@@ -6,11 +6,14 @@
 * æ•°æ®æƒé™è¿‡æ»¤æ³¨è§£
 *
 * @author ruoyi
 * @deprecated 3.6.0 ç§»é™¤ {@link com.ruoyi.common.annotation.DataPermission}
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Deprecated
public @interface DataScope {
    /**
     * éƒ¨é—¨è¡¨çš„别名
     */
@@ -25,4 +28,5 @@
     * æ˜¯å¦è¿‡æ»¤ç”¨æˆ·æƒé™
     */
    boolean isUser() default false;
}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
@@ -10,11 +10,13 @@
 * ä¼˜å…ˆçº§ï¼šå…ˆæ–¹æ³•,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
 *
 * @author ruoyi
 * @deprecated 3.6.0 ç§»é™¤ ä½¿ç”¨åŽŸç”Ÿæ³¨è§£å¤„ç† æ–¹æ³•æ›´å…¨ {@link com.baomidou.dynamic.datasource.annotation.DS}
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Deprecated
public @interface DataSource {
    /**
     * åˆ‡æ¢æ•°æ®æºåç§°
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -5,61 +5,62 @@
 *
 * @author ruoyi
 */
public class Constants {
public interface Constants {
    /**
     * UTF-8 å­—符集
     */
    public static final String UTF8 = "UTF-8";
    String UTF8 = "UTF-8";
    /**
     * GBK å­—符集
     */
    public static final String GBK = "GBK";
    String GBK = "GBK";
    /**
     * http请求
     */
    public static final String HTTP = "http://";
    String HTTP = "http://";
    /**
     * https请求
     */
    public static final String HTTPS = "https://";
    String HTTPS = "https://";
    /**
     * é€šç”¨æˆåŠŸæ ‡è¯†
     */
    public static final String SUCCESS = "0";
    String SUCCESS = "0";
    /**
     * é€šç”¨å¤±è´¥æ ‡è¯†
     */
    public static final String FAIL = "1";
    String FAIL = "1";
    /**
     * ç™»å½•成功
     */
    public static final String LOGIN_SUCCESS = "Success";
    String LOGIN_SUCCESS = "Success";
    /**
     * æ³¨é”€
     */
    public static final String LOGOUT = "Logout";
    String LOGOUT = "Logout";
    /**
     * æ³¨å†Œ
     */
    public static final String REGISTER = "Register";
    String REGISTER = "Register";
    /**
     * ç™»å½•失败
     */
    public static final String LOGIN_FAIL = "Error";
    String LOGIN_FAIL = "Error";
    /**
     * éªŒè¯ç  redis key
     */
    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
    String CAPTCHA_CODE_KEY = "captcha_codes:";
    /**
     * ç™»å½•用户 redis key
@@ -74,36 +75,51 @@
    /**
     * é˜²é‡æäº¤ redis key
     */
    public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
    String REPEAT_SUBMIT_KEY = "repeat_submit:";
    /**
     * é™æµ redis key
     */
    public static final String RATE_LIMIT_KEY = "rate_limit:";
    String RATE_LIMIT_KEY = "rate_limit:";
    /**
     * éªŒè¯ç æœ‰æ•ˆæœŸï¼ˆåˆ†é’Ÿï¼‰
     */
    public static final Integer CAPTCHA_EXPIRATION = 2;
    Integer CAPTCHA_EXPIRATION = 2;
    /**
     * ç™»é™†é”™è¯¯ redis key
     */
    String LOGIN_ERROR = "login_error:";
    /**
     * ç™»å½•错误次数
     */
    Integer LOGIN_ERROR_NUMBER = 5;
    /**
     * ç™»å½•错误限制时间(分钟)
     */
    Integer LOGIN_ERROR_LIMIT_TIME = 10;
    /**
     * ä»¤ç‰Œ
     */
    public static final String TOKEN = "token";
    String TOKEN = "token";
    /**
     * ä»¤ç‰Œå‰ç¼€
     */
    public static final String LOGIN_USER_KEY = "login_user_key";
    String LOGIN_USER_KEY = "login_user_key";
    /**
     * å‚数管理 cache key
     */
    public static final String SYS_CONFIG_KEY = "sys_config:";
    String SYS_CONFIG_KEY = "sys_config:";
    /**
     * å­—典管理 cache key
     */
    public static final String SYS_DICT_KEY = "sys_dict:";
    String SYS_DICT_KEY = "sys_dict:";
}
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -5,184 +5,184 @@
 *
 * @author ruoyi
 */
public class GenConstants {
public interface GenConstants {
    /**
     * å•表(增删改查)
     */
    public static final String TPL_CRUD = "crud";
    String TPL_CRUD = "crud";
    /**
     * æ ‘表(增删改查)
     */
    public static final String TPL_TREE = "tree";
    String TPL_TREE = "tree";
    /**
     * ä¸»å­è¡¨ï¼ˆå¢žåˆ æ”¹æŸ¥ï¼‰
     */
    public static final String TPL_SUB = "sub";
    String TPL_SUB = "sub";
    /**
     * æ ‘编码字段
     */
    public static final String TREE_CODE = "treeCode";
    String TREE_CODE = "treeCode";
    /**
     * æ ‘父编码字段
     */
    public static final String TREE_PARENT_CODE = "treeParentCode";
    String TREE_PARENT_CODE = "treeParentCode";
    /**
     * æ ‘名称字段
     */
    public static final String TREE_NAME = "treeName";
    String TREE_NAME = "treeName";
    /**
     * ä¸Šçº§èœå•ID字段
     */
    public static final String PARENT_MENU_ID = "parentMenuId";
    String PARENT_MENU_ID = "parentMenuId";
    /**
     * ä¸Šçº§èœå•名称字段
     */
    public static final String PARENT_MENU_NAME = "parentMenuName";
    String PARENT_MENU_NAME = "parentMenuName";
    /**
     * æ•°æ®åº“字符串类型
     */
    public static final String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"};
    String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"};
    /**
     * æ•°æ®åº“文本类型
     */
    public static final String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"};
    String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"};
    /**
     * æ•°æ®åº“时间类型
     */
    public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};
    String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};
    /**
     * æ•°æ®åº“数字类型
     */
    public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
            "bit", "bigint", "float", "double", "decimal"};
    String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
        "bit", "bigint", "float", "double", "decimal"};
    /**
     * BO对象 ä¸éœ€è¦æ·»åŠ å­—æ®µ
     */
    public static final String[] COLUMNNAME_NOT_ADD = {"create_by", "create_time", "del_flag", "update_by",
            "update_time", "version"};
    String[] COLUMNNAME_NOT_ADD = {"create_by", "create_time", "del_flag", "update_by",
        "update_time", "version"};
    /**
     * BO对象 ä¸éœ€è¦ç¼–辑字段
     */
    public static final String[] COLUMNNAME_NOT_EDIT = {"create_by", "create_time", "del_flag", "update_by",
            "update_time", "version"};
    String[] COLUMNNAME_NOT_EDIT = {"create_by", "create_time", "del_flag", "update_by",
        "update_time", "version"};
    /**
     * VO对象 ä¸éœ€è¦è¿”回字段
     */
    public static final String[] COLUMNNAME_NOT_LIST = {"create_by", "create_time", "del_flag", "update_by",
            "update_time", "version"};
    String[] COLUMNNAME_NOT_LIST = {"create_by", "create_time", "del_flag", "update_by",
        "update_time", "version"};
    /**
     * BO对象 ä¸éœ€è¦æŸ¥è¯¢å­—段
     */
    public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by",
            "update_time", "remark", "version"};
    String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by",
        "update_time", "remark", "version"};
    /**
     * Entity基类字段
     */
    public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime"};
    String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime"};
    /**
     * Tree基类字段
     */
    public static final String[] TREE_ENTITY = {"parentName", "parentId", "children"};
    String[] TREE_ENTITY = {"parentName", "parentId", "children"};
    /**
     * æ–‡æœ¬æ¡†
     */
    public static final String HTML_INPUT = "input";
    String HTML_INPUT = "input";
    /**
     * æ–‡æœ¬åŸŸ
     */
    public static final String HTML_TEXTAREA = "textarea";
    String HTML_TEXTAREA = "textarea";
    /**
     * ä¸‹æ‹‰æ¡†
     */
    public static final String HTML_SELECT = "select";
    String HTML_SELECT = "select";
    /**
     * å•选框
     */
    public static final String HTML_RADIO = "radio";
    String HTML_RADIO = "radio";
    /**
     * å¤é€‰æ¡†
     */
    public static final String HTML_CHECKBOX = "checkbox";
    String HTML_CHECKBOX = "checkbox";
    /**
     * æ—¥æœŸæŽ§ä»¶
     */
    public static final String HTML_DATETIME = "datetime";
    String HTML_DATETIME = "datetime";
    /**
     * å›¾ç‰‡ä¸Šä¼ æŽ§ä»¶
     */
    public static final String HTML_IMAGE_UPLOAD = "imageUpload";
    String HTML_IMAGE_UPLOAD = "imageUpload";
    /**
     * æ–‡ä»¶ä¸Šä¼ æŽ§ä»¶
     */
    public static final String HTML_FILE_UPLOAD = "fileUpload";
    String HTML_FILE_UPLOAD = "fileUpload";
    /**
     * å¯Œæ–‡æœ¬æŽ§ä»¶
     */
    public static final String HTML_EDITOR = "editor";
    String HTML_EDITOR = "editor";
    /**
     * å­—符串类型
     */
    public static final String TYPE_STRING = "String";
    String TYPE_STRING = "String";
    /**
     * æ•´åž‹
     */
    public static final String TYPE_INTEGER = "Integer";
    String TYPE_INTEGER = "Integer";
    /**
     * é•¿æ•´åž‹
     */
    public static final String TYPE_LONG = "Long";
    String TYPE_LONG = "Long";
    /**
     * æµ®ç‚¹åž‹
     */
    public static final String TYPE_DOUBLE = "Double";
    String TYPE_DOUBLE = "Double";
    /**
     * é«˜ç²¾åº¦è®¡ç®—类型
     */
    public static final String TYPE_BIGDECIMAL = "BigDecimal";
    String TYPE_BIGDECIMAL = "BigDecimal";
    /**
     * æ—¶é—´ç±»åž‹
     */
    public static final String TYPE_DATE = "Date";
    String TYPE_DATE = "Date";
    /**
     * æ¨¡ç³ŠæŸ¥è¯¢
     */
    public static final String QUERY_LIKE = "LIKE";
    String QUERY_LIKE = "LIKE";
    /**
     * éœ€è¦
     */
    public static final String REQUIRE = "1";
    String REQUIRE = "1";
}
ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -5,108 +5,108 @@
 *
 * @author ruoyi
 */
public class UserConstants {
public interface UserConstants {
    /**
     * å¹³å°å†…系统用户的唯一标志
     */
    public static final String SYS_USER = "SYS_USER";
    String SYS_USER = "SYS_USER";
    /**
     * æ­£å¸¸çŠ¶æ€
     */
    public static final String NORMAL = "0";
    String NORMAL = "0";
    /**
     * å¼‚常状态
     */
    public static final String EXCEPTION = "1";
    String EXCEPTION = "1";
    /**
     * ç”¨æˆ·å°ç¦çŠ¶æ€
     */
    public static final String USER_DISABLE = "1";
    String USER_DISABLE = "1";
    /**
     * è§’色封禁状态
     */
    public static final String ROLE_DISABLE = "1";
    String ROLE_DISABLE = "1";
    /**
     * éƒ¨é—¨æ­£å¸¸çŠ¶æ€
     */
    public static final String DEPT_NORMAL = "0";
    String DEPT_NORMAL = "0";
    /**
     * éƒ¨é—¨åœç”¨çŠ¶æ€
     */
    public static final String DEPT_DISABLE = "1";
    String DEPT_DISABLE = "1";
    /**
     * å­—典正常状态
     */
    public static final String DICT_NORMAL = "0";
    String DICT_NORMAL = "0";
    /**
     * æ˜¯å¦ä¸ºç³»ç»Ÿé»˜è®¤ï¼ˆæ˜¯ï¼‰
     */
    public static final String YES = "Y";
    String YES = "Y";
    /**
     * æ˜¯å¦èœå•外链(是)
     */
    public static final String YES_FRAME = "0";
    String YES_FRAME = "0";
    /**
     * æ˜¯å¦èœå•外链(否)
     */
    public static final String NO_FRAME = "1";
    String NO_FRAME = "1";
    /**
     * èœå•类型(目录)
     */
    public static final String TYPE_DIR = "M";
    String TYPE_DIR = "M";
    /**
     * èœå•类型(菜单)
     */
    public static final String TYPE_MENU = "C";
    String TYPE_MENU = "C";
    /**
     * èœå•类型(按钮)
     */
    public static final String TYPE_BUTTON = "F";
    String TYPE_BUTTON = "F";
    /**
     * Layout组件标识
     */
    public final static String LAYOUT = "Layout";
    String LAYOUT = "Layout";
    /**
     * ParentView组件标识
     */
    public final static String PARENT_VIEW = "ParentView";
    String PARENT_VIEW = "ParentView";
    /**
     * InnerLink组件标识
     */
    public final static String INNER_LINK = "InnerLink";
    String INNER_LINK = "InnerLink";
    /**
     * æ ¡éªŒè¿”回结果码
     */
    public final static String UNIQUE = "0";
    public final static String NOT_UNIQUE = "1";
    String UNIQUE = "0";
    String NOT_UNIQUE = "1";
    /**
     * ç”¨æˆ·åé•¿åº¦é™åˆ¶
     */
    public static final int USERNAME_MIN_LENGTH = 2;
    public static final int USERNAME_MAX_LENGTH = 20;
    int USERNAME_MIN_LENGTH = 2;
    int USERNAME_MAX_LENGTH = 20;
    /**
     * å¯†ç é•¿åº¦é™åˆ¶
     */
    public static final int PASSWORD_MIN_LENGTH = 5;
    public static final int PASSWORD_MAX_LENGTH = 20;
    int PASSWORD_MIN_LENGTH = 5;
    int PASSWORD_MAX_LENGTH = 20;
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/PageQuery.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
package com.ruoyi.common.core.domain;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sql.SqlUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
 * åˆ†é¡µæŸ¥è¯¢å®žä½“ç±»
 *
 * @author Lion Li
 */
@Data
@Accessors(chain = true)
public class PageQuery implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * åˆ†é¡µå¤§å°
     */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /**
     * å½“前页数
     */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /**
     * æŽ’序列
     */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /**
     * æŽ’序的方向desc或者asc
     */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
    /**
     * å½“前记录起始索引 é»˜è®¤å€¼
     */
    public static final int DEFAULT_PAGE_NUM = 1;
    /**
     * æ¯é¡µæ˜¾ç¤ºè®°å½•æ•° é»˜è®¤å€¼ é»˜è®¤æŸ¥å…¨éƒ¨
     */
    public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
    public <T> Page<T> build() {
        Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
        Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
        if (pageNum <= 0) {
            pageNum = DEFAULT_PAGE_NUM;
        }
        Page<T> page = new Page<>(pageNum, pageSize);
        OrderItem orderItem = buildOrderItem();
        if (ObjectUtil.isNotNull(orderItem)) {
            page.addOrder(orderItem);
        }
        return page;
    }
    private OrderItem buildOrderItem() {
        // å…¼å®¹å‰ç«¯æŽ’序类型
        if ("ascending".equals(isAsc)) {
            isAsc = "asc";
        } else if ("descending".equals(isAsc)) {
            isAsc = "desc";
        }
        if (StringUtils.isNotBlank(orderByColumn)) {
            String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
            orderBy = StringUtils.toUnderScoreCase(orderBy);
            if ("asc".equals(isAsc)) {
                return OrderItem.asc(orderBy);
            } else if ("desc".equals(isAsc)) {
                return OrderItem.desc(orderBy);
            }
        }
        return null;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.TreeEntity;
@@ -65,6 +66,7 @@
     * è·¯ç”±å‚æ•°
     */
    @ApiModelProperty(value = "路由参数")
    @TableField("`query`")
    private String query;
    /**
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -4,6 +4,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.xss.Xss;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -48,15 +49,17 @@
     * ç”¨æˆ·è´¦å·
     */
    @ApiModelProperty(value = "用户账号")
    @NotBlank(message = "用户账号不能为空")
    @Xss(message = "用户账号不能包含脚本字符")
    @NotBlank(message = "用户账号不能为空")
    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
    private String userName;
    /**
     * ç”¨æˆ·æ˜µç§°
     */
    @ApiModelProperty(value = "用户昵称")
    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
    @ApiModelProperty(value = "用户昵称")
    @Xss(message = "用户昵称不能包含脚本字符")
    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
    private String nickName;
    /**
@@ -162,7 +165,7 @@
    private Long[] postIds;
    /**
     * è§’色ID
     * æ•°æ®æƒé™ å½“前角色ID
     */
    @ApiModelProperty(value = "角色ID")
    @TableField(exist = false)
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/core/BaseMapperPlus.java
@@ -1,9 +1,18 @@
package com.ruoyi.common.core.mybatisplus.core;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.BeanCopyUtils;
import org.apache.ibatis.annotations.Param;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
 * è‡ªå®šä¹‰ Mapper æŽ¥å£, å®žçް è‡ªå®šä¹‰æ‰©å±•
@@ -18,4 +27,72 @@
     */
    int insertAll(@Param("list") Collection<T> batchList);
    /**
     * æ ¹æ® ID æŸ¥è¯¢
     */
    default <V> V selectVoById(Serializable id, Class<V> voClass){
        T obj = this.selectById(id);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return BeanCopyUtils.copy(obj, voClass);
    }
    /**
     * æŸ¥è¯¢ï¼ˆæ ¹æ®ID æ‰¹é‡æŸ¥è¯¢ï¼‰
     */
    default <V> List<V> selectVoBatchIds(Collection<? extends Serializable> idList, Class<V> voClass){
        List<T> list = this.selectBatchIds(idList);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanCopyUtils.copyList(list, voClass);
    }
    /**
     * æŸ¥è¯¢ï¼ˆæ ¹æ® columnMap æ¡ä»¶ï¼‰
     */
    default <V> List<V> selectVoByMap(Map<String, Object> map, Class<V> voClass){
        List<T> list = this.selectByMap(map);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanCopyUtils.copyList(list, voClass);
    }
    /**
     * æ ¹æ® entity æ¡ä»¶ï¼ŒæŸ¥è¯¢ä¸€æ¡è®°å½•
     */
    default <V> V selectVoOne(Wrapper<T> wrapper, Class<V> voClass) {
        T obj = this.selectOne(wrapper);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return BeanCopyUtils.copy(obj, voClass);
    }
    /**
     * æ ¹æ® entity æ¡ä»¶ï¼ŒæŸ¥è¯¢å…¨éƒ¨è®°å½•
     */
    default <V> List<V> selectVoList(Wrapper<T> wrapper, Class<V> voClass) {
        List<T> list = this.selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanCopyUtils.copyList(list, voClass);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢VO
     */
    default <V, P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<V> voClass) {
        IPage<T> pageData = this.selectPage(page, wrapper);
        IPage<V> voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
        if (CollUtil.isEmpty(pageData.getRecords())) {
            return (P) voPage;
        }
        voPage.setRecords(BeanCopyUtils.copyList(pageData.getRecords(), voClass));
        return (P) voPage;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/core/IServicePlus.java
@@ -1,7 +1,7 @@
package com.ruoyi.common.core.mybatisplus.core;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.page.PagePlus;
@@ -23,14 +23,9 @@
    /**
     * @param id          ä¸»é”®id
     * @param copyOptions copy条件
     * @return V对象
     */
    V getVoById(Serializable id, CopyOptions copyOptions);
    default V getVoById(Serializable id) {
        return getVoById(id, new CopyOptions());
    }
    V getVoById(Serializable id);
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
@@ -41,14 +36,9 @@
    /**
     * @param idList      id列表
     * @param copyOptions copy条件
     * @return V对象
     */
    List<V> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions);
    default List<V> listVoByIds(Collection<? extends Serializable> idList) {
        return listVoByIds(idList, new CopyOptions());
    }
    List<V> listVoByIds(Collection<? extends Serializable> idList);
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
@@ -64,14 +54,9 @@
    /**
     * @param columnMap   è¡¨å­—段 map å¯¹è±¡
     * @param copyOptions copy条件
     * @return V对象
     */
    List<V> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions);
    default List<V> listVoByMap(Map<String, Object> columnMap) {
        return listVoByMap(columnMap, new CopyOptions());
    }
    List<V> listVoByMap(Map<String, Object> columnMap);
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
@@ -87,14 +72,9 @@
    /**
     * @param queryWrapper æŸ¥è¯¢æ¡ä»¶
     * @param copyOptions  copy条件
     * @return V对象
     */
    V getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions);
    default V getVoOne(Wrapper<T> queryWrapper) {
        return getVoOne(queryWrapper, new CopyOptions());
    }
    V getVoOne(Wrapper<T> queryWrapper);
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
@@ -105,14 +85,9 @@
    /**
     * @param queryWrapper æŸ¥è¯¢æ¡ä»¶
     * @param copyOptions  copy条件
     * @return V对象
     */
    List<V> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions);
    default List<V> listVo(Wrapper<T> queryWrapper) {
        return listVo(queryWrapper, new CopyOptions());
    }
    List<V> listVo(Wrapper<T> queryWrapper);
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
@@ -139,31 +114,36 @@
    /**
     * @param page         åˆ†é¡µå¯¹è±¡
     * @param queryWrapper æŸ¥è¯¢æ¡ä»¶
     * @param copyOptions  copy条件
     * @return V对象
     * @deprecated 3.6.0 ç§»é™¤ è¯·ä½¿ç”¨ {@link ServicePlusImpl#pageVo(IPage, Wrapper)}
     */
    PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper, CopyOptions copyOptions);
    @Deprecated
    PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper);
    default PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper) {
        return pageVo(page, queryWrapper, new CopyOptions());
    }
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
     */
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
     * @deprecated 3.6.0 ç§»é™¤ è¯·ä½¿ç”¨ {@link ServicePlusImpl#pageVo(IPage, Wrapper)}
     */
    @Deprecated
    default PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper,
                                  Function<Collection<T>, List<V>> convertor) {
        PagePlus<T, V> result = getBaseMapper().selectPage(page, queryWrapper);
        return result.setRecordsVo(convertor.apply(result.getRecords()));
    }
    /**
     * @deprecated 3.6.0 ç§»é™¤ è¯·ä½¿ç”¨ {@link ServicePlusImpl#pageVo(IPage, Wrapper)}
     */
    @Deprecated
    default PagePlus<T, V> pageVo(PagePlus<T, V> page) {
        return pageVo(page, Wrappers.emptyWrapper());
    }
    /**
     * @param convertor è‡ªå®šä¹‰è½¬æ¢å™¨
     * @deprecated 3.6.0 ç§»é™¤ è¯·ä½¿ç”¨ {@link ServicePlusImpl#pageVo(IPage, Wrapper)}
     */
    @Deprecated
    default PagePlus<T, V> pageVo(PagePlus<T, V> page, Function<Collection<T>, List<V>> convertor) {
        return pageVo(page, Wrappers.emptyWrapper(), convertor);
    }
ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/core/ServicePlusImpl.java
@@ -1,9 +1,9 @@
package com.ruoyi.common.core.mybatisplus.core;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
@@ -161,81 +161,66 @@
    /**
     * æ ¹æ® ID æŸ¥è¯¢
     *
     * @param id ä¸»é”®ID
     */
    @Override
    public V getVoById(Serializable id, CopyOptions copyOptions) {
        T t = getBaseMapper().selectById(id);
        return BeanCopyUtils.oneCopy(t, copyOptions, voClass);
    public V getVoById(Serializable id) {
        return getBaseMapper().selectVoById(id, voClass);
    }
    /**
     * æŸ¥è¯¢ï¼ˆæ ¹æ®ID æ‰¹é‡æŸ¥è¯¢ï¼‰
     *
     * @param idList ä¸»é”®ID列表
     */
    @Override
    public List<V> listVoByIds(Collection<? extends Serializable> idList, CopyOptions copyOptions) {
        List<T> list = getBaseMapper().selectBatchIds(idList);
        if (list == null) {
            return null;
        }
        return BeanCopyUtils.listCopy(list, copyOptions, voClass);
    public List<V> listVoByIds(Collection<? extends Serializable> idList) {
        return getBaseMapper().selectVoBatchIds(idList, voClass);
    }
    /**
     * æŸ¥è¯¢ï¼ˆæ ¹æ® columnMap æ¡ä»¶ï¼‰
     *
     * @param columnMap è¡¨å­—段 map å¯¹è±¡
     */
    @Override
    public List<V> listVoByMap(Map<String, Object> columnMap, CopyOptions copyOptions) {
        List<T> list = getBaseMapper().selectByMap(columnMap);
        if (list == null) {
            return null;
        }
        return BeanCopyUtils.listCopy(list, copyOptions, voClass);
    public List<V> listVoByMap(Map<String, Object> columnMap) {
        return getBaseMapper().selectVoByMap(columnMap, voClass);
    }
    /**
     * æ ¹æ® Wrapper,查询一条记录 <br/>
     * <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper å®žä½“对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    @Override
    public V getVoOne(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
        T t = getOne(queryWrapper, true);
        return BeanCopyUtils.oneCopy(t, copyOptions, voClass);
    public V getVoOne(Wrapper<T> queryWrapper) {
        return getBaseMapper().selectVoOne(queryWrapper, voClass);
    }
    /**
     * æŸ¥è¯¢åˆ—表
     *
     * @param queryWrapper å®žä½“对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    @Override
    public List<V> listVo(Wrapper<T> queryWrapper, CopyOptions copyOptions) {
        List<T> list = getBaseMapper().selectList(queryWrapper);
        if (list == null) {
            return null;
        }
        return BeanCopyUtils.listCopy(list, copyOptions, voClass);
    public List<V> listVo(Wrapper<T> queryWrapper) {
        return getBaseMapper().selectVoList(queryWrapper, voClass);
    }
    /**
     * ç¿»é¡µæŸ¥è¯¢
     *
     * @param page         ç¿»é¡µå¯¹è±¡
     * @param queryWrapper å®žä½“对象封装操作类
     * @deprecated 3.6.0 ç§»é™¤ è¯·ä½¿ç”¨ {@link #pageVo(IPage, Wrapper)}
     */
    @Override
    public PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper, CopyOptions copyOptions) {
    @Deprecated
    public PagePlus<T, V> pageVo(PagePlus<T, V> page, Wrapper<T> queryWrapper) {
        PagePlus<T, V> result = getBaseMapper().selectPage(page, queryWrapper);
        List<V> volist = BeanCopyUtils.listCopy(result.getRecords(), copyOptions, voClass);
        List<V> volist = BeanCopyUtils.copyList(result.getRecords(), voClass);
        result.setRecordsVo(volist);
        return result;
    }
    /**
     * ç¿»é¡µæŸ¥è¯¢
     *
     * @param page         ç¿»é¡µå¯¹è±¡
     * @param queryWrapper å®žä½“对象封装操作类
     */
    public <P extends IPage<V>> P pageVo(IPage<T> page, Wrapper<T> queryWrapper) {
        return getBaseMapper().selectVoPage(page, queryWrapper, voClass);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/core/page/PagePlus.java
@@ -16,9 +16,11 @@
 * @param <T> æ•°æ®åº“实体
 * @param <K> vo实体
 * @author Lion Li
 * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link com.ruoyi.common.core.domain.PageQuery#build()}
 */
@Data
@Accessors(chain = true)
@Deprecated
public class PagePlus<T,K> implements IPage<T> {
    /**
ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.page;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -57,4 +59,29 @@
        this.total = total;
    }
    public static <T> TableDataInfo<T> build(IPage<T> page) {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
        rspData.setMsg("查询成功");
        rspData.setRows(page.getRecords());
        rspData.setTotal(page.getTotal());
        return rspData;
    }
    public static <T> TableDataInfo<T> build(List<T> list) {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
        rspData.setMsg("查询成功");
        rspData.setRows(list);
        rspData.setTotal(list.size());
        return rspData;
    }
    public static <T> TableDataInfo<T> build() {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
        rspData.setMsg("查询成功");
        return rspData;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataScopeType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package com.ruoyi.common.enums;
import com.ruoyi.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * æ•°æ®æƒé™ç±»åž‹
 *
 * è¯­æ³•支持 spel æ¨¡æ¿è¡¨è¾¾å¼
 *
 * å†…置数据 user å½“前用户 å†…容参考 SysUser
 * å¦‚需扩展数据 å¯ä½¿ç”¨ {@link com.ruoyi.common.helper.DataPermissionHelper} æ“ä½œ
 * å†…置服务 sdss ç³»ç»Ÿæ•°æ®æƒé™æœåŠ¡ å†…容参考 SysDataScopeService
 * å¦‚需扩展更多自定义服务 å¯ä»¥å‚考 sdss è‡ªè¡Œç¼–写
 *
 * @author Lion Li
 * @version 3.5.0
 */
@Getter
@AllArgsConstructor
public enum DataScopeType {
    /**
     * å…¨éƒ¨æ•°æ®æƒé™
     */
    ALL("1", "", ""),
    /**
     * è‡ªå®šæ•°æ®æƒé™
     */
    CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""),
    /**
     * éƒ¨é—¨æ•°æ®æƒé™
     */
    DEPT("3", " #{#deptName} = #{#user.deptId} ", ""),
    /**
     * éƒ¨é—¨åŠä»¥ä¸‹æ•°æ®æƒé™
     */
    DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""),
    /**
     * ä»…本人数据权限
     */
    SELF("5", " #{#userName} = #{#user.userId} " , " 1 = 0 ");
    private final String code;
    /**
     * è¯­æ³• é‡‡ç”¨ spel æ¨¡æ¿è¡¨è¾¾å¼
     */
    private final String sqlTemplate;
    /**
     * ä¸æ»¡è¶³ sqlTemplate åˆ™å¡«å……
     */
    private final String elseSql;
    public static DataScopeType findCode(String code) {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        for (DataScopeType type : values()) {
            if (type.getCode().equals(code)) {
                return type;
            }
        }
        return null;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
@@ -7,8 +7,10 @@
 * æ•°æ®æº
 *
 * @author Lion Li
 * @deprecated 3.6.0 ç§»é™¤
 */
@AllArgsConstructor
@Deprecated
public enum DataSourceType {
    /**
     * ä¸»åº“
ruoyi-common/src/main/java/com/ruoyi/common/excel/DefaultExcelListener.java
@@ -5,7 +5,7 @@
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.JsonUtils;
import com.ruoyi.common.utils.ValidatorUtils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -84,7 +84,7 @@
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap = headMap;
        log.debug("解析到一条表头数据: {}", JSON.toJSONString(headMap));
        log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap));
    }
    @Override
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
@@ -9,6 +9,6 @@
    private static final long serialVersionUID = 1L;
    public CaptchaException() {
        super("user.jcaptcha.error", null);
        super("user.jcaptcha.error");
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
@@ -9,6 +9,6 @@
    private static final long serialVersionUID = 1L;
    public CaptchaExpireException() {
        super("user.jcaptcha.expire", null);
        super("user.jcaptcha.expire");
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
@@ -9,6 +9,6 @@
    private static final long serialVersionUID = 1L;
    public UserPasswordNotMatchException() {
        super("user.password.not.match", null);
        super("user.password.not.match");
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/helper/DataPermissionHelper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package com.ruoyi.common.helper;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.utils.ServletUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
 * æ•°æ®æƒé™åŠ©æ‰‹
 *
 * @author Lion Li
 * @version 3.5.0
 */
@SuppressWarnings("unchecked cast")
public class DataPermissionHelper {
    private static final String DATA_PERMISSION_KEY = "data:permission";
    public static <T> T getVariable(String key) {
        Map<String, Object> context = getContext();
        return (T) context.get(key);
    }
    public static void setVariable(String key, Object value) {
        Map<String, Object> context = getContext();
        context.put(key, value);
    }
    public static Map<String, Object> getContext() {
        HttpServletRequest request = ServletUtils.getRequest();
        Object attribute = request.getAttribute(DATA_PERMISSION_KEY);
        if (ObjectUtil.isNull(attribute)) {
            request.setAttribute(DATA_PERMISSION_KEY, new HashMap<>());
            attribute = request.getAttribute(DATA_PERMISSION_KEY);
        }
        if (attribute instanceof Map) {
            return (Map<String, Object>) attribute;
        }
        throw new NullPointerException("data permission context type exception");
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/BeanCopyUtils.java
@@ -1,66 +1,120 @@
package com.ruoyi.common.utils;
import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.cglib.CglibUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
/**
 * bean深拷贝工具
 * bean深拷贝工具(基于 cglib æ€§èƒ½ä¼˜å¼‚)
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanCopyUtils {
    /**
     * å•对象基于class创建拷贝
     *
     * @param source      æ•°æ®æ¥æºå®žä½“
     * @param copyOptions copy条件
     * @param desc        æè¿°å¯¹è±¡ è½¬æ¢åŽçš„对象
     * @param source æ•°æ®æ¥æºå®žä½“
     * @param desc   æè¿°å¯¹è±¡ è½¬æ¢åŽçš„对象
     * @return desc
     */
    public static <T, V> V oneCopy(T source, CopyOptions copyOptions, Class<V> desc) {
        V v = ReflectUtil.newInstanceIfPossible(desc);
        return oneCopy(source, copyOptions, v);
    public static <T, V> V copy(T source, Class<V> desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        return CglibUtil.copy(source, desc);
    }
    /**
     * å•对象基于对象创建拷贝
     *
     * @param source      æ•°æ®æ¥æºå®žä½“
     * @param copyOptions copy条件
     * @param desc        è½¬æ¢åŽçš„对象
     * @param source æ•°æ®æ¥æºå®žä½“
     * @param desc   è½¬æ¢åŽçš„对象
     * @return desc
     */
    public static <T, V> V oneCopy(T source, CopyOptions copyOptions, V desc) {
    public static <T, V> V copy(T source, V desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        return BeanCopier.create(source, desc, copyOptions).copy();
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        CglibUtil.copy(source, desc);
        return desc;
    }
    /**
     * åˆ—表对象基于class创建拷贝
     *
     * @param sourceList  æ•°æ®æ¥æºå®žä½“列表
     * @param copyOptions copy条件
     * @param desc        æè¿°å¯¹è±¡ è½¬æ¢åŽçš„对象
     * @param sourceList æ•°æ®æ¥æºå®žä½“列表
     * @param desc       æè¿°å¯¹è±¡ è½¬æ¢åŽçš„对象
     * @return desc
     */
    public static <T, V> List<V> listCopy(List<T> sourceList, CopyOptions copyOptions, Class<V> desc) {
    public static <T, V> List<V> copyList(List<T> sourceList, Class<V> desc) {
        if (ObjectUtil.isNull(sourceList)) {
            return null;
        }
        if (CollUtil.isEmpty(sourceList)) {
            return CollUtil.newArrayList();
        }
        return sourceList.stream()
                .map(source -> oneCopy(source, copyOptions, desc))
                .collect(Collectors.toList());
        return CglibUtil.copyList(sourceList, () -> ReflectUtil.newInstanceIfPossible(desc));
    }
    /**
     * bean拷贝到map
     *
     * @param bean æ•°æ®æ¥æºå®žä½“
     * @return map对象
     */
    public static <T> Map<String, Object> copyToMap(T bean) {
        if (ObjectUtil.isNull(bean)) {
            return null;
        }
        return CglibUtil.toMap(bean);
    }
    /**
     * map拷贝到bean
     *
     * @param map       æ•°æ®æ¥æº
     * @param beanClass beanç±»
     * @return bean对象
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> beanClass) {
        if (MapUtil.isEmpty(map)) {
            return null;
        }
        if (ObjectUtil.isNull(beanClass)) {
            return null;
        }
        return CglibUtil.toBean(map, beanClass);
    }
    /**
     * map拷贝到bean
     *
     * @param map  æ•°æ®æ¥æº
     * @param bean bean对象
     * @return bean对象
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        if (MapUtil.isEmpty(map)) {
            return null;
        }
        if (ObjectUtil.isNull(bean)) {
            return null;
        }
        return CglibUtil.fillBean(map, bean);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.management.ManagementFactory;
@@ -12,6 +14,7 @@
 *
 * @author ruoyi
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
@@ -21,14 +21,18 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonUtils {
    private static ObjectMapper objectMapper = SpringUtils.getBean(ObjectMapper.class);
    private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class);
    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER;
    }
    public static String toJsonString(Object object) {
        if (StringUtils.isNull(object)) {
            return null;
        }
        try {
            return objectMapper.writeValueAsString(object);
            return OBJECT_MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
@@ -39,7 +43,7 @@
            return null;
        }
        try {
            return objectMapper.readValue(text, clazz);
            return OBJECT_MAPPER.readValue(text, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
@@ -50,7 +54,7 @@
            return null;
        }
        try {
            return objectMapper.readValue(bytes, clazz);
            return OBJECT_MAPPER.readValue(bytes, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
@@ -61,7 +65,7 @@
            return null;
        }
        try {
            return objectMapper.readValue(text, typeReference);
            return OBJECT_MAPPER.readValue(text, typeReference);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
@@ -72,7 +76,7 @@
            return null;
        }
        try {
            return objectMapper.readValue(text, new TypeReference<Map<String, T>>() {
            return OBJECT_MAPPER.readValue(text, new TypeReference<Map<String, T>>() {
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
@@ -84,7 +88,7 @@
            return new ArrayList<>();
        }
        try {
            return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
            return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java
@@ -1,15 +1,21 @@
package com.ruoyi.common.utils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
/**
 * èŽ·å–i18n资源文件
 *
 * @author ruoyi
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MessageUtils {
    private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class);
    /**
     * æ ¹æ®æ¶ˆæ¯é”®å’Œå‚æ•° èŽ·å–æ¶ˆæ¯ å§”托给spring messageSource
     *
@@ -18,7 +24,6 @@
     * @return èŽ·å–å›½é™…åŒ–ç¿»è¯‘å€¼
     */
    public static String message(String code, Object... args) {
        MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
        return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
@@ -2,11 +2,15 @@
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.sql.SqlUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.List;
@@ -14,37 +18,46 @@
 * åˆ†é¡µå·¥å…·
 *
 * @author Lion Li
 * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link PageQuery} ä¸Ž {@link TableDataInfo}
 */
@Deprecated
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PageUtils {
    /**
     * å½“前记录起始索引
     */
    @Deprecated
    public static final String PAGE_NUM = "pageNum";
    /**
     * æ¯é¡µæ˜¾ç¤ºè®°å½•æ•°
     */
    @Deprecated
    public static final String PAGE_SIZE = "pageSize";
    /**
     * æŽ’序列
     */
    @Deprecated
    public static final String ORDER_BY_COLUMN = "orderByColumn";
    /**
     * æŽ’序的方向 "desc" æˆ–者 "asc".
     */
    @Deprecated
    public static final String IS_ASC = "isAsc";
    /**
     * å½“前记录起始索引 é»˜è®¤å€¼
     */
    @Deprecated
    public static final int DEFAULT_PAGE_NUM = 1;
    /**
     * æ¯é¡µæ˜¾ç¤ºè®°å½•æ•° é»˜è®¤å€¼ é»˜è®¤æŸ¥å…¨éƒ¨
     */
    @Deprecated
    public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
    /**
@@ -53,7 +66,10 @@
     * @param <T> domain å®žä½“
     * @param <K> vo å®žä½“
     * @return åˆ†é¡µå¯¹è±¡
     * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link PageQuery#build()}
     * ç”±äºŽä½¿ç”¨ Servlet èŽ·å–åªèƒ½ä»Ž param èŽ·å– çµæ´»æ€§é™ä½Ž æ•…将传参操作交给用户
     */
    @Deprecated
    public static <T, K> PagePlus<T, K> buildPagePlus() {
        Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM, DEFAULT_PAGE_NUM);
        Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
@@ -70,6 +86,7 @@
        return page;
    }
    @Deprecated
    public static <T> Page<T> buildPage() {
        return buildPage(null, null);
    }
@@ -79,7 +96,10 @@
     *
     * @param <T> domain å®žä½“
     * @return åˆ†é¡µå¯¹è±¡
     * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link PageQuery#build()}
     * ç”±äºŽä½¿ç”¨ Servlet èŽ·å–åªèƒ½ä»Ž param èŽ·å– çµæ´»æ€§é™ä½Ž æ•…将传参操作交给用户
     */
    @Deprecated
    public static <T> Page<T> buildPage(String defaultOrderByColumn, String defaultIsAsc) {
        Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM, DEFAULT_PAGE_NUM);
        Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
@@ -115,6 +135,15 @@
        return null;
    }
    /**
     * æž„建 MP æ™®é€šåˆ†é¡µå¯¹è±¡
     *
     * @param <T> domain å®žä½“
     * @return åˆ†é¡µå¯¹è±¡
     * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link PageQuery#build()}
     * ç”±äºŽä½¿ç”¨ Servlet èŽ·å–åªèƒ½ä»Ž param èŽ·å– çµæ´»æ€§é™ä½Ž æ•…将传参操作交给用户
     */
    @Deprecated
    public static <T, K> TableDataInfo<K> buildDataInfo(PagePlus<T, K> page) {
        TableDataInfo<K> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
@@ -124,6 +153,10 @@
        return rspData;
    }
    /**
     * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link TableDataInfo#build(IPage)}
     */
    @Deprecated
    public static <T> TableDataInfo<T> buildDataInfo(Page<T> page) {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
@@ -133,6 +166,10 @@
        return rspData;
    }
    /**
     * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link TableDataInfo#build(List)}
     */
    @Deprecated
    public static <T> TableDataInfo<T> buildDataInfo(List<T> list) {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
@@ -142,6 +179,10 @@
        return rspData;
    }
    /**
     * @deprecated 3.6.0 åˆ é™¤ è¯·ä½¿ç”¨ {@link TableDataInfo#build()}
     */
    @Deprecated
    public static <T> TableDataInfo<T> buildDataInfo() {
        TableDataInfo<T> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.HTTP_OK);
ruoyi-common/src/main/java/com/ruoyi/common/utils/RedisUtils.java
@@ -1,6 +1,6 @@
package com.ruoyi.common.utils;
import com.google.common.collect.Lists;
import cn.hutool.core.collection.IterUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@@ -23,7 +23,7 @@
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class RedisUtils {
    private static RedissonClient client = SpringUtils.getBean(RedissonClient.class);
    private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class);
    /**
     * é™æµ
@@ -35,7 +35,7 @@
     * @return -1 è¡¨ç¤ºå¤±è´¥
     */
    public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
        RRateLimiter rateLimiter = client.getRateLimiter(key);
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
        if (rateLimiter.tryAcquire()) {
            return rateLimiter.availablePermits();
@@ -45,10 +45,10 @@
    }
    /**
     * èŽ·å–å®žä¾‹id
     * èŽ·å–å®¢æˆ·ç«¯å®žä¾‹
     */
    public static String getClientId() {
        return client.getId();
    public static RedissonClient getClient() {
        return CLIENT;
    }
    /**
@@ -59,13 +59,13 @@
     * @param consumer   è‡ªå®šä¹‰å¤„理
     */
    public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
        RTopic topic = client.getTopic(channelKey);
        RTopic topic = CLIENT.getTopic(channelKey);
        topic.publish(msg);
        consumer.accept(msg);
    }
    public static <T> void publish(String channelKey, T msg) {
        RTopic topic = client.getTopic(channelKey);
        RTopic topic = CLIENT.getTopic(channelKey);
        topic.publish(msg);
    }
@@ -77,7 +77,7 @@
     * @param consumer   è‡ªå®šä¹‰å¤„理
     */
    public static <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
        RTopic topic = client.getTopic(channelKey);
        RTopic topic = CLIENT.getTopic(channelKey);
        topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
    }
@@ -94,13 +94,13 @@
    /**
     * ç¼“存基本的对象,保留当前对象 TTL æœ‰æ•ˆæœŸ
     *
     * @param key   ç¼“存的键值
     * @param value ç¼“存的值
     * @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);
        RBucket<Object> bucket = CLIENT.getBucket(key);
        if (isSaveTtl) {
            try {
                bucket.setAndKeepTTL(value);
@@ -123,9 +123,22 @@
     * @param timeUnit æ—¶é—´é¢—粒度
     */
    public static <T> void setCacheObject(final String key, final T value, final long timeout, final TimeUnit timeUnit) {
        RBucket<T> result = client.getBucket(key);
        RBucket<T> result = CLIENT.getBucket(key);
        result.set(value);
        result.expire(timeout, timeUnit);
    }
    /**
     * æ³¨å†Œå¯¹è±¡ç›‘听器
     *
     * key ç›‘听器需开启 `notify-keyspace-events` ç­‰ redis ç›¸å…³é…ç½®
     *
     * @param key      ç¼“存的键值
     * @param listener ç›‘听器配置
     */
    public static <T> void addObjectListener(final String key, final ObjectListener listener) {
        RBucket<T> result = CLIENT.getBucket(key);
        result.addListener(listener);
    }
    /**
@@ -148,7 +161,7 @@
     * @return true=设置成功;false=设置失败
     */
    public static boolean expire(final String key, final long timeout, final TimeUnit unit) {
        RBucket rBucket = client.getBucket(key);
        RBucket rBucket = CLIENT.getBucket(key);
        return rBucket.expire(timeout, unit);
    }
@@ -159,7 +172,7 @@
     * @return ç¼“存键值对应的数据
     */
    public static <T> T getCacheObject(final String key) {
        RBucket<T> rBucket = client.getBucket(key);
        RBucket<T> rBucket = CLIENT.getBucket(key);
        return rBucket.get();
    }
@@ -170,29 +183,26 @@
     * @return å‰©ä½™å­˜æ´»æ—¶é—´
     */
    public static <T> long getTimeToLive(final String key) {
        RBucket<T> rBucket = client.getBucket(key);
        RBucket<T> rBucket = CLIENT.getBucket(key);
        return rBucket.remainTimeToLive();
    }
    /**
     * åˆ é™¤å•个对象
     *
     * @param key
     * @param key ç¼“存的键值
     */
    public static boolean deleteObject(final String key) {
        return client.getBucket(key).delete();
        return CLIENT.getBucket(key).delete();
    }
    /* */
    /**
     * åˆ é™¤é›†åˆå¯¹è±¡
     *
     * @param collection å¤šä¸ªå¯¹è±¡
     * @return
     */
    public static void deleteObject(final Collection collection) {
        RBatch batch = client.createBatch();
        RBatch batch = CLIENT.createBatch();
        collection.forEach(t -> {
            batch.getBucket(t.toString()).deleteAsync();
        });
@@ -207,8 +217,21 @@
     * @return ç¼“存的对象
     */
    public static <T> boolean setCacheList(final String key, final List<T> dataList) {
        RList<T> rList = client.getList(key);
        RList<T> rList = CLIENT.getList(key);
        return rList.addAll(dataList);
    }
    /**
     * æ³¨å†ŒList监听器
     *
     * key ç›‘听器需开启 `notify-keyspace-events` ç­‰ redis ç›¸å…³é…ç½®
     *
     * @param key      ç¼“存的键值
     * @param listener ç›‘听器配置
     */
    public static <T> void addListListener(final String key, final ObjectListener listener) {
        RList<T> rList = CLIENT.getList(key);
        rList.addListener(listener);
    }
    /**
@@ -218,7 +241,7 @@
     * @return ç¼“存键值对应的数据
     */
    public static <T> List<T> getCacheList(final String key) {
        RList<T> rList = client.getList(key);
        RList<T> rList = CLIENT.getList(key);
        return rList.readAll();
    }
@@ -230,42 +253,68 @@
     * @return ç¼“存数据的对象
     */
    public static <T> boolean setCacheSet(final String key, final Set<T> dataSet) {
        RSet<T> rSet = client.getSet(key);
        RSet<T> rSet = CLIENT.getSet(key);
        return rSet.addAll(dataSet);
    }
    /**
     * æ³¨å†ŒSet监听器
     *
     * key ç›‘听器需开启 `notify-keyspace-events` ç­‰ redis ç›¸å…³é…ç½®
     *
     * @param key      ç¼“存的键值
     * @param listener ç›‘听器配置
     */
    public static <T> void addSetListener(final String key, final ObjectListener listener) {
        RSet<T> rSet = CLIENT.getSet(key);
        rSet.addListener(listener);
    }
    /**
     * èŽ·å¾—ç¼“å­˜çš„set
     *
     * @param key
     * @return
     * @param key ç¼“存的key
     * @return set对象
     */
    public static <T> Set<T> getCacheSet(final String key) {
        RSet<T> rSet = client.getSet(key);
        RSet<T> rSet = CLIENT.getSet(key);
        return rSet.readAll();
    }
    /**
     * ç¼“å­˜Map
     *
     * @param key
     * @param dataMap
     * @param key     ç¼“存的键值
     * @param dataMap ç¼“存的数据
     */
    public static <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            RMap<String, T> rMap = client.getMap(key);
            RMap<String, T> rMap = CLIENT.getMap(key);
            rMap.putAll(dataMap);
        }
    }
    /**
     * æ³¨å†ŒMap监听器
     *
     * key ç›‘听器需开启 `notify-keyspace-events` ç­‰ redis ç›¸å…³é…ç½®
     *
     * @param key      ç¼“存的键值
     * @param listener ç›‘听器配置
     */
    public static <T> void addMapListener(final String key, final ObjectListener listener) {
        RMap<String, T> rMap = CLIENT.getMap(key);
        rMap.addListener(listener);
    }
    /**
     * èŽ·å¾—ç¼“å­˜çš„Map
     *
     * @param key
     * @return
     * @param key ç¼“存的键值
     * @return map对象
     */
    public static <T> Map<String, T> getCacheMap(final String key) {
        RMap<String, T> rMap = client.getMap(key);
        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.getAll(rMap.keySet());
    }
@@ -277,7 +326,7 @@
     * @param value å€¼
     */
    public static <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        RMap<String, T> rMap = client.getMap(key);
        RMap<String, T> rMap = CLIENT.getMap(key);
        rMap.put(hKey, value);
    }
@@ -289,7 +338,7 @@
     * @return Hash中的对象
     */
    public static <T> T getCacheMapValue(final String key, final String hKey) {
        RMap<String, T> rMap = client.getMap(key);
        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.get(hKey);
    }
@@ -301,7 +350,7 @@
     * @return Hash中的对象
     */
    public static <T> T delCacheMapValue(final String key, final String hKey) {
        RMap<String, T> rMap = client.getMap(key);
        RMap<String, T> rMap = CLIENT.getMap(key);
        return rMap.remove(hKey);
    }
@@ -313,7 +362,7 @@
     * @return Hash对象集合
     */
    public static <K, V> Map<K, V> getMultiCacheMapValue(final String key, final Set<K> hKeys) {
        RMap<K, V> rMap = client.getMap(key);
        RMap<K, V> rMap = CLIENT.getMap(key);
        return rMap.getAll(hKeys);
    }
@@ -324,7 +373,7 @@
     * @return å¯¹è±¡åˆ—表
     */
    public static Collection<String> keys(final String pattern) {
        Iterable<String> iterable = client.getKeys().getKeysByPattern(pattern);
        return Lists.newArrayList(iterable);
        Iterable<String> iterable = CLIENT.getKeys().getKeysByPattern(pattern);
        return IterUtil.toList(iterable);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -5,6 +5,10 @@
import com.ruoyi.common.core.service.UserService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
@@ -12,6 +16,7 @@
 *
 * @author Long Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SecurityUtils {
    /**
ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
@@ -3,6 +3,8 @@
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpStatus;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@@ -19,6 +21,7 @@
 *
 * @author ruoyi
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ServletUtils extends ServletUtil {
    /**
ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -7,6 +7,8 @@
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.*;
@@ -15,6 +17,7 @@
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class StringUtils extends org.apache.commons.lang3.StringUtils {
    /**
ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
@@ -1,7 +1,8 @@
package com.ruoyi.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.*;
@@ -10,8 +11,9 @@
 *
 * @author ruoyi
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Threads {
    private static final Logger logger = LoggerFactory.getLogger(Threads.class);
    /**
     * sleep等待,单位为毫秒
@@ -38,7 +40,7 @@
                if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
                    pool.shutdownNow();
                    if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
                        logger.info("Pool did not terminate");
                        log.info("Pool did not terminate");
                    }
                }
            } catch (InterruptedException ie) {
@@ -67,7 +69,7 @@
            }
        }
        if (t != null) {
            logger.error(t.getMessage(), t);
            log.error(t.getMessage(), t);
        }
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeBuildUtils.java
@@ -4,6 +4,8 @@
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.lang.tree.parser.NodeParser;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.List;
@@ -12,6 +14,7 @@
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class TreeBuildUtils extends TreeUtil {
    /**
@@ -19,13 +22,8 @@
     */
    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);
    public static <T> List<Tree<Long>> build(List<T> list, Long parentId, NodeParser<T, Long> nodeParser) {
        return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/ValidatorUtils.java
@@ -1,8 +1,11 @@
package com.ruoyi.common.utils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
@@ -11,9 +14,10 @@
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtils {
    private static final Validator VALID = Validation.buildDefaultValidatorFactory().getValidator();
    private static final Validator VALID = SpringUtils.getBean(Validator.class);
    public static <T> void validate(T object, Class<?>... groups) {
        Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -1,6 +1,8 @@
package com.ruoyi.common.utils.file;
import cn.hutool.core.io.FileUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
@@ -12,6 +14,7 @@
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FileUtils extends FileUtil {
    /**
ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
@@ -7,6 +7,8 @@
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
@@ -17,6 +19,7 @@
 * @author Lion Li
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class AddressUtils {
    // IP地址查询
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -9,6 +9,8 @@
import com.ruoyi.common.excel.ExcelResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
@@ -21,6 +23,7 @@
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExcelUtil {
    /**
ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
@@ -2,6 +2,8 @@
import cn.hutool.core.util.ReflectUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.lang.reflect.Method;
@@ -11,6 +13,7 @@
 * @author Lion Li
 */
@SuppressWarnings("rawtypes")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ReflectUtils extends ReflectUtil {
    private static final String SETTER_PREFIX = "set";
ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
@@ -2,17 +2,26 @@
import com.ruoyi.common.exception.UtilException;
import com.ruoyi.common.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
/**
 * sql操作工具类
 *
 * @author ruoyi
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SqlUtil {
    /**
     * å®šä¹‰å¸¸ç”¨çš„ sql关键字
     */
    public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
    /**
     * ä»…支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
     */
    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
    public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
    /**
     * æ£€æŸ¥å­—符,防止注入绕过
@@ -30,4 +39,19 @@
    public static boolean isValidOrderBySql(String value) {
        return value.matches(SQL_PATTERN);
    }
    /**
     * SQL关键字检查
     */
    public static void filterKeyword(String value) {
        if (StringUtils.isEmpty(value)) {
            return;
        }
        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
        for (String sqlKeyword : sqlKeywords) {
            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
                throw new UtilException("参数存在SQL注入风险");
            }
        }
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.ruoyi.common.xss;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * è‡ªå®šä¹‰xss校验注解
 *
 * @author Lion Li
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Constraint(validatedBy = {XssValidator.class})
public @interface Xss {
    String message() default "不允许任何脚本运行";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.ruoyi.common.xss;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HtmlUtil;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
 * è‡ªå®šä¹‰xss校验注解实现
 *
 * @author Lion Li
 */
public class XssValidator implements ConstraintValidator<Xss, String> {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value);
    }
}
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestBatchController.java
@@ -33,10 +33,12 @@
    /**
     * æ–°å¢žæ‰¹é‡æ–¹æ³• å¯å®Œç¾Žæ›¿ä»£ saveBatch ç§’级插入上万数据 (对mysql负荷较大)
     *
     * 3.5.0 ç‰ˆæœ¬ å¢žåŠ  rewriteBatchedStatements=true æ‰¹å¤„理参数 ä½¿ MP åŽŸç”Ÿæ‰¹å¤„ç†å¯ä»¥è¾¾åˆ°åŒæ ·çš„é€Ÿåº¦
     */
    @ApiOperation(value = "新增批量方法")
    @PostMapping("/add")
//    @DataSource(DataSourceType.SLAVE)
//    @DS("slave")
    public AjaxResult<Void> add() {
        List<TestDemo> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
@@ -47,10 +49,12 @@
    /**
     * æ–°å¢žæˆ–æ›´æ–° å¯å®Œç¾Žæ›¿ä»£ saveOrUpdateBatch é«˜æ€§èƒ½
     *
     * 3.5.0 ç‰ˆæœ¬ å¢žåŠ  rewriteBatchedStatements=true æ‰¹å¤„理参数 ä½¿ MP åŽŸç”Ÿæ‰¹å¤„ç†å¯ä»¥è¾¾åˆ°åŒæ ·çš„é€Ÿåº¦
     */
    @ApiOperation(value = "新增或更新批量方法")
    @PostMapping("/addOrUpdate")
//    @DataSource(DataSourceType.SLAVE)
//    @DS("slave")
    public AjaxResult<Void> addOrUpdate() {
        List<TestDemo> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
@@ -72,7 +76,7 @@
     */
    @ApiOperation(value = "删除批量方法")
    @DeleteMapping()
//    @DataSource(DataSourceType.SLAVE)
//    @DS("slave")
    public AjaxResult<Void> remove() {
        return toAjax(iTestDemoService.remove(new LambdaQueryWrapper<TestDemo>()
            .eq(TestDemo::getOrderNum, -1L)) ? 1 : 0);
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestDemoController.java
@@ -6,6 +6,7 @@
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
@@ -54,8 +55,8 @@
    @ApiOperation("查询测试单表列表")
    @SaCheckPermission("demo:demo:list")
    @GetMapping("/list")
    public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo) {
        return iTestDemoService.queryPageList(bo);
    public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
        return iTestDemoService.queryPageList(bo, pageQuery);
    }
    /**
@@ -65,7 +66,7 @@
    @SaCheckPermission("demo:demo:list")
    @GetMapping("/page")
    public TableDataInfo<TestDemoVo> page(@Validated(QueryGroup.class) TestDemoBo bo) {
        return iTestDemoService.customPageList(bo);
        return iTestDemoService.customPageList(bo, pageQuery);
    }
    @ApiOperation("导入测试-校验")
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestDemoBo.java
@@ -1,16 +1,15 @@
package com.ruoyi.demo.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import com.ruoyi.common.core.domain.BaseEntity;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
 * æµ‹è¯•单表业务对象 test_demo
@@ -65,30 +64,5 @@
    @ApiModelProperty("值")
    @NotBlank(message = "值不能为空", groups = { AddGroup.class, EditGroup.class })
    private String value;
    /**
     * åˆ†é¡µå¤§å°
     */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /**
     * å½“前页数
     */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /**
     * æŽ’序列
     */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /**
     * æŽ’序的方向desc或者asc
     */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
}
ruoyi-demo/src/main/java/com/ruoyi/demo/domain/bo/TestTreeBo.java
@@ -51,29 +51,4 @@
    @NotBlank(message = "树节点名不能为空", groups = { AddGroup.class, EditGroup.class })
    private String treeName;
    /**
     * åˆ†é¡µå¤§å°
     */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /**
     * å½“前页数
     */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /**
     * æŽ’序列
     */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /**
     * æŽ’序的方向desc或者asc
     */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
}
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java
@@ -1,11 +1,19 @@
package com.ruoyi.demo.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
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.Param;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
 * æµ‹è¯•单表Mapper接口
@@ -15,6 +23,37 @@
 */
public interface TestDemoMapper extends BaseMapperPlus<TestDemo> {
    @DataPermission({
        @DataColumn(key = "deptName", value = "dept_id"),
        @DataColumn(key = "userName", value = "user_id")
    })
    Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
    @Override
    @DataPermission({
        @DataColumn(key = "deptName", value = "dept_id"),
        @DataColumn(key = "userName", value = "user_id")
    })
    <P extends IPage<TestDemo>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
    @Override
    @DataPermission({
        @DataColumn(key = "deptName", value = "dept_id"),
        @DataColumn(key = "userName", value = "user_id")
    })
    List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
    @Override
    @DataPermission({
        @DataColumn(key = "deptName", value = "dept_id"),
        @DataColumn(key = "userName", value = "user_id")
    })
    int updateById(@Param(Constants.ENTITY) TestDemo entity);
    @Override
    @DataPermission({
        @DataColumn(key = "deptName", value = "dept_id"),
        @DataColumn(key = "userName", value = "user_id")
    })
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
}
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestTreeMapper.java
@@ -1,5 +1,7 @@
package com.ruoyi.demo.mapper;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import com.ruoyi.demo.domain.TestTree;
@@ -9,6 +11,10 @@
 * @author Lion Li
 * @date 2021-07-26
 */
@DataPermission({
    @DataColumn(key = "deptName", value = "dept_id"),
    @DataColumn(key = "userName", value = "user_id")
})
public interface TestTreeMapper extends BaseMapperPlus<TestTree> {
}
ruoyi-demo/src/main/java/com/ruoyi/demo/service/ITestDemoService.java
@@ -1,5 +1,6 @@
package com.ruoyi.demo.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
@@ -26,12 +27,12 @@
    /**
     * æŸ¥è¯¢åˆ—表
     */
    TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo);
    TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery);
    /**
     * è‡ªå®šä¹‰åˆ†é¡µæŸ¥è¯¢
     */
    TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo);
    TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢åˆ—表
ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestDemoServiceImpl.java
@@ -1,15 +1,13 @@
package com.ruoyi.demo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.domain.bo.TestDemoBo;
import com.ruoyi.demo.domain.vo.TestDemoVo;
@@ -35,24 +33,23 @@
        return getVoById(id);
    }
    @DataScope(isUser = true)
    @Override
    public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo) {
        PagePlus<TestDemo, TestDemoVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
        return PageUtils.buildDataInfo(result);
    public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
        Page<TestDemoVo> result = pageVo(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * è‡ªå®šä¹‰åˆ†é¡µæŸ¥è¯¢
     */
    @DataScope(isUser = true)
    @Override
    public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo) {
        Page<TestDemoVo> result = baseMapper.customPageList(PageUtils.buildPage(), buildQueryWrapper(bo));
        return PageUtils.buildDataInfo(result);
    public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
        Page<TestDemoVo> result = baseMapper.customPageList(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    @DataScope(isUser = true)
    @Override
    public List<TestDemoVo> queryList(TestDemoBo bo) {
        return listVo(buildQueryWrapper(bo));
@@ -60,14 +57,11 @@
    private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
        Map<String, Object> params = bo.getParams();
        Object dataScope = params.get("dataScope");
        LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
        lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
            dataScope != null ? dataScope.toString() : null);
        return lqw;
    }
ruoyi-demo/src/main/java/com/ruoyi/demo/service/impl/TestTreeServiceImpl.java
@@ -3,7 +3,6 @@
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.demo.domain.TestTree;
@@ -23,7 +22,7 @@
 * @author Lion Li
 * @date 2021-07-26
 */
//@DataSource(DataSourceType.SLAVE) // åˆ‡æ¢ä»Žåº“查询
// @DS("slave") // åˆ‡æ¢ä»Žåº“查询
@Service
public class TestTreeServiceImpl extends ServicePlusImpl<TestTreeMapper, TestTree, TestTreeVo> implements ITestTreeService {
@@ -32,22 +31,19 @@
        return getVoById(id);
    }
//    @DataSource(DataSourceType.SLAVE) // åˆ‡æ¢ä»Žåº“查询
    @DataScope(isUser = true)
//    @DS("slave") // åˆ‡æ¢ä»Žåº“查询
    @Override
    public List<TestTreeVo> queryList(TestTreeBo bo) {
        return listVo(buildQueryWrapper(bo));
        LambdaQueryWrapper<TestTree> lqw = buildQueryWrapper(bo);
        return listVo(lqw);
    }
    private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) {
        Map<String, Object> params = bo.getParams();
        Object dataScope = params.get("dataScope");
        LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.apply(dataScope != null && StringUtils.isNotBlank(dataScope.toString()),
            dataScope != null ? dataScope.toString() : null);
        return lqw;
    }
ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java
@@ -2,7 +2,6 @@
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -15,7 +14,6 @@
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final String adminContextPath;
@@ -34,8 +32,8 @@
            //授予对所有静态资产和登录页面的公共访问权限。
            .antMatchers(adminContextPath + "/assets/**").permitAll()
            .antMatchers(adminContextPath + "/login").permitAll()
            .antMatchers("/actuator").anonymous()
            .antMatchers("/actuator/**").anonymous()
            .antMatchers("/actuator").permitAll()
            .antMatchers("/actuator/**").permitAll()
            //必须对每个其他请求进行身份验证
            .anyRequest().authenticated().and()
            //配置登录和注销
ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
@@ -102,6 +102,7 @@
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <nonFilteredFileExtensions>
                        <nonFilteredFileExtension>ttf</nonFilteredFileExtension>
ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java
@@ -3,8 +3,8 @@
import com.xxl.job.admin.core.util.FtlUtil;
import com.xxl.job.admin.core.util.I18nUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
@@ -17,7 +17,7 @@
 * @author xuxueli 2015-12-12 18:09:04
 */
@Component
public class CookieInterceptor extends HandlerInterceptorAdapter {
public class CookieInterceptor implements AsyncHandlerInterceptor {
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@@ -36,8 +36,8 @@
        if (modelAndView != null) {
            modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
        }
        super.postHandle(request, response, handler, modelAndView);
        AsyncHandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
}
ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java
@@ -6,7 +6,7 @@
import com.xxl.job.admin.service.LoginService;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@@ -18,16 +18,16 @@
 * @author xuxueli 2015-12-12 18:09:04
 */
@Component
public class PermissionInterceptor extends HandlerInterceptorAdapter {
public class PermissionInterceptor implements AsyncHandlerInterceptor {
    @Resource
    private LoginService loginService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return super.preHandle(request, response, handler);
            return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
        }
        // if need login
@@ -53,7 +53,7 @@
            request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
        }
        return super.preHandle(request, response, handler);
        return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
    }
}
ruoyi-framework/pom.xml
@@ -46,23 +46,33 @@
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!-- dynamic-datasource å¤šæ•°æ®æº-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        </dependency>
        <!-- sql性能分析插件 -->
        <dependency>
            <groupId>p6spy</groupId>
            <artifactId>p6spy</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!-- ç³»ç»Ÿæ¨¡å—-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-common</artifactId>
        </dependency>
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-web-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-framework/src/main/java/com/ruoyi/framework/Interceptor/PlusWebInvokeTimeInterceptor.java
ÎļþÒÑɾ³ý
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
@@ -12,15 +12,15 @@
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
 * æ•°æ®è¿‡æ»¤å¤„理
 *
 * @author Lion Li
 * @deprecated 3.6.0 ç§»é™¤ {@link com.ruoyi.framework.handler.PlusDataPermissionHandler}
 */
@Aspect
@Component
@Deprecated
public class DataScopeAspect {
    /**
@@ -131,9 +131,6 @@
            if (params instanceof BaseEntity) {
                BaseEntity baseEntity = (BaseEntity) params;
                baseEntity.getParams().put(DATA_SCOPE, sql);
            } else {
                Map<String, Object> invoke = ReflectUtils.invokeGetter(params, "params");
                invoke.put(DATA_SCOPE, sql);
            }
        }
    }
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
@@ -18,10 +18,12 @@
 * å¤šæ•°æ®æºå¤„理
 *
 * @author Lion Li
 * @deprecated 3.6.0 ç§»é™¤ ä½¿ç”¨åŽŸç”Ÿæ–¹æ³•å¤„ç† åŠŸèƒ½æ›´å…¨
 */
@Aspect
@Order(-500)
@Component
@Deprecated
public class DataSourceAspect {
    @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -54,7 +54,7 @@
            stringBuffer.append(ServletUtils.getClientIP()).append("-");
        } else if (rateLimiter.limitType() == LimitType.CLUSTER){
            // èŽ·å–å®¢æˆ·ç«¯å®žä¾‹id
            stringBuffer.append(RedisUtils.getClientId()).append("-");
            stringBuffer.append(RedisUtils.getClient().getId()).append("-");
        }
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java
@@ -1,6 +1,9 @@
package com.ruoyi.framework.config;
import cn.hutool.core.net.NetUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
@@ -10,6 +13,7 @@
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.ruoyi.common.core.mybatisplus.methods.InsertAll;
import com.ruoyi.framework.handler.CreateAndUpdateMetaObjectHandler;
import com.ruoyi.framework.interceptor.PlusDataPermissionInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -30,12 +34,21 @@
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // æ•°æ®æƒé™å¤„理
        interceptor.addInnerInterceptor(dataPermissionInterceptor());
        // åˆ†é¡µæ’ä»¶
        interceptor.addInnerInterceptor(paginationInnerInterceptor());
        // ä¹è§‚锁插件
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
        return interceptor;
    }
    /**
     * æ•°æ®æƒé™æ‹¦æˆªå™¨
     */
    public PlusDataPermissionInterceptor dataPermissionInterceptor() {
        return new PlusDataPermissionInterceptor();
    }
    /**
     * åˆ†é¡µæ’件,自动识别数据库类型
@@ -79,24 +92,33 @@
        };
    }
    /**
     * ä½¿ç”¨ç½‘卡信息绑定雪花生成器
     * é˜²æ­¢é›†ç¾¤é›ªèбID重复
     */
    @Bean
    public IdentifierGenerator idGenerator() {
        return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
    }
    /**
     * PaginationInnerInterceptor åˆ†é¡µæ’件,自动识别数据库类型
     * https://baomidou.com/guide/interceptor-pagination.html
     * https://baomidou.com/pages/97710a/
     * OptimisticLockerInnerInterceptor ä¹è§‚锁插件
     * https://baomidou.com/guide/interceptor-optimistic-locker.html
     * https://baomidou.com/pages/0d93c0/
     * MetaObjectHandler å…ƒå¯¹è±¡å­—段填充控制器
     * https://baomidou.com/guide/auto-fill-metainfo.html
     * https://baomidou.com/pages/4c6bcf/
     * ISqlInjector sql注入器
     * https://baomidou.com/guide/sql-injector.html
     * https://baomidou.com/pages/42ea4a/
     * BlockAttackInnerInterceptor å¦‚果是对全表的删除或更新操作,就会终止该操作
     * https://baomidou.com/guide/interceptor-block-attack.html
     * https://baomidou.com/pages/f9a237/
     * IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截)
     * IdentifierGenerator è‡ªå®šä¹‰ä¸»é”®ç­–ç•¥
     * https://baomidou.com/guide/id-generator.html
     * https://baomidou.com/pages/568eb2/
     * TenantLineInnerInterceptor å¤šç§Ÿæˆ·æ’ä»¶
     * https://baomidou.com/guide/interceptor-tenant-line.html
     * https://baomidou.com/pages/aef2f2/
     * DynamicTableNameInnerInterceptor åŠ¨æ€è¡¨åæ’ä»¶
     * https://baomidou.com/guide/interceptor-dynamic-table-name.html
     * https://baomidou.com/pages/2a45ff/
     */
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
@@ -23,6 +23,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * redis配置
@@ -34,158 +35,164 @@
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    private static final String REDIS_PROTOCOL_PREFIX = "redis://";
    private static final String REDISS_PROTOCOL_PREFIX = "rediss://";
    private static final String REDIS_PROTOCOL_PREFIX = "redis://";
    private static final String REDISS_PROTOCOL_PREFIX = "rediss://";
    @Autowired
    private RedisProperties redisProperties;
    @Autowired
    private RedisProperties redisProperties;
    @Autowired
    private RedissonProperties redissonProperties;
    @Autowired
    private RedissonProperties redissonProperties;
    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(RedissonClient.class)
    public RedissonClient redisson() throws IOException {
        String prefix = REDIS_PROTOCOL_PREFIX;
        if (redisProperties.isSsl()) {
            prefix = REDISS_PROTOCOL_PREFIX;
        }
        Config config = new Config();
        config.setThreads(redissonProperties.getThreads())
            .setNettyThreads(redissonProperties.getNettyThreads())
            .setCodec(JsonJacksonCodec.INSTANCE)
            .setTransportMode(redissonProperties.getTransportMode());
    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingBean(RedissonClient.class)
    public RedissonClient redisson() throws IOException {
        String prefix = REDIS_PROTOCOL_PREFIX;
        if (redisProperties.isSsl()) {
            prefix = REDISS_PROTOCOL_PREFIX;
        }
        Config config = new Config();
        config.setThreads(redissonProperties.getThreads())
            .setNettyThreads(redissonProperties.getNettyThreads())
            .setCodec(JsonJacksonCodec.INSTANCE)
            .setTransportMode(redissonProperties.getTransportMode());
        RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
        if (ObjectUtil.isNotNull(singleServerConfig)) {
            // ä½¿ç”¨å•机模式
            config.useSingleServer()
                    .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
                    .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
                    .setDatabase(redisProperties.getDatabase())
                    .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
                    .setTimeout(singleServerConfig.getTimeout())
                    .setRetryAttempts(singleServerConfig.getRetryAttempts())
                    .setRetryInterval(singleServerConfig.getRetryInterval())
                    .setSubscriptionsPerConnection(singleServerConfig.getSubscriptionsPerConnection())
                    .setClientName(singleServerConfig.getClientName())
                    .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
                    .setSubscriptionConnectionMinimumIdleSize(singleServerConfig.getSubscriptionConnectionMinimumIdleSize())
                    .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
                    .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
                    .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize())
                    .setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval());
        }
        // é›†ç¾¤é…ç½®æ–¹å¼ å‚考下方注释
        RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();
        if (ObjectUtil.isNotNull(clusterServersConfig)) {
            // ä½¿ç”¨é›†ç¾¤æ¨¡å¼
            config.useClusterServers()
                    .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
                    .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
                    .setTimeout(clusterServersConfig.getTimeout())
                    .setRetryAttempts(clusterServersConfig.getRetryAttempts())
                    .setRetryInterval(clusterServersConfig.getRetryInterval())
                    .setSubscriptionsPerConnection(clusterServersConfig.getSubscriptionsPerConnection())
                    .setClientName(clusterServersConfig.getClientName())
                    .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
                    .setPingConnectionInterval(clusterServersConfig.getPingConnectionInterval())
                    .setSubscriptionConnectionMinimumIdleSize(clusterServersConfig.getSubscriptionConnectionMinimumIdleSize())
                    .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
                    .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
                    .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
                    .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
                    .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
                    .setDnsMonitoringInterval(clusterServersConfig.getDnsMonitoringInterval())
                    .setFailedSlaveReconnectionInterval(clusterServersConfig.getFailedSlaveReconnectionInterval())
                    .setScanInterval(clusterServersConfig.getScanInterval())
                    .setReadMode(clusterServersConfig.getReadMode())
                    .setSubscriptionMode(clusterServersConfig.getSubscriptionMode())
                    .setNodeAddresses(redisProperties.getCluster().getNodes());
        }
        RedissonClient redissonClient = Redisson.create(config);
        log.info("初始化 redis é…ç½®");
        return redissonClient;
    }
        RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
        if (ObjectUtil.isNotNull(singleServerConfig)) {
            // ä½¿ç”¨å•机模式
            config.useSingleServer()
                .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
                .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
                .setDatabase(redisProperties.getDatabase())
                .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
                .setTimeout(singleServerConfig.getTimeout())
                .setRetryAttempts(singleServerConfig.getRetryAttempts())
                .setRetryInterval(singleServerConfig.getRetryInterval())
                .setSubscriptionsPerConnection(singleServerConfig.getSubscriptionsPerConnection())
                .setClientName(singleServerConfig.getClientName())
                .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
                .setSubscriptionConnectionMinimumIdleSize(singleServerConfig.getSubscriptionConnectionMinimumIdleSize())
                .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
                .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
                .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize())
                .setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval());
        }
        // é›†ç¾¤é…ç½®æ–¹å¼ å‚考下方注释
        RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();
        if (ObjectUtil.isNotNull(clusterServersConfig)) {
            // ä½¿ç”¨é›†ç¾¤æ¨¡å¼
            String finalPrefix = prefix;
            List<String> nodes = redisProperties.getCluster().getNodes()
                .stream()
                .map(node -> finalPrefix + node)
                .collect(Collectors.toList());
    /**
     * æ•´åˆspring-cache
     */
    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) {
        List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
        Map<String, CacheConfig> config = new HashMap<>();
        for (RedissonProperties.CacheGroup group : cacheGroup) {
            CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
            cacheConfig.setMaxSize(group.getMaxSize());
            config.put(group.getGroupId(), cacheConfig);
        }
        return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE);
    }
            config.useClusterServers()
                .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
                .setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
                .setTimeout(clusterServersConfig.getTimeout())
                .setRetryAttempts(clusterServersConfig.getRetryAttempts())
                .setRetryInterval(clusterServersConfig.getRetryInterval())
                .setSubscriptionsPerConnection(clusterServersConfig.getSubscriptionsPerConnection())
                .setClientName(clusterServersConfig.getClientName())
                .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
                .setPingConnectionInterval(clusterServersConfig.getPingConnectionInterval())
                .setSubscriptionConnectionMinimumIdleSize(clusterServersConfig.getSubscriptionConnectionMinimumIdleSize())
                .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
                .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
                .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
                .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
                .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
                .setDnsMonitoringInterval(clusterServersConfig.getDnsMonitoringInterval())
                .setFailedSlaveReconnectionInterval(clusterServersConfig.getFailedSlaveReconnectionInterval())
                .setScanInterval(clusterServersConfig.getScanInterval())
                .setReadMode(clusterServersConfig.getReadMode())
                .setSubscriptionMode(clusterServersConfig.getSubscriptionMode())
                .setNodeAddresses(nodes);
        }
        RedissonClient redissonClient = Redisson.create(config);
        log.info("初始化 redis é…ç½®");
        return redissonClient;
    }
    /**
     * redis集群配置 yml
     *
     * --- # redis é›†ç¾¤é…ç½®(单机与集群只能开启一个另一个需要注释掉)
     * spring:
     *   redis:
     *     cluster:
     *       nodes:
     *         - 192.168.0.100:6379
     *         - 192.168.0.101:6379
     *         - 192.168.0.102:6379
     *     # å¯†ç 
     *     password:
     *     # è¿žæŽ¥è¶…æ—¶æ—¶é—´
     *     timeout: 10s
     *     # æ˜¯å¦å¼€å¯ssl
     *     ssl: false
     *
     * redisson:
     *   # çº¿ç¨‹æ± æ•°é‡
     *   threads: 16
     *   # Netty线程池数量
     *   nettyThreads: 32
     *   # ä¼ è¾“模式
     *   transportMode: "NIO"
     *   # é›†ç¾¤é…ç½®
     *   clusterServersConfig:
     *     # å®¢æˆ·ç«¯åç§°
     *     clientName: ${ruoyi.name}
     *     # master最小空闲连接数
     *     masterConnectionMinimumIdleSize: 32
     *     # master连接池大小
     *     masterConnectionPoolSize: 64
     *     # slave最小空闲连接数
     *     slaveConnectionMinimumIdleSize: 32
     *     # slave连接池大小
     *     slaveConnectionPoolSize: 64
     *     # è¿žæŽ¥ç©ºé—²è¶…时,单位:毫秒
     *     idleConnectionTimeout: 10000
     *     # ping连接间隔
     *     pingConnectionInterval: 1000
     *     # å‘½ä»¤ç­‰å¾…超时,单位:毫秒
     *     timeout: 3000
     *     # å¦‚果尝试在此限制之内发送成功,则开始启用 timeout è®¡æ—¶ã€‚
     *     retryAttempts: 3
     *     # å‘½ä»¤é‡è¯•发送时间间隔,单位:毫秒
     *     retryInterval: 1500
     *     # ä»Žå¯ç”¨æœåŠ¡å™¨çš„å†…éƒ¨åˆ—è¡¨ä¸­æŽ’é™¤ Redis Slave é‡æ–°è¿žæŽ¥å°è¯•的间隔。
     *     failedSlaveReconnectionInterval: 3000
     *     # å‘布和订阅连接池最小空闲连接数
     *     subscriptionConnectionMinimumIdleSize: 1
     *     # å‘布和订阅连接池大小
     *     subscriptionConnectionPoolSize: 50
     *     # å•个连接最大订阅数量
     *     subscriptionsPerConnection: 5
     *     # æ‰«æé—´éš”
     *     scanInterval: 1000
     *     # DNS监测时间间隔,单位:毫秒
     *     dnsMonitoringInterval: 5000
     *     # è¯»å–模式
     *     readMode: "SLAVE"
     *     # è®¢é˜…模式
     *     subscriptionMode: "MASTER"
     */
    /**
     * æ•´åˆspring-cache
     */
    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) {
        List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
        Map<String, CacheConfig> config = new HashMap<>();
        for (RedissonProperties.CacheGroup group : cacheGroup) {
            CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
            cacheConfig.setMaxSize(group.getMaxSize());
            config.put(group.getGroupId(), cacheConfig);
        }
        return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE);
    }
    /**
     * redis集群配置 yml
     *
     * --- # redis é›†ç¾¤é…ç½®(单机与集群只能开启一个另一个需要注释掉)
     * spring:
     *   redis:
     *     cluster:
     *       nodes:
     *         - 192.168.0.100:6379
     *         - 192.168.0.101:6379
     *         - 192.168.0.102:6379
     *     # å¯†ç 
     *     password:
     *     # è¿žæŽ¥è¶…æ—¶æ—¶é—´
     *     timeout: 10s
     *     # æ˜¯å¦å¼€å¯ssl
     *     ssl: false
     *
     * redisson:
     *   # çº¿ç¨‹æ± æ•°é‡
     *   threads: 16
     *   # Netty线程池数量
     *   nettyThreads: 32
     *   # ä¼ è¾“模式
     *   transportMode: "NIO"
     *   # é›†ç¾¤é…ç½®
     *   clusterServersConfig:
     *     # å®¢æˆ·ç«¯åç§°
     *     clientName: ${ruoyi.name}
     *     # master最小空闲连接数
     *     masterConnectionMinimumIdleSize: 32
     *     # master连接池大小
     *     masterConnectionPoolSize: 64
     *     # slave最小空闲连接数
     *     slaveConnectionMinimumIdleSize: 32
     *     # slave连接池大小
     *     slaveConnectionPoolSize: 64
     *     # è¿žæŽ¥ç©ºé—²è¶…时,单位:毫秒
     *     idleConnectionTimeout: 10000
     *     # ping连接间隔
     *     pingConnectionInterval: 1000
     *     # å‘½ä»¤ç­‰å¾…超时,单位:毫秒
     *     timeout: 3000
     *     # å¦‚果尝试在此限制之内发送成功,则开始启用 timeout è®¡æ—¶ã€‚
     *     retryAttempts: 3
     *     # å‘½ä»¤é‡è¯•发送时间间隔,单位:毫秒
     *     retryInterval: 1500
     *     # ä»Žå¯ç”¨æœåŠ¡å™¨çš„å†…éƒ¨åˆ—è¡¨ä¸­æŽ’é™¤ Redis Slave é‡æ–°è¿žæŽ¥å°è¯•的间隔。
     *     failedSlaveReconnectionInterval: 3000
     *     # å‘布和订阅连接池最小空闲连接数
     *     subscriptionConnectionMinimumIdleSize: 1
     *     # å‘布和订阅连接池大小
     *     subscriptionConnectionPoolSize: 50
     *     # å•个连接最大订阅数量
     *     subscriptionsPerConnection: 5
     *     # æ‰«æé—´éš”
     *     scanInterval: 1000
     *     # DNS监测时间间隔,单位:毫秒
     *     dnsMonitoringInterval: 5000
     *     # è¯»å–模式
     *     readMode: "SLAVE"
     *     # è®¢é˜…模式
     *     subscriptionMode: "MASTER"
     */
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -1,6 +1,6 @@
package com.ruoyi.framework.config;
import com.ruoyi.framework.Interceptor.PlusWebInvokeTimeInterceptor;
import com.ruoyi.framework.interceptor.PlusWebInvokeTimeInterceptor;
import com.yomahub.tlog.web.interceptor.TLogWebInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
ruoyi-framework/src/main/java/com/ruoyi/framework/config/TLogConfig.java
@@ -1,13 +1,8 @@
package com.ruoyi.framework.config;
import com.yomahub.tlog.core.aop.AspectLogAop;
import com.yomahub.tlog.spring.TLogPropertyInit;
import com.yomahub.tlog.spring.TLogSpringAware;
import com.yomahub.tlog.springboot.property.TLogProperty;
import org.springframework.context.annotation.Bean;
import com.yomahub.tlog.springboot.TLogWebAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
/**
 * æ•´åˆ TLog æ¡†æž¶é…ç½®
@@ -15,29 +10,9 @@
 * @author Lion Li
 * @since 3.3.0
 */
@Order(-999)
@Configuration
@Import(TLogProperty.class)
// æŽ’除 web è‡ªåŠ¨é…ç½® è‡ªå®šä¹‰å®žçް
@EnableAutoConfiguration(exclude = TLogWebAutoConfiguration.class)
public class TLogConfig {
    @Bean
    public TLogPropertyInit tLogPropertyInit(TLogProperty tLogProperty) {
        TLogPropertyInit tLogPropertyInit = new TLogPropertyInit();
        tLogPropertyInit.setPattern(tLogProperty.getPattern());
        tLogPropertyInit.setEnableInvokeTimePrint(tLogProperty.enableInvokeTimePrint());
        tLogPropertyInit.setIdGenerator(tLogProperty.getIdGenerator());
        tLogPropertyInit.setMdcEnable(tLogProperty.getMdcEnable());
        return tLogPropertyInit;
    }
    @Bean
    public TLogSpringAware tLogSpringAware(){
        return new TLogSpringAware();
    }
    @Bean
    public AspectLogAop aspectLogAop() {
        return new AspectLogAop();
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,192 @@
package com.ruoyi.framework.handler;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.service.UserService;
import com.ruoyi.common.enums.DataScopeType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.DataPermissionHelper;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
 * æ•°æ®æƒé™è¿‡æ»¤
 *
 * @author Lion Li
 * @version 3.5.0
 */
@Slf4j
public class PlusDataPermissionHandler {
    /**
     * æ–¹æ³•或类(名称) ä¸Ž æ³¨è§£çš„æ˜ å°„关系缓存
     */
    private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
    /**
     * æ— æ•ˆæ³¨è§£æ–¹æ³•缓存用于快速返回
     */
    private final Set<String> inavlidCacheSet = new ConcurrentHashSet<>();
    /**
     * spel è§£æžå™¨
     */
    private final ExpressionParser parser = new SpelExpressionParser();
    private final ParserContext parserContext = new TemplateParserContext();
    /**
     * bean解析器 ç”¨äºŽå¤„理 spel è¡¨è¾¾å¼ä¸­å¯¹ bean çš„调用
     */
    private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
    public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
        DataColumn[] dataColumns = findAnnotation(mappedStatementId);
        if (ArrayUtil.isEmpty(dataColumns)) {
            inavlidCacheSet.add(mappedStatementId);
            return where;
        }
        SysUser currentUser = DataPermissionHelper.getVariable("user");
        if (ObjectUtil.isNull(currentUser)) {
            currentUser = SpringUtils.getBean(UserService.class).selectUserById(SecurityUtils.getUserId());
            DataPermissionHelper.setVariable("user", currentUser);
        }
        // å¦‚果是超级管理员,则不过滤数据
        if (ObjectUtil.isNull(currentUser) || currentUser.isAdmin()) {
            return where;
        }
        String dataFilterSql = buildDataFilter(dataColumns, isSelect);
        if (StringUtils.isBlank(dataFilterSql)) {
            return where;
        }
        try {
            Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
            // æ•°æ®æƒé™ä½¿ç”¨å•独的括号 é˜²æ­¢ä¸Žå…¶ä»–条件冲突
            Parenthesis parenthesis = new Parenthesis(expression);
            if (ObjectUtil.isNotNull(where)) {
                return new AndExpression(where, parenthesis);
            } else {
                return parenthesis;
            }
        } catch (JSQLParserException e) {
            throw new ServiceException("数据权限解析异常 => " + e.getMessage());
        }
    }
    /**
     * æž„造数据过滤sql
     */
    private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
        StringBuilder sqlString = new StringBuilder();
        // æ›´æ–°æˆ–删除需满足所有条件
        String joinStr = isSelect ? " OR " : " AND ";
        SysUser user = DataPermissionHelper.getVariable("user");
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setBeanResolver(beanResolver);
        DataPermissionHelper.getContext().forEach(context::setVariable);
        for (SysRole role : user.getRoles()) {
            user.setRoleId(role.getRoleId());
            // èŽ·å–è§’è‰²æƒé™æ³›åž‹
            DataScopeType type = DataScopeType.findCode(role.getDataScope());
            if (ObjectUtil.isNull(type)) {
                throw new ServiceException("角色数据范围异常 => " + role.getDataScope());
            }
            // å…¨éƒ¨æ•°æ®æƒé™ç›´æŽ¥è¿”回
            if (type == DataScopeType.ALL) {
                return "";
            }
            boolean isSuccess = false;
            for (DataColumn dataColumn : dataColumns) {
                // ä¸åŒ…含 key å˜é‡ åˆ™ä¸å¤„理
                if (!StringUtils.contains(type.getSqlTemplate(), "#" + dataColumn.key())) {
                    continue;
                }
                // è®¾ç½®æ³¨è§£å˜é‡ key ä¸ºè¡¨è¾¾å¼å˜é‡ value ä¸ºå˜é‡å€¼
                context.setVariable(dataColumn.key(), dataColumn.value());
                // è§£æžsql模板并填充
                String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class);
                sqlString.append(joinStr).append(sql);
                isSuccess = true;
            }
            // æœªå¤„理成功则填充兜底方案
            if (!isSuccess) {
                sqlString.append(joinStr).append(type.getElseSql());
            }
        }
        if (StringUtils.isNotBlank(sqlString.toString())) {
            return sqlString.substring(joinStr.length());
        }
        return "";
    }
    private DataColumn[] findAnnotation(String mappedStatementId) {
        StringBuilder sb = new StringBuilder(mappedStatementId);
        int index = sb.lastIndexOf(".");
        String clazzName = sb.substring(0, index);
        String methodName = sb.substring(index + 1, sb.length());
        Class<?> clazz = ClassUtil.loadClass(clazzName);
        List<Method> methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz))
            .filter(method -> method.getName().equals(methodName)).collect(Collectors.toList());
        DataPermission dataPermission;
        // èŽ·å–æ–¹æ³•æ³¨è§£
        for (Method method : methods) {
            dataPermission = dataPermissionCacheMap.get(method.getName());
            if (ObjectUtil.isNotNull(dataPermission)) {
                return dataPermission.value();
            }
            if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
                dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
                dataPermissionCacheMap.put(method.getName(), dataPermission);
                return dataPermission.value();
            }
        }
        dataPermission = dataPermissionCacheMap.get(clazz.getName());
        if (ObjectUtil.isNotNull(dataPermission)) {
            return dataPermission.value();
        }
        // èŽ·å–ç±»æ³¨è§£
        if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
            dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
            dataPermissionCacheMap.put(clazz.getName(), dataPermission);
            return dataPermission.value();
        }
        return null;
    }
    /**
     * æ˜¯å¦ä¸ºæ— æ•ˆæ–¹æ³• æ— æ•°æ®æƒé™
     */
    public boolean isInvalid(String mappedStatementId) {
        return inavlidCacheSet.contains(mappedStatementId);
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusDataPermissionInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
package com.ruoyi.framework.interceptor;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.ruoyi.framework.handler.PlusDataPermissionHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
 * æ•°æ®æƒé™æ‹¦æˆªå™¨
 *
 * @author Lion Li
 * @version 3.5.0
 */
public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {
    private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler();
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // æ£€æŸ¥å¿½ç•¥æ³¨è§£
        if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
            return;
        }
        // æ£€æŸ¥æ˜¯å¦æ— æ•ˆ æ— æ•°æ®æƒé™æ³¨è§£
        if (dataPermissionHandler.isInvalid(ms.getId())) {
            return;
        }
        // è§£æž sql åˆ†é…å¯¹åº”方法
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
    }
    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
                return;
            }
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
            mpBs.sql(parserMulti(mpBs.sql(), ms.getId()));
        }
    }
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        SelectBody selectBody = select.getSelectBody();
        if (selectBody instanceof PlainSelect) {
            this.setWhere((PlainSelect) selectBody, (String) obj);
        } else if (selectBody instanceof SetOperationList) {
            SetOperationList setOperationList = (SetOperationList) selectBody;
            List<SelectBody> selectBodyList = setOperationList.getSelects();
            selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
        }
    }
    @Override
    protected void processUpdate(Update update, int index, String sql, Object obj) {
        Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false);
        if (null != sqlSegment) {
            update.setWhere(sqlSegment);
        }
    }
    @Override
    protected void processDelete(Delete delete, int index, String sql, Object obj) {
        Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false);
        if (null != sqlSegment) {
            delete.setWhere(sqlSegment);
        }
    }
    /**
     * è®¾ç½® where æ¡ä»¶
     *
     * @param plainSelect       æŸ¥è¯¢å¯¹è±¡
     * @param mappedStatementId æ‰§è¡Œæ–¹æ³•id
     */
    protected void setWhere(PlainSelect plainSelect, String mappedStatementId) {
        Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true);
        if (null != sqlSegment) {
            plainSelect.setWhere(sqlSegment);
        }
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/PlusWebInvokeTimeInterceptor.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
package com.ruoyi.framework.interceptor;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.util.Map;
/**
 * web的调用时间统计拦截器
 * dev环境有效
 *
 * @author Lion Li
 * @since 3.3.0
 */
@Slf4j
public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
    private final TransmittableThreadLocal<StopWatch> invokeTimeTL = new TransmittableThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!"prod".equals(SpringUtils.getActiveProfile())) {
            String url = request.getMethod() + " " + request.getRequestURI();
            // æ‰“印请求参数
            if (isJsonRequest(request)) {
                String jsonParam = "";
                if (request instanceof RepeatedlyRequestWrapper) {
                    BufferedReader reader = request.getReader();
                    jsonParam = IoUtil.read(reader);
                }
                log.debug("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
            } else {
                Map<String, String[]> parameterMap = request.getParameterMap();
                if (MapUtil.isNotEmpty(parameterMap)) {
                    String parameters = JsonUtils.toJsonString(parameterMap);
                    log.debug("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters);
                } else {
                    log.debug("[PLUS]开始请求 => URL[{}],无参数", url);
                }
            }
            StopWatch stopWatch = new StopWatch();
            invokeTimeTL.set(stopWatch);
            stopWatch.start();
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        if (!"prod".equals(SpringUtils.getActiveProfile())) {
            StopWatch stopWatch = invokeTimeTL.get();
            stopWatch.stop();
            log.debug("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
            invokeTimeTL.remove();
        }
    }
    /**
     * åˆ¤æ–­æœ¬æ¬¡è¯·æ±‚的数据类型是否为json
     *
     * @param request request
     * @return boolean
     */
    private boolean isJsonRequest(HttpServletRequest request) {
        String contentType = request.getContentType();
        if (contentType != null) {
            return StringUtils.startsWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE);
        }
        return false;
    }
}
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
@@ -6,6 +6,7 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.generator.domain.GenTable;
@@ -46,8 +47,8 @@
    @ApiOperation("查询代码生成列表")
    @SaCheckPermission("tool:gen:list")
    @GetMapping("/list")
    public TableDataInfo<GenTable> genList(GenTable genTable) {
        return genTableService.selectPageGenTableList(genTable);
    public TableDataInfo<GenTable> genList(GenTable genTable, PageQuery pageQuery) {
        return genTableService.selectPageGenTableList(genTable, pageQuery);
    }
    /**
@@ -73,8 +74,8 @@
    @ApiOperation("查询数据库列表")
    @SaCheckPermission("tool:gen:list")
    @GetMapping("/db/list")
    public TableDataInfo<GenTable> dataList(GenTable genTable) {
        return genTableService.selectPageDbTableList(genTable);
    public TableDataInfo<GenTable> dataList(GenTable genTable, PageQuery pageQuery) {
        return genTableService.selectPageDbTableList(genTable, pageQuery);
    }
    /**
ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java
@@ -1,5 +1,6 @@
package com.ruoyi.generator.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import com.ruoyi.generator.domain.GenTableColumn;
@@ -10,6 +11,7 @@
 *
 * @author Lion Li
 */
@InterceptorIgnore(dataPermission = "true")
public interface GenTableColumnMapper extends BaseMapperPlus<GenTableColumn> {
    /**
     * æ ¹æ®è¡¨åç§°æŸ¥è¯¢åˆ—信息
ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java
@@ -1,5 +1,6 @@
package com.ruoyi.generator.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import com.ruoyi.generator.domain.GenTable;
@@ -12,6 +13,7 @@
 *
 * @author Lion Li
 */
@InterceptorIgnore(dataPermission = "true")
public interface GenTableMapper extends BaseMapperPlus<GenTable> {
ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
@@ -4,8 +4,10 @@
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
@@ -63,13 +65,15 @@
    }
    @Override
    public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable) {
        return PageUtils.buildDataInfo(baseMapper.selectPageGenTableList(PageUtils.buildPage(), genTable));
    public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
        Page<GenTable> page = baseMapper.selectPageGenTableList(pageQuery.build(), genTable);
        return TableDataInfo.build(page);
    }
    @Override
    public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable) {
        return PageUtils.buildDataInfo(baseMapper.selectPageDbTableList(PageUtils.buildPage(), genTable));
    public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
        Page<GenTable> page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable);
        return TableDataInfo.build(page);
    }
    /**
@@ -122,7 +126,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public void updateGenTable(GenTable genTable) {
        String options = JsonUtils.toJsonString(genTable.getParams());
        genTable.setOptions(options);
@@ -141,7 +145,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public void deleteGenTableByIds(Long[] tableIds) {
        List<Long> ids = Arrays.asList(tableIds);
        removeByIds(ids);
@@ -154,7 +158,7 @@
     * @param tableList å¯¼å…¥è¡¨åˆ—表
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public void importGenTable(List<GenTable> tableList) {
        String operName = LoginUtils.getUsername();
        try {
@@ -268,7 +272,7 @@
     * @param tableName è¡¨åç§°
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public void synchDb(String tableName) {
        GenTable table = baseMapper.selectGenTableByName(tableName);
        List<GenTableColumn> tableColumns = table.getColumns();
ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
@@ -1,6 +1,7 @@
package com.ruoyi.generator.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.generator.domain.GenTable;
@@ -15,10 +16,10 @@
public interface IGenTableService extends IService<GenTable> {
    TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable);
    TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
    TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable);
    TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ä¸šåŠ¡åˆ—è¡¨
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
@@ -9,10 +9,7 @@
import com.ruoyi.generator.domain.GenTableColumn;
import org.apache.velocity.VelocityContext;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
 * æ¨¡æ¿å¤„理工具类
@@ -244,7 +241,7 @@
     */
    public static String getDicts(GenTable genTable) {
        List<GenTableColumn> columns = genTable.getColumns();
        List<String> dicts = new ArrayList<String>();
        Set<String> dicts = new HashSet<String>();
        for (GenTableColumn column : columns) {
            if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
                    column.getHtmlType(),
ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -27,7 +27,7 @@
        <result property="remark"         column="remark"            />
        <collection  property="columns"  javaType="java.util.List"  resultMap="GenTableColumnResult" />
    </resultMap>
    <resultMap type="GenTableColumn" id="GenTableColumnResult">
        <id     property="columnId"       column="column_id"      />
        <result property="tableId"        column="table_id"       />
@@ -52,7 +52,7 @@
        <result property="updateBy"       column="update_by"      />
        <result property="updateTime"     column="update_time"    />
    </resultMap>
    <sql id="selectGenTableVo">
        select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
    </sql>
@@ -78,7 +78,7 @@
    <select id="selectPageDbTableList" parameterType="GenTable" resultMap="GenTableResult">
        select table_name, table_comment, create_time, update_time from information_schema.tables
        where table_schema = (select database())
        AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%'
        AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
        AND table_name NOT IN (select table_name from gen_table)
        <if test="genTable.tableName != null and genTable.tableName != ''">
            AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
@@ -117,7 +117,7 @@
    <select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
        select table_name, table_comment, create_time, update_time from information_schema.tables
        where table_schema = (select database())
        AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%'
        AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
        AND table_name NOT IN (select table_name from gen_table)
        <if test="tableName != null and tableName != ''">
            AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
@@ -133,22 +133,22 @@
        </if>
        order by create_time desc
    </select>
    <select id="selectDbTableListByNames" resultMap="GenTableResult">
        select table_name, table_comment, create_time, update_time from information_schema.tables
        where table_name NOT LIKE 'qrtz_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
        where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
        and table_name in
        <foreach collection="array" item="name" open="(" separator="," close=")">
             #{name}
        </foreach>
        </foreach>
    </select>
    <select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
        select table_name, table_comment, create_time, update_time from information_schema.tables
        where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database())
        and table_name = #{tableName}
    </select>
    <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
        SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
               c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
@@ -156,7 +156,7 @@
             LEFT JOIN gen_table_column c ON t.table_id = c.table_id
        where t.table_id = #{tableId} order by c.sort
    </select>
    <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
        SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
               c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
@@ -164,7 +164,7 @@
             LEFT JOIN gen_table_column c ON t.table_id = c.table_id
        where t.table_name = #{tableName} order by c.sort
    </select>
    <select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
        SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
               c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
@@ -173,4 +173,4 @@
        order by c.sort
    </select>
</mapper>
</mapper>
ruoyi-generator/src/main/resources/vm/java/bo.java.vm
@@ -63,28 +63,4 @@
#end
#end
    /**
     * åˆ†é¡µå¤§å°
     */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /**
     * å½“前页数
     */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /**
     * æŽ’序列
     */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /**
     * æŽ’序的方向desc或者asc
     */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
}
ruoyi-generator/src/main/resources/vm/java/controller.java.vm
@@ -14,6 +14,7 @@
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
@@ -53,8 +54,8 @@
    @SaCheckPermission("${permissionPrefix}:list")
    @GetMapping("/list")
#if($table.crud || $table.sub)
    public TableDataInfo<${ClassName}Vo> list(@Validated(QueryGroup.class) ${ClassName}Bo bo) {
        return i${ClassName}Service.queryPageList(bo);
    public TableDataInfo<${ClassName}Vo> list(@Validated(QueryGroup.class) ${ClassName}Bo bo, PageQuery pageQuery) {
        return i${ClassName}Service.queryPageList(bo, pageQuery);
    }
#elseif($table.tree)
    public AjaxResult<List<${ClassName}Vo>> list(@Validated(QueryGroup.class) ${ClassName}Bo bo) {
ruoyi-generator/src/main/resources/vm/java/service.java.vm
@@ -6,6 +6,7 @@
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
#if($table.crud || $table.sub)
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
#end
import java.util.Collection;
@@ -28,7 +29,7 @@
    /**
     * æŸ¥è¯¢åˆ—表
     */
    TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo);
    TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery);
#end
    /**
ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -3,12 +3,12 @@
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
#if($table.crud || $table.sub)
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
#end
import org.springframework.stereotype.Service;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import ${packageName}.domain.bo.${ClassName}Bo;
@@ -37,15 +37,17 @@
#if($table.crud || $table.sub)
    @Override
    public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo) {
        PagePlus<${ClassName}, ${ClassName}Vo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
        return PageUtils.buildDataInfo(result);
    public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
        Page<${ClassName}Vo> result = pageVo(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
#end
    @Override
    public List<${ClassName}Vo> queryList(${ClassName}Bo bo) {
        return listVo(buildQueryWrapper(bo));
        LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
        return listVo(lqw);
    }
    private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) {
ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,476 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input" || $column.htmlType == "textarea")
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-input
          v-model="queryParams.${column.javaField}"
          placeholder="请输入${comment}"
          clearable
          size="small"
          @keyup.enter="handleQuery"
        />
      </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
          <el-option
            v-for="dict in ${dictType}"
            :key="dict.value"
            :label="dict.label"
            :value="dict.value"
          />
        </el-select>
      </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
          <el-option label="请选择字典生成" value="" />
        </el-select>
      </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-date-picker clearable size="small"
          v-model="queryParams.${column.javaField}"
          type="date"
          value-format="YYYY-MM-DD"
          placeholder="选择${comment}">
        </el-date-picker>
      </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
      <el-form-item label="${comment}">
        <el-date-picker
          v-model="daterange${AttrName}"
          size="small"
          style="width: 240px"
          value-format="YYYY-MM-DD"
          type="daterange"
          range-separator="-"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        ></el-date-picker>
      </el-form-item>
#end
#end
#end
      <el-form-item>
        <el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button
          type="primary"
          plain
          icon="Plus"
          size="mini"
          @click="handleAdd"
          v-hasPermi="['${moduleName}:${businessName}:add']"
        >新增</el-button>
      </el-col>
      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>
    <el-table
      v-loading="loading"
      :data="${businessName}List"
      row-key="${treeCode}"
      default-expand-all
      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
    >
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk)
#elseif($column.list && $column.htmlType == "datetime")
      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
        <template #default="scope">
          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
#elseif($column.list && $column.dictType && "" != $column.dictType)
      <el-table-column label="${comment}" align="center" prop="${javaField}">
        <template #default="scope">
#if($column.htmlType == "checkbox")
          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
#end
        </template>
      </el-table-column>
#elseif($column.list && "" != $javaField)
#if(${foreach.index} == 1)
      <el-table-column label="${comment}" prop="${javaField}" />
#else
      <el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#end
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template #default="scope">
          <el-button
            size="mini"
            type="text"
            icon="Edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['${moduleName}:${businessName}:edit']"
          >修改</el-button>
          <el-button
            size="mini"
            type="text"
            icon="Plus"
            @click="handleAdd(scope.row)"
            v-hasPermi="['${moduleName}:${businessName}:add']"
          >新增</el-button>
          <el-button
            size="mini"
            type="text"
            icon="Delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['${moduleName}:${businessName}:remove']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- æ·»åŠ æˆ–ä¿®æ”¹${functionName}对话框 -->
    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
      <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px">
#foreach($column in $columns)
#set($field=$column.javaField)
#if($column.insert && !$column.pk)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#set($dictType=$column.dictType)
#if("" != $treeParentCode && $column.javaField == $treeParentCode)
        <el-form-item label="${comment}" prop="${treeParentCode}">
          <tree-select
            v-model:value="form.${treeParentCode}"
            :options="${businessName}Options"
            :objMap="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
            placeholder="请选择${comment}"
          />
        </el-form-item>
#elseif($column.htmlType == "input")
        <el-form-item label="${comment}" prop="${field}">
          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
        </el-form-item>
#elseif($column.htmlType == "imageUpload")
        <el-form-item label="${comment}">
          <imageUpload v-model="form.${field}"/>
        </el-form-item>
#elseif($column.htmlType == "fileUpload")
        <el-form-item label="${comment}">
          <fileUpload v-model="form.${field}"/>
        </el-form-item>
#elseif($column.htmlType == "editor")
        <el-form-item label="${comment}">
          <editor v-model="form.${field}" :min-height="192"/>
        </el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType)
        <el-form-item label="${comment}" prop="${field}">
          <el-select v-model="form.${field}" placeholder="请选择${comment}">
            <el-option
              v-for="dict in ${dictType}"
              :key="dict.value"
              :label="dict.label"
              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
            ></el-option>
          </el-select>
        </el-form-item>
#elseif($column.htmlType == "select" && $dictType)
        <el-form-item label="${comment}" prop="${field}">
          <el-select v-model="form.${field}" placeholder="请选择${comment}">
            <el-option label="请选择字典生成" value="" />
          </el-select>
        </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
        <el-form-item label="${comment}">
          <el-checkbox-group v-model="form.${field}">
            <el-checkbox
              v-for="dict in ${dictType}"
              :key="dict.value"
              :label="dict.value">
              {{dict.label}}
            </el-checkbox>
          </el-checkbox-group>
        </el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
        <el-form-item label="${comment}">
          <el-checkbox-group v-model="form.${field}">
            <el-checkbox>请选择字典生成</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType)
        <el-form-item label="${comment}">
          <el-radio-group v-model="form.${field}">
            <el-radio
              v-for="dict in ${dictType}"
              :key="dict.value"
              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
            >{{dict.label}}</el-radio>
          </el-radio-group>
        </el-form-item>
#elseif($column.htmlType == "radio" && $dictType)
        <el-form-item label="${comment}">
          <el-radio-group v-model="form.${field}">
            <el-radio label="1">请选择字典生成</el-radio>
          </el-radio-group>
        </el-form-item>
#elseif($column.htmlType == "datetime")
        <el-form-item label="${comment}" prop="${field}">
          <el-date-picker clearable size="small"
            v-model="form.${field}"
            type="datetime"
            value-format="YYYY-MM-DD HH:mm:ss"
            placeholder="选择${comment}">
          </el-date-picker>
        </el-form-item>
#elseif($column.htmlType == "textarea")
        <el-form-item label="${comment}" prop="${field}">
          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
        </el-form-item>
#end
#end
#end
#end
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
const { proxy } = getCurrentInstance();
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
#end
const ${businessName}List = ref([]);
const ${businessName}Options = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([]);
#end
#end
const data = reactive({
  form: {},
  queryParams: {
#foreach ($column in $columns)
#if($column.query)
    $column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
  },
  rules: {
#foreach ($column in $columns)
#if($column.required)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
    $column.javaField: [
      { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
    ]#if($foreach.count != $columns.size()),#end
#end
#end
  }
});
const { queryParams, form, rules } = toRefs(data);
/** æŸ¥è¯¢${functionName}列表 */
function getList() {
  loading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
  queryParams.value.params = {};
#break
#end
#end
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
  }
#end
#end
  list${BusinessName}(queryParams.value).then(response => {
    ${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
    loading.value = false;
  });
}
/** æŸ¥è¯¢${functionName}下拉树结构 */
async function getTreeselect() {
  await list${BusinessName}().then(response => {
    ${businessName}Options.value = [];
    const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
    data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
    ${businessName}Options.value.push(data);
  });
}
// å–消按钮
function cancel() {
  open.value = false;
  reset();
}
// è¡¨å•重置
function reset() {
  form.value = {
#foreach ($column in $columns)
#if($column.htmlType == "radio")
    $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($foreach.count != $columns.size()),#end
#else
    $column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
  };
  proxy.resetForm("${businessName}Ref");
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
function handleQuery() {
  getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
function resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  daterange${AttrName}.value = [];
#end
#end
  proxy.resetForm("queryRef");
  handleQuery();
}
/** æ–°å¢žæŒ‰é’®æ“ä½œ */
async function handleAdd(row) {
  reset();
  await getTreeselect();
  if (row != null && row.${treeCode}) {
    form.value.${treeParentCode} = row.${treeCode};
  } else {
    form.value.${treeParentCode} = 0;
  }
  open.value = true;
  title.value = "添加${functionName}";
}
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
async function handleUpdate(row) {
  loading.value = true;
  reset();
  await getTreeselect();
  if (row != null) {
    form.value.${treeParentCode} = row.${treeCode};
  }
  get${BusinessName}(row.${pkColumn.javaField}).then(response => {
    loading.value = false;
    form.value = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
    form.value.$column.javaField = form.value.${column.javaField}.split(",");
#end
#end
    open.value = true;
    title.value = "修改${functionName}";
  });
}
/** æäº¤æŒ‰é’® */
function submitForm() {
  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
    if (valid) {
      buttonLoading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
      form.value.$column.javaField = form.value.${column.javaField}.join(",");
#end
#end
      if (form.value.${pkColumn.javaField} != null) {
        update${BusinessName}(form.value).then(response => {
          proxy.#[[$modal]]#.msgSuccess("修改成功");
          open.value = false;
          getList();
        }).finally(() => {
          buttonLoading.value = false;
        });
      } else {
        add${BusinessName}(form.value).then(response => {
          proxy.#[[$modal]]#.msgSuccess("新增成功");
          open.value = false;
          getList();
        }).finally(() => {
          buttonLoading.value = false;
        });
      }
    }
  });
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
function handleDelete(row) {
  proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
    loading.value = true;
    return del${BusinessName}(row.${pkColumn.javaField});
  }).then(() => {
    loading.value = false;
    getList();
    proxy.#[[$modal]]#.msgSuccess("删除成功");
  }).finally(() => {
    loading.value = false;
  });
}
getList();
</script>
ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,577 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input" || $column.htmlType == "textarea")
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-input
          v-model="queryParams.${column.javaField}"
          placeholder="请输入${comment}"
          clearable
          size="small"
          @keyup.enter="handleQuery"
        />
      </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
          <el-option
            v-for="dict in ${dictType}"
            :key="dict.value"
            :label="dict.label"
            :value="dict.value"
          />
        </el-select>
      </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
          <el-option label="请选择字典生成" value="" />
        </el-select>
      </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-date-picker clearable size="small"
          v-model="queryParams.${column.javaField}"
          type="date"
          value-format="YYYY-MM-DD"
          placeholder="选择${comment}">
        </el-date-picker>
      </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
      <el-form-item label="${comment}">
        <el-date-picker
          v-model="daterange${AttrName}"
          size="small"
          style="width: 240px"
          value-format="YYYY-MM-DD"
          type="daterange"
          range-separator="-"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        ></el-date-picker>
      </el-form-item>
#end
#end
#end
      <el-form-item>
        <el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button
          type="primary"
          plain
          icon="Plus"
          size="mini"
          @click="handleAdd"
          v-hasPermi="['${moduleName}:${businessName}:add']"
        >新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="success"
          plain
          icon="Edit"
          size="mini"
          :disabled="single"
          @click="handleUpdate"
          v-hasPermi="['${moduleName}:${businessName}:edit']"
        >修改</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          plain
          icon="Delete"
          size="mini"
          :disabled="multiple"
          @click="handleDelete"
          v-hasPermi="['${moduleName}:${businessName}:remove']"
        >删除</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="Download"
          size="mini"
          @click="handleExport"
          v-hasPermi="['${moduleName}:${businessName}:export']"
        >导出</el-button>
      </el-col>
      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>
    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk)
      <el-table-column label="${comment}" align="center" prop="${javaField}" v-if="${column.list}"/>
#elseif($column.list && $column.htmlType == "datetime")
      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
        <template #default="scope">
          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
#elseif($column.list && $column.dictType && "" != $column.dictType)
      <el-table-column label="${comment}" align="center" prop="${javaField}">
        <template #default="scope">
#if($column.htmlType == "checkbox")
          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
#end
        </template>
      </el-table-column>
#elseif($column.list && "" != $javaField)
      <el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template #default="scope">
          <el-button
            size="mini"
            type="text"
            icon="Edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['${moduleName}:${businessName}:edit']"
          >修改</el-button>
          <el-button
            size="mini"
            type="text"
            icon="Delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['${moduleName}:${businessName}:remove']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination
      v-show="total>0"
      :total="total"
      v-model:p:page="queryParams.pageNum"
      v-model:p:limit="queryParams.pageSize"
      @pagination="getList"
    />
    <!-- æ·»åŠ æˆ–ä¿®æ”¹${functionName}对话框 -->
    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
      <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px">
#foreach($column in $columns)
#set($field=$column.javaField)
#if($column.insert && !$column.pk)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#set($dictType=$column.dictType)
#if($column.htmlType == "input")
        <el-form-item label="${comment}" prop="${field}">
          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
        </el-form-item>
#elseif($column.htmlType == "imageUpload")
        <el-form-item label="${comment}">
          <imageUpload v-model="form.${field}"/>
        </el-form-item>
#elseif($column.htmlType == "fileUpload")
        <el-form-item label="${comment}">
          <fileUpload v-model="form.${field}"/>
        </el-form-item>
#elseif($column.htmlType == "editor")
        <el-form-item label="${comment}">
          <editor v-model="form.${field}" :min-height="192"/>
        </el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType)
        <el-form-item label="${comment}" prop="${field}">
          <el-select v-model="form.${field}" placeholder="请选择${comment}">
            <el-option
              v-for="dict in ${dictType}"
              :key="dict.value"
              :label="dict.label"
              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
            ></el-option>
          </el-select>
        </el-form-item>
#elseif($column.htmlType == "select" && $dictType)
        <el-form-item label="${comment}" prop="${field}">
          <el-select v-model="form.${field}" placeholder="请选择${comment}">
            <el-option label="请选择字典生成" value="" />
          </el-select>
        </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
        <el-form-item label="${comment}">
          <el-checkbox-group v-model="form.${field}">
            <el-checkbox
              v-for="dict in ${dictType}"
              :key="dict.value"
              :label="dict.value">
              {{dict.label}}
            </el-checkbox>
          </el-checkbox-group>
        </el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
        <el-form-item label="${comment}">
          <el-checkbox-group v-model="form.${field}">
            <el-checkbox>请选择字典生成</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType)
        <el-form-item label="${comment}">
          <el-radio-group v-model="form.${field}">
            <el-radio
              v-for="dict in ${dictType}"
              :key="dict.value"
              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
            >{{dict.label}}</el-radio>
          </el-radio-group>
        </el-form-item>
#elseif($column.htmlType == "radio" && $dictType)
        <el-form-item label="${comment}">
          <el-radio-group v-model="form.${field}">
            <el-radio label="1">请选择字典生成</el-radio>
          </el-radio-group>
        </el-form-item>
#elseif($column.htmlType == "datetime")
        <el-form-item label="${comment}" prop="${field}">
          <el-date-picker clearable size="small"
            v-model="form.${field}"
            type="datetime"
            value-format="YYYY-MM-DD HH:mm:ss"
            placeholder="选择${comment}">
          </el-date-picker>
        </el-form-item>
#elseif($column.htmlType == "textarea")
        <el-form-item label="${comment}" prop="${field}">
          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
        </el-form-item>
#end
#end
#end
#if($table.sub)
        <el-divider content-position="center">${subTable.functionName}信息</el-divider>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button type="primary" icon="Plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button type="danger" icon="Delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
          </el-col>
        </el-row>
        <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
          <el-table-column type="selection" width="50" align="center" />
          <el-table-column label="序号" align="center" prop="index" width="50"/>
#foreach($column in $subTable.columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk || $javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
          <el-table-column label="$comment" prop="${javaField}">
            <template #default="scope">
              <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
            </template>
          </el-table-column>
#end
#end
        </el-table>
#end
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®š</el-button>
          <el-button @click="cancel">取 æ¶ˆ</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
const { proxy } = getCurrentInstance();
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
#end
const ${businessName}List = ref([]);
#if($table.sub)
const ${subclassName}List = ref([]);
#end
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
#if($table.sub)
const checked${subClassName} = ref([]);
#end
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([]);
#end
#end
const data = reactive({
  form: {},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
#foreach ($column in $columns)
#if($column.query)
    $column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
  },
  rules: {
#foreach ($column in $columns)
#if($column.required)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
    $column.javaField: [
      { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
    ]#if($foreach.count != $columns.size()),#end
#end
#end
  }
});
const { queryParams, form, rules } = toRefs(data);
/** æŸ¥è¯¢${functionName}列表 */
function getList() {
  loading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
  queryParams.value.params = {};
#break
#end
#end
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
  }
#end
#end
  list${BusinessName}(queryParams.value).then(response => {
    ${businessName}List.value = response.rows;
    total.value = response.total;
    loading.value = false;
  });
}
// å–消按钮
function cancel() {
  open.value = false;
  reset();
}
// è¡¨å•重置
function reset() {
  form.value = {
#foreach ($column in $columns)
#if($column.htmlType == "radio")
    $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($foreach.count != $columns.size()),#end
#else
    $column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
  };
#if($table.sub)
  ${subclassName}List.value = [];
#end
  proxy.resetForm("${businessName}Ref");
}
/** æœç´¢æŒ‰é’®æ“ä½œ */
function handleQuery() {
  queryParams.value.pageNum = 1;
  getList();
}
/** é‡ç½®æŒ‰é’®æ“ä½œ */
function resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  daterange${AttrName}.value = [];
#end
#end
  proxy.resetForm("queryRef");
  handleQuery();
}
// å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
function handleSelectionChange(selection) {
  ids.value = selection.map(item => item.${pkColumn.javaField});
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}
/** æ–°å¢žæŒ‰é’®æ“ä½œ */
function handleAdd() {
  reset();
  open.value = true;
  title.value = "添加${functionName}";
}
/** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
function handleUpdate(row) {
  loading.value = true
  reset();
  const ${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
  get${BusinessName}(${pkColumn.javaField}).then(response => {
    loading.value = false;
    form.value = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
    form.value.$column.javaField = form.value.${column.javaField}.split(",");
#end
#end
#if($table.sub)
    ${subclassName}List.value = response.data.${subclassName}List;
#end
    open.value = true;
    title.value = "修改${functionName}";
  });
}
/** æäº¤æŒ‰é’® */
function submitForm() {
  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
    if (valid) {
      buttonLoading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
      form.value.$column.javaField = form.value.${column.javaField}.join(",");
#end
#end
#if($table.sub)
      form.value.${subclassName}List = ${subclassName}List.value;
#end
      if (form.value.${pkColumn.javaField} != null) {
        update${BusinessName}(form.value).then(response => {
          proxy.#[[$modal]]#.msgSuccess("修改成功");
          open.value = false;
          getList();
        }).finally(() => {
          buttonLoading.value = false;
        });
      } else {
        add${BusinessName}(form.value).then(response => {
          proxy.#[[$modal]]#.msgSuccess("新增成功");
          open.value = false;
          getList();
        }).finally(() => {
          buttonLoading.value = false;
        });
      }
    }
  });
}
/** åˆ é™¤æŒ‰é’®æ“ä½œ */
function handleDelete(row) {
  const ${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
  proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
    loading.value = true;
    return del${BusinessName}(${pkColumn.javaField}s);
  }).then(() => {
    loading.value = true;
    getList();
    proxy.#[[$modal]]#.msgSuccess("删除成功");
  }).finally(() => {
    loading.value = false;
  });
}
#if($table.sub)
/** ${subTable.functionName}序号 */
function row${subClassName}Index({ row, rowIndex }) {
  row.index = rowIndex + 1;
}
/** ${subTable.functionName}添加按钮操作 */
function handleAdd${subClassName}() {
  let obj = {};
#foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
  obj.$column.javaField = "";
#end
#end
  ${subclassName}List.value.push(obj);
}
/** ${subTable.functionName}删除按钮操作 */
function handleDelete${subClassName}() {
  if (checked${subClassName}.value.length == 0) {
    proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
  } else {
    const ${subclassName}s = ${subclassName}List.value;
    const checked${subClassName}s = checked${subClassName}.value;
    ${subclassName}List.value = ${subclassName}s.filter(function(item) {
      return checked${subClassName}s.indexOf(item.index) == -1
    });
  }
}
/** å¤é€‰æ¡†é€‰ä¸­æ•°æ® */
function handle${subClassName}SelectionChange(selection) {
  checked${subClassName}.value = selection.map(item => item.index)
}
#end
/** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
function handleExport() {
  proxy.download('${moduleName}/${businessName}/export', {
    ...queryParams.value
  }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
}
getList();
</script>
ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
如果使用的是RuoYi-Vue3前端,那么需要覆盖一下此目录的模板index.vue.vm、index-tree.vue.vm文件到上级vue目录。
ruoyi-job/pom.xml
@@ -31,7 +31,7 @@
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>tlog-xxl-job</artifactId>
            <artifactId>tlog-xxljob-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
ruoyi-job/src/main/java/com/ruoyi/job/config/XxlJobConfig.java
@@ -2,7 +2,6 @@
import com.ruoyi.job.config.properties.XxlJobProperties;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import com.yomahub.tlog.springboot.lifecircle.TLogXxljobEnhanceInit;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -40,9 +39,4 @@
        return xxlJobSpringExecutor;
    }
    @Bean
    public TLogXxljobEnhanceInit tLogXxljobEnhanceInit(){
        return new TLogXxljobEnhanceInit();
    }
}
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.xss.Xss;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -10,6 +11,7 @@
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
 * é€šçŸ¥å…¬å‘Šè¡¨ sys_notice
@@ -32,6 +34,7 @@
    /**
     * å…¬å‘Šæ ‡é¢˜
     */
    @Xss(message = "公告标题不能包含脚本字符")
    @ApiModelProperty(value = "公告标题")
    @NotBlank(message = "公告标题不能为空")
    @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOssConfig.java
@@ -22,7 +22,7 @@
     * ä¸»å»º
     */
    @TableId(value = "oss_config_id")
    private Integer ossConfigId;
    private Long ossConfigId;
    /**
     * é…ç½®key
ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssBo.java
@@ -17,28 +17,6 @@
public class SysOssBo extends BaseEntity {
    /**
     * åˆ†é¡µå¤§å°
     */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /**
     * å½“前页数
     */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /**
     * æŽ’序列
     */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /**
     * æŽ’序的方向desc或者asc
     */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
    /**
     * æ–‡ä»¶å
     */
    @ApiModelProperty("文件名")
ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOssConfigBo.java
@@ -102,29 +102,4 @@
    @ApiModelProperty(value = "扩展字段")
    private String ext1;
    /**
     * åˆ†é¡µå¤§å°
     */
    @ApiModelProperty("分页大小")
    private Integer pageSize;
    /**
     * å½“前页数
     */
    @ApiModelProperty("当前页数")
    private Integer pageNum;
    /**
     * æŽ’序列
     */
    @ApiModelProperty("排序列")
    private String orderByColumn;
    /**
     * æŽ’序的方向desc或者asc
     */
    @ApiModelProperty(value = "排序的方向", example = "asc,desc")
    private String isAsc;
}
ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java
@@ -10,6 +10,7 @@
import com.ruoyi.common.utils.LoginUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ValidatorUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.vo.SysUserImportVo;
import com.ruoyi.system.service.ISysConfigService;
@@ -40,9 +41,9 @@
    private final StringBuilder failureMsg = new StringBuilder();
    public SysUserImportListener(Boolean isUpdateSupport) {
        String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword");
        this.userService = SpringUtils.getBean(ISysUserService.class);
        this.password = SpringUtils.getBean(ISysConfigService.class)
            .selectConfigByKey("sys.user.initPassword");
        this.password = SecurityUtils.encryptPassword(initPassword);
        this.isUpdateSupport = isUpdateSupport;
        this.operName = LoginUtils.getUsername();
    }
@@ -54,12 +55,14 @@
            // éªŒè¯æ˜¯å¦å­˜åœ¨è¿™ä¸ªç”¨æˆ·
            if (StringUtils.isNull(user)) {
                user = BeanUtil.toBean(userVo, SysUser.class);
                user.setPassword(SecurityUtils.encryptPassword(password));
                ValidatorUtils.validate(user);
                user.setPassword(password);
                user.setCreateBy(operName);
                userService.insertUser(user);
                successNum++;
                successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" å¯¼å…¥æˆåŠŸ");
            } else if (isUpdateSupport) {
                ValidatorUtils.validate(user);
                user.setUpdateBy(operName);
                userService.updateUser(user);
                successNum++;
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
@@ -1,5 +1,7 @@
package com.ruoyi.system.mapper;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
@@ -19,6 +21,9 @@
     * @param dept éƒ¨é—¨ä¿¡æ¯
     * @return éƒ¨é—¨ä¿¡æ¯é›†åˆ
     */
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id")
    })
    List<SysDept> selectDeptList(SysDept dept);
    /**
@@ -28,7 +33,7 @@
     * @param deptCheckStrictly éƒ¨é—¨æ ‘选择项是否关联显示
     * @return é€‰ä¸­éƒ¨é—¨åˆ—表
     */
    List<Integer> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
    List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
    /**
     * ä¿®æ”¹å­å…ƒç´ å…³ç³»
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
@@ -18,7 +18,7 @@
     * @param userId ç”¨æˆ·ID
     * @return é€‰ä¸­å²—位ID列表
     */
    List<Integer> selectPostListByUserId(Long userId);
    List<Long> selectPostListByUserId(Long userId);
    /**
     * æŸ¥è¯¢ç”¨æˆ·æ‰€å±žå²—位组
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
@@ -1,6 +1,8 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
@@ -14,6 +16,9 @@
 */
public interface SysRoleMapper extends BaseMapperPlus<SysRole> {
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id")
    })
    Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param("role") SysRole role);
    /**
@@ -22,6 +27,9 @@
     * @param role è§’色信息
     * @return è§’色数据集合信息
     */
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id")
    })
    List<SysRole> selectRoleList(SysRole role);
    /**
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -1,6 +1,8 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
@@ -14,6 +16,10 @@
 */
public interface SysUserMapper extends BaseMapperPlus<SysUser> {
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id"),
        @DataColumn(key = "userName", value = "u.user_id")
    })
    Page<SysUser> selectPageUserList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
    /**
@@ -22,6 +28,10 @@
     * @param sysUser ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id"),
        @DataColumn(key = "userName", value = "u.user_id")
    })
    List<SysUser> selectUserList(SysUser sysUser);
    /**
@@ -30,6 +40,10 @@
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id"),
        @DataColumn(key = "userName", value = "u.user_id")
    })
    Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
    /**
@@ -38,6 +52,10 @@
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @DataPermission({
        @DataColumn(key = "deptName", value = "d.dept_id"),
        @DataColumn(key = "userName", value = "u.user_id")
    })
    Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysConfig;
@@ -14,7 +15,7 @@
public interface ISysConfigService extends IService<SysConfig> {
    TableDataInfo<SysConfig> selectPageConfigList(SysConfig config);
    TableDataInfo<SysConfig> selectPageConfigList(SysConfig config, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢å‚数配置信息
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
@@ -34,7 +34,7 @@
     * @param roleId è§’色ID
     * @return é€‰ä¸­éƒ¨é—¨åˆ—表
     */
    List<Integer> selectDeptListByRoleId(Long roleId);
    List<Long> selectDeptListByRoleId(Long roleId);
    /**
     * æ ¹æ®éƒ¨é—¨ID查询信息
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -14,7 +15,7 @@
public interface ISysDictDataService extends IService<SysDictData> {
    TableDataInfo<SysDictData> selectPageDictDataList(SysDictData dictData);
    TableDataInfo<SysDictData> selectPageDictDataList(SysDictData dictData, PageQuery pageQuery);
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢å­—典数据
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysDictType;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -15,7 +16,7 @@
public interface ISysDictTypeService extends IService<SysDictType> {
    TableDataInfo<SysDictType> selectPageDictTypeList(SysDictType dictType);
    TableDataInfo<SysDictType> selectPageDictTypeList(SysDictType dictType, PageQuery pageQuery);
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢å­—典类型
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysLogininfor;
@@ -14,7 +15,7 @@
public interface ISysLogininforService extends IService<SysLogininfor> {
    TableDataInfo<SysLogininfor> selectPageLogininforList(SysLogininfor logininfor);
    TableDataInfo<SysLogininfor> selectPageLogininforList(SysLogininfor logininfor, PageQuery pageQuery);
    /**
     * æ–°å¢žç³»ç»Ÿç™»å½•日志
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysNotice;
@@ -14,7 +15,7 @@
public interface ISysNoticeService extends IService<SysNotice> {
    TableDataInfo<SysNotice> selectPageNoticeList(SysNotice notice);
    TableDataInfo<SysNotice> selectPageNoticeList(SysNotice notice, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢å…¬å‘Šä¿¡æ¯
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysOperLog;
@@ -13,7 +14,7 @@
 */
public interface ISysOperLogService extends IService<SysOperLog> {
    TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog);
    TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery);
    /**
     * æ–°å¢žæ“ä½œæ—¥å¿—
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssConfigService.java
@@ -1,5 +1,6 @@
package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysOssConfig;
@@ -30,7 +31,7 @@
    /**
     * æŸ¥è¯¢åˆ—表
     */
    TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo);
    TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery);
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOssService.java
@@ -1,5 +1,6 @@
package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysOss;
@@ -16,7 +17,7 @@
 */
public interface ISysOssService extends IServicePlus<SysOss, SysOssVo> {
    TableDataInfo<SysOssVo> queryPageList(SysOssBo sysOss);
    TableDataInfo<SysOssVo> queryPageList(SysOssBo sysOss, PageQuery pageQuery);
    SysOss upload(MultipartFile file);
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysPost;
@@ -14,7 +15,7 @@
public interface ISysPostService extends IService<SysPost> {
    TableDataInfo<SysPost> selectPagePostList(SysPost post);
    TableDataInfo<SysPost> selectPagePostList(SysPost post, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢å²—位信息集合
@@ -45,7 +46,7 @@
     * @param userId ç”¨æˆ·ID
     * @return é€‰ä¸­å²—位ID列表
     */
    List<Integer> selectPostListByUserId(Long userId);
    List<Long> selectPostListByUserId(Long userId);
    /**
     * æ ¡éªŒå²—位名称
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.SysUserRole;
@@ -16,7 +17,7 @@
public interface ISysRoleService extends IService<SysRole> {
    TableDataInfo<SysRole> selectPageRoleList(SysRole role);
    TableDataInfo<SysRole> selectPageRoleList(SysRole role, PageQuery pageQuery);
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢è§’色数据
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.UserService;
@@ -15,7 +16,7 @@
public interface ISysUserService extends IService<SysUser>, UserService {
    TableDataInfo<SysUser> selectPageUserList(SysUser user);
    TableDataInfo<SysUser> selectPageUserList(SysUser user, PageQuery pageQuery);
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢ç”¨æˆ·åˆ—表
@@ -31,7 +32,7 @@
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    TableDataInfo<SysUser> selectAllocatedList(SysUser user);
    TableDataInfo<SysUser> selectAllocatedList(SysUser user, PageQuery pageQuery);
    /**
     * æ ¹æ®æ¡ä»¶åˆ†é¡µæŸ¥è¯¢æœªåˆ†é…ç”¨æˆ·è§’色列表
@@ -39,7 +40,7 @@
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    TableDataInfo<SysUser> selectUnallocatedList(SysUser user);
    TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery);
    /**
     * é€šè¿‡ç”¨æˆ·åæŸ¥è¯¢ç”¨æˆ·
@@ -203,13 +204,4 @@
     */
    int deleteUserByIds(Long[] userIds);
    /**
     * å¯¼å…¥ç”¨æˆ·æ•°æ®
     *
     * @param userList        ç”¨æˆ·æ•°æ®åˆ—表
     * @param isUpdateSupport æ˜¯å¦æ›´æ–°æ”¯æŒï¼Œå¦‚果已存在,则进行更新数据
     * @param operName        æ“ä½œç”¨æˆ·
     * @return ç»“æžœ
     */
    String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/SysDataScopeService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.system.service;
/**
 * é€šç”¨ æ•°æ®æƒé™ æœåŠ¡
 *
 * @author Lion Li
 */
public interface SysDataScopeService {
    /**
     * èŽ·å–è§’è‰²è‡ªå®šä¹‰æƒé™
     * @param roleId è§’色id
     * @return éƒ¨é—¨id组
     */
    String getRoleCustom(Long roleId);
    /**
     * èŽ·å–éƒ¨é—¨åŠä»¥ä¸‹æƒé™
     * @param deptId éƒ¨é—¨id
     * @return éƒ¨é—¨id组
     */
    String getDeptAndChild(Long deptId);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
@@ -11,13 +12,14 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
/**
 * ç™»å½•校验方法
@@ -56,21 +58,46 @@
        if (captchaOnOff) {
            validateCaptcha(username, code, uuid, request);
        }
        // èŽ·å–ç”¨æˆ·ç™»å½•é”™è¯¯æ¬¡æ•°(可自定义限制策略 ä¾‹å¦‚: key + username + ip)
        Integer errorNumber = RedisUtils.getCacheObject(Constants.LOGIN_ERROR + username);
        // é”å®šæ—¶é—´å†…登录 åˆ™è¸¢å‡º
        if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
            asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
            throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
        }
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user)) {
            log.info("登录用户:{} ä¸å­˜åœ¨.", username);
            throw new ServiceException("登录用户:" + username + " ä¸å­˜åœ¨");
            throw new UserException("user.not.exists", username);
        } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            log.info("登录用户:{} å·²è¢«åˆ é™¤.", username);
            throw new ServiceException("对不起,您的账号:" + username + " å·²è¢«åˆ é™¤");
            throw new UserException("user.password.delete", username);
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户:{} å·²è¢«åœç”¨.", username);
            throw new ServiceException("对不起,您的账号:" + username + " å·²åœç”¨");
            throw new UserException("user.blocked", username);
        }
        if (!SecurityUtils.matchesPassword(password, user.getPassword())) {
            asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"), request);
            throw new UserPasswordNotMatchException();
            // æ˜¯å¦ç¬¬ä¸€æ¬¡
            errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
            // è¾¾åˆ°è§„定错误次数 åˆ™é”å®šç™»å½•
            if (errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) {
                RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber, Constants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES);
                asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request);
                throw new UserException("user.password.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME);
            } else {
                // æœªè¾¾åˆ°è§„定错误次数 åˆ™é€’增
                RedisUtils.setCacheObject(Constants.LOGIN_ERROR + username, errorNumber);
                asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", errorNumber), request);
                throw new UserException("user.password.retry.limit.count", errorNumber);
            }
        }
        // ç™»å½•成功 æ¸…空错误次数
        RedisUtils.deleteObject(Constants.LOGIN_ERROR + username);
        asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
        recordLoginInfo(user.getUserId(), username);
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getUserId());
        loginUser.setDeptId(user.getDeptId());
@@ -78,8 +105,6 @@
        loginUser.setMenuPermission(permissionService.getMenuPermission(user));
        loginUser.setRolePermission(permissionService.getRolePermission(user));
        asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
        recordLoginInfo(user.getUserId(), username);
        // ç”Ÿæˆtoken
        LoginUtils.loginByDevice(loginUser, UserType.SYS_USER, DeviceType.PC);
        return StpUtil.getTokenValue();
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -1,16 +1,16 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.DataSource;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
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;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysConfig;
@@ -32,7 +32,7 @@
public class SysConfigServiceImpl extends ServicePlusImpl<SysConfigMapper, SysConfig, SysConfig> implements ISysConfigService, ConfigService {
    @Override
    public TableDataInfo<SysConfig> selectPageConfigList(SysConfig config) {
    public TableDataInfo<SysConfig> selectPageConfigList(SysConfig config, PageQuery pageQuery) {
        Map<String, Object> params = config.getParams();
        LambdaQueryWrapper<SysConfig> lqw = new LambdaQueryWrapper<SysConfig>()
            .like(StringUtils.isNotBlank(config.getConfigName()), SysConfig::getConfigName, config.getConfigName())
@@ -40,7 +40,8 @@
            .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));
        Page<SysConfig> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
@@ -50,7 +51,7 @@
     * @return å‚数配置信息
     */
    @Override
    @DataSource(DataSourceType.MASTER)
    @DS("master")
    public SysConfig selectConfigById(Long configId) {
        return baseMapper.selectById(configId);
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDataScopeServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.domain.SysRoleDept;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysRoleDeptMapper;
import com.ruoyi.system.service.SysDataScopeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service("sdss")
public class SysDataScopeServiceImpl implements SysDataScopeService {
    @Autowired
    private SysRoleDeptMapper roleDeptMapper;
    @Autowired
    private SysDeptMapper deptMapper;
    @Override
    public String getRoleCustom(Long roleId) {
        List<SysRoleDept> list = roleDeptMapper.selectList(
            new LambdaQueryWrapper<SysRoleDept>()
                .select(SysRoleDept::getDeptId)
                .eq(SysRoleDept::getRoleId, roleId));
        if (CollUtil.isNotEmpty(list)) {
            return list.stream().map(rd -> Convert.toStr(rd.getDeptId())).collect(Collectors.joining(","));
        }
        return null;
    }
    @Override
    public String getDeptAndChild(Long deptId) {
        List<SysDept> list = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
            .select(SysDept::getDeptId)
            .eq(SysDept::getDeptId, deptId)
            .or()
            .apply("find_in_set({0},ancestors)", deptId));
        if (CollUtil.isNotEmpty(list)) {
            return list.stream().map(d -> Convert.toStr(d.getDeptId())).collect(Collectors.joining(","));
        }
        return null;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -1,10 +1,10 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.collection.CollUtil;
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.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
@@ -46,8 +46,9 @@
     * @return éƒ¨é—¨ä¿¡æ¯é›†åˆ
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysDept> selectDeptList(SysDept dept) {
//        return baseMapper.selectList();
//        return baseMapper.selectList(new LambdaQueryWrapper<>());
        return baseMapper.selectDeptList(dept);
    }
@@ -59,7 +60,11 @@
     */
    @Override
    public List<Tree<Long>> buildDeptTreeSelect(List<SysDept> depts) {
        return TreeBuildUtils.build(depts, (dept, tree) ->
        if (CollUtil.isEmpty(depts)) {
            return CollUtil.newArrayList();
        }
        Long parentId = depts.get(0).getParentId();
        return TreeBuildUtils.build(depts, parentId, (dept, tree) ->
            tree.setId(dept.getDeptId())
                .setParentId(dept.getParentId())
                .setName(dept.getDeptName())
@@ -73,7 +78,7 @@
     * @return é€‰ä¸­éƒ¨é—¨åˆ—表
     */
    @Override
    public List<Integer> selectDeptListByRoleId(Long roleId) {
    public List<Long> selectDeptListByRoleId(Long roleId) {
        SysRole role = roleMapper.selectById(roleId);
        return baseMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
    }
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.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.PageQuery;
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.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDictDataMapper;
@@ -23,13 +24,14 @@
public class SysDictDataServiceImpl extends ServicePlusImpl<SysDictDataMapper, SysDictData, SysDictData> implements ISysDictDataService {
    @Override
    public TableDataInfo<SysDictData> selectPageDictDataList(SysDictData dictData) {
    public TableDataInfo<SysDictData> selectPageDictDataList(SysDictData dictData, PageQuery pageQuery) {
        LambdaQueryWrapper<SysDictData> lqw = new LambdaQueryWrapper<SysDictData>()
                .eq(StringUtils.isNotBlank(dictData.getDictType()), SysDictData::getDictType, dictData.getDictType())
                .like(StringUtils.isNotBlank(dictData.getDictLabel()), SysDictData::getDictLabel, dictData.getDictLabel())
                .eq(StringUtils.isNotBlank(dictData.getStatus()), SysDictData::getStatus, dictData.getStatus())
                .orderByAsc(SysDictData::getDictSort);
        return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
        Page<SysDictData> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
@@ -3,15 +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.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
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.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDictDataMapper;
@@ -38,7 +39,7 @@
    private SysDictDataMapper dictDataMapper;
    @Override
    public TableDataInfo<SysDictType> selectPageDictTypeList(SysDictType dictType) {
    public TableDataInfo<SysDictType> selectPageDictTypeList(SysDictType dictType, PageQuery pageQuery) {
        Map<String, Object> params = dictType.getParams();
        LambdaQueryWrapper<SysDictType> lqw = new LambdaQueryWrapper<SysDictType>()
            .like(StringUtils.isNotBlank(dictType.getDictName()), SysDictType::getDictName, dictType.getDictName())
@@ -46,7 +47,8 @@
            .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));
        Page<SysDictType> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
@@ -189,7 +191,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int updateDictType(SysDictType dict) {
        SysDictType oldDict = getById(dict.getDictId());
        dictDataMapper.update(null, new LambdaUpdateWrapper<SysDictData>()
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
@@ -3,11 +3,12 @@
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.LogininforService;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
@@ -87,7 +88,7 @@
    }
    @Override
    public TableDataInfo<SysLogininfor> selectPageLogininforList(SysLogininfor logininfor) {
    public TableDataInfo<SysLogininfor> selectPageLogininforList(SysLogininfor logininfor, PageQuery pageQuery) {
        Map<String, Object> params = logininfor.getParams();
        LambdaQueryWrapper<SysLogininfor> lqw = new LambdaQueryWrapper<SysLogininfor>()
            .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
@@ -95,7 +96,11 @@
            .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));
        if(StringUtils.isBlank(pageQuery.getOrderByColumn())) {
            pageQuery.setOrderByColumn("info_id").setIsAsc("desc");
        }
        Page<SysLogininfor> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -1,5 +1,6 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
@@ -157,7 +158,7 @@
                router.setPath("/inner");
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                String routerPath = StringUtils.replaceEach(menu.getPath(), new String[]{Constants.HTTP, Constants.HTTPS}, new String[]{"", ""});
                String routerPath = innerLinkReplaceEach(menu.getPath());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
@@ -178,7 +179,11 @@
     */
    @Override
    public List<Tree<Long>> buildMenuTreeSelect(List<SysMenu> menus) {
        return TreeBuildUtils.build(menus, (menu, tree) ->
        if (CollUtil.isEmpty(menus)) {
            return CollUtil.newArrayList();
        }
        Long parentId = menus.get(0).getParentId();
        return TreeBuildUtils.build(menus, parentId, (menu, tree) ->
            tree.setId(menu.getMenuId())
                .setParentId(menu.getParentId())
                .setName(menu.getMenuName())
@@ -297,7 +302,7 @@
        String routerPath = menu.getPath();
        // å†…链打开外网方式
        if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
            routerPath = StringUtils.replaceEach(routerPath, new String[]{Constants.HTTP, Constants.HTTPS}, new String[]{"", ""});
            routerPath = innerLinkReplaceEach(routerPath);
        }
        // éžå¤–链并且是一级目录(类型为目录)
        if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
@@ -415,4 +420,15 @@
    private boolean hasChild(List<SysMenu> list, SysMenu t) {
        return getChildList(list, t).size() > 0;
    }
    /**
     * å†…链域名特殊字符替换
     *
     * @return
     */
    public String innerLinkReplaceEach(String path)
    {
        return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS },
                new String[] { "", "" });
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
@@ -1,9 +1,10 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.mapper.SysNoticeMapper;
@@ -22,12 +23,13 @@
public class SysNoticeServiceImpl extends ServicePlusImpl<SysNoticeMapper, SysNotice, SysNotice> implements ISysNoticeService {
    @Override
    public TableDataInfo<SysNotice> selectPageNoticeList(SysNotice notice) {
    public TableDataInfo<SysNotice> selectPageNoticeList(SysNotice notice, PageQuery pageQuery) {
        LambdaQueryWrapper<SysNotice> lqw = new LambdaQueryWrapper<SysNotice>()
                .like(StringUtils.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle())
                .eq(StringUtils.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType())
                .like(StringUtils.isNotBlank(notice.getCreateBy()), SysNotice::getCreateBy, notice.getCreateBy());
        return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
        Page<SysNotice> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
@@ -3,11 +3,12 @@
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.dto.OperLogDTO;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.OperLogService;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.system.domain.SysOperLog;
@@ -44,7 +45,7 @@
    }
    @Override
    public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog) {
    public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery) {
        Map<String, Object> params = operLog.getParams();
        LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
@@ -60,7 +61,11 @@
            .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));
        if(StringUtils.isBlank(pageQuery.getOrderByColumn())) {
            pageQuery.setOrderByColumn("oper_id").setIsAsc("desc");
        }
        Page<SysOperLog> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssConfigServiceImpl.java
@@ -5,14 +5,14 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.constant.OssConstant;
@@ -67,9 +67,10 @@
    }
    @Override
    public TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo) {
        PagePlus<SysOssConfig, SysOssConfigVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
        return PageUtils.buildDataInfo(result);
    public TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysOssConfig> lqw = buildQueryWrapper(bo);
        Page<SysOssConfigVo> result = pageVo(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
@@ -2,11 +2,11 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.factory.OssFactory;
@@ -33,9 +33,10 @@
public class SysOssServiceImpl extends ServicePlusImpl<SysOssMapper, SysOss, SysOssVo> implements ISysOssService {
    @Override
    public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo) {
        PagePlus<SysOss, SysOssVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
        return PageUtils.buildDataInfo(result);
    public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysOss> lqw = buildQueryWrapper(bo);
        Page<SysOssVo> result = pageVo(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    private LambdaQueryWrapper<SysOss> buildQueryWrapper(SysOssBo bo) {
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
@@ -1,11 +1,12 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.domain.SysUserPost;
@@ -30,12 +31,13 @@
    private SysUserPostMapper userPostMapper;
    @Override
    public TableDataInfo<SysPost> selectPagePostList(SysPost post) {
    public TableDataInfo<SysPost> selectPagePostList(SysPost post, PageQuery pageQuery) {
        LambdaQueryWrapper<SysPost> lqw = new LambdaQueryWrapper<SysPost>()
                .like(StringUtils.isNotBlank(post.getPostCode()), SysPost::getPostCode, post.getPostCode())
                .eq(StringUtils.isNotBlank(post.getStatus()), SysPost::getStatus, post.getStatus())
                .like(StringUtils.isNotBlank(post.getPostName()), SysPost::getPostName, post.getPostName());
        return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw));
        Page<SysPost> page = page(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }
    /**
@@ -80,7 +82,7 @@
     * @return é€‰ä¸­å²—位ID列表
     */
    @Override
    public List<Integer> selectPostListByUserId(Long userId) {
    public List<Long> selectPostListByUserId(Long userId) {
        return baseMapper.selectPostListByUserId(userId);
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -1,15 +1,15 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.DataScope;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
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.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.LoginUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.SysRoleDept;
@@ -44,9 +44,9 @@
    private SysRoleDeptMapper roleDeptMapper;
    @Override
    @DataScope(deptAlias = "d")
    public TableDataInfo<SysRole> selectPageRoleList(SysRole role) {
        return PageUtils.buildDataInfo(baseMapper.selectPageRoleList(PageUtils.buildPage(), role));
    public TableDataInfo<SysRole> selectPageRoleList(SysRole role, PageQuery pageQuery) {
        Page<SysRole> page = baseMapper.selectPageRoleList(pageQuery.build(), role);
        return TableDataInfo.build(page);
    }
    /**
@@ -56,7 +56,6 @@
     * @return è§’色数据集合信息
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysRole> selectRoleList(SysRole role) {
        return baseMapper.selectRoleList(role);
    }
@@ -215,7 +214,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int insertRole(SysRole role) {
        // æ–°å¢žè§’色信息
        baseMapper.insert(role);
@@ -229,7 +228,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int updateRole(SysRole role) {
        // ä¿®æ”¹è§’色信息
        baseMapper.updateById(role);
@@ -256,7 +255,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int authDataScope(SysRole role) {
        // ä¿®æ”¹è§’色信息
        baseMapper.updateById(role);
@@ -315,7 +314,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int deleteRoleById(Long roleId) {
        // åˆ é™¤è§’色与菜单关联
        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
@@ -331,7 +330,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int deleteRoleByIds(Long[] roleIds) {
        for (Long roleId : roleIds) {
            checkRoleAllowed(new SysRole(roleId));
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -1,9 +1,11 @@
package com.ruoyi.system.service.impl;
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.annotation.DataScope;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
@@ -11,7 +13,6 @@
import com.ruoyi.common.core.service.UserService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.LoginUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
@@ -19,7 +20,6 @@
import com.ruoyi.system.domain.SysUserPost;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,6 +29,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
 * ç”¨æˆ· ä¸šåŠ¡å±‚å¤„ç†
@@ -51,13 +52,10 @@
    @Autowired
    private SysUserPostMapper userPostMapper;
    @Autowired
    private ISysConfigService configService;
    @Override
    @DataScope(deptAlias = "d", userAlias = "u", isUser = true)
    public TableDataInfo<SysUser> selectPageUserList(SysUser user) {
        return PageUtils.buildDataInfo(baseMapper.selectPageUserList(PageUtils.buildPage(), user));
    public TableDataInfo<SysUser> selectPageUserList(SysUser user, PageQuery pageQuery) {
        Page<SysUser> page = baseMapper.selectPageUserList(pageQuery.build(), user);
        return TableDataInfo.build(page);
    }
    /**
@@ -67,7 +65,6 @@
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u", isUser = true)
    public List<SysUser> selectUserList(SysUser user) {
        return baseMapper.selectUserList(user);
    }
@@ -79,9 +76,9 @@
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u", isUser = true)
    public TableDataInfo<SysUser> selectAllocatedList(SysUser user) {
        return PageUtils.buildDataInfo(baseMapper.selectAllocatedList(PageUtils.buildPage(), user));
    public TableDataInfo<SysUser> selectAllocatedList(SysUser user, PageQuery pageQuery) {
        Page<SysUser> page = baseMapper.selectAllocatedList(pageQuery.build(), user);
        return TableDataInfo.build(page);
    }
    /**
@@ -91,9 +88,9 @@
     * @return ç”¨æˆ·ä¿¡æ¯é›†åˆä¿¡æ¯
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u", isUser = true)
    public TableDataInfo<SysUser> selectUnallocatedList(SysUser user) {
        return PageUtils.buildDataInfo(baseMapper.selectUnallocatedList(PageUtils.buildPage(), user));
    public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) {
        Page<SysUser> page = baseMapper.selectUnallocatedList(pageQuery.build(), user);
        return TableDataInfo.build(page);
    }
    /**
@@ -127,14 +124,10 @@
    @Override
    public String selectUserRoleGroup(String userName) {
        List<SysRole> list = roleMapper.selectRolesByUserName(userName);
        StringBuilder idsStr = new StringBuilder();
        for (SysRole role : list) {
            idsStr.append(role.getRoleName()).append(",");
        if (CollUtil.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        if (StringUtils.isNotEmpty(idsStr.toString())) {
            return idsStr.substring(0, idsStr.length() - 1);
        }
        return idsStr.toString();
        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
    }
    /**
@@ -146,14 +139,10 @@
    @Override
    public String selectUserPostGroup(String userName) {
        List<SysPost> list = postMapper.selectPostsByUserName(userName);
        StringBuilder idsStr = new StringBuilder();
        for (SysPost post : list) {
            idsStr.append(post.getPostName()).append(",");
        if (CollUtil.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        if (StringUtils.isNotEmpty(idsStr.toString())) {
            return idsStr.substring(0, idsStr.length() - 1);
        }
        return idsStr.toString();
        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
    }
    /**
@@ -243,7 +232,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int insertUser(SysUser user) {
        // æ–°å¢žç”¨æˆ·ä¿¡æ¯
        int rows = baseMapper.insert(user);
@@ -272,7 +261,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int updateUser(SysUser user) {
        Long userId = user.getUserId();
        // åˆ é™¤ç”¨æˆ·ä¸Žè§’色关联
@@ -293,7 +282,7 @@
     * @param roleIds è§’色组
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public void insertUserAuth(Long userId, Long[] roleIds) {
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, userId));
@@ -436,7 +425,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserById(Long userId) {
        // åˆ é™¤ç”¨æˆ·ä¸Žè§’色关联
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
@@ -452,7 +441,7 @@
     * @return ç»“æžœ
     */
    @Override
    @Transactional
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserByIds(Long[] userIds) {
        for (Long userId : userIds) {
            checkUserAllowed(new SysUser(userId));
@@ -465,56 +454,4 @@
        return baseMapper.deleteBatchIds(ids);
    }
    /**
     * å¯¼å…¥ç”¨æˆ·æ•°æ®
     *
     * @param userList        ç”¨æˆ·æ•°æ®åˆ—表
     * @param isUpdateSupport æ˜¯å¦æ›´æ–°æ”¯æŒï¼Œå¦‚果已存在,则进行更新数据
     * @param operName        æ“ä½œç”¨æˆ·
     * @return ç»“æžœ
     */
    @Override
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(userList) || userList.size() == 0) {
            throw new ServiceException("导入用户数据不能为空!");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String password = configService.selectConfigByKey("sys.user.initPassword");
        for (SysUser user : userList) {
            try {
                // éªŒè¯æ˜¯å¦å­˜åœ¨è¿™ä¸ªç”¨æˆ·
                SysUser u = baseMapper.selectUserByUserName(user.getUserName());
                if (StringUtils.isNull(u)) {
                    user.setPassword(SecurityUtils.encryptPassword(password));
                    user.setCreateBy(operName);
                    this.insertUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " å¯¼å…¥æˆåŠŸ");
                } else if (isUpdateSupport) {
                    user.setUpdateBy(operName);
                    this.updateUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " æ›´æ–°æˆåŠŸ");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " å·²å­˜åœ¨");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " å¯¼å…¥å¤±è´¥ï¼š";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " æ¡æ•°æ®æ ¼å¼ä¸æ­£ç¡®ï¼Œé”™è¯¯å¦‚下:");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " æ¡ï¼Œæ•°æ®å¦‚下:");
        }
        return successMsg.toString();
    }
}
ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -42,17 +42,17 @@
        <if test="status != null and status != ''">
            AND status = #{status}
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        <if test="params.dataScope != null and params.dataScope != ''">
            AND ( ${params.dataScope} )
        </if>
<!--        &lt;!&ndash; æ•°æ®èŒƒå›´è¿‡æ»¤ &ndash;&gt;-->
<!--        <if test="params.dataScope != null and params.dataScope != ''">-->
<!--            AND ( ${params.dataScope} )-->
<!--        </if>-->
        order by d.parent_id, d.order_num
    </select>
    <select id="selectDeptListByRoleId" resultType="Integer">
    <select id="selectDeptListByRoleId" resultType="Long">
        select d.dept_id
        from sys_dept d
        left join sys_role_dept rd on d.dept_id = rd.dept_id
            left join sys_role_dept rd on d.dept_id = rd.dept_id
        where rd.role_id = #{roleId}
            <if test="deptCheckStrictly">
                and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -27,33 +27,13 @@
        <result property="remark" column="remark"/>
    </resultMap>
    <sql id="selectMenuVo">
        select menu_id,
               menu_name,
               parent_id,
               order_num,
               path,
               component,
               query,
               is_frame,
               is_cache,
               menu_type,
               visible,
               status,
               ifnull(perms, '') as perms,
               icon,
               create_time
        from sys_menu
    </sql>
    <select id="selectMenuTreeAll" resultMap="SysMenuResult">
        select distinct m.menu_id,
                        m.parent_id,
                        m.menu_name,
                        m.path,
                        m.component,
                        m.query,
                        m.`query`,
                        m.visible,
                        m.status,
                        ifnull(m.perms, '') as perms,
@@ -70,7 +50,7 @@
    </select>
    <select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query, m.visible, m.status,
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status,
        ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        from sys_menu m
        left join sys_role_menu rm on m.menu_id = rm.menu_id
@@ -95,7 +75,7 @@
                        m.menu_name,
                        m.path,
                        m.component,
                        m.query,
                        m.`query`,
                        m.visible,
                        m.status,
                        ifnull(m.perms, '') as perms,
ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
@@ -29,7 +29,7 @@
        from sys_post
    </sql>
    <select id="selectPostListByUserId" parameterType="Long" resultType="Integer">
    <select id="selectPostListByUserId" parameterType="Long" resultType="Long">
        select p.post_id
        from sys_post p
                 left join sys_user_post up on up.post_id = p.post_id
@@ -45,4 +45,4 @@
        where u.user_name = #{userName}
    </select>
</mapper>
</mapper>
ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
@@ -60,10 +60,10 @@
        <if test="role.params.endTime != null and role.params.endTime != ''"><!-- ç»“束时间检索 -->
            and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{role.params.endTime},'%y%m%d')
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        <if test="role.params.dataScope != null and role.params.dataScope != ''">
            AND ( ${role.params.dataScope} )
        </if>
<!--        &lt;!&ndash; æ•°æ®èŒƒå›´è¿‡æ»¤ &ndash;&gt;-->
<!--        <if test="role.params.dataScope != null and role.params.dataScope != ''">-->
<!--            AND ( ${role.params.dataScope} )-->
<!--        </if>-->
        order by r.role_sort
    </select>
@@ -88,10 +88,10 @@
        <if test="params.endTime != null and params.endTime != ''"><!-- ç»“束时间检索 -->
            and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        <if test="params.dataScope != null and params.dataScope != ''">
            AND ( ${params.dataScope} )
        </if>
<!--        &lt;!&ndash; æ•°æ®èŒƒå›´è¿‡æ»¤ &ndash;&gt;-->
<!--        <if test="params.dataScope != null and params.dataScope != ''">-->
<!--            AND ( ${params.dataScope} )-->
<!--        </if>-->
        order by r.role_sort
    </select>
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -108,10 +108,10 @@
            AND (u.dept_id = #{user.deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{user.deptId},
            ancestors) ))
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        <if test="user.params.dataScope != null and user.params.dataScope != ''">
            AND ( ${user.params.dataScope} )
        </if>
<!--        &lt;!&ndash; æ•°æ®èŒƒå›´è¿‡æ»¤ &ndash;&gt;-->
<!--        <if test="user.params.dataScope != null and user.params.dataScope != ''">-->
<!--            AND ( ${user.params.dataScope} )-->
<!--        </if>-->
    </select>
    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
@@ -142,10 +142,10 @@
            AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId},
            ancestors) ))
        </if>
        <!-- æ•°æ®èŒƒå›´è¿‡æ»¤ -->
        <if test="params.dataScope != null and params.dataScope != ''">
            AND ( ${params.dataScope} )
        </if>
<!--        &lt;!&ndash; æ•°æ®èŒƒå›´è¿‡æ»¤ &ndash;&gt;-->
<!--        <if test="params.dataScope != null and params.dataScope != ''">-->
<!--            AND ( ${params.dataScope} )-->
<!--        </if>-->
    </select>
    <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
ruoyi-ui/package.json
@@ -38,7 +38,7 @@
  "dependencies": {
    "@riophae/vue-treeselect": "0.4.0",
    "axios": "0.24.0",
    "clipboard": "2.0.6",
    "clipboard": "2.0.8",
    "core-js": "3.19.1",
    "echarts": "4.9.0",
    "element-ui": "2.15.6",
@@ -65,7 +65,9 @@
    "@vue/cli-plugin-eslint": "4.4.6",
    "@vue/cli-service": "4.4.6",
    "babel-eslint": "10.1.0",
    "babel-plugin-dynamic-import-node": "2.3.3",
    "chalk": "4.1.0",
    "compression-webpack-plugin": "5.0.2",
    "connect": "3.6.6",
    "eslint": "7.15.0",
    "eslint-plugin-vue": "7.2.0",
ruoyi-ui/src/components/Crontab/day.vue
@@ -2,7 +2,7 @@
    <el-form size="small">
        <el-form-item>
            <el-radio v-model='radioValue' :label="1">
                æ—¥ï¼Œå…è®¸çš„通配符[, - * / L M]
                æ—¥ï¼Œå…è®¸çš„通配符[, - * ? / L W]
            </el-radio>
        </el-form-item>
@@ -15,23 +15,23 @@
        <el-form-item>
            <el-radio v-model='radioValue' :label="3">
                å‘¨æœŸä»Ž
                <el-input-number v-model='cycle01' :min="0" :max="31" /> -
                <el-input-number v-model='cycle02' :min="0" :max="31" /> æ—¥
                <el-input-number v-model='cycle01' :min="1" :max="30" /> -
                <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="31" /> æ—¥
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="4">
                ä»Ž
                <el-input-number v-model='average01' :min="0" :max="31" /> å·å¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="0" :max="31" /> æ—¥æ‰§è¡Œä¸€æ¬¡
                <el-input-number v-model='average01' :min="1" :max="30" /> å·å¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="1" :max="31 - average01 || 1" /> æ—¥æ‰§è¡Œä¸€æ¬¡
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="5">
                æ¯æœˆ
                <el-input-number v-model='workday' :min="0" :max="31" /> å·æœ€è¿‘的那个工作日
                <el-input-number v-model='workday' :min="1" :max="31" /> å·æœ€è¿‘的那个工作日
            </el-radio>
        </el-form-item>
@@ -72,31 +72,22 @@
        // å•选按钮值变化时
        radioChange() {
            ('day rachange');
            if (this.radioValue === 1) {
                this.$emit('update', 'day', '*', 'day');
                this.$emit('update', 'week', '?', 'day');
                this.$emit('update', 'month', '*', 'day');
            } else {
                if (this.cron.hour === '*') {
                    this.$emit('update', 'hour', '0', 'day');
                }
                if (this.cron.min === '*') {
                    this.$emit('update', 'min', '0', 'day');
                }
                if (this.cron.second === '*') {
                    this.$emit('update', 'second', '0', 'day');
                }
            if (this.radioValue !== 2 && this.cron.week !== '?') {
                this.$emit('update', 'week', '?', 'day')
            }
            switch (this.radioValue) {
                case 1:
                    this.$emit('update', 'day', '*');
                    break;
                case 2:
                    this.$emit('update', 'day', '?');
                    break;
                case 3:
                    this.$emit('update', 'day', this.cycle01 + '-' + this.cycle02);
                    this.$emit('update', 'day', this.cycleTotal);
                    break;
                case 4:
                    this.$emit('update', 'day', this.average01 + '/' + this.average02);
                    this.$emit('update', 'day', this.averageTotal);
                    break;
                case 5:
                    this.$emit('update', 'day', this.workday + 'W');
@@ -125,7 +116,7 @@
        // æœ€è¿‘工作日值变化时
        workdayChange() {
            if (this.radioValue == '5') {
                this.$emit('update', 'day', this.workday + 'W');
                this.$emit('update', 'day', this.workdayCheck + 'W');
            }
        },
        // checkbox值变化时
@@ -133,19 +124,10 @@
            if (this.radioValue == '7') {
                this.$emit('update', 'day', this.checkboxString);
            }
        },
        // çˆ¶ç»„件传递的week发生变化触发
        weekChange() {
            //判断week值与day不能同时为“?”
            if (this.cron.week == '?' && this.radioValue == '2') {
                this.radioValue = '1';
            } else if (this.cron.week !== '?' && this.radioValue != '2') {
                this.radioValue = '2';
            }
        },
        }
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'workdayCheck': 'workdayChange',
@@ -154,20 +136,20 @@
    computed: {
        // è®¡ç®—两个周期值
        cycleTotal: function () {
            this.cycle01 = this.checkNum(this.cycle01, 1, 31)
            this.cycle02 = this.checkNum(this.cycle02, 1, 31)
            return this.cycle01 + '-' + this.cycle02;
            const cycle01 = this.checkNum(this.cycle01, 1, 30)
            const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 31, 31)
            return cycle01 + '-' + cycle02;
        },
        // è®¡ç®—平均用到的值
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, 1, 31)
            this.average02 = this.checkNum(this.average02, 1, 31)
            return this.average01 + '/' + this.average02;
            const average01 = this.checkNum(this.average01, 1, 30)
            const average02 = this.checkNum(this.average02, 1, 31 - average01 || 0)
            return average01 + '/' + average02;
        },
        // è®¡ç®—工作日格式
        workdayCheck: function () {
            this.workday = this.checkNum(this.workday, 1, 31)
            return this.workday;
            const workday = this.checkNum(this.workday, 1, 31)
            return workday;
        },
        // è®¡ç®—勾选的checkbox值合集
        checkboxString: function () {
ruoyi-ui/src/components/Crontab/hour.vue
@@ -9,16 +9,16 @@
        <el-form-item>
            <el-radio v-model='radioValue' :label="2">
                å‘¨æœŸä»Ž
                <el-input-number v-model='cycle01' :min="0" :max="60" /> -
                <el-input-number v-model='cycle02' :min="0" :max="60" /> å°æ—¶
                <el-input-number v-model='cycle01' :min="0" :max="22" /> -
                <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="23" /> å°æ—¶
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="3">
                ä»Ž
                <el-input-number v-model='average01' :min="0" :max="60" /> å°æ—¶å¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="0" :max="60" /> å°æ—¶æ‰§è¡Œä¸€æ¬¡
                <el-input-number v-model='average01' :min="0" :max="22" /> å°æ—¶å¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="1" :max="23 - average01 || 0" /> å°æ—¶æ‰§è¡Œä¸€æ¬¡
            </el-radio>
        </el-form-item>
@@ -51,23 +51,15 @@
    methods: {
        // å•选按钮值变化时
        radioChange() {
            if (this.radioValue === 1) {
                this.$emit('update', 'hour', '*', 'hour');
                this.$emit('update', 'day', '*', 'hour');
            } else {
                if (this.cron.min === '*') {
                    this.$emit('update', 'min', '0', 'hour');
                }
                if (this.cron.second === '*') {
                    this.$emit('update', 'second', '0', 'hour');
                }
            }
            switch (this.radioValue) {
                case 1:
            this.$emit('update', 'hour', '*')
            break;
                case 2:
                    this.$emit('update', 'hour', this.cycle01 + '-' + this.cycle02);
                    this.$emit('update', 'hour', this.cycleTotal);
                    break;
                case 3:
                    this.$emit('update', 'hour', this.average01 + '/' + this.average02);
                    this.$emit('update', 'hour', this.averageTotal);
                    break;
                case 4:
                    this.$emit('update', 'hour', this.checkboxString);
@@ -94,7 +86,7 @@
        }
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'checkboxString': 'checkboxChange'
@@ -102,15 +94,15 @@
    computed: {
        // è®¡ç®—两个周期值
        cycleTotal: function () {
            this.cycle01 = this.checkNum(this.cycle01, 0, 23)
            this.cycle02 = this.checkNum(this.cycle02, 0, 23)
            return this.cycle01 + '-' + this.cycle02;
            const cycle01 = this.checkNum(this.cycle01, 0, 22)
            const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 23)
            return cycle01 + '-' + cycle02;
        },
        // è®¡ç®—平均用到的值
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, 0, 23)
            this.average02 = this.checkNum(this.average02, 1, 23)
            return this.average01 + '/' + this.average02;
            const average01 = this.checkNum(this.average01, 0, 22)
            const average02 = this.checkNum(this.average02, 1, 23 - average01 || 0)
            return average01 + '/' + average02;
        },
        // è®¡ç®—勾选的checkbox值合集
        checkboxString: function () {
ruoyi-ui/src/components/Crontab/index.vue
@@ -2,7 +2,12 @@
  <div>
    <el-tabs type="border-card">
      <el-tab-pane label="秒" v-if="shouldHide('second')">
        <CrontabSecond @update="updateCrontabValue" :check="checkNumber" ref="cronsecond" />
        <CrontabSecond
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronsecond"
        />
      </el-tab-pane>
      <el-tab-pane label="分钟" v-if="shouldHide('min')">
@@ -268,7 +273,7 @@
          insValue = 5;
        } else {
          this.$refs[refName].checkboxList = value.split(",");
          insValue = 7;
          insValue = 6;
        }
      } else if (name == "year") {
        if (value == "") {
ruoyi-ui/src/components/Crontab/min.vue
@@ -9,16 +9,16 @@
        <el-form-item>
            <el-radio v-model='radioValue' :label="2">
                å‘¨æœŸä»Ž
                <el-input-number v-model='cycle01' :min="0" :max="60" /> -
                <el-input-number v-model='cycle02' :min="0" :max="60" /> åˆ†é’Ÿ
                <el-input-number v-model='cycle01' :min="0" :max="58" /> -
                <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> åˆ†é’Ÿ
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="3">
                ä»Ž
                <el-input-number v-model='average01' :min="0" :max="60" /> åˆ†é’Ÿå¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="0" :max="60" /> åˆ†é’Ÿæ‰§è¡Œä¸€æ¬¡
                <el-input-number v-model='average01' :min="0" :max="58" /> åˆ†é’Ÿå¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> åˆ†é’Ÿæ‰§è¡Œä¸€æ¬¡
            </el-radio>
        </el-form-item>
@@ -52,19 +52,15 @@
    methods: {
        // å•选按钮值变化时
        radioChange() {
            if (this.radioValue !== 1 && this.cron.second === '*') {
                this.$emit('update', 'second', '0', 'min');
            }
            switch (this.radioValue) {
                case 1:
                    this.$emit('update', 'min', '*', 'min');
                    this.$emit('update', 'hour', '*', 'min');
                    break;
                case 2:
                    this.$emit('update', 'min', this.cycle01 + '-' + this.cycle02, 'min');
                    this.$emit('update', 'min', this.cycleTotal, 'min');
                    break;
                case 3:
                    this.$emit('update', 'min', this.average01 + '/' + this.average02, 'min');
                    this.$emit('update', 'min', this.averageTotal, 'min');
                    break;
                case 4:
                    this.$emit('update', 'min', this.checkboxString, 'min');
@@ -92,7 +88,7 @@
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'checkboxString': 'checkboxChange',
@@ -100,15 +96,15 @@
    computed: {
        // è®¡ç®—两个周期值
        cycleTotal: function () {
            this.cycle01 = this.checkNum(this.cycle01, 0, 59)
            this.cycle02 = this.checkNum(this.cycle02, 0, 59)
            return this.cycle01 + '-' + this.cycle02;
            const cycle01 = this.checkNum(this.cycle01, 0, 58)
            const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
            return cycle01 + '-' + cycle02;
        },
        // è®¡ç®—平均用到的值
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, 0, 59)
            this.average02 = this.checkNum(this.average02, 1, 59)
            return this.average01 + '/' + this.average02;
            const average01 = this.checkNum(this.average01, 0, 58)
            const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
            return average01 + '/' + average02;
        },
        // è®¡ç®—勾选的checkbox值合集
        checkboxString: function () {
ruoyi-ui/src/components/Crontab/month.vue
@@ -9,16 +9,16 @@
        <el-form-item>
            <el-radio v-model='radioValue' :label="2">
                å‘¨æœŸä»Ž
                <el-input-number v-model='cycle01' :min="1" :max="12" /> -
                <el-input-number v-model='cycle02' :min="1" :max="12" /> æœˆ
                <el-input-number v-model='cycle01' :min="1" :max="11" /> -
                <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="12" /> æœˆ
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="3">
                ä»Ž
                <el-input-number v-model='average01' :min="1" :max="12" /> æœˆå¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="1" :max="12" /> æœˆæœˆæ‰§è¡Œä¸€æ¬¡
                <el-input-number v-model='average01' :min="1" :max="11" /> æœˆå¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="1" :max="12 - average01 || 0" /> æœˆæœˆæ‰§è¡Œä¸€æ¬¡
            </el-radio>
        </el-form-item>
@@ -51,29 +51,15 @@
    methods: {
        // å•选按钮值变化时
        radioChange() {
            if (this.radioValue === 1) {
                this.$emit('update', 'month', '*');
                this.$emit('update', 'year', '*');
            } else {
                if (this.cron.day === '*') {
                    this.$emit('update', 'day', '0', 'month');
                }
                if (this.cron.hour === '*') {
                    this.$emit('update', 'hour', '0', 'month');
                }
                if (this.cron.min === '*') {
                    this.$emit('update', 'min', '0', 'month');
                }
                if (this.cron.second === '*') {
                    this.$emit('update', 'second', '0', 'month');
                }
            }
            switch (this.radioValue) {
                case 1:
                    this.$emit('update', 'month', '*');
                    break;
                case 2:
                    this.$emit('update', 'month', this.cycle01 + '-' + this.cycle02);
                    this.$emit('update', 'month', this.cycleTotal);
                    break;
                case 3:
                    this.$emit('update', 'month', this.average01 + '/' + this.average02);
                    this.$emit('update', 'month', this.averageTotal);
                    break;
                case 4:
                    this.$emit('update', 'month', this.checkboxString);
@@ -100,7 +86,7 @@
        }
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'checkboxString': 'checkboxChange'
@@ -108,15 +94,15 @@
    computed: {
        // è®¡ç®—两个周期值
        cycleTotal: function () {
            this.cycle01 = this.checkNum(this.cycle01, 1, 12)
            this.cycle02 = this.checkNum(this.cycle02, 1, 12)
            return this.cycle01 + '-' + this.cycle02;
            const cycle01 = this.checkNum(this.cycle01, 1, 11)
            const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
            return cycle01 + '-' + cycle02;
        },
        // è®¡ç®—平均用到的值
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, 1, 12)
            this.average02 = this.checkNum(this.average02, 1, 12)
            return this.average01 + '/' + this.average02;
            const average01 = this.checkNum(this.average01, 1, 11)
            const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
            return average01 + '/' + average02;
        },
        // è®¡ç®—勾选的checkbox值合集
        checkboxString: function () {
ruoyi-ui/src/components/Crontab/result.vue
@@ -179,7 +179,7 @@
                            // èŽ·å–è¾¾åˆ°æ¡ä»¶çš„æ—¥æœŸæ˜¯æ˜ŸæœŸX
                            let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
                            // å½“星期日时
                            if (thisWeek == 0) {
                            if (thisWeek == 1) {
                                // å…ˆæ‰¾ä¸‹ä¸€ä¸ªæ—¥ï¼Œå¹¶åˆ¤æ–­æ˜¯å¦ä¸ºæœˆåº•
                                DD++;
                                thisDD = DD < 10 ? '0' + DD : DD;
@@ -187,7 +187,7 @@
                                if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
                                    DD -= 3;
                                }
                            } else if (thisWeek == 6) {
                            } else if (thisWeek == 7) {
                                // å½“星期6时只需判断不是1号就可进行操作
                                if (this.dayRuleSup !== 1) {
                                    DD--;
@@ -200,7 +200,7 @@
                            // èŽ·å–å½“å‰æ—¥æœŸæ˜¯å±žäºŽæ˜ŸæœŸå‡ 
                            let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
                            // æ ¡éªŒå½“前星期是否在星期池(dayRuleSup)中
                            if (Array.indexOf(this.dayRuleSup, thisWeek) < 0) {
                            if (this.dayRuleSup.indexOf(thisWeek) < 0) {
                                // å¦‚果到达最大值时
                                if (Di == DDate.length - 1) {
                                    resetDay();
@@ -385,7 +385,7 @@
                } else if (rule.indexOf('#') >= 0) {
                    this.dayRule = 'assWeek';
                    let matchRule = rule.match(/[0-9]{1}/g);
                    this.dayRuleSup = [Number(matchRule[0]), Number(matchRule[1])];
                    this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])];
                    this.dateArr[3] = [1];
                    if (this.dayRuleSup[1] == 7) {
                        this.dayRuleSup[1] = 0;
@@ -400,14 +400,6 @@
                } else if (rule !== '*' && rule !== '?') {
                    this.dayRule = 'weekDay';
                    this.dayRuleSup = this.getAssignArr(rule)
                }
                // å¦‚æžœweekDay时将7调整为0【week值0即是星期日】
                if (this.dayRule == 'weekDay') {
                    for (let i = 0; i < this.dayRuleSup.length; i++) {
                        if (this.dayRuleSup[i] == 7) {
                            this.dayRuleSup[i] = 0;
                        }
                    }
                }
            }
        },
@@ -543,14 +535,15 @@
            if (type == undefined) {
                return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
            } else if (type == 'week') {
                return week;
                // åœ¨quartz中 1为星期日
                return week + 1;
            }
        },
        // æ£€æŸ¥æ—¥æœŸæ˜¯å¦å­˜åœ¨
        checkDate(value) {
            let time = new Date(value);
            let format = this.formatDate(time)
            return value == format ? true : false;
            return value === format;
        }
    },
    watch: {
ruoyi-ui/src/components/Crontab/second.vue
@@ -9,16 +9,16 @@
        <el-form-item>
            <el-radio v-model='radioValue' :label="2">
                å‘¨æœŸä»Ž
                <el-input-number v-model='cycle01' :min="0" :max="60" /> -
                <el-input-number v-model='cycle02' :min="0" :max="60" /> ç§’
                <el-input-number v-model='cycle01' :min="0" :max="58" /> -
                <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> ç§’
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="3">
                ä»Ž
                <el-input-number v-model='average01' :min="0" :max="60" /> ç§’开始,每
                <el-input-number v-model='average02' :min="0" :max="60" /> ç§’执行一次
                <el-input-number v-model='average01' :min="0" :max="58" /> ç§’开始,每
                <el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> ç§’执行一次
            </el-radio>
        </el-form-item>
@@ -54,13 +54,12 @@
            switch (this.radioValue) {
                case 1:
                    this.$emit('update', 'second', '*', 'second');
                    this.$emit('update', 'min', '*', 'second');
                    break;
                case 2:
                    this.$emit('update', 'second', this.cycle01 + '-' + this.cycle02);
                    this.$emit('update', 'second', this.cycleTotal);
                    break;
                case 3:
                    this.$emit('update', 'second', this.average01 + '/' + this.average02);
                    this.$emit('update', 'second', this.averageTotal);
                    break;
                case 4:
                    this.$emit('update', 'second', this.checkboxString);
@@ -84,25 +83,10 @@
            if (this.radioValue == '4') {
                this.$emit('update', 'second', this.checkboxString);
            }
        },
        othChange() {
            // åè§£æž
            let ins = this.cron.second
            ('反解析 second', ins);
            if (ins === '*') {
                this.radioValue = 1;
            } else if (ins.indexOf('-') > -1) {
                this.radioValue = 2
            } else if (ins.indexOf('/') > -1) {
                this.radioValue = 3
            } else {
                this.radioValue = 4
                this.checkboxList = ins.split(',')
            }
        }
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'checkboxString': 'checkboxChange',
@@ -113,15 +97,15 @@
    computed: {
        // è®¡ç®—两个周期值
        cycleTotal: function () {
            this.cycle01 = this.checkNum(this.cycle01, 0, 59)
            this.cycle02 = this.checkNum(this.cycle02, 0, 59)
            return this.cycle01 + '-' + this.cycle02;
            const cycle01 = this.checkNum(this.cycle01, 0, 58)
            const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
            return cycle01 + '-' + cycle02;
        },
        // è®¡ç®—平均用到的值
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, 0, 59)
            this.average02 = this.checkNum(this.average02, 1, 59)
            return this.average01 + '/' + this.average02;
            const average01 = this.checkNum(this.average01, 0, 58)
            const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
            return average01 + '/' + average02;
        },
        // è®¡ç®—勾选的checkbox值合集
        checkboxString: function () {
ruoyi-ui/src/components/Crontab/week.vue
@@ -2,7 +2,7 @@
    <el-form size='small'>
        <el-form-item>
            <el-radio v-model='radioValue' :label="1">
                å‘¨ï¼Œå…è®¸çš„通配符[, - * / L #]
                å‘¨ï¼Œå…è®¸çš„通配符[, - * ? / L #]
            </el-radio>
        </el-form-item>
@@ -15,8 +15,25 @@
        <el-form-item>
            <el-radio v-model='radioValue' :label="3">
                å‘¨æœŸä»Žæ˜ŸæœŸ
                <el-input-number v-model='cycle01' :min="1" :max="7" /> -
                <el-input-number v-model='cycle02' :min="1" :max="7" />
                <el-select clearable v-model="cycle01">
                    <el-option
                        v-for="(item,index) of weekList"
                        :key="index"
                        :label="item.value"
                        :value="item.key"
                        :disabled="item.key === 1"
                    >{{item.value}}</el-option>
                </el-select>
                -
                <el-select clearable v-model="cycle02">
                    <el-option
                        v-for="(item,index) of weekList"
                        :key="index"
                        :label="item.value"
                        :value="item.key"
                        :disabled="item.key < cycle01 && item.key !== 1"
                    >{{item.value}}</el-option>
                </el-select>
            </el-radio>
        </el-form-item>
@@ -24,14 +41,18 @@
            <el-radio v-model='radioValue' :label="4">
                ç¬¬
                <el-input-number v-model='average01' :min="1" :max="4" /> å‘¨çš„æ˜ŸæœŸ
                <el-input-number v-model='average02' :min="1" :max="7" />
                <el-select clearable v-model="average02">
                    <el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
                </el-select>
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio v-model='radioValue' :label="5">
                æœ¬æœˆæœ€åŽä¸€ä¸ªæ˜ŸæœŸ
                <el-input-number v-model='weekday' :min="1" :max="7" />
                <el-select clearable v-model="weekday">
                    <el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
                </el-select>
            </el-radio>
        </el-form-item>
@@ -39,7 +60,7 @@
            <el-radio v-model='radioValue' :label="6">
                æŒ‡å®š
                <el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
                    <el-option v-for="(item,index) of weekList" :key="index" :value="index+1">{{item}}</el-option>
                    <el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="String(item.key)">{{item.value}}</el-option>
                </el-select>
            </el-radio>
        </el-form-item>
@@ -52,13 +73,42 @@
    data() {
        return {
            radioValue: 2,
            weekday: 1,
            cycle01: 1,
            cycle02: 2,
            weekday: 2,
            cycle01: 2,
            cycle02: 3,
            average01: 1,
            average02: 1,
            average02: 2,
            checkboxList: [],
            weekList: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            weekList: [
                {
                    key: 2,
                    value: '星期一'
                },
                {
                    key: 3,
                    value: '星期二'
                },
                {
                    key: 4,
                    value: '星期三'
                },
                {
                    key: 5,
                    value: '星期四'
                },
                {
                    key: 6,
                    value: '星期五'
                },
                {
                    key: 7,
                    value: '星期六'
                },
                {
                    key: 1,
                    value: '星期日'
                }
            ],
            checkNum: this.$options.propsData.check
        }
    },
@@ -67,45 +117,30 @@
    methods: {
        // å•选按钮值变化时
        radioChange() {
            if (this.radioValue === 1) {
                this.$emit('update', 'week', '*');
                this.$emit('update', 'year', '*');
            } else {
                if (this.cron.month === '*') {
                    this.$emit('update', 'month', '0', 'week');
                }
                if (this.cron.day === '*') {
                    this.$emit('update', 'day', '0', 'week');
                }
                if (this.cron.hour === '*') {
                    this.$emit('update', 'hour', '0', 'week');
                }
                if (this.cron.min === '*') {
                    this.$emit('update', 'min', '0', 'week');
                }
                if (this.cron.second === '*') {
                    this.$emit('update', 'second', '0', 'week');
                }
            if (this.radioValue !== 2 && this.cron.day !== '?') {
                this.$emit('update', 'day', '?', 'week');
            }
            switch (this.radioValue) {
                case 1:
                    this.$emit('update', 'week', '*');
                    break;
                case 2:
                    this.$emit('update', 'week', '?');
                    break;
                case 3:
                    this.$emit('update', 'week', this.cycle01 + '-' + this.cycle02);
                    this.$emit('update', 'week', this.cycleTotal);
                    break;
                case 4:
                    this.$emit('update', 'week', this.average01 + '#' + this.average02);
                    this.$emit('update', 'week', this.averageTotal);
                    break;
                case 5:
                    this.$emit('update', 'week', this.weekday + 'L');
                    this.$emit('update', 'week', this.weekdayCheck + 'L');
                    break;
                case 6:
                    this.$emit('update', 'week', this.checkboxString);
                    break;
            }
        },
        // æ ¹æ®äº’斥事件,更改radio的值
        // å‘¨æœŸä¸¤ä¸ªå€¼å˜åŒ–æ—¶
        cycleChange() {
@@ -133,7 +168,7 @@
        },
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'weekdayCheck': 'weekdayChange',
@@ -150,7 +185,7 @@
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, 1, 4)
            this.average02 = this.checkNum(this.average02, 1, 7)
            return this.average01 + '#' + this.average02;
            return this.average02 + '#' + this.average01;
        },
        // æœ€è¿‘的工作日(格式)
        weekdayCheck: function () {
ruoyi-ui/src/components/Crontab/year.vue
@@ -15,16 +15,16 @@
        <el-form-item>
            <el-radio :label="3" v-model='radioValue'>
                å‘¨æœŸä»Ž
                <el-input-number v-model='cycle01' :min='fullYear' /> -
                <el-input-number v-model='cycle02' :min='fullYear' />
                <el-input-number v-model='cycle01' :min='fullYear' :max="2098" /> -
                <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : fullYear + 1" :max="2099" />
            </el-radio>
        </el-form-item>
        <el-form-item>
            <el-radio :label="4" v-model='radioValue'>
                ä»Ž
                <el-input-number v-model='average01' :min='fullYear' /> å¹´å¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min='fullYear' /> å¹´æ‰§è¡Œä¸€æ¬¡
                <el-input-number v-model='average01' :min='fullYear' :max="2098"/> å¹´å¼€å§‹ï¼Œæ¯
                <el-input-number v-model='average02' :min="1" :max="2099 - average01 || fullYear" /> å¹´æ‰§è¡Œä¸€æ¬¡
            </el-radio>
        </el-form-item>
@@ -59,21 +59,6 @@
    methods: {
        // å•选按钮值变化时
        radioChange() {
            if (this.cron.month === '*') {
                this.$emit('update', 'month', '0', 'year');
            }
            if (this.cron.day === '*') {
                this.$emit('update', 'day', '0', 'year');
            }
            if (this.cron.hour === '*') {
                this.$emit('update', 'hour', '0', 'year');
            }
            if (this.cron.min === '*') {
                this.$emit('update', 'min', '0', 'year');
            }
            if (this.cron.second === '*') {
                this.$emit('update', 'second', '0', 'year');
            }
            switch (this.radioValue) {
                case 1:
                    this.$emit('update', 'year', '');
@@ -82,10 +67,10 @@
                    this.$emit('update', 'year', '*');
                    break;
                case 3:
                    this.$emit('update', 'year', this.cycle01 + '-' + this.cycle02);
                    this.$emit('update', 'year', this.cycleTotal);
                    break;
                case 4:
                    this.$emit('update', 'year', this.average01 + '/' + this.average02);
                    this.$emit('update', 'year', this.averageTotal);
                    break;
                case 5:
                    this.$emit('update', 'year', this.checkboxString);
@@ -112,7 +97,7 @@
        }
    },
    watch: {
        "radioValue": "radioChange",
        'radioValue': 'radioChange',
        'cycleTotal': 'cycleChange',
        'averageTotal': 'averageChange',
        'checkboxString': 'checkboxChange'
@@ -120,15 +105,15 @@
    computed: {
        // è®¡ç®—两个周期值
        cycleTotal: function () {
            this.cycle01 = this.checkNum(this.cycle01, this.fullYear, this.fullYear + 100)
            this.cycle02 = this.checkNum(this.cycle02, this.fullYear + 1, this.fullYear + 101)
            return this.cycle01 + '-' + this.cycle02;
            const cycle01 = this.checkNum(this.cycle01, this.fullYear, 2098)
            const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : this.fullYear + 1, 2099)
            return cycle01 + '-' + cycle02;
        },
        // è®¡ç®—平均用到的值
        averageTotal: function () {
            this.average01 = this.checkNum(this.average01, this.fullYear, this.fullYear + 100)
            this.average02 = this.checkNum(this.average02, 1, 10)
            return this.average01 + '/' + this.average02;
            const average01 = this.checkNum(this.average01, this.fullYear, 2098)
            const average02 = this.checkNum(this.average02, 1, 2099 - average01 || this.fullYear)
            return average01 + '/' + average02;
        },
        // è®¡ç®—勾选的checkbox值合集
        checkboxString: function () {
@@ -139,6 +124,8 @@
    mounted: function () {
        // ä»…获取当前年份
        this.fullYear = Number(new Date().getFullYear());
        this.cycle01 = this.fullYear
        this.average01 = this.fullYear
    }
}
</script>
ruoyi-ui/src/components/ImagePreview/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
<template>
    <el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="[`${realSrc}`]">
        <div slot="error" class="image-slot">
          <i class="el-icon-picture-outline"></i>
        </div>
    </el-image>
</template>
<script>
import { isExternal } from '@/utils/validate'
export default {
    name: 'ImagePreview',
    props: {
        src: {
            type: String,
            required: true
        },
        width: {
            type: [Number, String],
            default: ''
        },
        height: {
            type: [Number, String],
            default: ''
        }
    },
    computed: {
        realSrc() {
            if (isExternal(this.src)) {
                return this.src
            }
            return process.env.VUE_APP_BASE_API + this.src
        },
        realWidth() {
            return typeof this.width == 'string' ? this.width : `${this.width}px`
        },
        realHeight() {
            return typeof this.height == 'string' ? this.height : `${this.height}px`
        }
    }
}
</script>
<style lang="scss" scoped>
.el-image {
    border-radius: 5px;
    background-color: #ebeef5;
    box-shadow: 0 0 5px 1px #ccc;
    ::v-deep .el-image__inner {
        transition: all 0.3s;
        cursor: pointer;
        &:hover {
            transform: scale(1.2);
        }
    }
    ::v-deep .image-slot {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        color: #909399;
        font-size: 30px;
    }
}
</style>
ruoyi-ui/src/directive/index.js
@@ -3,10 +3,12 @@
import dialogDrag from './dialog/drag'
import dialogDragWidth from './dialog/dragWidth'
import dialogDragHeight from './dialog/dragHeight'
import clipboard from './module/clipboard'
const install = function(Vue) {
  Vue.directive('hasRole', hasRole)
  Vue.directive('hasPermi', hasPermi)
  Vue.directive('clipboard', clipboard)
  Vue.directive('dialogDrag', dialogDrag)
  Vue.directive('dialogDragWidth', dialogDragWidth)
  Vue.directive('dialogDragHeight', dialogDragHeight)
ruoyi-ui/src/directive/module/clipboard.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
/**
* v-clipboard æ–‡å­—复制剪贴
* Copyright (c) 2021 ruoyi
*/
import Clipboard from 'clipboard'
export default {
  bind(el, binding, vnode) {
    switch (binding.arg) {
      case 'success':
        el._vClipBoard_success = binding.value;
        break;
      case 'error':
        el._vClipBoard_error = binding.value;
        break;
      default: {
        const clipboard = new Clipboard(el, {
          text: () => binding.value,
          action: () => binding.arg === 'cut' ? 'cut' : 'copy'
        });
        clipboard.on('success', e => {
          const callback = el._vClipBoard_success;
          callback && callback(e);
        });
        clipboard.on('error', e => {
          const callback = el._vClipBoard_error;
          callback && callback(e);
        });
        el._vClipBoard = clipboard;
      }
    }
  },
  update(el, binding) {
    if (binding.arg === 'success') {
      el._vClipBoard_success = binding.value;
    } else if (binding.arg === 'error') {
      el._vClipBoard_error = binding.value;
    } else {
      el._vClipBoard.text = function () { return binding.value; };
      el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy';
    }
  },
  unbind(el, binding) {
    if (!el._vClipboard) return
    if (binding.arg === 'success') {
      delete el._vClipBoard_success;
    } else if (binding.arg === 'error') {
      delete el._vClipBoard_error;
    } else {
      el._vClipBoard.destroy();
      delete el._vClipBoard;
    }
  }
}
ruoyi-ui/src/main.js
@@ -29,6 +29,8 @@
import FileUpload from "@/components/FileUpload"
// å›¾ç‰‡ä¸Šä¼ ç»„ä»¶
import ImageUpload from "@/components/ImageUpload"
// å›¾ç‰‡é¢„览组件
import ImagePreview from "@/components/ImagePreview"
// å­—典标签组件
import DictTag from '@/components/DictTag'
// å¤´éƒ¨æ ‡ç­¾ç»„ä»¶
@@ -54,6 +56,7 @@
Vue.component('Editor', Editor)
Vue.component('FileUpload', FileUpload)
Vue.component('ImageUpload', ImageUpload)
Vue.component('ImagePreview', ImagePreview)
Vue.use(directive)
Vue.use(plugins)
ruoyi-ui/src/plugins/download.js
@@ -1,14 +1,17 @@
import axios from 'axios'
import { Message } from 'element-ui'
import {Loading, Message} from 'element-ui'
import { saveAs } from 'file-saver'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { blobValidate } from "@/utils/ruoyi";
const baseURL = process.env.VUE_APP_BASE_API
let downloadLoadingInstance;
export default {
  oss(ossId) {
    var url = baseURL + '/system/oss/download/' + ossId
    downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
    axios({
      method: 'get',
      url: url,
@@ -20,8 +23,13 @@
        const blob = new Blob([res.data], { type: 'application/octet-stream' })
        this.saveAs(blob, decodeURI(res.headers['download-filename']))
      } else {
        Message.error('无效的会话,或者会话已过期,请重新登录。');
        this.printErrMsg(res.data);
      }
      downloadLoadingInstance.close();
    }).catch((r) => {
      console.error(r)
      Message.error('下载文件出现错误,请联系管理员!')
      downloadLoadingInstance.close();
    })
  },
  zip(url, name) {
@@ -37,12 +45,18 @@
        const blob = new Blob([res.data], { type: 'application/zip' })
        this.saveAs(blob, name)
      } else {
        Message.error('无效的会话,或者会话已过期,请重新登录。');
        this.printErrMsg(res.data);
      }
    })
  },
  saveAs(text, name, opts) {
    saveAs(text, name, opts);
  },
  async printErrMsg(data) {
    const resText = await data.text();
    const rspObj = JSON.parse(resText);
    const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
    Message.error(errMsg);
  }
}
ruoyi-ui/src/plugins/modal.js
@@ -59,6 +59,14 @@
      type: "warning",
    })
  },
  // æäº¤å†…容
  prompt(content) {
    return MessageBox.prompt(content, "系统提示", {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: "warning",
    })
  },
  // æ‰“开遮罩层
  loading(content) {
    loadingInstance = Loading.service({
ruoyi-ui/src/router/index.js
@@ -17,6 +17,8 @@
 * redirect: noRedirect             // å½“设置 noRedirect çš„æ—¶å€™è¯¥è·¯ç”±åœ¨é¢åŒ…屑导航中不可被点击
 * name:'router-name'               // è®¾å®šè·¯ç”±çš„名字,一定要填写不然使用<keep-alive>时会出现各种问题
 * query: '{"id": 1, "name": "ry"}' // è®¿é—®è·¯ç”±çš„默认传递参数
 * roles: ['admin', 'common']       // è®¿é—®è·¯ç”±çš„角色权限
 * permissions: ['a:a:a', 'b:b:b']  // è®¿é—®è·¯ç”±çš„菜单权限
 * meta : {
    noCache: true                   // å¦‚果设置为true,则不会被 <keep-alive> ç¼“å­˜(默认 false)
    title: 'title'                  // è®¾ç½®è¯¥è·¯ç”±åœ¨ä¾§è¾¹æ å’Œé¢åŒ…屑中展示的名字
@@ -35,28 +37,28 @@
    children: [
      {
        path: '/redirect/:path(.*)',
        component: (resolve) => require(['@/views/redirect'], resolve)
        component: () => import('@/views/redirect')
      }
    ]
  },
  {
    path: '/login',
    component: (resolve) => require(['@/views/login'], resolve),
    component: () => import('@/views/login'),
    hidden: true
  },
  {
    path: '/register',
    component: (resolve) => require(['@/views/register'], resolve),
    component: () => import('@/views/register'),
    hidden: true
  },
  {
    path: '/404',
    component: (resolve) => require(['@/views/error/404'], resolve),
    component: () => import('@/views/error/404'),
    hidden: true
  },
  {
    path: '/401',
    component: (resolve) => require(['@/views/error/401'], resolve),
    component: () => import('@/views/error/401'),
    hidden: true
  },
  {
@@ -66,7 +68,7 @@
    children: [
      {
        path: 'index',
        component: (resolve) => require(['@/views/index'], resolve),
        component: () => import('@/views/index'),
        name: 'Index',
        meta: { title: '首页', icon: 'dashboard', affix: true }
      }
@@ -80,20 +82,25 @@
    children: [
      {
        path: 'profile',
        component: (resolve) => require(['@/views/system/user/profile/index'], resolve),
        component: () => import('@/views/system/user/profile/index'),
        name: 'Profile',
        meta: { title: '个人中心', icon: 'user' }
      }
    ]
  },
  }
]
// åŠ¨æ€è·¯ç”±ï¼ŒåŸºäºŽç”¨æˆ·æƒé™åŠ¨æ€åŽ»åŠ è½½
export const dynamicRoutes = [
  {
    path: '/system/user-auth',
    component: Layout,
    hidden: true,
    permissions: ['system:user:edit'],
    children: [
      {
        path: 'role/:userId(\\d+)',
        component: (resolve) => require(['@/views/system/user/authRole'], resolve),
        component: () => import('@/views/system/user/authRole'),
        name: 'AuthRole',
        meta: { title: '分配角色', activeMenu: '/system/user' }
      }
@@ -103,10 +110,11 @@
    path: '/system/role-auth',
    component: Layout,
    hidden: true,
    permissions: ['system:role:edit'],
    children: [
      {
        path: 'user/:roleId(\\d+)',
        component: (resolve) => require(['@/views/system/role/authUser'], resolve),
        component: () => import('@/views/system/role/authUser'),
        name: 'AuthUser',
        meta: { title: '分配用户', activeMenu: '/system/role' }
      }
@@ -116,10 +124,11 @@
    path: '/system/dict-data',
    component: Layout,
    hidden: true,
    permissions: ['system:dict:list'],
    children: [
      {
        path: 'index/:dictId(\\d+)',
        component: (resolve) => require(['@/views/system/dict/data'], resolve),
        component: () => import('@/views/system/dict/data'),
        name: 'Data',
        meta: { title: '字典数据', activeMenu: '/system/dict' }
      }
@@ -129,12 +138,13 @@
    path: '/system/oss-config',
    component: Layout,
    hidden: true,
    permissions: ['system:oss:list'],
    children: [
      {
        path: 'index',
        component: (resolve) => require(['@/views/system/oss/config'], resolve),
        component: () => import('@/views/system/oss/config'),
        name: 'OssConfig',
        meta: { title: '配置管理', activeMenu: '/system/oss'}
        meta: { title: '配置管理', activeMenu: '/system/oss' }
      }
    ]
  },
@@ -142,10 +152,11 @@
    path: '/tool/gen-edit',
    component: Layout,
    hidden: true,
    permissions: ['tool:gen:edit'],
    children: [
      {
        path: 'index',
        component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
        component: () => import('@/views/tool/gen/editTable'),
        name: 'GenEdit',
        meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
      }
ruoyi-ui/src/store/modules/permission.js
@@ -1,4 +1,5 @@
import { constantRoutes } from '@/router'
import auth from '@/plugins/auth'
import router, { constantRoutes, dynamicRoutes } from '@/router'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'
@@ -42,7 +43,9 @@
          const rdata = JSON.parse(JSON.stringify(res.data))
          const sidebarRoutes = filterAsyncRouter(sdata)
          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
          const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
          router.addRoutes(asyncRoutes);
          commit('SET_ROUTES', rewriteRoutes)
          commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
          commit('SET_DEFAULT_ROUTES', sidebarRoutes)
@@ -106,6 +109,23 @@
  return children
}
// åŠ¨æ€è·¯ç”±éåŽ†ï¼ŒéªŒè¯æ˜¯å¦å…·å¤‡æƒé™
export function filterDynamicRoutes(routes) {
  const res = []
  routes.forEach(route => {
    if (route.permissions) {
      if (auth.hasPermiOr(route.permissions)) {
        res.push(route)
      }
    } else if (route.roles) {
      if (auth.hasRoleOr(route.roles)) {
        res.push(route)
      }
    }
  })
  return res
}
export const loadView = (view) => {
  if (process.env.NODE_ENV === 'development') {
    return (resolve) => require([`@/views/${view}`], resolve)
ruoyi-ui/src/utils/request.js
@@ -110,7 +110,10 @@
      const blob = new Blob([data])
      saveAs(blob, filename)
    } else {
      Message.error('无效的会话,或者会话已过期,请重新登录。');
      const resText = await data.text();
      const rspObj = JSON.parse(resText);
      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
      Message.error(errMsg);
    }
    downloadLoadingInstance.close();
  }).catch((r) => {
ruoyi-ui/src/views/monitor/online/index.vue
@@ -111,7 +111,7 @@
    },
    /** å¼ºé€€æŒ‰é’®æ“ä½œ */
    handleForceLogout(row) {
      this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的数据项?').then(function() {
      this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function() {
        return forceLogout(row.tokenId);
      }).then(() => {
        this.getList();
ruoyi-ui/src/views/system/menu/index.vue
@@ -128,7 +128,7 @@
            </el-form-item>
          </el-col>
          <el-col :span="24" v-if="form.menuType != 'F'">
            <el-form-item label="菜单图标">
            <el-form-item label="菜单图标" prop="icon">
              <el-popover
                placement="bottom-start"
                width="460"
ruoyi-ui/src/views/system/user/authRole.vue
@@ -9,7 +9,7 @@
          </el-form-item>
        </el-col>
        <el-col :span="8" :offset="2">
          <el-form-item label="登录账号" prop="phonenumber">
          <el-form-item label="登录账号" prop="userName">
            <el-input  v-model="form.userName" disabled />
          </el-form-item>
        </el-col>
ruoyi-ui/src/views/system/user/index.vue
@@ -596,7 +596,7 @@
        cancelButtonText: "取消",
        closeOnClickModal: false,
        inputPattern: /^.{5,20}$/,
        inputErrorMessage: "用户密码长度必须介于 5 å’Œ 20 ä¹‹é—´",
        inputErrorMessage: "用户密码长度必须介于 5 å’Œ 20 ä¹‹é—´"
      }).then(({ value }) => {
          resetUserPwd(row.userId, value).then(response => {
            this.$modal.msgSuccess("修改成功,新密码是:" + value);
@@ -663,7 +663,7 @@
      this.upload.open = false;
      this.upload.isUploading = false;
      this.$refs.upload.clearFiles();
      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
      this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
      this.getList();
    },
    // æäº¤ä¸Šä¼ æ–‡ä»¶
ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
@@ -11,7 +11,6 @@
          <el-input placeholder="请输入" v-model="info.tableComment" />
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="实体类名称" prop="className">
          <el-input placeholder="请输入" v-model="info.className" />
@@ -30,9 +29,9 @@
    </el-row>
  </el-form>
</template>
<script>
export default {
  name: "BasicInfoForm",
  props: {
    info: {
      type: Object,
ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -124,6 +124,7 @@
    </el-form>
  </el-card>
</template>
<script>
import { getGenTable, updateGenTable } from "@/api/tool/gen";
import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
ruoyi-ui/src/views/tool/gen/genInfoForm.vue
@@ -11,7 +11,6 @@
          </el-select>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item prop="packageName">
          <span slot="label">
@@ -213,12 +212,12 @@
    </el-row>
  </el-form>
</template>
<script>
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "BasicInfoForm",
  components: { Treeselect },
  props: {
    info: {
ruoyi-ui/src/views/tool/gen/index.vue
@@ -169,7 +169,8 @@
          :name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
          :key="key"
        >
        <pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre>
          <el-link :underline="false" icon="el-icon-document-copy" v-clipboard:copy="value" v-clipboard:success="clipboardSuccess" style="float:right">复制</el-link>
          <pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre>
        </el-tab-pane>
      </el-tabs>
    </el-dialog>
@@ -306,6 +307,10 @@
      const result = hljs.highlight(language, code || "", true);
      return result.value || '&nbsp;';
    },
    /** å¤åˆ¶ä»£ç æˆåŠŸ */
    clipboardSuccess(){
      this.$modal.msgSuccess("复制成功");
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.tableId);
ruoyi-ui/vue.config.js
@@ -5,6 +5,8 @@
  return path.join(__dirname, dir)
}
const CompressionPlugin = require('compression-webpack-plugin')
const name = process.env.VUE_APP_TITLE || 'RuoYi-Vue-Plus后台管理系统' // ç½‘页标题
const port = process.env.port || process.env.npm_config_port || 80 // ç«¯å£
@@ -42,13 +44,29 @@
    },
    disableHostCheck: true
  },
  css: {
    loaderOptions: {
      sass: {
        sassOptions: { outputStyle: "expanded" }
      }
    }
  },
  configureWebpack: {
    name: name,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
    },
    plugins: [
      // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
      new CompressionPlugin({
        test: /\.(js|css|html)?$/i,     // åŽ‹ç¼©æ–‡ä»¶æ ¼å¼
        filename: '[path].gz[query]',   // åŽ‹ç¼©åŽçš„æ–‡ä»¶å
        algorithm: 'gzip',              // ä½¿ç”¨gzip压缩
        minRatio: 0.8                   // åŽ‹ç¼©çŽ‡å°äºŽ1才会压缩
      })
    ],
  },
  chainWebpack(config) {
    config.plugins.delete('preload') // TODO: need test
script/docker/nginx/nginx.conf
@@ -52,6 +52,16 @@
        #ssl_prefer_server_ciphers on;
        # https配置参考 end
        # æ¼”示环境配置 æ‹¦æˆªé™¤ GET POST ä¹‹å¤–的所有请求
        # if ($request_method !~* GET|POST) {
        #     rewrite  ^/(.*)$  /403;
        # }
        # location = /403 {
        #     default_type application/json;
        #     return 200 '{"msg":"演示模式,不允许操作","code":500}';
        # }
        location / {
            root   /usr/share/nginx/html;
            try_files $uri $uri/ /index.html;
@@ -66,6 +76,9 @@
            proxy_pass http://server/;
        }
        # https ä¼šæ‹¦æˆªå†…链所有的 http è¯·æ±‚ é€ æˆåŠŸèƒ½æ— æ³•ä½¿ç”¨
        # è§£å†³æ–¹æ¡ˆ1 å°† admin æœåŠ¡ ä¹Ÿé…ç½®æˆ https
        # è§£å†³æ–¹æ¡ˆ2 å°†èœå•配置为外链访问 èµ°ç‹¬ç«‹é¡µé¢ http è®¿é—®
        location /admin/ {
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
@@ -74,6 +87,9 @@
            proxy_pass http://monitor-admin/admin/;
        }
        # https ä¼šæ‹¦æˆªå†…链所有的 http è¯·æ±‚ é€ æˆåŠŸèƒ½æ— æ³•ä½¿ç”¨
        # è§£å†³æ–¹æ¡ˆ1 å°† xxljob æœåŠ¡ ä¹Ÿé…ç½®æˆ https
        # è§£å†³æ–¹æ¡ˆ2 å°†èœå•配置为外链访问 èµ°ç‹¬ç«‹é¡µé¢ http è®¿é—®
        location /xxl-job-admin/ {
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
script/docker/redis/redis.conf
@@ -1,6 +1,9 @@
# redis å¯†ç 
# requirepass ruoyi123
# key ç›‘听器配置
# notify-keyspace-events Ex
# é…ç½®æŒä¹…化文件存储路径
dir /redis/data
# é…ç½®rdb