From 5ba051c16ac788a06d5d433c5aa9d3d07b6ea9b6 Mon Sep 17 00:00:00 2001 From: dataprince Date: Tue, 15 Aug 2023 22:24:31 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=A1=B9=E7=9B=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E9=9B=86=E6=88=90Sa-Token=E3=80=81Lombok?= =?UTF-8?q?=E3=80=81Hutool=E7=AD=89=E8=BD=AF=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 227 ++++++-- ruoyi-admin/pom.xml | 57 +- .../main/java/com/ruoyi/RuoYiApplication.java | 2 +- .../ruoyi/web/controller/AuthController.java | 151 ++++++ .../web/controller/CaptchaController.java | 84 +++ .../{system => }/SysIndexController.java | 7 +- .../controller/common/CaptchaController.java | 94 ---- .../controller/common/CommonController.java | 6 +- .../controller/monitor/CacheController.java | 120 ----- .../monitor/SysUserOnlineController.java | 83 --- .../controller/system/SysLoginController.java | 86 --- .../system/SysRegisterController.java | 38 -- .../com/ruoyi/web/domain/vo/CaptchaVo.java | 25 + .../java/com/ruoyi/web/domain/vo/LoginVo.java | 54 ++ .../com/ruoyi/web/service/IAuthStrategy.java | 45 ++ .../ruoyi/web/service/SysLoginService.java | 175 +++++++ .../ruoyi/web/service/SysRegisterService.java | 115 ++++ .../web/service/impl/EmailAuthStrategy.java | 112 ++++ .../service/impl/PasswordAuthStrategy.java | 137 +++++ .../src/main/resources/application-dev.yml | 80 ++- .../src/main/resources/application-prod.yml | 110 ++++ .../src/main/resources/application.yml | 167 ++++-- .../main/resources/i18n/messages.properties | 37 +- .../resources/i18n/messages_en_US.properties | 57 ++ .../resources/i18n/messages_zh_CN.properties | 57 ++ ruoyi-common/pom.xml | 15 +- ruoyi-common/ruoyi-common-bom/pom.xml | 109 ++++ ruoyi-common/ruoyi-common-core/pom.xml | 76 ++- .../common/core/annotation/DataSource.java | 28 - .../com/ruoyi/common/core/annotation/Log.java | 51 -- .../common/core/config/ApplicationConfig.java | 18 + .../ruoyi/common/core/config/AsyncConfig.java | 48 ++ .../ruoyi/common/core/config/RuoYiConfig.java | 100 +--- .../common/core/config/ThreadPoolConfig.java | 76 +++ .../common/core/config/ValidatorConfig.java | 40 ++ .../properties/ThreadPoolProperties.java | 30 ++ .../common/core/constant/CacheConstants.java | 5 + .../common/core/constant/CacheNames.java | 63 +++ .../ruoyi/common/core/constant/Constants.java | 5 + .../common/core/constant/GlobalConstants.java | 39 ++ .../common/core/constant/TenantConstants.java | 45 ++ .../common/core/constant/UserConstants.java | 100 +++- .../common/core/core/domain/AjaxResult.java | 22 +- .../common/core/core/domain/BaseEntity.java | 121 ----- .../com/ruoyi/common/core/core/domain/R.java | 63 +-- .../common/core/core/domain/dto/RoleDTO.java | 38 ++ .../core/core/domain/dto/UserOnlineDTO.java | 62 +++ .../core/domain/model/EmailLoginBody.java | 35 ++ .../core/core/domain/model/LoginBody.java | 115 ++-- .../core/core/domain/model/LoginUser.java | 243 ++------- .../core/core/domain/model/RegisterBody.java | 9 +- .../common/core/core/page/PageDomain.java | 2 +- .../common/core/core/page/TableDataInfo.java | 17 +- .../common/core/core/page/TableSupport.java | 2 +- .../common/core/core/redis/RedisCache.java | 268 ---------- .../common/core/core/text/CharsetKit.java | 8 +- .../common/core/core/text/StrFormatter.java | 4 +- .../common/core/enums/DataSourceType.java | 19 - .../ruoyi/common/core/enums/DeviceType.java | 35 ++ .../ruoyi/common/core/enums/LoginType.java | 44 ++ .../com/ruoyi/common/core/enums/UserType.java | 41 ++ .../core/exception/GlobalException.java | 4 +- .../core/exception/ServiceException.java | 4 +- .../common/core/exception/UtilException.java | 3 + .../core/exception/base/BaseException.java | 3 + .../core/exception/file/FileException.java | 3 + .../FileNameLengthLimitExceededException.java | 3 + .../file/FileSizeLimitExceededException.java | 3 + .../exception/file/FileUploadException.java | 3 +- .../file/InvalidExtensionException.java | 2 + .../core/exception/job/TaskException.java | 3 + .../exception/user/BlackListException.java | 3 + .../core/exception/user/CaptchaException.java | 3 + .../user/CaptchaExpireException.java | 3 + .../core/exception/user/UserException.java | 7 +- .../user/UserNotExistsException.java | 3 + .../user/UserPasswordNotMatchException.java | 3 + ...UserPasswordRetryLimitExceedException.java | 3 + .../factory/YmlPropertySourceFactory.java | 31 ++ .../core/filter/PropertyPreExcludeFilter.java | 24 - .../common/core/manager/ShutdownManager.java | 41 ++ .../common/core/service/ConfigService.java | 18 + .../common/core/service/DeptService.java | 18 + .../common/core/service/DictService.java | 67 +++ .../common/core/service/UserService.java | 18 + .../ruoyi/common/core/utils/DictUtils.java | 186 ------- .../com/ruoyi/common/core/utils/LogUtils.java | 18 - .../common/core/utils/MapstructUtils.java | 93 ++++ .../ruoyi/common/core/utils/MessageUtils.java | 3 +- .../ruoyi/common/core/utils/PageUtils.java | 2 +- .../common/core/utils/SecurityUtils.java | 120 ----- .../ruoyi/common/core/utils/ServletUtils.java | 17 +- .../ruoyi/common/core/utils/SpringUtils.java | 101 ++++ .../ruoyi/common/core/utils/StreamUtils.java | 254 +++++++++ .../ruoyi/common/core/utils/StringUtils.java | 199 ++++--- .../com/ruoyi/common/core/utils/Threads.java | 11 +- .../common/core/utils/ValidatorUtils.java | 28 + .../common/core/utils/file/FileUtils.java | 11 +- .../common/core/utils/poi/ExcelUtil.java | 75 +-- .../core/utils/reflect/ReflectUtils.java | 95 ++-- .../common/core/utils/spring/SpringUtils.java | 158 ------ .../ruoyi/common/core/validate/AddGroup.java | 9 + .../ruoyi/common/core/validate/EditGroup.java | 9 + .../common/core/validate/QueryGroup.java | 9 + .../common/core/validate/auth/EmailGroup.java | 7 + .../core/validate/auth/PasswordGroup.java | 7 + .../common/core/validate/auth/SmsGroup.java | 7 + .../core/validate/auth/SocialGroup.java | 4 + .../core/validate/auth/WechatGroup.java | 7 + ...ot.autoconfigure.AutoConfiguration.imports | 5 + ruoyi-common/ruoyi-common-excel/pom.xml | 30 ++ .../common/excel/annotation/CellMerge.java | 24 + .../excel/annotation/ExcelDictFormat.java | 32 ++ .../excel/annotation/ExcelEnumFormat.java | 30 ++ .../excel/convert/ExcelBigNumberConvert.java | 52 ++ .../excel/convert/ExcelDictConvert.java | 73 +++ .../excel/convert/ExcelEnumConvert.java | 87 ++++ .../common/excel/core/CellMergeStrategy.java | 121 +++++ .../excel/core/DefaultExcelListener.java | 104 ++++ .../common/excel/core/DefaultExcelResult.java | 73 +++ .../common/excel/core/DropDownOptions.java | 149 ++++++ .../common/excel/core/ExcelDownHandler.java | 371 +++++++++++++ .../common/excel/core/ExcelListener.java | 14 + .../ruoyi/common/excel/core/ExcelResult.java | 26 + .../ruoyi/common/excel/utils/ExcelUtil.java | 380 ++++++++++++++ ruoyi-common/ruoyi-common-json/pom.xml | 37 ++ .../common/json/config/JacksonConfig.java | 47 ++ .../json/handler/BigNumberSerializer.java | 42 ++ .../ruoyi/common/json/utils/JsonUtils.java | 113 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-log/pom.xml | 37 ++ .../com/ruoyi/common/log/annotation/Log.java | 48 ++ .../ruoyi/common/log/aspect}/LogAspect.java | 226 ++++---- .../common/log}/enums/BusinessStatus.java | 8 +- .../ruoyi/common/log}/enums/BusinessType.java | 9 +- .../ruoyi/common/log}/enums/OperatorType.java | 7 +- .../common/log/event/LogininforEvent.java | 52 ++ .../ruoyi/common/log/event/OperLogEvent.java | 115 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../ruoyi-common-orm/mybatis-flex.config | 13 + ruoyi-common/ruoyi-common-orm/pom.xml | 45 ++ .../common/orm/annotation/DataColumn.java | 27 + .../common/orm/annotation/DataPermission.java | 17 + .../common/orm/config/MyBatisFlexConfig.java | 118 +++++ .../orm/config/MyBatisFlexInitConfig.java | 28 + .../orm/config/MyConfigurationCustomizer.java | 19 + .../common/orm/config/PagehelperConfig.java | 19 + .../common/orm/core/domain/BaseEntity.java | 73 +++ .../common/orm}/core/domain/TreeEntity.java | 4 +- .../orm/core/mapper/BaseMapperFlex.java | 192 +++++++ .../ruoyi/common/orm/core/page/PageQuery.java | 112 ++++ .../common/orm/core/page/TableDataInfo.java | 80 +++ .../ruoyi/common/orm/decipher/Decipher.java | 24 + .../ruoyi/common/orm/enums/DataBaseType.java | 49 ++ .../ruoyi/common/orm/enums/DataScopeType.java | 71 +++ .../orm/handler/MybatisExceptionHandler.java | 46 ++ .../handler/PlusDataPermissionHandler.java | 197 +++++++ .../common/orm/helper/DataBaseHelper.java | 69 +++ .../orm/helper/DataPermissionHelper.java | 90 ++++ .../orm/listener/EntityInsertListener.java | 26 + .../orm/listener/EntityUpdateListener.java | 21 + ...ot.autoconfigure.AutoConfiguration.imports | 4 + ruoyi-common/ruoyi-common-ratelimiter/pom.xml | 30 ++ .../ratelimiter/annotation/RateLimiter.java | 41 ++ .../aspectj/RateLimiterAspect.java | 127 +++++ .../ratelimiter/config/RateLimiterConfig.java | 20 + .../common/ratelimiter/enums/LimitType.java | 24 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-redis/pom.xml | 51 ++ .../common/redis/config/RedisConfig.java | 142 +++++ .../config/properties/RedissonProperties.java | 135 +++++ .../redis/handler/KeyPrefixHandler.java | 49 ++ .../redis/manager/FlexSpringCacheManager.java | 192 +++++++ .../ruoyi/common/redis/utils/CacheUtils.java | 75 +++ .../ruoyi/common/redis/utils/QueueUtils.java | 179 +++++++ .../ruoyi/common/redis/utils/RedisUtils.java | 489 ++++++++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-security/pom.xml | 46 ++ .../common/security/config/SaTokenConfig.java | 46 ++ .../security/config/SecurityConfig.java | 59 +++ .../config/properties/SecurityProperties.java | 21 + .../security/core/dao/FlexSaTokenDao.java | 176 +++++++ .../core/service/SaPermissionImpl.java | 47 ++ .../security/handler/AllUrlHandler.java | 39 ++ .../handler/GlobalExceptionHandler.java | 172 ++++++ .../security/listener/UserActionListener.java | 139 +++++ .../common/security/utils/LoginHelper.java | 172 ++++++ ...ot.autoconfigure.AutoConfiguration.imports | 4 + .../src/main/resources/common-satoken.yml | 13 + ruoyi-common/ruoyi-common-springdoc/pom.xml | 7 +- .../SpringDocConfig.java | 2 +- ruoyi-common/ruoyi-common-tenant/pom.xml | 36 ++ .../common/tenant/core/TenantEntity.java | 24 + .../common/tenant/core/TenantSaTokenDao.java | 148 ++++++ .../tenant/exception/TenantException.java | 20 + .../tenant/handle/PlusTenantLineHandler.java | 57 ++ .../tenant/handle/TenantKeyPrefixHandler.java | 58 +++ .../common/tenant/helper/TenantHelper.java | 138 +++++ .../manager/TenantSpringCacheManager.java | 32 ++ .../tenant/properties/TenantProperties.java | 27 + ruoyi-common/ruoyi-common-translation/pom.xml | 27 + .../translation/annotation/Translation.java | 39 ++ .../annotation/TranslationType.java | 23 + .../translation/config/TranslationConfig.java | 50 ++ .../translation/constant/TransConstant.java | 30 ++ .../core/TranslationInterface.java | 20 + .../TranslationBeanSerializerModifier.java | 29 ++ .../core/handler/TranslationHandler.java | 65 +++ .../core/impl/DeptNameTranslationImpl.java | 29 ++ .../core/impl/DictTypeTranslationImpl.java | 28 + .../core/impl/UserNameTranslationImpl.java | 27 + ...ot.autoconfigure.AutoConfiguration.imports | 4 + .../ruoyi-common-web}/pom.xml | 64 ++- .../common/web}/annotation/RepeatSubmit.java | 11 +- .../web/aspectj/RepeatSubmitAspect.java | 146 ++++++ .../common/web/config/CaptchaConfig.java | 65 +++ .../common/web}/config/FilterConfig.java | 49 +- .../ruoyi/common/web/config/I18nConfig.java | 22 + .../common/web/config/RepeatSubmitConfig.java | 21 + .../common/web}/config/ResourcesConfig.java | 46 +- .../common/web/config/UndertowConfig.java | 30 ++ .../config/properties/CaptchaProperties.java | 38 ++ .../web/config/properties/XssProperties.java | 30 ++ .../common/web/core}/BaseController.java | 54 +- .../common/web/core/I18nLocaleResolver.java | 31 ++ .../common/web/enums/CaptchaCategory.java | 35 ++ .../ruoyi/common/web/enums/CaptchaType.java | 29 ++ .../common/web}/filter/RepeatableFilter.java | 39 +- .../web}/filter/RepeatedlyRequestWrapper.java | 49 +- .../ruoyi/common/web}/filter/XssFilter.java | 52 +- .../filter/XssHttpServletRequestWrapper.java | 83 ++- .../FlexWebInvokeTimeInterceptor.java | 93 ++++ .../web/utils/UnsignedMathGenerator.java | 88 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 6 + ruoyi-extra/pom.xml | 19 + .../framework/aspectj/RateLimiterAspect.java | 89 ---- .../framework/config/ApplicationConfig.java | 30 -- .../ruoyi/framework/config/CaptchaConfig.java | 83 --- .../config/FastJson2JsonRedisSerializer.java | 48 -- .../framework/config/KaptchaTextCreator.java | 68 --- .../ruoyi/framework/config/MyBatisConfig.java | 47 -- .../ruoyi/framework/config/RedisConfig.java | 69 --- .../framework/config/SecurityConfig.java | 184 ------- .../framework/config/ThreadPoolConfig.java | 63 --- .../properties/PermitAllUrlProperties.java | 73 --- .../interceptor/RepeatSubmitInterceptor.java | 55 -- .../impl/SameUrlDataInterceptor.java | 110 ---- .../ruoyi/framework/manager/AsyncManager.java | 55 -- .../framework/manager/ShutdownManager.java | 39 -- .../manager/factory/AsyncFactory.java | 102 ---- .../context/AuthenticationContextHolder.java | 28 - .../context/PermissionContextHolder.java | 27 - .../filter/JwtAuthenticationTokenFilter.java | 44 -- .../handle/AuthenticationEntryPointImpl.java | 34 -- .../handle/LogoutSuccessHandlerImpl.java | 54 -- .../web/exception/GlobalExceptionHandler.java | 138 ----- .../web/service/PermissionService.java | 168 ------ .../web/service/SysLoginService.java | 181 ------- .../web/service/SysPasswordService.java | 94 ---- .../web/service/SysPermissionService.java | 83 --- .../web/service/SysRegisterService.java | 114 ---- .../framework/web/service/TokenService.java | 226 -------- .../web/service/UserDetailsServiceImpl.java | 66 --- ruoyi-modules/pom.xml | 3 +- ruoyi-modules/ruoyi-demo/pom.xml | 6 + .../controller/DemoCustomerController.java | 27 +- .../controller/DemoProductController.java | 27 +- .../controller/DemoStudentController.java | 27 +- .../com/ruoyi/demo/domain/DemoCustomer.java | 24 +- .../java/com/ruoyi/demo/domain/DemoGoods.java | 32 +- .../com/ruoyi/demo/domain/DemoProduct.java | 16 +- .../com/ruoyi/demo/domain/DemoStudent.java | 32 +- ruoyi-modules/ruoyi-generator/pom.xml | 8 +- .../generator/controller/GenController.java | 48 +- .../com/ruoyi/generator/domain/GenTable.java | 8 +- .../generator/domain/GenTableColumn.java | 7 +- .../service/GenTableColumnServiceImpl.java | 17 +- .../service/GenTableServiceImpl.java | 51 +- .../com/ruoyi/generator/util/GenUtils.java | 24 +- .../main/resources/vm/java/controller.java.vm | 19 +- .../src/main/resources/vm/java/domain.java.vm | 7 +- .../resources/vm/java/serviceImpl.java.vm | 18 +- .../main/resources/vm/java/sub-domain.java.vm | 6 +- ruoyi-modules/ruoyi-quartz/pom.xml | 7 +- .../quartz/controller/SysJobController.java | 39 +- .../controller/SysJobLogController.java | 31 +- .../java/com/ruoyi/quartz/domain/SysJob.java | 6 +- .../com/ruoyi/quartz/domain/SysJobLog.java | 8 +- .../ruoyi/quartz/util/AbstractQuartzJob.java | 2 +- .../com/ruoyi/quartz/util/JobInvokeUtil.java | 14 +- .../com/ruoyi/quartz/util/ScheduleUtils.java | 6 +- ruoyi-modules/ruoyi-system/pom.xml | 59 ++- .../system}/aspectj/DataScopeAspect.java | 100 ++-- .../ruoyi/system}/config/ServerConfig.java | 6 +- .../controller/monitor/CacheController.java | 143 +++++ .../controller/monitor/ServerController.java | 10 +- .../monitor/SysLogininforController.java | 51 +- .../monitor/SysOperlogController.java | 38 +- .../monitor/SysUserOnlineController.java | 85 +++ .../system/SysClientController.java | 101 ++++ .../system/SysConfigController.java | 40 +- .../controller/system/SysDeptController.java | 88 ++-- .../system/SysDictDataController.java | 47 +- .../system/SysDictTypeController.java | 40 +- .../controller/system/SysMenuController.java | 47 +- .../system/SysNoticeController.java | 34 +- .../controller/system/SysPostController.java | 47 +- .../system/SysProfileController.java | 71 ++- .../controller/system/SysRoleController.java | 85 ++- .../controller/system/SysUserController.java | 189 ++++--- .../java/com/ruoyi/system}/domain/Server.java | 18 +- .../com/ruoyi/system/domain/SysClient.java | 80 +++ .../com/ruoyi/system/domain/SysConfig.java | 9 +- .../com/ruoyi/system/domain}/SysDept.java | 20 +- .../com/ruoyi/system/domain}/SysDictData.java | 33 +- .../com/ruoyi/system/domain}/SysDictType.java | 31 +- .../ruoyi/system/domain/SysLogininfor.java | 6 +- .../com/ruoyi/system/domain}/SysMenu.java | 15 +- .../com/ruoyi/system/domain/SysNotice.java | 7 +- .../com/ruoyi/system/domain/SysOperLog.java | 4 +- .../java/com/ruoyi/system/domain/SysPost.java | 9 +- .../com/ruoyi/system/domain}/SysRole.java | 26 +- .../com/ruoyi/system/domain}/SysUser.java | 61 ++- .../ruoyi/system/domain/SysUserOnline.java | 123 ++--- .../com/ruoyi/system}/domain/TreeSelect.java | 8 +- .../ruoyi/system/domain/bo/SysClientBo.java | 79 +++ .../ruoyi/system/domain/bo/SysConfigBo.java | 62 +++ .../com/ruoyi/system/domain/bo/SysDeptBo.java | 73 +++ .../ruoyi/system/domain/bo/SysDictDataBo.java | 83 +++ .../ruoyi/system/domain/bo/SysDictTypeBo.java | 53 ++ .../system/domain/bo/SysLogininforBo.java | 77 +++ .../com/ruoyi/system/domain/bo/SysMenuBo.java | 111 ++++ .../ruoyi/system/domain/bo/SysNoticeBo.java | 65 +++ .../ruoyi/system/domain/bo/SysOperLogBo.java | 127 +++++ .../com/ruoyi/system/domain/bo/SysPostBo.java | 62 +++ .../com/ruoyi/system/domain/bo/SysRoleBo.java | 97 ++++ .../com/ruoyi/system/domain/bo/SysUserBo.java | 114 ++++ .../system/domain/bo/SysUserProfileBo.java | 55 ++ .../com/ruoyi/system}/domain/server/Cpu.java | 4 +- .../com/ruoyi/system}/domain/server/Jvm.java | 4 +- .../com/ruoyi/system}/domain/server/Mem.java | 4 +- .../com/ruoyi/system}/domain/server/Sys.java | 4 +- .../ruoyi/system}/domain/server/SysFile.java | 4 +- .../com/ruoyi/system/domain/vo/AvatarVo.java | 18 + .../system/domain/vo/CacheListInfoVo.java | 23 + .../system/domain/vo/DeptTreeSelectVo.java | 26 + .../system/domain/vo/MenuTreeSelectVo.java | 26 + .../com/ruoyi/system/domain/vo/ProfileVo.java | 29 ++ .../ruoyi/system/domain/vo/SysClientVo.java | 90 ++++ .../ruoyi/system/domain/vo/SysConfigVo.java | 72 +++ .../com/ruoyi/system/domain/vo/SysDeptVo.java | 91 ++++ .../ruoyi/system/domain/vo/SysDictDataVo.java | 88 ++++ .../ruoyi/system/domain/vo/SysDictTypeVo.java | 59 +++ .../system/domain/vo/SysLogininforVo.java | 92 ++++ .../com/ruoyi/system/domain/vo/SysMenuVo.java | 116 +++++ .../ruoyi/system/domain/vo/SysNoticeVo.java | 73 +++ .../ruoyi/system/domain/vo/SysOperLogVo.java | 144 ++++++ .../com/ruoyi/system/domain/vo/SysPostVo.java | 73 +++ .../com/ruoyi/system/domain/vo/SysRoleVo.java | 100 ++++ .../system/domain/vo/SysUserExportVo.java | 99 ++++ .../system/domain/vo/SysUserImportVo.java | 76 +++ .../ruoyi/system/domain/vo/SysUserInfoVo.java | 40 ++ .../com/ruoyi/system/domain/vo/SysUserVo.java | 141 +++++ .../ruoyi/system/domain/vo/UserInfoVo.java | 30 ++ .../ruoyi/system/mapper/SysClientMapper.java | 17 + .../ruoyi/system/mapper/SysDeptMapper.java | 31 +- .../system/mapper/SysDictDataMapper.java | 25 +- .../system/mapper/SysDictTypeMapper.java | 23 +- .../ruoyi/system/mapper/SysMenuMapper.java | 7 +- .../ruoyi/system/mapper/SysRoleMapper.java | 29 +- .../ruoyi/system/mapper/SysUserMapper.java | 38 +- .../system/service/ISysClientService.java | 15 + .../system/service/ISysConfigService.java | 28 +- .../ruoyi/system/service/ISysDeptService.java | 34 +- .../system/service/ISysDictDataService.java | 17 +- .../system/service/ISysDictTypeService.java | 31 +- .../ruoyi/system/service/ISysMenuService.java | 39 +- .../system/service/ISysPermissionService.java | 28 + .../ruoyi/system/service/ISysRoleService.java | 51 +- .../system/service/ISysUserOnlineService.java | 48 -- .../ruoyi/system/service/ISysUserService.java | 57 +- .../service/impl/SysClientServiceImpl.java | 19 + .../service/impl/SysConfigServiceImpl.java | 104 ++-- .../service/impl/SysDeptServiceImpl.java | 194 ++++--- .../service/impl/SysDictDataServiceImpl.java | 32 +- .../service/impl/SysDictTypeServiceImpl.java | 164 +++--- .../service/impl/SysMenuServiceImpl.java | 250 ++++----- .../impl/SysPermissionServiceImpl.java | 61 +++ .../service/impl/SysPostServiceImpl.java | 27 +- .../service/impl/SysRoleServiceImpl.java | 237 ++++----- .../impl/SysUserOnlineServiceImpl.java | 96 ---- .../service/impl/SysUserServiceImpl.java | 270 +++++----- .../mapper/system/SysClientMapper.xml | 28 + .../mapper/system/SysDictDataMapper.xml | 41 +- .../mapper/system/SysDictTypeMapper.xml | 31 +- .../resources/mapper/system/SysUserMapper.xml | 58 ++- ruoyi-ui/package.json | 2 +- ruoyi-ui/src/api/login.js | 16 +- ruoyi-ui/src/store/modules/user.js | 3 +- ruoyi-ui/src/views/login.vue | 63 ++- sql/update.sql | 132 +++++ 401 files changed, 16632 insertions(+), 6914 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java rename ruoyi-admin/src/main/java/com/ruoyi/web/controller/{system => }/SysIndexController.java (84%) delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java delete mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/CaptchaVo.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/LoginVo.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java create mode 100644 ruoyi-admin/src/main/resources/application-prod.yml create mode 100644 ruoyi-admin/src/main/resources/i18n/messages_en_US.properties create mode 100644 ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties create mode 100644 ruoyi-common/ruoyi-common-bom/pom.xml delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-excel/pom.xml create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelDownHandler.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelListener.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelResult.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/utils/ExcelUtil.java create mode 100644 ruoyi-common/ruoyi-common-json/pom.xml create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/config/JacksonConfig.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/handler/BigNumberSerializer.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/utils/JsonUtils.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-log/pom.xml create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java rename {ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj => ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect}/LogAspect.java (52%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-log/src/main/java/com/ruoyi/common/log}/enums/BusinessStatus.java (65%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-log/src/main/java/com/ruoyi/common/log}/enums/BusinessType.java (86%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-log/src/main/java/com/ruoyi/common/log}/enums/OperatorType.java (73%) create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/LogininforEvent.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/OperLogEvent.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-orm/mybatis-flex.config create mode 100644 ruoyi-common/ruoyi-common-orm/pom.xml create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataColumn.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataPermission.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexConfig.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexInitConfig.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyConfigurationCustomizer.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/PagehelperConfig.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/BaseEntity.java rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-orm/src/main/java/com/ruoyi/common/orm}/core/domain/TreeEntity.java (96%) create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/mapper/BaseMapperFlex.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/PageQuery.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/TableDataInfo.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/decipher/Decipher.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataBaseType.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataScopeType.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/MybatisExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/PlusDataPermissionHandler.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataBaseHelper.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataPermissionHelper.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityInsertListener.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityUpdateListener.java create mode 100644 ruoyi-common/ruoyi-common-orm/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/pom.xml create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/config/RateLimiterConfig.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/enums/LimitType.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-redis/pom.xml create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/properties/RedissonProperties.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/handler/KeyPrefixHandler.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/CacheUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/QueueUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/RedisUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-security/pom.xml create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SaTokenConfig.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/properties/SecurityProperties.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/service/SaPermissionImpl.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/AllUrlHandler.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/listener/UserActionListener.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/LoginHelper.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-security/src/main/resources/common-satoken.yml rename ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/{springdoc => security}/SpringDocConfig.java (98%) create mode 100644 ruoyi-common/ruoyi-common-tenant/pom.xml create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantEntity.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/exception/TenantException.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/PlusTenantLineHandler.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/properties/TenantProperties.java create mode 100644 ruoyi-common/ruoyi-common-translation/pom.xml create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/Translation.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/TranslationType.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/config/TranslationConfig.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/constant/TransConstant.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/TranslationInterface.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationBeanSerializerModifier.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationHandler.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DeptNameTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DictTypeTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/UserNameTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename {ruoyi-framework => ruoyi-common/ruoyi-common-web}/pom.xml (54%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-web/src/main/java/com/ruoyi/common/web}/annotation/RepeatSubmit.java (69%) create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/aspectj/RepeatSubmitAspect.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/CaptchaConfig.java rename {ruoyi-framework/src/main/java/com/ruoyi/framework => ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web}/config/FilterConfig.java (58%) create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/RepeatSubmitConfig.java rename {ruoyi-framework/src/main/java/com/ruoyi/framework => ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web}/config/ResourcesConfig.java (51%) create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/UndertowConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/CaptchaProperties.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/XssProperties.java rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/controller => ruoyi-common-web/src/main/java/com/ruoyi/common/web/core}/BaseController.java (84%) create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaCategory.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaType.java rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-web/src/main/java/com/ruoyi/common/web}/filter/RepeatableFilter.java (55%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-web/src/main/java/com/ruoyi/common/web}/filter/RepeatedlyRequestWrapper.java (70%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-web/src/main/java/com/ruoyi/common/web}/filter/XssFilter.java (64%) rename ruoyi-common/{ruoyi-common-core/src/main/java/com/ruoyi/common/core => ruoyi-common-web/src/main/java/com/ruoyi/common/web}/filter/XssHttpServletRequestWrapper.java (59%) create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/interceptor/FlexWebInvokeTimeInterceptor.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/utils/UnsignedMathGenerator.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-extra/pom.xml delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java delete mode 100644 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java rename {ruoyi-framework/src/main/java/com/ruoyi/framework => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/aspectj/DataScopeAspect.java (64%) rename {ruoyi-framework/src/main/java/com/ruoyi/framework => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/config/ServerConfig.java (94%) create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/monitor/ServerController.java (72%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/monitor/SysLogininforController.java (64%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/monitor/SysOperlogController.java (71%) create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysClientController.java rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysConfigController.java (81%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysDeptController.java (62%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysDictDataController.java (77%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysDictTypeController.java (80%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysMenuController.java (78%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysNoticeController.java (75%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysPostController.java (74%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysProfileController.java (66%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysRoleController.java (76%) rename {ruoyi-admin/src/main/java/com/ruoyi/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/controller/system/SysUserController.java (59%) rename {ruoyi-framework/src/main/java/com/ruoyi/framework/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/Server.java (95%) create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysClient.java rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain}/SysDept.java (92%) rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain}/SysDictData.java (85%) rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain}/SysDictType.java (73%) rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain}/SysMenu.java (96%) rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain}/SysRole.java (93%) rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain}/SysUser.java (84%) rename {ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/TreeSelect.java (90%) create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysClientBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysConfigBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDeptBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictDataBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictTypeBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysLogininforBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysMenuBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysNoticeBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOperLogBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysPostBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysRoleBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java rename {ruoyi-framework/src/main/java/com/ruoyi/framework/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/server/Cpu.java (96%) rename {ruoyi-framework/src/main/java/com/ruoyi/framework/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/server/Jvm.java (97%) rename {ruoyi-framework/src/main/java/com/ruoyi/framework/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/server/Mem.java (94%) rename {ruoyi-framework/src/main/java/com/ruoyi/framework/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/server/Sys.java (95%) rename {ruoyi-framework/src/main/java/com/ruoyi/framework/web => ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system}/domain/server/SysFile.java (96%) create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AvatarVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CacheListInfoVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeptTreeSelectVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuTreeSelectVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ProfileVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysClientVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysConfigVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDeptVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictDataVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictTypeVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysLogininforVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysMenuVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysNoticeVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysPostVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysRoleVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserInfoVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserInfoVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysClientMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysClientService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java delete mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysClientServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java delete mode 100644 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml diff --git a/pom.xml b/pom.xml index 592c75a..6a95a85 100644 --- a/pom.xml +++ b/pom.xml @@ -3,22 +3,23 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - + com.ruoyi ruoyi-flex ${revision} Ruoyi-Flex - http://www.ruoyi.vip - 若依管理系统 - + https://gitee.com/dataprince/ruoyi-flex + Ruoyi-Flex管理系统 + - 4.1.3 + 4.1.4-SNAPSHOT UTF-8 UTF-8 17 - 3.0.8 - 1.5.3 + 3.1.2 + 1.5.7 + 1.35.0.RC 8.0.33 3.1.1 5.0.1 @@ -30,7 +31,8 @@ 6.4.3 2.11.0 3.2.2 - 4.1.2 + 5.2.3 + 3.3.2 2.3 0.9.1 6.0.0 @@ -39,14 +41,47 @@ 2.1.0 2.1.0 0.15.0 + 1.18.28 + 1.3.5 + 0.2.0 + 5.8.21 + 3.23.2 + 2.2.4 + 2.14.3 + + 3.2.2 + 3.2.2 3.11.0 + 3.1.2 + 1.3.0 - + + + + dev + + + dev + debug + + + + true + + + + prod + + prod + warn + + + + - org.springframework.boot @@ -56,10 +91,27 @@ import + + + cn.hutool + hutool-bom + ${hutool.version} + pom + import + + + + + com.ruoyi + ruoyi-common-bom + ${revision} + pom + import + + org.springframework.boot spring-boot-starter-jdbc - ${spring-boot.version} @@ -76,6 +128,30 @@ ${mybatis-flex.version} + + + cn.dev33 + sa-token-spring-boot3-starter + ${satoken.version} + + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-all + + + + + cn.dev33 + sa-token-core + ${satoken.version} + + mysql @@ -124,12 +200,30 @@ + + org.apache.poi + poi + ${poi.version} + + org.apache.poi poi-ooxml ${poi.version} + + com.alibaba + easyexcel + ${easyexcel.version} + + + org.apache.poi + poi-ooxml-schemas + + + + org.apache.velocity @@ -185,7 +279,6 @@ ${springdoc.version} - org.springdoc springdoc-openapi-starter-common @@ -198,6 +291,45 @@ ${therapi-runtime-javadoc.version} + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + ${mapstruct-plus.version} + + + + + org.projectlombok + lombok + ${lombok.version} + + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + + com.alibaba + transmittable-thread-local + ${alibaba-ttl.version} + + com.ruoyi @@ -212,13 +344,6 @@ ${revision} - - - com.ruoyi - ruoyi-framework - ${revision} - - com.ruoyi @@ -226,20 +351,6 @@ ${revision} - - - com.ruoyi - ruoyi-common-core - ${revision} - - - - - com.ruoyi - ruoyi-common-springdoc - ${revision} - - com.ruoyi @@ -252,8 +363,8 @@ ruoyi-admin - ruoyi-framework ruoyi-common + ruoyi-extra ruoyi-modules pom @@ -274,7 +385,35 @@ therapi-runtime-javadoc-scribe ${therapi-runtime-javadoc.version} + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + io.github.linpeilie + mapstruct-plus-processor + ${mapstruct-plus.version} + + + org.projectlombok + lombok-mapstruct-binding + ${mapstruct-plus.lombok.version} + + + com.mybatis-flex + mybatis-flex-processor + ${mybatis-flex.version} + + + -parameters + @@ -307,6 +446,24 @@ + + + src/main/resources + + false + + + src/main/resources + + + application* + bootstrap* + banner* + + + true + + @@ -334,4 +491,4 @@ - \ No newline at end of file + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 587a65e..fa9e812 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -3,12 +3,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - ruoyi-flex com.ruoyi + ruoyi-flex ${revision} 4.0.0 jar + ruoyi-admin @@ -30,16 +31,22 @@ mysql-connector-java + + + org.postgresql + postgresql + + com.mybatis-flex mybatis-flex-spring-boot-starter - + com.ruoyi - ruoyi-framework + ruoyi-system @@ -54,13 +61,6 @@ ruoyi-generator - - - com.ruoyi - ruoyi-common-springdoc - ${revision} - - com.ruoyi @@ -74,29 +74,34 @@ org.springframework.boot spring-boot-maven-plugin - 2.1.1.RELEASE + ${spring-boot.version} - true + - - - - repackage - - - + + + + + + + - - org.apache.maven.plugins - maven-war-plugin - 3.1.0 + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} false ${project.artifactId} - - + + ${project.artifactId} - \ No newline at end of file + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java index 68c7cd2..b69b609 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java @@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 启动程序 - * + * * @author ruoyi */ @SpringBootApplication diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java new file mode 100644 index 0000000..40cb4aa --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java @@ -0,0 +1,151 @@ +package com.ruoyi.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +import com.mybatisflex.core.query.QueryWrapper; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.core.domain.AjaxResult; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.service.*; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.core.domain.R; +import com.ruoyi.common.core.core.domain.model.LoginBody; +import com.ruoyi.common.core.core.domain.model.RegisterBody; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.domain.SysClient; +import com.ruoyi.web.service.IAuthStrategy; +import com.ruoyi.web.service.SysLoginService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Set; + +import static com.ruoyi.system.domain.table.SysClientTableDef.SYS_CLIENT; + + +/** + * 认证 + * + * @author Lion Li + */ +@Slf4j +@SaIgnore +@Validated +@RequiredArgsConstructor +@RestController +public class AuthController { + + @Resource + private final SysLoginService loginService; + @Resource + private final ISysClientService clientService; + @Resource + private final ISysUserService sysUserService; + @Resource + private final ISysPermissionService permissionService; + @Resource + private ISysMenuService menuService; + + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @PostMapping("/login") + public AjaxResult login(@Validated @RequestBody LoginBody loginBody) { + + AjaxResult ajax = AjaxResult.success(); + // 授权类型和客户端id + String clientId = loginBody.getClientId(); + String grantType = loginBody.getGrantType(); + QueryWrapper query=QueryWrapper.create().from(SYS_CLIENT).where(SYS_CLIENT.CLIENT_ID.eq(clientId)); + SysClient client = clientService.getOne(query); + // 查询不到 client 或 client 内不包含 grantType + if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { + log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); + return AjaxResult.error(MessageUtils.message("auth.grant.type.error")); + } + + // TODO:校验租户 + //loginService.checkTenant(loginBody.getTenantId()); + + // 生成令牌 + String token =IAuthStrategy.login(loginBody, client); + ajax.put(Constants.TOKEN, token); + + // 登录 + return ajax; + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("/getInfo") + public AjaxResult getInfo() { + + LoginUser loginUser = LoginHelper.getLoginUser(); + + //TODO:多租户 超级管理员 如果重新加载用户信息需清除动态租户 + + SysUser user = sysUserService.selectUserById(loginUser.getUserId()); + // 角色集合 + Set roles = permissionService.getRolePermission(user.getUserId()); + // 权限集合 + Set permissions = permissionService.getMenuPermission(user.getUserId()); + + AjaxResult ajax = AjaxResult.success(); + ajax.put("user", user); + ajax.put("roles", roles); + ajax.put("permissions", permissions); + return ajax; + } + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("/getRouters") + public AjaxResult getRouters() + { + LoginUser loginUser = LoginHelper.getLoginUser(); + // 用户信息 + SysUser user = sysUserService.selectUserById(loginUser.getUserId()); + List menus = menuService.selectMenuTreeByUserId(user.getUserId()); + return AjaxResult.success(menuService.buildMenus(menus)); + } + + /** + * 退出登录 + */ + @PostMapping("/logout") + public AjaxResult logout() { + loginService.logout(); + return AjaxResult.error("退出成功!"); + } + + /** + * 用户注册 + */ + @PostMapping("LoginHelper.getUserId()") + public R register(@Validated @RequestBody RegisterBody user) { + //if (!configService.selectRegisterEnabled(user.getTenantId())) // TODO:注册代码 + { + return R.fail("当前系统没有开启注册功能!"); + } +// registerService.register(user); +// return R.ok(); + } + + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java new file mode 100644 index 0000000..99a0dc6 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java @@ -0,0 +1,84 @@ +package com.ruoyi.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import java.time.Duration; + +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.util.IdUtil; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.core.domain.AjaxResult; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.reflect.ReflectUtils; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.core.domain.R; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.web.enums.CaptchaType; +import com.ruoyi.web.domain.vo.CaptchaVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.web.config.properties.CaptchaProperties; + +/** + * 验证码操作处理 + * + * @author ruoyi + */ +@SaIgnore +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +public class CaptchaController +{ + private final CaptchaProperties captchaProperties; + + /** + * 生成验证码 + */ + @GetMapping("/captchaImage") + public AjaxResult getCode() { + CaptchaVo captchaVo = new CaptchaVo(); + boolean captchaEnabled = captchaProperties.getEnable(); + if (!captchaEnabled) { + captchaVo.setCaptchaEnabled(false); + return AjaxResult.success(captchaVo); + } + // 保存验证码信息 + String uuid = IdUtil.simpleUUID(); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; + // 生成验证码 + CaptchaType captchaType = captchaProperties.getType(); + boolean isMath = CaptchaType.MATH == captchaType; + Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); + CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); + AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); + captcha.setGenerator(codeGenerator); + captcha.createCode(); + String code = captcha.getCode(); + if (isMath) { + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); + code = exp.getValue(String.class); + } + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + +// AjaxResult ajax = AjaxResult.success(); +// ajax.put("uuid", uuid); +// ajax.put("img", captcha.getImageBase64()); +// return ajax; + + captchaVo.setUuid(uuid); + captchaVo.setImg(captcha.getImageBase64()); + return AjaxResult.success(captchaVo); + + + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/SysIndexController.java similarity index 84% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java rename to ruoyi-admin/src/main/java/com/ruoyi/web/controller/SysIndexController.java index 645bb5f..f600ce2 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/SysIndexController.java @@ -1,5 +1,7 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.web.controller; +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -11,11 +13,12 @@ import com.ruoyi.common.core.utils.StringUtils; * * @author ruoyi */ +@SaIgnore @RestController public class SysIndexController { /** 系统基础配置 */ - @Autowired + @Resource private RuoYiConfig ruoyiConfig; /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java deleted file mode 100644 index 79002cb..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.ruoyi.web.controller.common; - -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import jakarta.annotation.Resource; -import javax.imageio.ImageIO; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.FastByteArrayOutputStream; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; -import com.google.code.kaptcha.Producer; -import com.ruoyi.common.core.config.RuoYiConfig; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.utils.sign.Base64; -import com.ruoyi.common.core.utils.uuid.IdUtils; -import com.ruoyi.system.service.ISysConfigService; - -/** - * 验证码操作处理 - * - * @author ruoyi - */ -@RestController -public class CaptchaController -{ - @Resource(name = "captchaProducer") - private Producer captchaProducer; - - @Resource(name = "captchaProducerMath") - private Producer captchaProducerMath; - - @Autowired - private RedisCache redisCache; - - @Autowired - private ISysConfigService configService; - /** - * 生成验证码 - */ - @GetMapping("/captchaImage") - public AjaxResult getCode(HttpServletResponse response) throws IOException - { - AjaxResult ajax = AjaxResult.success(); - boolean captchaEnabled = configService.selectCaptchaEnabled(); - ajax.put("captchaEnabled", captchaEnabled); - if (!captchaEnabled) - { - return ajax; - } - - // 保存验证码信息 - String uuid = IdUtils.simpleUUID(); - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; - - String capStr = null, code = null; - BufferedImage image = null; - - // 生成验证码 - String captchaType = RuoYiConfig.getCaptchaType(); - if ("math".equals(captchaType)) - { - String capText = captchaProducerMath.createText(); - capStr = capText.substring(0, capText.lastIndexOf("@")); - code = capText.substring(capText.lastIndexOf("@") + 1); - image = captchaProducerMath.createImage(capStr); - } - else if ("char".equals(captchaType)) - { - capStr = code = captchaProducer.createText(); - image = captchaProducer.createImage(capStr); - } - - redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); - // 转换流信息写出 - FastByteArrayOutputStream os = new FastByteArrayOutputStream(); - try - { - ImageIO.write(image, "jpg", os); - } - catch (IOException e) - { - return AjaxResult.error(e.getMessage()); - } - - ajax.put("uuid", uuid); - ajax.put("img", Base64.encode(os.toByteArray())); - return ajax; - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java index 88e197a..ac261cc 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java @@ -19,11 +19,11 @@ import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.file.FileUploadUtils; import com.ruoyi.common.core.utils.file.FileUtils; -import com.ruoyi.framework.config.ServerConfig; +import com.ruoyi.system.config.ServerConfig; /** * 通用请求处理 - * + * * @author ruoyi */ @RestController @@ -39,7 +39,7 @@ public class CommonController /** * 通用下载请求 - * + * * @param fileName 文件名称 * @param delete 是否删除 */ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java deleted file mode 100644 index e0ffd5a..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.ruoyi.web.controller.monitor; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisCallback; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.system.domain.SysCache; - -/** - * 缓存监控 - * - * @author ruoyi - */ -@RestController -@RequestMapping("/monitor/cache") -public class CacheController -{ - @Autowired - private RedisTemplate redisTemplate; - - private final static List caches = new ArrayList(); - { - caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); - caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息")); - caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典")); - caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); - caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); - caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); - caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @GetMapping() - public AjaxResult getInfo() throws Exception - { - Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); - Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); - Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); - - Map result = new HashMap<>(3); - result.put("info", info); - result.put("dbSize", dbSize); - - List> pieList = new ArrayList<>(); - commandStats.stringPropertyNames().forEach(key -> { - Map data = new HashMap<>(2); - String property = commandStats.getProperty(key); - data.put("name", StringUtils.removeStart(key, "cmdstat_")); - data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); - pieList.add(data); - }); - result.put("commandStats", pieList); - return AjaxResult.success(result); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @GetMapping("/getNames") - public AjaxResult cache() - { - return AjaxResult.success(caches); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @GetMapping("/getKeys/{cacheName}") - public AjaxResult getCacheKeys(@PathVariable String cacheName) - { - Set cacheKeys = redisTemplate.keys(cacheName + "*"); - return AjaxResult.success(cacheKeys); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @GetMapping("/getValue/{cacheName}/{cacheKey}") - public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) - { - String cacheValue = redisTemplate.opsForValue().get(cacheKey); - SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue); - return AjaxResult.success(sysCache); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @DeleteMapping("/clearCacheName/{cacheName}") - public AjaxResult clearCacheName(@PathVariable String cacheName) - { - Collection cacheKeys = redisTemplate.keys(cacheName + "*"); - redisTemplate.delete(cacheKeys); - return AjaxResult.success(); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @DeleteMapping("/clearCacheKey/{cacheKey}") - public AjaxResult clearCacheKey(@PathVariable String cacheKey) - { - redisTemplate.delete(cacheKey); - return AjaxResult.success(); - } - - @PreAuthorize("@ss.hasPermi('monitor:cache:list')") - @DeleteMapping("/clearCacheAll") - public AjaxResult clearCacheAll() - { - Collection cacheKeys = redisTemplate.keys("*"); - redisTemplate.delete(cacheKeys); - return AjaxResult.success(); - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java deleted file mode 100644 index 895d67a..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.ruoyi.web.controller.monitor; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.core.controller.BaseController; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.enums.BusinessType; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.system.domain.SysUserOnline; -import com.ruoyi.system.service.ISysUserOnlineService; - -/** - * 在线用户监控 - * - * @author ruoyi - */ -@RestController -@RequestMapping("/monitor/online") -public class SysUserOnlineController extends BaseController -{ - @Autowired - private ISysUserOnlineService userOnlineService; - - @Autowired - private RedisCache redisCache; - - @PreAuthorize("@ss.hasPermi('monitor:online:list')") - @GetMapping("/list") - public TableDataInfo list(String ipaddr, String userName) - { - Collection keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*"); - List userOnlineList = new ArrayList<>(); - for (String key : keys) - { - LoginUser user = redisCache.getCacheObject(key); - if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) - { - userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user)); - } - else if (StringUtils.isNotEmpty(ipaddr)) - { - userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user)); - } - else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) - { - userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); - } - else - { - userOnlineList.add(userOnlineService.loginUserToUserOnline(user)); - } - } - Collections.reverse(userOnlineList); - userOnlineList.removeAll(Collections.singleton(null)); - return getDataTable(userOnlineList); - } - - /** - * 强退用户 - */ - @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')") - @Log(title = "在线用户", businessType = BusinessType.FORCE) - @DeleteMapping("/{tokenId}") - public AjaxResult forceLogout(@PathVariable String tokenId) - { - redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId); - return success(); - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java deleted file mode 100644 index 44b48a5..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ruoyi.web.controller.system; - -import java.util.List; -import java.util.Set; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysMenu; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.common.core.core.domain.model.LoginBody; -import com.ruoyi.common.core.utils.SecurityUtils; -import com.ruoyi.framework.web.service.SysLoginService; -import com.ruoyi.framework.web.service.SysPermissionService; -import com.ruoyi.system.service.ISysMenuService; - -/** - * 登录验证 - * - * @author ruoyi - */ -@RestController -public class SysLoginController -{ - @Autowired - private SysLoginService loginService; - - @Autowired - private ISysMenuService menuService; - - @Autowired - private SysPermissionService permissionService; - - /** - * 登录方法 - * - * @param loginBody 登录信息 - * @return 结果 - */ - @PostMapping("/login") - public AjaxResult login(@RequestBody LoginBody loginBody) - { - AjaxResult ajax = AjaxResult.success(); - // 生成令牌 - String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), - loginBody.getUuid()); - ajax.put(Constants.TOKEN, token); - return ajax; - } - - /** - * 获取用户信息 - * - * @return 用户信息 - */ - @GetMapping("getInfo") - public AjaxResult getInfo() - { - SysUser user = SecurityUtils.getLoginUser().getUser(); - // 角色集合 - Set roles = permissionService.getRolePermission(user); - // 权限集合 - Set permissions = permissionService.getMenuPermission(user); - AjaxResult ajax = AjaxResult.success(); - ajax.put("user", user); - ajax.put("roles", roles); - ajax.put("permissions", permissions); - return ajax; - } - - /** - * 获取路由信息 - * - * @return 路由信息 - */ - @GetMapping("getRouters") - public AjaxResult getRouters() - { - Long userId = SecurityUtils.getUserId(); - List menus = menuService.selectMenuTreeByUserId(userId); - return AjaxResult.success(menuService.buildMenus(menus)); - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java deleted file mode 100644 index 1ce15b6..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ruoyi.web.controller.system; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.core.controller.BaseController; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.model.RegisterBody; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.framework.web.service.SysRegisterService; -import com.ruoyi.system.service.ISysConfigService; - -/** - * 注册验证 - * - * @author ruoyi - */ -@RestController -public class SysRegisterController extends BaseController -{ - @Autowired - private SysRegisterService registerService; - - @Autowired - private ISysConfigService configService; - - @PostMapping("/register") - public AjaxResult register(@RequestBody RegisterBody user) - { - if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) - { - return error("当前系统没有开启注册功能!"); - } - String msg = registerService.register(user); - return StringUtils.isEmpty(msg) ? success() : error(msg); - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/CaptchaVo.java b/ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/CaptchaVo.java new file mode 100644 index 0000000..8c717f0 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/CaptchaVo.java @@ -0,0 +1,25 @@ +package com.ruoyi.web.domain.vo; + +import lombok.Data; + +/** + * 验证码信息 + * + * @author Michelle.Chung + */ +@Data +public class CaptchaVo { + + /** + * 是否开启验证码 + */ + private Boolean captchaEnabled = true; + + private String uuid; + + /** + * 验证码图片 + */ + private String img; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/LoginVo.java b/ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/LoginVo.java new file mode 100644 index 0000000..07e9d95 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/domain/vo/LoginVo.java @@ -0,0 +1,54 @@ +package com.ruoyi.web.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 登录验证信息 + * + * @author Michelle.Chung + */ +@Data +public class LoginVo { + + /** + * 授权令牌 + */ + @JsonProperty("access_token") + private String accessToken; + + /** + * 刷新令牌 + */ + @JsonProperty("refresh_token") + private String refreshToken; + + /** + * 授权令牌 access_token 的有效期 + */ + @JsonProperty("expire_in") + private Long expireIn; + + /** + * 刷新令牌 refresh_token 的有效期 + */ + @JsonProperty("refresh_expire_in") + private Long refreshExpireIn; + + /** + * 应用id + */ + @JsonProperty("client_id") + private String clientId; + + /** + * 令牌权限 + */ + private String scope; + + /** + * 用户 openid + */ + private String openid; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java new file mode 100644 index 0000000..8e0c020 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java @@ -0,0 +1,45 @@ +package com.ruoyi.web.service; + + +import com.ruoyi.common.core.core.domain.AjaxResult; +import com.ruoyi.common.core.core.domain.model.LoginBody; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.system.domain.SysClient; + +/** + * 授权策略 + * + * @author Michelle.Chung + */ +public interface IAuthStrategy { + + String BASE_NAME = "AuthStrategy"; + + /** + * 登录 + */ + static String login(LoginBody loginBody, SysClient client) { + // 授权类型和客户端id + String clientId = loginBody.getClientId(); + String grantType = loginBody.getGrantType(); + String beanName = grantType + BASE_NAME; + if (!SpringUtils.containsBean(beanName)) { + throw new ServiceException("授权类型不正确!"); + } + IAuthStrategy instance = SpringUtils.getBean(beanName); + instance.validate(loginBody); + return instance.login(clientId, loginBody, client); + } + + /** + * 参数校验 + */ + void validate(LoginBody loginBody); + + /** + * 登录 + */ + String login(String clientId, LoginBody loginBody, SysClient client); + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java new file mode 100644 index 0000000..787ffb5 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java @@ -0,0 +1,175 @@ +package com.ruoyi.web.service; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.constant.*; +import com.ruoyi.common.core.core.domain.dto.RoleDTO; +import com.ruoyi.common.core.enums.LoginType; +import com.ruoyi.common.core.exception.user.*; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.log.event.LogininforEvent; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.vo.SysUserVo; +import com.ruoyi.system.service.ISysPermissionService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.system.service.ISysUserService; +import org.springframework.stereotype.Service; +import org.springframework.beans.factory.annotation.Value; + +import java.time.Duration; +import java.util.List; +import java.util.function.Supplier; + +/** + * 登录校验方法 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLoginService { + + @Value("${user.password.maxRetryCount}") + private Integer maxRetryCount; + + @Value("${user.password.lockTime}") + private Integer lockTime; + + private final ISysPermissionService permissionService; + + @Autowired + private ISysUserService userService; + + /** + * 登录校验 + */ + public void checkLogin(LoginType loginType, Long tenantId, String username, Supplier supplier) { + String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; + String loginFail = Constants.LOGIN_FAIL; + + // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) + int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); + // 锁定时间内登录 则踢出 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } + + if (supplier.get()) { + // 错误次数递增 + errorNumber++; + RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); + // 达到规定错误次数 则锁定登录 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } else { + // 未达到规定错误次数 + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); + throw new UserException(loginType.getRetryLimitCount(), errorNumber); + } + } + + // 登录成功 清空错误次数 + RedisUtils.deleteObject(errorKey); + } + + /** + * 校验租户 + * + * @param tenantId 租户ID + */ + public void checkTenant(String tenantId) { + if (!TenantHelper.isEnable()) { + return; + } + if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + return; + } + + //TODO:完善heckTenant功能 + } + + /** + * 构建登录用户 + */ + public LoginUser buildLoginUser(SysUser user) { + LoginUser loginUser = new LoginUser(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(user.getUserId()); + loginUser.setDeptId(user.getDeptId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); + loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); + loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); + List roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); + loginUser.setRoles(roles); + return loginUser; + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(ServletUtils.getClientIP()); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUser.setUpdateBy(userId); + userService.updateUserProfile(sysUser); + } + + /** + * 记录租户登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + */ + public void recordLogininfor(Long tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + + /** + * 退出登录 + */ + public void logout() { + try { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 登出清除动态租户 + TenantHelper.clearDynamic(); + } + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } + } + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java new file mode 100644 index 0000000..8286487 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java @@ -0,0 +1,115 @@ +package com.ruoyi.web.service; + +import cn.dev33.satoken.secure.BCrypt; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.enums.UserType; +import com.ruoyi.common.core.exception.user.UserException; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.log.event.LogininforEvent; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.web.config.properties.CaptchaProperties; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.bo.SysUserBo; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.core.domain.model.RegisterBody; +import com.ruoyi.common.core.exception.user.CaptchaException; +import com.ruoyi.common.core.exception.user.CaptchaExpireException; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysUserService; +import org.springframework.stereotype.Service; + +/** + * 注册校验方法 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@Service +public class SysRegisterService +{ + @Resource + private ISysUserService userService; + + @Resource + private ISysConfigService configService; + + private final CaptchaProperties captchaProperties; + + /** + * 注册 + */ + public void register(RegisterBody registerBody) + { + Long tenantId = registerBody.getTenantId(); + String username = registerBody.getUsername(); + String password = registerBody.getPassword(); + // 校验用户类型是否存在 + String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); + } + SysUser sysUser = new SysUser(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType(userType); + + if (!userService.checkUserNameUnique(sysUser)) { + throw new UserException("user.register.save.error", username); + } + boolean regFlag = userService.registerUser(sysUser, tenantId); + if (!regFlag) { + throw new UserException("user.register.error"); + } + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + } + + /** + * 校验验证码 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + public void validateCaptcha(Long tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + * @return + */ + private void recordLogininfor(Long tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java new file mode 100644 index 0000000..fceba2f --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java @@ -0,0 +1,112 @@ +package com.ruoyi.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.core.domain.AjaxResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.core.domain.model.LoginBody; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.enums.LoginType; +import com.ruoyi.common.core.enums.UserStatus; +import com.ruoyi.common.core.exception.user.CaptchaExpireException; +import com.ruoyi.common.core.exception.user.UserException; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.ValidatorUtils; +import com.ruoyi.common.core.validate.auth.EmailGroup; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysClient; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.web.service.IAuthStrategy; +import com.ruoyi.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 邮件认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("email" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class EmailAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public void validate(LoginBody loginBody) { + ValidatorUtils.validate(loginBody, EmailGroup.class); + } + + @Override + public String login(String clientId, LoginBody loginBody, SysClient client) { + Long tenantId = loginBody.getTenantId(); + String email = loginBody.getEmail(); + String emailCode = loginBody.getEmailCode(); + + // 通过邮箱查找用户 + SysUser user = loadUserByEmail(tenantId, email); + + loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + LoginUser loginUser = loginService.buildLoginUser(user); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, clientId); + // 生成token + LoginHelper.login(loginUser, model); + + loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + loginService.recordLoginInfo(user.getUserId()); + +// LoginVo loginVo = new LoginVo(); +// loginVo.setAccessToken(StpUtil.getTokenValue()); +// loginVo.setExpireIn(StpUtil.getTokenTimeout()); +// loginVo.setClientId(clientId); +// return loginVo; + return StpUtil.getTokenValue(); + } + + /** + * 校验邮箱验证码 + */ + private boolean validateEmailCode(Long tenantId, String email, String emailCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(emailCode); + } + + private SysUser loadUserByEmail(Long tenantId, String email) { +// SysUser user = userMapper.selectOne(new LambdaQueryWrapper() +// .select(SysUser::getEmail, SysUser::getStatus) +// .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) +// .eq(SysUser::getEmail, email)); + SysUser user =userMapper.selectUserByEmail(email); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", email); + throw new UserException("user.not.exists", email); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", email); + throw new UserException("user.blocked", email); + } +// if (TenantHelper.isEnable()) { +// return userMapper.selectTenantUserByEmail(email, tenantId); +// } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java new file mode 100644 index 0000000..924d7ee --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java @@ -0,0 +1,137 @@ +package com.ruoyi.web.service.impl; + +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.core.domain.AjaxResult; +import com.ruoyi.system.service.ISysUserService; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.core.domain.model.LoginBody; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.enums.LoginType; +import com.ruoyi.common.core.enums.UserStatus; +import com.ruoyi.common.core.exception.user.CaptchaException; +import com.ruoyi.common.core.exception.user.CaptchaExpireException; +import com.ruoyi.common.core.exception.user.UserException; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.ValidatorUtils; +import com.ruoyi.common.core.validate.auth.PasswordGroup; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.web.config.properties.CaptchaProperties; +import com.ruoyi.system.domain.SysClient; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.vo.SysUserVo; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.web.domain.vo.LoginVo; +import com.ruoyi.web.service.IAuthStrategy; +import com.ruoyi.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 密码认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("password" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class PasswordAuthStrategy implements IAuthStrategy { + + private final CaptchaProperties captchaProperties; + private final SysLoginService loginService; + + @Resource + private ISysUserService userService; + //private final SysUserMapper userMapper; + + @Override + public void validate(LoginBody loginBody) { + ValidatorUtils.validate(loginBody, PasswordGroup.class); + } + + @Override + public String login(String clientId, LoginBody loginBody, SysClient client) { + Long tenantId = loginBody.getTenantId(); + String username = loginBody.getUsername(); + String password = loginBody.getPassword(); + String code = loginBody.getCode(); + String uuid = loginBody.getUuid(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, code, uuid); + } + + SysUser user = loadUserByUsername(tenantId, username); + loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); + // 此处可根据登录用户的数据不同 自行创建 loginUser + LoginUser loginUser = loginService.buildLoginUser(user); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, clientId); + // 生成token + LoginHelper.login(loginUser, model); + + loginService.recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); + loginService.recordLoginInfo(user.getUserId()); + +// LoginVo loginVo = new LoginVo(); +// loginVo.setAccessToken(StpUtil.getTokenValue()); +// loginVo.setExpireIn(StpUtil.getTokenTimeout()); +// loginVo.setClientId(clientId); +// return loginVo; + + return StpUtil.getTokenValue(); + + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + private void validateCaptcha(Long tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + private SysUser loadUserByUsername(Long tenantId, String username) { + //TODO:以后根据tenantId条件过滤查询: + SysUser user = userService.selectUserByUserName(username); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new UserException("user.not.exists", username); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new UserException("user.blocked", username); + } +// if (TenantHelper.isEnable()) { +// return userMapper.selectTenantUserByUserName(username, tenantId); +// } + return user; + } + +} diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index ea3125d..7132031 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -1,14 +1,49 @@ -# 多数据源配置 +# 数据源及mybatis、mybatis-flex配置 mybatis-flex: + # 搜索指定包别名 + typeAliasesPackage: com.ruoyi.**.domain + # 不支持多包, 如有需要可在注解配置 或 提升扫包等级:com.**.**.mapper + mapperPackage: com.ruoyi.**.mapper + # 配置mapper的扫描,找到所有的mapper.xml映射文件 + mapper-locations: classpath*:mapper/**/*Mapper.xml + cacheEnabled: true + useGeneratedKeys: true + defaultExecutorType: SIMPLE + + #本部分(Configuration)的配置都为 MyBatis 原生支持的配置,有关配置请参考:https://mybatis.org/mybatis-3/zh/configuration.html#%E8%AE%BE%E7%BD%AE%EF%BC%88settings%EF%BC%89 + configuration: + # 自动驼峰命名规则(camel case)映射 + mapUnderscoreToCamelCase: true + # MyBatis 自动映射策略 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 + autoMappingBehavior: FULL + # MyBatis 自动映射时未知列或未知属性处理策 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 + autoMappingUnknownColumnBehavior: NONE + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl + + # MyBatis-Flex全局配置 + global-config: + # 是否控制台打印 MyBatis-Flex 的 LOGO 及版本号 + print-banner: false + # 逻辑删除数据存在标记值 + normal-value-of-logic-delete: 0 + # 逻辑删除数据存在标记值 + deleted-value-of-logic-delete: 1 + + datasource: # 数据源-1 PrimaryDS: # 指定为HikariDataSource type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: root - password: Root@369 + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true + username: root123 + password: Root@369---0000 hikari: #连接池名 @@ -32,5 +67,42 @@ mybatis-flex: # 连接测试query connection-test-query: SELECT 1 +# redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: localhost + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码(如没有密码请注释掉) + # password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..5f6feb2 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -0,0 +1,110 @@ +# 临时文件存储位置 避免临时文件被系统清理报错 +spring.servlet.multipart.location: /ruoyi/server/temp + +# 数据源及mybatis、mybatis-flex配置 +mybatis-flex: + # 搜索指定包别名 + typeAliasesPackage: com.ruoyi.**.domain + # 配置mapper的扫描,找到所有的mapper.xml映射文件 + mapper-locations: classpath*:mapper/**/*Mapper.xml + cacheEnabled: true + useGeneratedKeys: true + defaultExecutorType: SIMPLE + + #本部分(Configuration)的配置都为 MyBatis 原生支持的配置,有关配置请参考:https://mybatis.org/mybatis-3/zh/configuration.html#%E8%AE%BE%E7%BD%AE%EF%BC%88settings%EF%BC%89 + configuration: + # 自动驼峰命名规则(camel case)映射 + mapUnderscoreToCamelCase: true + # MyBatis 自动映射策略 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 + autoMappingBehavior: FULL + # MyBatis 自动映射时未知列或未知属性处理策 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 + autoMappingUnknownColumnBehavior: NONE + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl + + + # MyBatis-Flex全局配置 + global-config: + # 是否控制台打印 MyBatis-Flex 的 LOGO 及版本号 + print-banner: false + # 逻辑删除数据存在标记值 + normal-value-of-logic-delete: 0 + # 逻辑删除数据存在标记值 + deleted-value-of-logic-delete: 1 + + + datasource: + # 数据源-1 + PrimaryDS: + # 指定为HikariDataSource + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: 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&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true + username: root123 + password: Root@369---0000 + + hikari: + #连接池名 + pool-name: HikariCP-PrimaryDS + #最小空闲连接数 + minimum-idle: 10 + # 空闲连接存活最大时间,默认10分钟 + idle-timeout: 600000 + # 连接池最大连接数,默认是10 + maximum-pool-size: 20 + # 此属性控制从池返回的连接的默认自动提交行为,默认值:true + auto-commit: true + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + max-lifetime: 1800000 + # 数据库连接超时时间,默认30秒 + connection-timeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + # 连接测试query + connection-test-query: SELECT 1 + +# redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: localhost + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码(如没有密码请注释掉) + # password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + + diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 107aa63..d222cfc 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -3,7 +3,7 @@ ruoyi: # 名称 name: RuoYi-Flex # 版本 - version: 4.1.3 + version: 4.1.4-SNAPSHOT # 版权年份 copyrightYear: 2023 # 实例演示开关 @@ -12,8 +12,18 @@ ruoyi: profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false - # 验证码类型 math 数字计算 char 字符验证 - captchaType: math + +captcha: + enable: true + # 页面 <参数设置> 可开启关闭 验证码校验 + # 验证码类型 math 数组计算 char 字符验证 + type: MATH + # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 + category: CIRCLE + # 数字验证码位数 + numberLength: 1 + # 字符验证码长度 + charLength: 4 # 开发环境配置 server: @@ -43,6 +53,7 @@ logging: level: com.ruoyi: debug org.springframework: warn + config: classpath:logback.xml # 用户配置 user: @@ -54,12 +65,14 @@ user: # Spring配置 spring: + application: + name: ${ruoyi.name} # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: - active: dev + active: @profiles.active@ # 文件上传 servlet: multipart: @@ -67,33 +80,25 @@ spring: max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB + mvc: + format: + date-time: yyyy-MM-dd HH:mm:ss + jackson: + # 日期格式化 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + # 格式化输出 + indent_output: false + # 忽略无法转换的对象 + fail_on_empty_beans: false + deserialization: + # 允许对象忽略json中不存在的属性 + fail_on_unknown_properties: false # 服务模块 devtools: restart: # 热部署开关 enabled: true - # redis 配置 - redis: - # 地址 - host: localhost - # 端口,默认为6379 - port: 6379 - # 数据库索引 - database: 0 - # 密码 - password: - # 连接超时时间 - timeout: 10s - lettuce: - pool: - # 连接池中的最小空闲连接 - min-idle: 0 - # 连接池中的最大空闲连接 - max-idle: 8 - # 连接池的最大数据库连接数 - max-active: 8 - # #连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms # token配置 token: @@ -104,21 +109,6 @@ token: # 令牌有效期(默认30分钟) expireTime: 30 -# MyBatis配置 -mybatis-flex: - # 搜索指定包别名 - typeAliasesPackage: com.ruoyi.**.domain - # 配置mapper的扫描,找到所有的mapper.xml映射文件 - mapper-locations: classpath*:mapper/**/*Mapper.xml - cacheEnabled: true - useGeneratedKeys: true - defaultExecutorType: SIMPLE - configuration: - # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl - # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl - # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl - logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl - # PageHelper分页插件 pagehelper: helperDialect: mysql @@ -143,6 +133,25 @@ springdoc: enabled: true #开启/禁止api-docs, prod可以设置为false use-management-port: false enable-spring-security: true + info: + # 标题 + title: 'Ruoyi-Flex API Doc' + # 描述 + description: 'Ruoyi-Flex SrpingDoc demo' + # 版本 + version: '版本号: ${ruoyi.version}' + # 作者信息 + contact: + name: 数据小王子 + email: 738981257@qq.com + url: https://gitee.com/dataprince/ruoyi-flex + components: + # 鉴权方式配置 + security-schemes: + apiKey: + type: APIKEY + in: HEADER + name: ${sa-token.token-name} # 防止XSS攻击 xss: @@ -152,3 +161,79 @@ xss: excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/*,/demo/* + +# 全局线程池相关配置 +thread-pool: + # 是否开启线程池 + enabled: false + # 队列最大长度 + queueCapacity: 128 + # 线程池维护线程所允许的空闲时间 + keepAliveSeconds: 300 + +# 分布式锁 lock4j 全局配置 +lock4j: + # 获取分布式锁超时时间,默认为 3000 毫秒 + acquire-timeout: 3000 + # 分布式锁的超时时间,默认为 30 秒 + expire: 30000 + +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # token固定超时 设为七天 (必定过期) 单位: 秒 + timeout: 604800 + # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义 + # token最低活跃时间 (指定时间无操作就过期) 单位: 秒 + active-timeout: 1800 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: true + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + +# security配置 +security: + # 排除路径 + excludes: + # 静态资源 + - /*.html + - /**/*.html + - /**/*.css + - /**/*.js + # 公共路径 + - /favicon.ico + - /error + # swagger 文档配置 + - /*/api-docs + - /*/api-docs/** + # actuator 监控配置 + - /actuator + - /actuator/** + # 其它链接 + - /login + - /register + - /captchaImage + - /captcha/get + - /captcha/check + +# 多租户配置 +tenant: + # 是否开启 + enable: false + # 排除表 + excludes: + - sys_menu + - sys_tenant + - sys_tenant_package + - sys_role_dept + - sys_role_menu + - sys_user_post + - sys_user_role + - sys_client diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties index 93de005..5c9f422 100644 --- a/ruoyi-admin/src/main/resources/i18n/messages.properties +++ b/ruoyi-admin/src/main/resources/i18n/messages.properties @@ -2,33 +2,38 @@ 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}次,帐户锁定{1}分钟 -user.password.delete=对不起,您的账号已被删除 -user.blocked=用户已封禁,请联系管理员 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 role.blocked=角色已封禁,请联系管理员 -login.blocked=很遗憾,访问IP已被列入系统黑名单 user.logout.success=退出成功 - length.not.valid=长度必须在{min}到{max}个字符之间 - +user.username.not.blank=用户名不能为空 user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 user.password.not.valid=* 5-50个字符 - user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 user.mobile.phone.number.not.valid=手机号格式错误 user.login.success=登录成功 user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 user.notfound=请重新登录 user.forcelogout=管理员强制退出,请重新登录 user.unknown.error=未知错误,请重新登录 - +auth.grant.type.error=认证权限类型错误 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 ##文件上传消息 upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! upload.filename.exceed.length=上传的文件名最长{0}个字符 - ##权限 no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] @@ -36,3 +41,17 @@ no.update.permission=您没有修改数据的权限,请联系管理员添加 no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序code不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..2ab82a6 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,57 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +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 {1} 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 +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.email.not.valid=Mailbox format error +user.email.not.blank=Mailbox cannot be blank +user.phonenumber.not.blank=Phone number cannot be blank +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +auth.grant.type.error=Auth grant type error +auth.grant.type.not.blank=Auth grant type cannot be blank +auth.clientid.not.blank=Auth clientid cannot be blank +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] +repeat.submit.message=Repeat submit is not allowed, please try again later +rate.limiter.message=Visit too frequently, please try again later +sms.code.not.blank=Sms code cannot be blank +sms.code.retry.limit.count=Sms code input error {0} times +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes +email.code.not.blank=Email code cannot be blank +email.code.retry.limit.count=Email code input error {0} times +email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes +xcx.code.not.blank=Mini program code cannot be blank +##租户 +tenant.number.not.blank=Tenant number cannot be blank +tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator +tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator +tenant.expired=Sorry, your tenant has expired. Please contact the administrator. diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..5c9f422 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,57 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序code不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 85dbf26..719a7e3 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -8,14 +8,25 @@ ${revision} 4.0.0 + pom + ruoyi-common-bom ruoyi-common-core - ruoyi-common-springdoc + ruoyi-common-excel + ruoyi-common-json + ruoyi-common-log + ruoyi-common-orm + ruoyi-common-ratelimiter + ruoyi-common-redis + ruoyi-common-security + ruoyi-common-springdoc + ruoyi-common-tenant + ruoyi-common-translation + ruoyi-common-web ruoyi-common - pom ruoyi-common 公共模块 diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml new file mode 100644 index 0000000..a8caf98 --- /dev/null +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + + com.ruoyi + ruoyi-common-bom + ${revision} + pom + + + ruoyi-common-bom common依赖项 + + + + 4.1.4-SNAPSHOT + + + + + + + com.ruoyi + ruoyi-common-core + ${revision} + + + + + com.ruoyi + ruoyi-common-excel + ${revision} + + + + + com.ruoyi + ruoyi-common-json + ${revision} + + + + + com.ruoyi + ruoyi-common-log + ${revision} + + + + + com.ruoyi + ruoyi-common-orm + ${revision} + + + + + com.ruoyi + ruoyi-common-ratelimiter + ${revision} + + + + + com.ruoyi + ruoyi-common-redis + ${revision} + + + + + com.ruoyi + ruoyi-common-security + ${revision} + + + + + com.ruoyi + ruoyi-common-springdoc + ${revision} + + + + + com.ruoyi + ruoyi-common-tenant + ${revision} + + + + + com.ruoyi + ruoyi-common-translation + ${revision} + + + + + com.ruoyi + ruoyi-common-web + ${revision} + + + + + + diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml index 9e82ead..0db4dce 100644 --- a/ruoyi-common/ruoyi-common-core/pom.xml +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -3,11 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - ruoyi-common com.ruoyi + ruoyi-common ${revision} 4.0.0 + jar ruoyi-common-core @@ -35,24 +36,6 @@ spring-web - - - org.springframework.boot - spring-boot-starter-security - - - - - com.github.pagehelper - pagehelper - - - - - com.mybatis-flex - mybatis-flex-spring-boot-starter - - org.springframework.boot @@ -64,7 +47,7 @@ org.apache.commons commons-lang3 - + com.fasterxml.jackson.core @@ -108,12 +91,6 @@ 2.3.1 - - - org.springframework.boot - spring-boot-starter-data-redis - - org.apache.commons @@ -132,6 +109,51 @@ jakarta.servlet-api + + + org.projectlombok + lombok + + + + + cn.hutool + hutool-core + + + + cn.hutool + hutool-http + + + + cn.hutool + hutool-extra + + + + cn.hutool + hutool-json + provided + + + + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + + + com.github.pagehelper + pagehelper + + + - \ No newline at end of file + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java deleted file mode 100644 index 6f836dc..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ruoyi.common.core.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import com.ruoyi.common.core.enums.DataSourceType; - -/** - * 自定义多数据源切换注解 - * - * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 - * - * @author ruoyi - */ -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -public @interface DataSource -{ - /** - * 切换数据源名称 - */ - public DataSourceType value() default DataSourceType.MASTER; -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java deleted file mode 100644 index f283537..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ruoyi.common.core.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import com.ruoyi.common.core.enums.BusinessType; -import com.ruoyi.common.core.enums.OperatorType; - -/** - * 自定义操作日志记录注解 - * - * @author ruoyi - * - */ -@Target({ ElementType.PARAMETER, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface Log -{ - /** - * 模块 - */ - public String title() default ""; - - /** - * 功能 - */ - public BusinessType businessType() default BusinessType.OTHER; - - /** - * 操作人类别 - */ - public OperatorType operatorType() default OperatorType.MANAGE; - - /** - * 是否保存请求的参数 - */ - public boolean isSaveRequestData() default true; - - /** - * 是否保存响应的参数 - */ - public boolean isSaveResponseData() default true; - - /** - * 排除指定的请求参数 - */ - public String[] excludeParamNames() default {}; -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java new file mode 100644 index 0000000..0bfa503 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.core.config; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +/** + * 程序注解配置 + * + * @author ruoyi + */ +@AutoConfiguration +// 表示通过aop框架暴露该代理对象,AopContext能够访问 +@EnableAspectJAutoProxy(exposeProxy = true) +// 指定要扫描的Mapper类的包的路径 +public class ApplicationConfig +{ + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java new file mode 100644 index 0000000..14dc801 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java @@ -0,0 +1,48 @@ +package com.ruoyi.common.core.config; + +import cn.hutool.core.util.ArrayUtil; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.SpringUtils; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; + +import java.util.Arrays; +import java.util.concurrent.Executor; + +/** + * 异步配置 + * + * @author Lion Li + */ +@EnableAsync(proxyTargetClass = true) +@AutoConfiguration +public class AsyncConfig implements AsyncConfigurer { + + /** + * 自定义 @Async 注解使用系统线程池 + */ + @Override + public Executor getAsyncExecutor() { + return SpringUtils.getBean("scheduledExecutorService"); + } + + /** + * 异步执行异常处理 + */ + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + throwable.printStackTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Exception message - ").append(throwable.getMessage()) + .append(", Method name - ").append(method.getName()); + if (ArrayUtil.isNotEmpty(objects)) { + sb.append(", Parameter value - ").append(Arrays.toString(objects)); + } + throw new ServiceException(sb.toString()); + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java index c9fcffc..8b6fe87 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java @@ -1,76 +1,53 @@ package com.ruoyi.common.core.config; +import lombok.Data; +import lombok.Getter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * 读取项目相关配置 - * + * * @author ruoyi */ +@Data @Component @ConfigurationProperties(prefix = "ruoyi") -public class RuoYiConfig -{ - /** 项目名称 */ +public class RuoYiConfig { + + /** + * 项目名称 + */ private String name; - /** 版本 */ + /** + * 版本 + */ private String version; - /** 版权年份 */ + /** + * 版权年份 + */ private String copyrightYear; - /** 实例演示开关 */ + /** + * 实例演示开关 + */ private boolean demoEnabled; - /** 上传路径 */ + /** + * 文件路径 + */ private static String profile; - /** 获取地址开关 */ + /** + * 获取地址开关 + */ + @Getter private static boolean addressEnabled; - /** 验证码类型 */ - private static String captchaType; - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getVersion() - { - return version; - } - - public void setVersion(String version) - { - this.version = version; - } - - public String getCopyrightYear() - { - return copyrightYear; - } - - public void setCopyrightYear(String copyrightYear) - { - this.copyrightYear = copyrightYear; - } - - public boolean isDemoEnabled() - { - return demoEnabled; - } - - public void setDemoEnabled(boolean demoEnabled) - { - this.demoEnabled = demoEnabled; + public void setAddressEnabled(boolean addressEnabled) { + RuoYiConfig.addressEnabled = addressEnabled; } public static String getProfile() @@ -78,29 +55,6 @@ public class RuoYiConfig return profile; } - public void setProfile(String profile) - { - RuoYiConfig.profile = profile; - } - - public static boolean isAddressEnabled() - { - return addressEnabled; - } - - public void setAddressEnabled(boolean addressEnabled) - { - RuoYiConfig.addressEnabled = addressEnabled; - } - - public static String getCaptchaType() { - return captchaType; - } - - public void setCaptchaType(String captchaType) { - RuoYiConfig.captchaType = captchaType; - } - /** * 获取导入上传路径 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java new file mode 100644 index 0000000..727ad67 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java @@ -0,0 +1,76 @@ +package com.ruoyi.common.core.config; + +import com.ruoyi.common.core.config.properties.ThreadPoolProperties; +import com.ruoyi.common.core.utils.Threads; +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 线程池配置 + * + * @author ruoyi + **/ +@Slf4j +@AutoConfiguration +@EnableConfigurationProperties(ThreadPoolProperties.class) +public class ThreadPoolConfig +{ + /** + * 核心线程数 = cpu 核心数 + 1 + */ + private final int core = Runtime.getRuntime().availableProcessors() + 1; + + private ScheduledExecutorService scheduledExecutorService; + + @Bean(name = "threadPoolTaskExecutor") + @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") + public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(core); + executor.setMaxPoolSize(core * 2); + executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); + executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() { + ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core, + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), + new ThreadPoolExecutor.CallerRunsPolicy()) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + this.scheduledExecutorService = scheduledThreadPoolExecutor; + return scheduledThreadPoolExecutor; + } + + /** + * 销毁事件 + */ + @PreDestroy + public void destroy() { + try { + log.info("====关闭后台任务任务线程池===="); + Threads.shutdownAndAwaitTermination(scheduledExecutorService); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java new file mode 100644 index 0000000..cb0d786 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java @@ -0,0 +1,40 @@ +package com.ruoyi.common.core.config; + +import jakarta.validation.Validator; +import org.hibernate.validator.HibernateValidator; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; + +import java.util.Properties; + +/** + * 校验框架配置类 + * + * @author Lion Li + */ +@AutoConfiguration +public class ValidatorConfig { + + /** + * 配置校验框架 快速返回模式 + */ + @Bean + public Validator validator(MessageSource messageSource) { + try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { + // 国际化 + factoryBean.setValidationMessageSource(messageSource); + // 设置使用 HibernateValidator 校验器 + factoryBean.setProviderClass(HibernateValidator.class); + Properties properties = new Properties(); + // 设置 快速异常返回 + properties.setProperty("hibernate.validator.fail_fast", "true"); + factoryBean.setValidationProperties(properties); + // 加载配置 + factoryBean.afterPropertiesSet(); + return factoryBean.getValidator(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java new file mode 100644 index 0000000..d7f4678 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.core.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 线程池 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "thread-pool") +public class ThreadPoolProperties { + + /** + * 是否开启线程池 + */ + private boolean enabled; + + /** + * 队列最大长度 + */ + private int queueCapacity; + + /** + * 线程池维护线程所允许的空闲时间 + */ + private int keepAliveSeconds; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java index 3a871ad..77dd8ea 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java @@ -7,6 +7,11 @@ package com.ruoyi.common.core.constant; */ public class CacheConstants { + /** + * 在线用户 redis key + */ + public static final String ONLINE_TOKEN_KEY = "online_tokens:"; + /** * 登录用户 redis key */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java new file mode 100644 index 0000000..81e92f5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java @@ -0,0 +1,63 @@ +package com.ruoyi.common.core.constant; + +/** + * 缓存组名称常量 + *

+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize + *

+ * ttl 过期时间 如果设置为0则不过期 默认为0 + * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 + * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 + *

+ * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 + * + * @author Lion Li + */ +public interface CacheNames { + + /** + * 演示案例 + */ + String DEMO_CACHE = "demo:cache#60s#10m#20"; + + /** + * 系统配置 + */ + String SYS_CONFIG = "sys_config"; + + /** + * 数据字典 + */ + String SYS_DICT = "sys_dict"; + + /** + * 租户 + */ + String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; + + /** + * 用户账户 + */ + String SYS_USER_NAME = "sys_user_name#30d"; + + /** + * 部门 + */ + String SYS_DEPT = "sys_dept#30d"; + + /** + * OSS内容 + */ + String SYS_OSS = "sys_oss#30d"; + + /** + * OSS配置 + */ + String SYS_OSS_CONFIG = "sys_oss_config"; + + /** + * 在线用户 + */ + String ONLINE_TOKEN = "online_tokens"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java index f646e76..49bafa0 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java @@ -69,6 +69,11 @@ public class Constants */ public static final Integer CAPTCHA_EXPIRATION = 2; + /** + * 登录用户 redis key + */ + public static final String LOGIN_TOKEN_KEY = "login_tokens:"; + /** * 令牌 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java new file mode 100644 index 0000000..60fb162 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java @@ -0,0 +1,39 @@ +package com.ruoyi.common.core.constant; + +/** + * 全局的key常量 (业务无关的key) + * + * @author Lion Li + */ +public interface GlobalConstants { + + /** + * 全局 redis key (业务无关的key) + */ + String GLOBAL_REDIS_KEY = "global:"; + + /** + * 验证码 redis key + */ + String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; + + /** + * 防重提交 redis key + */ + String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; + + /** + * 限流 redis key + */ + String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; + + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:"; + + /** + * 三方认证 redis key + */ + String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java new file mode 100644 index 0000000..6411ba4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java @@ -0,0 +1,45 @@ +package com.ruoyi.common.core.constant; + +/** + * 租户常量信息 + * + * @author Lion Li + */ +public interface TenantConstants { + + /** + * 租户正常状态 + */ + String NORMAL = "0"; + + /** + * 租户封禁状态 + */ + String DISABLE = "1"; + + /** + * 超级管理员ID + */ + Long SUPER_ADMIN_ID = 1L; + + /** + * 超级管理员角色 roleKey + */ + String SUPER_ADMIN_ROLE_KEY = "superadmin"; + + /** + * 租户管理员角色 roleKey + */ + String TENANT_ADMIN_ROLE_KEY = "admin"; + + /** + * 租户管理员角色名称 + */ + String TENANT_ADMIN_ROLE_NAME = "管理员"; + + /** + * 默认租户ID + */ + String DEFAULT_TENANT_ID = "000000"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java index c3f4282..f696fe9 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java @@ -2,65 +2,118 @@ package com.ruoyi.common.core.constant; /** * 用户常量信息 - * + * * @author ruoyi */ -public class UserConstants -{ +public class UserConstants { /** * 平台内系统用户的唯一标志 */ public static final String SYS_USER = "SYS_USER"; - /** 正常状态 */ + /** + * 正常状态 + */ public static final String NORMAL = "0"; - /** 异常状态 */ + /** + * 异常状态 + */ public static final String EXCEPTION = "1"; - /** 用户封禁状态 */ + /** + * 用户正常状态 + */ + public static final String USER_NORMAL = "0"; + + /** + * 用户封禁状态 + */ public static final String USER_DISABLE = "1"; - /** 角色封禁状态 */ + /** + * 角色正常状态 + */ + public static final String ROLE_NORMAL = "0"; + + /** + * 角色封禁状态 + */ public static final String ROLE_DISABLE = "1"; - /** 部门正常状态 */ + /** + * 部门正常状态 + */ public static final String DEPT_NORMAL = "0"; - /** 部门停用状态 */ + /** + * 部门停用状态 + */ public static final String DEPT_DISABLE = "1"; - /** 字典正常状态 */ + /** + * 岗位正常状态 + */ + public static final String POST_NORMAL = "0"; + + /** + * 岗位停用状态 + */ + public static final String POST_DISABLE = "1"; + + /** + * 字典正常状态 + */ public static final String DICT_NORMAL = "0"; - /** 是否为系统默认(是) */ + /** + * 是否为系统默认(是) + */ public static final String YES = "Y"; - /** 是否菜单外链(是) */ + /** + * 是否菜单外链(是) + */ public static final String YES_FRAME = "0"; - /** 是否菜单外链(否) */ + /** + * 是否菜单外链(否) + */ public static final String NO_FRAME = "1"; - /** 菜单类型(目录) */ + /** + * 菜单类型(目录) + */ public static final String TYPE_DIR = "M"; - /** 菜单类型(菜单) */ + /** + * 菜单类型(菜单) + */ public static final String TYPE_MENU = "C"; - /** 菜单类型(按钮) */ + /** + * 菜单类型(按钮) + */ public static final String TYPE_BUTTON = "F"; - /** Layout组件标识 */ + /** + * Layout组件标识 + */ public final static String LAYOUT = "Layout"; - - /** ParentView组件标识 */ + + /** + * ParentView组件标识 + */ public final static String PARENT_VIEW = "ParentView"; - /** InnerLink组件标识 */ + /** + * InnerLink组件标识 + */ public final static String INNER_LINK = "InnerLink"; - /** 校验是否唯一的返回标识 */ + /** + * 校验是否唯一的返回标识 + */ public final static boolean UNIQUE = true; public final static boolean NOT_UNIQUE = false; @@ -75,4 +128,9 @@ public class UserConstants */ public static final int PASSWORD_MIN_LENGTH = 5; public static final int PASSWORD_MAX_LENGTH = 20; + + /** + * 超级管理员ID + */ + public static final Long SUPER_ADMIN_ID = 1L; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java index 16364c0..31ea6bd 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java @@ -7,7 +7,7 @@ import com.ruoyi.common.core.utils.StringUtils; /** * 操作消息提醒 - * + * * @author ruoyi */ public class AjaxResult extends HashMap @@ -32,7 +32,7 @@ public class AjaxResult extends HashMap /** * 初始化一个新创建的 AjaxResult 对象 - * + * * @param code 状态码 * @param msg 返回内容 */ @@ -44,7 +44,7 @@ public class AjaxResult extends HashMap /** * 初始化一个新创建的 AjaxResult 对象 - * + * * @param code 状态码 * @param msg 返回内容 * @param data 数据对象 @@ -61,7 +61,7 @@ public class AjaxResult extends HashMap /** * 返回成功消息 - * + * * @return 成功消息 */ public static AjaxResult success() @@ -71,7 +71,7 @@ public class AjaxResult extends HashMap /** * 返回成功数据 - * + * * @return 成功消息 */ public static AjaxResult success(Object data) @@ -81,7 +81,7 @@ public class AjaxResult extends HashMap /** * 返回成功消息 - * + * * @param msg 返回内容 * @return 成功消息 */ @@ -92,7 +92,7 @@ public class AjaxResult extends HashMap /** * 返回成功消息 - * + * * @param msg 返回内容 * @param data 数据对象 * @return 成功消息 @@ -127,7 +127,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @return 错误消息 */ public static AjaxResult error() @@ -137,7 +137,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @param msg 返回内容 * @return 错误消息 */ @@ -148,7 +148,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @param msg 返回内容 * @param data 数据对象 * @return 错误消息 @@ -160,7 +160,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @param code 状态码 * @param msg 返回内容 * @return 错误消息 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java deleted file mode 100644 index 0ac99f0..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.ruoyi.common.core.core.domain; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.mybatisflex.annotation.Column; - -/** - * Entity基类 - * - * @author ruoyi - */ -public class BaseEntity implements Serializable -{ - private static final long serialVersionUID = 1L; - - /** 搜索值 */ - @JsonIgnore - @Column(ignore = true) - private String searchValue; - - /** 创建者 */ - private String createBy; - - /** 创建时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; - - /** 更新者 */ - private String updateBy; - - /** 更新时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime; - - /** 备注 */ - private String remark; - - /** 请求参数 */ - @JsonInclude(JsonInclude.Include.NON_EMPTY) - @Column(ignore = true) - private Map params; - - public String getSearchValue() - { - return searchValue; - } - - public void setSearchValue(String searchValue) - { - this.searchValue = searchValue; - } - - public String getCreateBy() - { - return createBy; - } - - public void setCreateBy(String createBy) - { - this.createBy = createBy; - } - - public Date getCreateTime() - { - return createTime; - } - - public void setCreateTime(Date createTime) - { - this.createTime = createTime; - } - - public String getUpdateBy() - { - return updateBy; - } - - public void setUpdateBy(String updateBy) - { - this.updateBy = updateBy; - } - - public Date getUpdateTime() - { - return updateTime; - } - - public void setUpdateTime(Date updateTime) - { - this.updateTime = updateTime; - } - - public String getRemark() - { - return remark; - } - - public void setRemark(String remark) - { - this.remark = remark; - } - - public Map getParams() - { - if (params == null) - { - params = new HashMap<>(); - } - return params; - } - - public void setParams(Map params) - { - this.params = params; - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java index dad3fe3..65b1266 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java @@ -1,15 +1,21 @@ package com.ruoyi.common.core.core.domain; +import java.io.Serial; import java.io.Serializable; import com.ruoyi.common.core.constant.HttpStatus; +import lombok.Data; +import lombok.NoArgsConstructor; /** * 响应信息主体 * * @author ruoyi */ +@Data +@NoArgsConstructor public class R implements Serializable { + @Serial private static final long serialVersionUID = 1L; /** 成功 */ @@ -34,6 +40,10 @@ public class R implements Serializable return restResult(data, SUCCESS, "操作成功"); } + public static R ok(String msg) { + return restResult(null, SUCCESS, msg); + } + public static R ok(T data, String msg) { return restResult(data, SUCCESS, msg); @@ -54,7 +64,7 @@ public class R implements Serializable return restResult(data, FAIL, "操作失败"); } - public static R fail(T data, String msg) + public static R fail(String msg, T data) { return restResult(data, FAIL, msg); } @@ -64,6 +74,27 @@ public class R implements Serializable return restResult(null, code, msg); } + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static R warn(String msg) { + return restResult(null, HttpStatus.WARN, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static R warn(String msg, T data) { + return restResult(data, HttpStatus.WARN, msg); + } + private static R restResult(T data, int code, String msg) { R apiResult = new R<>(); @@ -73,36 +104,6 @@ public class R implements Serializable return apiResult; } - public int getCode() - { - return code; - } - - public void setCode(int code) - { - this.code = code; - } - - public String getMsg() - { - return msg; - } - - public void setMsg(String msg) - { - this.msg = msg; - } - - public T getData() - { - return data; - } - - public void setData(T data) - { - this.data = data; - } - public static Boolean isError(R ret) { return !isSuccess(ret); diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java new file mode 100644 index 0000000..bf488ce --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java @@ -0,0 +1,38 @@ +package com.ruoyi.common.core.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 角色 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class RoleDTO implements Serializable { + + /** + * 角色ID + */ + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java new file mode 100644 index 0000000..542f6ec --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java @@ -0,0 +1,62 @@ +package com.ruoyi.common.core.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 当前在线会话 + * + * @author ruoyi + */ + +@Data +@NoArgsConstructor +public class UserOnlineDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户名称 + */ + private String userName; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java new file mode 100644 index 0000000..189a4c9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java @@ -0,0 +1,35 @@ +package com.ruoyi.common.core.core.domain.model; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +/** + * 邮件登录对象 + * + * @author Lion Li + */ + +@Data +public class EmailLoginBody { + + /** + * 租户ID + */ + @NotBlank(message = "{tenant.number.not.blank}") + private String tenantId; + + /** + * 邮箱 + */ + @NotBlank(message = "{user.email.not.blank}") + @Email(message = "{user.email.not.valid}") + private String email; + + /** + * 邮箱code + */ + @NotBlank(message = "{email.code.not.blank}") + private String emailCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java index edd9607..ad8ecab 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java @@ -1,20 +1,60 @@ package com.ruoyi.common.core.core.domain.model; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.validate.auth.*; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + /** * 用户登录对象 - * + * * @author ruoyi */ +@Data public class LoginBody { + /** + * 客户端id + */ + @NotBlank(message = "{auth.clientid.not.blank}") + private String clientId; + + /** + * 客户端key + */ + private String clientKey; + + /** + * 客户端秘钥 + */ + private String clientSecret; + + /** + * 授权类型 + */ + @NotBlank(message = "{auth.grant.type.not.blank}") + private String grantType; + + /** + * 租户ID + */ + //@NotBlank(message = "{tenant.number.not.blank}") + private Long tenantId; + /** * 用户名 */ + @NotBlank(message = "{user.username.not.blank}", groups = {PasswordGroup.class}) + @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}", groups = {PasswordGroup.class}) private String username; /** * 用户密码 */ + @NotBlank(message = "{user.password.not.blank}", groups = {PasswordGroup.class}) + @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}", groups = {PasswordGroup.class}) private String password; /** @@ -27,43 +67,52 @@ public class LoginBody */ private String uuid; - public String getUsername() - { - return username; - } + /** + * 手机号 + */ + @NotBlank(message = "{user.phonenumber.not.blank}", groups = {SmsGroup.class}) + private String phonenumber; - public void setUsername(String username) - { - this.username = username; - } + /** + * 短信code + */ + @NotBlank(message = "{sms.code.not.blank}", groups = {SmsGroup.class}) + private String smsCode; - public String getPassword() - { - return password; - } + /** + * 邮箱 + */ + @NotBlank(message = "{user.email.not.blank}", groups = {EmailGroup.class}) + @Email(message = "{user.email.not.valid}") + private String email; - public void setPassword(String password) - { - this.password = password; - } + /** + * 邮箱code + */ + @NotBlank(message = "{email.code.not.blank}", groups = {EmailGroup.class}) + private String emailCode; - public String getCode() - { - return code; - } + /** + * 小程序code + */ + @NotBlank(message = "{xcx.code.not.blank}", groups = {WechatGroup.class}) + private String xcxCode; - public void setCode(String code) - { - this.code = code; - } + /** + * 第三方登录平台 + */ + @NotBlank(message = "{social.source.not.blank}" , groups = {SocialGroup.class}) + private String source; - public String getUuid() - { - return uuid; - } + /** + * 第三方登录code + */ + @NotBlank(message = "{social.code.not.blank}" , groups = {SocialGroup.class}) + private String socialCode; - public void setUuid(String uuid) - { - this.uuid = uuid; - } + /** + * 第三方登录socialState + */ + @NotBlank(message = "{social.state.not.blank}" , groups = {SocialGroup.class}) + private String socialState; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java index 8aac305..3de891a 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java @@ -1,21 +1,30 @@ package com.ruoyi.common.core.core.domain.model; -import com.alibaba.fastjson2.annotation.JSONField; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import java.util.Collection; +import com.ruoyi.common.core.core.domain.dto.RoleDTO; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; import java.util.Set; +import java.io.Serial; /** * 登录用户身份权限 - * - * @author ruoyi + * + * @author Lion Li */ -public class LoginUser implements UserDetails +@Data +@NoArgsConstructor +public class LoginUser { + @Serial private static final long serialVersionUID = 1L; + /** + * 租户ID + */ + private Long tenantId; + /** * 用户ID */ @@ -26,11 +35,21 @@ public class LoginUser implements UserDetails */ private Long deptId; + /** + * 部门名 + */ + private String deptName; + /** * 用户唯一标识 */ private String token; + /** + * 用户类型 + */ + private String userType; + /** * 登录时间 */ @@ -62,205 +81,47 @@ public class LoginUser implements UserDetails private String os; /** - * 权限列表 + * 菜单权限 */ - private Set permissions; + private Set menuPermission; /** - * 用户信息 + * 角色权限 */ - private SysUser user; - - public LoginUser() - { - } - - public LoginUser(SysUser user, Set permissions) - { - this.user = user; - this.permissions = permissions; - } - - public LoginUser(Long userId, Long deptId, SysUser user, Set permissions) - { - this.userId = userId; - this.deptId = deptId; - this.user = user; - this.permissions = permissions; - } - - public Long getUserId() - { - return userId; - } - - public void setUserId(Long userId) - { - this.userId = userId; - } - - public Long getDeptId() - { - return deptId; - } - - public void setDeptId(Long deptId) - { - this.deptId = deptId; - } - - public String getToken() - { - return token; - } - - public void setToken(String token) - { - this.token = token; - } - - @JSONField(serialize = false) - @Override - public String getPassword() - { - return user.getPassword(); - } - - @Override - public String getUsername() - { - return user.getUserName(); - } + private Set rolePermission; /** - * 账户是否未过期,过期无法验证 + * 用户名 */ - @JSONField(serialize = false) - @Override - public boolean isAccountNonExpired() - { - return true; - } + private String username; /** - * 指定用户是否解锁,锁定的用户无法进行身份验证 - * - * @return + * 用户昵称 */ - @JSONField(serialize = false) - @Override - public boolean isAccountNonLocked() - { - return true; - } + private String nickname; + /** - * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 - * - * @return + * 角色对象 */ - @JSONField(serialize = false) - @Override - public boolean isCredentialsNonExpired() - { - return true; - } + private List roles; /** - * 是否可用 ,禁用的用户不能身份验证 - * - * @return + * 数据权限 当前角色ID */ - @JSONField(serialize = false) - @Override - public boolean isEnabled() - { - return true; + private Long roleId; + + /** + * 获取登录id + */ + public String getLoginId() { + if (userType == null) { + throw new IllegalArgumentException("用户类型不能为空"); + } + if (userId == null) { + throw new IllegalArgumentException("用户ID不能为空"); + } + return userType + ":" + userId; } - public Long getLoginTime() - { - return loginTime; } - - public void setLoginTime(Long loginTime) - { - this.loginTime = loginTime; - } - - public String getIpaddr() - { - return ipaddr; - } - - public void setIpaddr(String ipaddr) - { - this.ipaddr = ipaddr; - } - - public String getLoginLocation() - { - return loginLocation; - } - - public void setLoginLocation(String loginLocation) - { - this.loginLocation = loginLocation; - } - - public String getBrowser() - { - return browser; - } - - public void setBrowser(String browser) - { - this.browser = browser; - } - - public String getOs() - { - return os; - } - - public void setOs(String os) - { - this.os = os; - } - - public Long getExpireTime() - { - return expireTime; - } - - public void setExpireTime(Long expireTime) - { - this.expireTime = expireTime; - } - - public Set getPermissions() - { - return permissions; - } - - public void setPermissions(Set permissions) - { - this.permissions = permissions; - } - - public SysUser getUser() - { - return user; - } - - public void setUser(SysUser user) - { - this.user = user; - } - - @Override - public Collection getAuthorities() - { - return null; - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java index 4438255..8135a93 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java @@ -1,11 +1,16 @@ package com.ruoyi.common.core.core.domain.model; +import lombok.Data; +import lombok.EqualsAndHashCode; + /** * 用户注册对象 - * + * * @author ruoyi */ +@Data +@EqualsAndHashCode(callSuper = true) public class RegisterBody extends LoginBody { - + private String userType; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java index 464036a..c46c821 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java @@ -4,7 +4,7 @@ import com.ruoyi.common.core.utils.StringUtils; /** * 分页数据 - * + * * @author ruoyi */ public class PageDomain diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java index 6370751..4f4cd26 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java @@ -1,15 +1,19 @@ package com.ruoyi.common.core.core.page; +import cn.hutool.http.HttpStatus; + +import java.io.Serial; import java.io.Serializable; import java.util.List; /** * 表格分页数据对象 - * + * * @author ruoyi */ public class TableDataInfo implements Serializable { + @Serial private static final long serialVersionUID = 1L; /** 总记录数 */ @@ -33,7 +37,7 @@ public class TableDataInfo implements Serializable /** * 分页 - * + * * @param list 列表数据 * @param total 总记录数 */ @@ -43,6 +47,15 @@ public class TableDataInfo implements Serializable this.total = total; } + public static TableDataInfo build(List list) { + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); + return rspData; + } + public long getTotal() { return total; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java index 99ec195..b979878 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java @@ -5,7 +5,7 @@ import com.ruoyi.common.core.utils.ServletUtils; /** * 表格数据处理 - * + * * @author ruoyi */ public class TableSupport diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java deleted file mode 100644 index 248fd6b..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.ruoyi.common.core.core.redis; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.BoundSetOperations; -import org.springframework.data.redis.core.HashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; -import org.springframework.stereotype.Component; - -/** - * spring redis 工具类 - * - * @author ruoyi - **/ -@SuppressWarnings(value = { "unchecked", "rawtypes" }) -@Component -public class RedisCache -{ - @Autowired - public RedisTemplate redisTemplate; - - /** - * 缓存基本的对象,Integer、String、实体类等 - * - * @param key 缓存的键值 - * @param value 缓存的值 - */ - public void setCacheObject(final String key, final T value) - { - redisTemplate.opsForValue().set(key, value); - } - - /** - * 缓存基本的对象,Integer、String、实体类等 - * - * @param key 缓存的键值 - * @param value 缓存的值 - * @param timeout 时间 - * @param timeUnit 时间颗粒度 - */ - public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) - { - redisTemplate.opsForValue().set(key, value, timeout, timeUnit); - } - - /** - * 设置有效时间 - * - * @param key Redis键 - * @param timeout 超时时间 - * @return true=设置成功;false=设置失败 - */ - public boolean expire(final String key, final long timeout) - { - return expire(key, timeout, TimeUnit.SECONDS); - } - - /** - * 设置有效时间 - * - * @param key Redis键 - * @param timeout 超时时间 - * @param unit 时间单位 - * @return true=设置成功;false=设置失败 - */ - public boolean expire(final String key, final long timeout, final TimeUnit unit) - { - return redisTemplate.expire(key, timeout, unit); - } - - /** - * 获取有效时间 - * - * @param key Redis键 - * @return 有效时间 - */ - public long getExpire(final String key) - { - return redisTemplate.getExpire(key); - } - - /** - * 判断 key是否存在 - * - * @param key 键 - * @return true 存在 false不存在 - */ - public Boolean hasKey(String key) - { - return redisTemplate.hasKey(key); - } - - /** - * 获得缓存的基本对象。 - * - * @param key 缓存键值 - * @return 缓存键值对应的数据 - */ - public T getCacheObject(final String key) - { - ValueOperations operation = redisTemplate.opsForValue(); - return operation.get(key); - } - - /** - * 删除单个对象 - * - * @param key - */ - public boolean deleteObject(final String key) - { - return redisTemplate.delete(key); - } - - /** - * 删除集合对象 - * - * @param collection 多个对象 - * @return - */ - public boolean deleteObject(final Collection collection) - { - return redisTemplate.delete(collection) > 0; - } - - /** - * 缓存List数据 - * - * @param key 缓存的键值 - * @param dataList 待缓存的List数据 - * @return 缓存的对象 - */ - public long setCacheList(final String key, final List dataList) - { - Long count = redisTemplate.opsForList().rightPushAll(key, dataList); - return count == null ? 0 : count; - } - - /** - * 获得缓存的list对象 - * - * @param key 缓存的键值 - * @return 缓存键值对应的数据 - */ - public List getCacheList(final String key) - { - return redisTemplate.opsForList().range(key, 0, -1); - } - - /** - * 缓存Set - * - * @param key 缓存键值 - * @param dataSet 缓存的数据 - * @return 缓存数据的对象 - */ - public BoundSetOperations setCacheSet(final String key, final Set dataSet) - { - BoundSetOperations setOperation = redisTemplate.boundSetOps(key); - Iterator it = dataSet.iterator(); - while (it.hasNext()) - { - setOperation.add(it.next()); - } - return setOperation; - } - - /** - * 获得缓存的set - * - * @param key - * @return - */ - public Set getCacheSet(final String key) - { - return redisTemplate.opsForSet().members(key); - } - - /** - * 缓存Map - * - * @param key - * @param dataMap - */ - public void setCacheMap(final String key, final Map dataMap) - { - if (dataMap != null) { - redisTemplate.opsForHash().putAll(key, dataMap); - } - } - - /** - * 获得缓存的Map - * - * @param key - * @return - */ - public Map getCacheMap(final String key) - { - return redisTemplate.opsForHash().entries(key); - } - - /** - * 往Hash中存入数据 - * - * @param key Redis键 - * @param hKey Hash键 - * @param value 值 - */ - public void setCacheMapValue(final String key, final String hKey, final T value) - { - redisTemplate.opsForHash().put(key, hKey, value); - } - - /** - * 获取Hash中的数据 - * - * @param key Redis键 - * @param hKey Hash键 - * @return Hash中的对象 - */ - public T getCacheMapValue(final String key, final String hKey) - { - HashOperations opsForHash = redisTemplate.opsForHash(); - return opsForHash.get(key, hKey); - } - - /** - * 获取多个Hash中的数据 - * - * @param key Redis键 - * @param hKeys Hash键集合 - * @return Hash对象集合 - */ - public List getMultiCacheMapValue(final String key, final Collection hKeys) - { - return redisTemplate.opsForHash().multiGet(key, hKeys); - } - - /** - * 删除Hash中的某条数据 - * - * @param key Redis键 - * @param hKey Hash键 - * @return 是否成功 - */ - public boolean deleteCacheMapValue(final String key, final String hKey) - { - return redisTemplate.opsForHash().delete(key, hKey) > 0; - } - - /** - * 获得缓存的基本对象列表 - * - * @param pattern 字符串前缀 - * @return 对象列表 - */ - public Collection keys(final String pattern) - { - return redisTemplate.keys(pattern); - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java index 8f46300..cd7d751 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java @@ -6,7 +6,7 @@ import com.ruoyi.common.core.utils.StringUtils; /** * 字符集工具类 - * + * * @author ruoyi */ public class CharsetKit @@ -27,7 +27,7 @@ public class CharsetKit /** * 转换为Charset对象 - * + * * @param charset 字符集,为空则返回默认字符集 * @return Charset */ @@ -38,7 +38,7 @@ public class CharsetKit /** * 转换字符串的字符集编码 - * + * * @param source 字符串 * @param srcCharset 源字符集,默认ISO-8859-1 * @param destCharset 目标字符集,默认UTF-8 @@ -51,7 +51,7 @@ public class CharsetKit /** * 转换字符串的字符集编码 - * + * * @param source 字符串 * @param srcCharset 源字符集,默认ISO-8859-1 * @param destCharset 目标字符集,默认UTF-8 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java index 7d2d555..cc32d0e 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java @@ -4,7 +4,7 @@ import com.ruoyi.common.core.utils.StringUtils; /** * 字符串格式化 - * + * * @author ruoyi */ public class StrFormatter @@ -22,7 +22,7 @@ public class StrFormatter * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
- * + * * @param strPattern 字符串模板 * @param argArray 参数列表 * @return 结果 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java deleted file mode 100644 index 2fdb2a7..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.ruoyi.common.core.enums; - -/** - * 数据源 - * - * @author ruoyi - */ -public enum DataSourceType -{ - /** - * 主库 - */ - MASTER, - - /** - * 从库 - */ - SLAVE -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java new file mode 100644 index 0000000..f449ded --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java @@ -0,0 +1,35 @@ +package com.ruoyi.common.core.enums; + +/** + * 设备类型 + * 针对一套 用户体系 + * + * @author Lion Li + */ +public enum DeviceType { + /** + * pc端 + */ + PC("pc"), + + /** + * app端 + */ + APP("app"), + + /** + * 小程序端 + */ + XCX("xcx"), + + /** + * social第三方端 + */ + SOCIAL("social"); + + private final String device; + + private DeviceType(String device) { + this.device = device; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java new file mode 100644 index 0000000..dbd6de1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java @@ -0,0 +1,44 @@ +package com.ruoyi.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum LoginType { + + /** + * 密码登录 + */ + PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), + + /** + * 短信登录 + */ + SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), + + /** + * 邮箱登录 + */ + EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), + + /** + * 小程序登录 + */ + XCX("", ""); + + /** + * 登录重试超出限制提示 + */ + final String retryLimitExceed; + + /** + * 登录重试限制计数提示 + */ + final String retryLimitCount; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java new file mode 100644 index 0000000..79cd304 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java @@ -0,0 +1,41 @@ +package com.ruoyi.common.core.enums; + +import com.ruoyi.common.core.utils.StringUtils; + +/** + * 设备类型 + * 针对多套 用户体系 + * + * @author Lion Li + */ +public enum UserType { + + /** + * pc端 + */ + SYS_USER("sys_user"), + + /** + * app端 + */ + APP_USER("app_user"); + + private final String userType; + + UserType(String userType) { + this.userType = userType; + } + + public String getUserType() { + return userType; + } + + public static UserType getUserType(String str) { + for (UserType value : values()) { + if (StringUtils.contains(str, value.getUserType())) { + return value; + } + } + throw new RuntimeException("'UserType' not found By " + str); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java index b55c7cd..cd59447 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception; +import java.io.Serial; + /** * 全局异常 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception; */ public class GlobalException extends RuntimeException { + @Serial private static final long serialVersionUID = 1L; /** @@ -17,7 +20,6 @@ public class GlobalException extends RuntimeException /** * 错误明细,内部调试错误 * - * 和 {@link CommonResult#getDetailMessage()} 一致的设计 */ private String detailMessage; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java index 4983866..53477b5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception; +import java.io.Serial; + /** * 业务异常 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception; */ public final class ServiceException extends RuntimeException { + @Serial private static final long serialVersionUID = 1L; /** @@ -22,7 +25,6 @@ public final class ServiceException extends RuntimeException /** * 错误明细,内部调试错误 * - * 和 {@link CommonResult#getDetailMessage()} 一致的设计 */ private String detailMessage; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java index 18c7be8..2674028 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception; +import java.io.Serial; + /** * 工具类异常 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception; */ public class UtilException extends RuntimeException { + @Serial private static final long serialVersionUID = 8247610319171014183L; public UtilException(Throwable e) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java index ddd4ee5..404df1d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java @@ -3,6 +3,8 @@ package com.ruoyi.common.core.exception.base; import com.ruoyi.common.core.utils.MessageUtils; import com.ruoyi.common.core.utils.StringUtils; +import java.io.Serial; + /** * 基础异常 * @@ -10,6 +12,7 @@ import com.ruoyi.common.core.utils.StringUtils; */ public class BaseException extends RuntimeException { + @Serial private static final long serialVersionUID = 1L; /** diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java index 8989dcd..62b42c0 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java @@ -2,6 +2,8 @@ package com.ruoyi.common.core.exception.file; import com.ruoyi.common.core.exception.base.BaseException; +import java.io.Serial; + /** * 文件信息异常类 * @@ -9,6 +11,7 @@ import com.ruoyi.common.core.exception.base.BaseException; */ public class FileException extends BaseException { + @Serial private static final long serialVersionUID = 1L; public FileException(String code, Object[] args) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java index 9135a00..a71b5d9 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.file; +import java.io.Serial; + /** * 文件名称超长限制异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.file; */ public class FileNameLengthLimitExceededException extends FileException { + @Serial private static final long serialVersionUID = 1L; public FileNameLengthLimitExceededException(int defaultFileNameLength) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java index a5f8bc1..6180bf8 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.file; +import java.io.Serial; + /** * 文件名大小限制异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.file; */ public class FileSizeLimitExceededException extends FileException { + @Serial private static final long serialVersionUID = 1L; public FileSizeLimitExceededException(long defaultMaxSize) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java index c0f57cb..78a781d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java @@ -2,6 +2,7 @@ package com.ruoyi.common.core.exception.file; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.Serial; /** * 文件上传异常类 @@ -10,7 +11,7 @@ import java.io.PrintWriter; */ public class FileUploadException extends Exception { - + @Serial private static final long serialVersionUID = 1L; private final Throwable cause; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java index 420520f..088e935 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java @@ -1,5 +1,6 @@ package com.ruoyi.common.core.exception.file; +import java.io.Serial; import java.util.Arrays; /** @@ -9,6 +10,7 @@ import java.util.Arrays; */ public class InvalidExtensionException extends FileUploadException { + @Serial private static final long serialVersionUID = 1L; private String[] allowedExtension; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java index 6cc3e58..4464587 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.job; +import java.io.Serial; + /** * 计划策略异常 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.job; */ public class TaskException extends Exception { + @Serial private static final long serialVersionUID = 1L; private Code code; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java index 1b09cdf..dbe688d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.user; +import java.io.Serial; + /** * 黑名单IP异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user; */ public class BlackListException extends UserException { + @Serial private static final long serialVersionUID = 1L; public BlackListException() diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java index f74c3dd..725d133 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.user; +import java.io.Serial; + /** * 验证码错误异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user; */ public class CaptchaException extends UserException { + @Serial private static final long serialVersionUID = 1L; public CaptchaException() diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java index ec68864..2caae30 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.user; +import java.io.Serial; + /** * 验证码失效异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user; */ public class CaptchaExpireException extends UserException { + @Serial private static final long serialVersionUID = 1L; public CaptchaExpireException() diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java index 8ae8ea3..e4249b7 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java @@ -2,16 +2,19 @@ package com.ruoyi.common.core.exception.user; import com.ruoyi.common.core.exception.base.BaseException; +import java.io.Serial; + /** * 用户信息异常类 - * + * * @author ruoyi */ public class UserException extends BaseException { + @Serial private static final long serialVersionUID = 1L; - public UserException(String code, Object[] args) + public UserException(String code, Object... args) { super("user", code, args, null); } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java index 95a6854..76f0c1d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.user; +import java.io.Serial; + /** * 用户不存在异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user; */ public class UserNotExistsException extends UserException { + @Serial private static final long serialVersionUID = 1L; public UserNotExistsException() diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java index 2e1a6b1..0c38d77 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.user; +import java.io.Serial; + /** * 用户密码不正确或不符合规范异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user; */ public class UserPasswordNotMatchException extends UserException { + @Serial private static final long serialVersionUID = 1L; public UserPasswordNotMatchException() diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java index 336875b..4f0c98d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.user; +import java.io.Serial; + /** * 用户错误最大次数异常类 * @@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user; */ public class UserPasswordRetryLimitExceedException extends UserException { + @Serial private static final long serialVersionUID = 1L; public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java new file mode 100644 index 0000000..014033e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java @@ -0,0 +1,31 @@ +package com.ruoyi.common.core.factory; + +import com.ruoyi.common.core.utils.StringUtils; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.DefaultPropertySourceFactory; +import org.springframework.core.io.support.EncodedResource; + +import java.io.IOException; + +/** + * yml 配置源工厂 + * + * @author Lion Li + */ +public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + String sourceName = resource.getResource().getFilename(); + if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resource.getResource()); + factory.afterPropertiesSet(); + return new PropertiesPropertySource(sourceName, factory.getObject()); + } + return super.createPropertySource(name, resource); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java deleted file mode 100644 index 2cebada..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ruoyi.common.core.filter; - -import com.alibaba.fastjson2.filter.SimplePropertyPreFilter; - -/** - * 排除JSON敏感属性 - * - * @author ruoyi - */ -public class PropertyPreExcludeFilter extends SimplePropertyPreFilter -{ - public PropertyPreExcludeFilter() - { - } - - public PropertyPreExcludeFilter addExcludes(String... filters) - { - for (int i = 0; i < filters.length; i++) - { - this.getExcludes().add(filters[i]); - } - return this; - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java new file mode 100644 index 0000000..0a6df41 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java @@ -0,0 +1,41 @@ +package com.ruoyi.common.core.manager; + +import com.ruoyi.common.core.utils.Threads; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import jakarta.annotation.PreDestroy; +import java.util.concurrent.ScheduledExecutorService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 确保应用退出时能关闭后台线程 + * + * @author ruoyi + */ +@Component +public class ShutdownManager +{ + private static final Logger logger = LoggerFactory.getLogger("ShutdownManager"); + @Resource + @Qualifier("scheduledExecutorService") + private ScheduledExecutorService scheduledExecutorService; + + @PreDestroy + public void destroy() { + shutdownAsyncManager(); + } + + /** + * 停止异步执行任务 + */ + private void shutdownAsyncManager() { + try { + logger.info("====关闭后台任务任务线程池===="); + Threads.shutdownAndAwaitTermination(scheduledExecutorService); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java new file mode 100644 index 0000000..c6badf6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.core.service; + +/** + * 通用 参数配置服务 + * + * @author Lion Li + */ +public interface ConfigService { + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + String getConfigValue(String configKey); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java new file mode 100644 index 0000000..c27f461 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.core.service; + +/** + * 通用 部门服务 + * + * @author Lion Li + */ +public interface DeptService { + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + String selectDeptNameByIds(String deptIds); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java new file mode 100644 index 0000000..22b8439 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java @@ -0,0 +1,67 @@ +package com.ruoyi.common.core.service; + +import java.util.Map; + +/** + * 通用 字典服务 + * + * @author Lion Li + */ +public interface DictService { + + /** + * 分隔符 + */ + String SEPARATOR = ","; + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + + /** + * 获取字典下所有的字典值与标签 + * + * @param dictType 字典类型 + * @return dictValue为key,dictLabel为值组成的Map + */ + Map getAllDictByDictType(String dictType); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java new file mode 100644 index 0000000..d2206c8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.core.service; + +/** + * 通用 用户服务 + * + * @author Lion Li + */ +public interface UserService { + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + String selectUserNameById(Long userId); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java deleted file mode 100644 index 89a4b83..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.ruoyi.common.core.utils; - -import java.util.Collection; -import java.util.List; -import com.alibaba.fastjson2.JSONArray; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.core.domain.entity.SysDictData; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.utils.spring.SpringUtils; - -/** - * 字典工具类 - * - * @author ruoyi - */ -public class DictUtils -{ - /** - * 分隔符 - */ - public static final String SEPARATOR = ","; - - /** - * 设置字典缓存 - * - * @param key 参数键 - * @param dictDatas 字典数据列表 - */ - public static void setDictCache(String key, List dictDatas) - { - SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas); - } - - /** - * 获取字典缓存 - * - * @param key 参数键 - * @return dictDatas 字典数据列表 - */ - public static List getDictCache(String key) - { - JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); - if (StringUtils.isNotNull(arrayCache)) - { - return arrayCache.toList(SysDictData.class); - } - return null; - } - - /** - * 根据字典类型和字典值获取字典标签 - * - * @param dictType 字典类型 - * @param dictValue 字典值 - * @return 字典标签 - */ - public static String getDictLabel(String dictType, String dictValue) - { - return getDictLabel(dictType, dictValue, SEPARATOR); - } - - /** - * 根据字典类型和字典标签获取字典值 - * - * @param dictType 字典类型 - * @param dictLabel 字典标签 - * @return 字典值 - */ - public static String getDictValue(String dictType, String dictLabel) - { - return getDictValue(dictType, dictLabel, SEPARATOR); - } - - /** - * 根据字典类型和字典值获取字典标签 - * - * @param dictType 字典类型 - * @param dictValue 字典值 - * @param separator 分隔符 - * @return 字典标签 - */ - public static String getDictLabel(String dictType, String dictValue, String separator) - { - StringBuilder propertyString = new StringBuilder(); - List datas = getDictCache(dictType); - - if (StringUtils.isNotNull(datas)) - { - if (StringUtils.containsAny(separator, dictValue)) - { - for (SysDictData dict : datas) - { - for (String value : dictValue.split(separator)) - { - if (value.equals(dict.getDictValue())) - { - propertyString.append(dict.getDictLabel()).append(separator); - break; - } - } - } - } - else - { - for (SysDictData dict : datas) - { - if (dictValue.equals(dict.getDictValue())) - { - return dict.getDictLabel(); - } - } - } - } - return StringUtils.stripEnd(propertyString.toString(), separator); - } - - /** - * 根据字典类型和字典标签获取字典值 - * - * @param dictType 字典类型 - * @param dictLabel 字典标签 - * @param separator 分隔符 - * @return 字典值 - */ - public static String getDictValue(String dictType, String dictLabel, String separator) - { - StringBuilder propertyString = new StringBuilder(); - List datas = getDictCache(dictType); - - if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) - { - for (SysDictData dict : datas) - { - for (String label : dictLabel.split(separator)) - { - if (label.equals(dict.getDictLabel())) - { - propertyString.append(dict.getDictValue()).append(separator); - break; - } - } - } - } - else - { - for (SysDictData dict : datas) - { - if (dictLabel.equals(dict.getDictLabel())) - { - return dict.getDictValue(); - } - } - } - return StringUtils.stripEnd(propertyString.toString(), separator); - } - - /** - * 删除指定字典缓存 - * - * @param key 字典键 - */ - public static void removeDictCache(String key) - { - SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key)); - } - - /** - * 清空字典缓存 - */ - public static void clearDictCache() - { - Collection keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*"); - SpringUtils.getBean(RedisCache.class).deleteObject(keys); - } - - /** - * 设置cache key - * - * @param configKey 参数键 - * @return 缓存键key - */ - public static String getCacheKey(String configKey) - { - return CacheConstants.SYS_DICT_KEY + configKey; - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java deleted file mode 100644 index f170231..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.ruoyi.common.core.utils; - -/** - * 处理并记录日志文件 - * - * @author ruoyi - */ -public class LogUtils -{ - public static String getBlock(Object msg) - { - if (msg == null) - { - msg = ""; - } - return "[" + msg.toString() + "]"; - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java new file mode 100644 index 0000000..3f6b633 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java @@ -0,0 +1,93 @@ +package com.ruoyi.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import io.github.linpeilie.Converter; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * Mapstruct 工具类 + *

参考文档:mapstruct-plus

+ * + * + * @author Michelle.Chung + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MapstructUtils { + + private final static Converter CONVERTER = SpringUtils.getBean(Converter.class); + + /** + * 将 T 类型对象,转换为 desc 类型的对象并返回 + * + * @param source 数据来源实体 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static V convert(T source, Class desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + return CONVERTER.convert(source, desc); + } + + /** + * 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象 + * + * @param source 数据来源实体 + * @param desc 转换后的对象 + * @return desc + */ + public static V convert(T source, V desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + return CONVERTER.convert(source, desc); + } + + /** + * 将 T 类型的集合,转换为 desc 类型的集合并返回 + * + * @param sourceList 数据来源实体列表 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static List convert(List sourceList, Class desc) { + if (ObjectUtil.isNull(sourceList)) { + return null; + } + if (CollUtil.isEmpty(sourceList)) { + return CollUtil.newArrayList(); + } + return CONVERTER.convert(sourceList, desc); + } + + /** + * 将 Map 转换为 beanClass 类型的集合并返回 + * + * @param map 数据来源 + * @param beanClass bean类 + * @return bean对象 + */ + public static T convert(Map map, Class beanClass) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(beanClass)) { + return null; + } + return CONVERTER.convert(map, beanClass); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java index 92bbd91..c346188 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java @@ -2,11 +2,10 @@ package com.ruoyi.common.core.utils; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; -import com.ruoyi.common.core.utils.spring.SpringUtils; /** * 获取i18n资源文件 - * + * * @author ruoyi */ public class MessageUtils diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java index a4c1735..79838a5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java @@ -7,7 +7,7 @@ import com.ruoyi.common.core.utils.sql.SqlUtil; /** * 分页工具类 - * + * * @author ruoyi */ public class PageUtils extends PageHelper diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java deleted file mode 100644 index b51fdfc..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.ruoyi.common.core.utils; - -import com.ruoyi.common.core.core.domain.model.LoginUser; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import com.ruoyi.common.core.constant.HttpStatus; -import com.ruoyi.common.core.exception.ServiceException; - -/** - * 安全服务工具类 - * - * @author ruoyi - */ -public class SecurityUtils -{ - /** - * 用户ID - **/ - public static Long getUserId() - { - try - { - return getLoginUser().getUserId(); - } - catch (Exception e) - { - throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED); - } - } - - /** - * 获取部门ID - **/ - public static Long getDeptId() - { - try - { - return getLoginUser().getDeptId(); - } - catch (Exception e) - { - throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED); - } - } - - /** - * 获取用户账户 - **/ - public static String getUsername() - { - try - { - return getLoginUser().getUsername(); - } - catch (Exception e) - { - throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED); - } - } - - /** - * 获取用户 - **/ - public static LoginUser getLoginUser() - { - try - { - return (LoginUser) getAuthentication().getPrincipal(); - } - catch (Exception e) - { - throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED); - } - } - - /** - * 获取Authentication - */ - public static Authentication getAuthentication() - { - return SecurityContextHolder.getContext().getAuthentication(); - } - - /** - * 生成BCryptPasswordEncoder密码 - * - * @param password 密码 - * @return 加密字符串 - */ - public static String encryptPassword(String password) - { - BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - return passwordEncoder.encode(password); - } - - /** - * 判断密码是否相同 - * - * @param rawPassword 真实密码 - * @param encodedPassword 加密后字符 - * @return 结果 - */ - public static boolean matchesPassword(String rawPassword, String encodedPassword) - { - BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - return passwordEncoder.matches(rawPassword, encodedPassword); - } - - /** - * 是否为管理员 - * - * @param userId 用户ID - * @return 结果 - */ - public static boolean isAdmin(Long userId) - { - return userId != null && 1L == userId; - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java index 41f6432..2c5a47b 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java @@ -17,13 +17,14 @@ import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.ruoyi.common.core.constant.Constants; +import cn.hutool.extra.servlet.JakartaServletUtil; /** * 客户端工具类 - * + * * @author ruoyi */ -public class ServletUtils +public class ServletUtils extends JakartaServletUtil { /** * 获取String参数 @@ -133,7 +134,7 @@ public class ServletUtils /** * 将字符串渲染到客户端 - * + * * @param response 渲染对象 * @param string 待渲染的字符串 */ @@ -154,7 +155,7 @@ public class ServletUtils /** * 是否是Ajax异步请求 - * + * * @param request */ public static boolean isAjaxRequest(HttpServletRequest request) @@ -181,9 +182,13 @@ public class ServletUtils return StringUtils.inStringIgnoreCase(ajax, "json", "xml"); } + public static String getClientIP() { + return getClientIP(getRequest()); + } + /** * 内容编码 - * + * * @param str 内容 * @return 编码后的内容 */ @@ -201,7 +206,7 @@ public class ServletUtils /** * 内容解码 - * + * * @param str 内容 * @return 解码后的内容 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java new file mode 100644 index 0000000..30624c3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java @@ -0,0 +1,101 @@ +package com.ruoyi.common.core.utils; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * spring工具类,方便在非spring管理环境中获取bean + * + * @author ruoyi + */ +@Component +public final class SpringUtils extends SpringUtil +{ + /** + * 获取spring上下文 + */ + public static ApplicationContext context() { + return getApplicationContext(); + } + + /** + * 获取aop代理对象 + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) + { + return getBeanFactory().containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { + return getBeanFactory().isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException + { + return getBeanFactory().getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { + return getBeanFactory().getAliases(name); + } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() + { + return context().getEnvironment().getActiveProfiles(); + } + + /** + * 获取当前的环境配置,当有多个环境配置时,只获取第一个 + * + * @return 当前的环境配置 + */ + public static String getActiveProfile() + { + final String[] activeProfiles = getActiveProfiles(); + return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java new file mode 100644 index 0000000..068d8d5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java @@ -0,0 +1,254 @@ +package com.ruoyi.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * stream 流工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StreamUtils { + + /** + * 将collection过滤 + * + * @param collection 需要转化的集合 + * @param function 过滤方法 + * @return 过滤后的list + */ + public static List filter(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + return collection.stream().filter(function).collect(Collectors.toList()); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function) { + return join(collection, function, StringUtils.SEPARATOR); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @param delimiter 拼接符 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function, CharSequence delimiter) { + if (CollUtil.isEmpty(collection)) { + return StringUtils.EMPTY; + } + return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); + } + + /** + * 将collection排序 + * + * @param collection 需要转化的集合 + * @param comparing 排序方法 + * @return 排序后的list + */ + public static List sorted(Collection collection, Comparator comparing) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList()); + } + + /** + * 将collection转化为类型不变的map
+ * {@code Collection ----> Map} + * + * @param collection 需要转化的集合 + * @param key V类型转化为K类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @return 转化后的map + */ + public static Map toIdentityMap(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); + } + + /** + * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map } + * + * @param collection 需要转化的集合 + * @param key E类型转化为K类型的lambda方法 + * @param value E类型转化为V类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @param map中的value类型 + * @return 转化后的map + */ + public static Map toMap(Collection collection, Function key, Function value) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l)); + } + + /** + * 将collection按照规则(比如有相同的班级id)分类成map
+ * {@code Collection -------> Map> } + * + * @param collection 需要分类的集合 + * @param key 分类的规则 + * @param collection中的泛型 + * @param map中的key类型 + * @return 分类后的map + */ + public static Map> groupByKey(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map>> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 集合元素类型 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @return 分类后的map + */ + public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @param collection中的泛型 + * @return 分类后的map + */ + public static Map> group2Map(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + } + + /** + * 将collection转化为List集合,但是两者的泛型不同
+ * {@code Collection ------> List } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为list泛型的lambda表达式 + * @param collection中的泛型 + * @param List中的泛型 + * @return 转化后的list + */ + public static List toList(Collection collection, Function function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + .collect(Collectors.toList()); + } + + /** + * 将collection转化为Set集合,但是两者的泛型不同
+ * {@code Collection ------> Set } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为set泛型的lambda表达式 + * @param collection中的泛型 + * @param Set中的泛型 + * @return 转化后的Set + */ + public static Set toSet(Collection collection, Function function) { + if (CollUtil.isEmpty(collection) || function == null) { + return CollUtil.newHashSet(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + + /** + * 合并两个相同key类型的map + * + * @param map1 第一个需要合并的 map + * @param map2 第二个需要合并的 map + * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况 + * @param map中的key类型 + * @param 第一个 map的value类型 + * @param 第二个 map的value类型 + * @param 最终map的value类型 + * @return 合并后的map + */ + public static Map merge(Map map1, Map map2, BiFunction merge) { + if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { + return MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map1)) { + map1 = MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map2)) { + map2 = MapUtil.newHashMap(); + } + Set key = new HashSet<>(); + key.addAll(map1.keySet()); + key.addAll(map2.keySet()); + Map map = new HashMap<>(); + for (K t : key) { + X x = map1.get(t); + Y y = map2.get(t); + V z = merge.apply(x, y); + if (z != null) { + map.put(t, z); + } + } + return map; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java index 4a6a224..a4398e8 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java @@ -1,32 +1,37 @@ package com.ruoyi.common.core.utils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import cn.hutool.core.util.StrUtil; import com.ruoyi.common.core.core.text.StrFormatter; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.springframework.util.AntPathMatcher; import com.ruoyi.common.core.constant.Constants; /** * 字符串工具类 - * + * * @author ruoyi */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class StringUtils extends org.apache.commons.lang3.StringUtils { + public static final String SEPARATOR = ","; + /** 空字符串 */ private static final String NULLSTR = ""; - /** 下划线 */ - private static final char SEPARATOR = '_'; - /** * 获取参数不为空值 - * + * * @param value defaultValue 要判断的value * @return value 返回值 */ @@ -37,7 +42,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个Collection是否为空, 包含List,Set,Queue - * + * * @param coll 要判断的Collection * @return true:为空 false:非空 */ @@ -48,7 +53,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个Collection是否非空,包含List,Set,Queue - * + * * @param coll 要判断的Collection * @return true:非空 false:空 */ @@ -59,7 +64,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个对象数组是否为空 - * + * * @param objects 要判断的对象数组 ** @return true:为空 false:非空 */ @@ -70,7 +75,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个对象数组是否非空 - * + * * @param objects 要判断的对象数组 * @return true:非空 false:空 */ @@ -81,7 +86,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个Map是否为空 - * + * * @param map 要判断的Map * @return true:为空 false:非空 */ @@ -92,7 +97,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个Map是否为空 - * + * * @param map 要判断的Map * @return true:非空 false:空 */ @@ -103,7 +108,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个字符串是否为空串 - * + * * @param str String * @return true:为空 false:非空 */ @@ -114,7 +119,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个字符串是否为非空串 - * + * * @param str String * @return true:非空串 false:空串 */ @@ -125,7 +130,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个对象是否为空 - * + * * @param object Object * @return true:为空 false:非空 */ @@ -136,7 +141,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个对象是否非空 - * + * * @param object Object * @return true:非空 false:空 */ @@ -147,7 +152,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * * 判断一个对象是否是数组类型(Java基本型别的数组) - * + * * @param object 对象 * @return true:是数组 false:不是数组 */ @@ -166,7 +171,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 截取字符串 - * + * * @param str 字符串 * @param start 开始 * @return 结果 @@ -197,7 +202,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 截取字符串 - * + * * @param str 字符串 * @param start 开始 * @param end 结束 @@ -249,7 +254,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
- * + * * @param template 文本模板,被替换的部分用 {} 表示 * @param params 参数值 * @return 格式化后的文本 @@ -265,7 +270,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 是否为http(s)://开头 - * + * * @param link 链接 * @return 结果 */ @@ -276,7 +281,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 字符串转set - * + * * @param str 字符串 * @param sep 分隔符 * @return set集合 @@ -288,7 +293,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 字符串转list - * + * * @param str 字符串 * @param sep 分隔符 * @param filterBlank 过滤纯空白 @@ -425,7 +430,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 是否包含字符串 - * + * * @param str 验证字符串 * @param strs 字符串组 * @return 包含返回true @@ -447,81 +452,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld - * + * * @param name 转换前的下划线大写方式命名的字符串 * @return 转换后的驼峰式命名的字符串 */ - public static String convertToCamelCase(String name) - { - StringBuilder result = new StringBuilder(); - // 快速检查 - if (name == null || name.isEmpty()) - { - // 没必要转换 - return ""; - } - else if (!name.contains("_")) - { - // 不含下划线,仅将首字母大写 - return name.substring(0, 1).toUpperCase() + name.substring(1); - } - // 用下划线将原始字符串分割 - String[] camels = name.split("_"); - for (String camel : camels) - { - // 跳过原始字符串中开头、结尾的下换线或双重下划线 - if (camel.isEmpty()) - { - continue; - } - // 首字母大写 - result.append(camel.substring(0, 1).toUpperCase()); - result.append(camel.substring(1).toLowerCase()); - } - return result.toString(); + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); } /** - * 驼峰式命名法 - * 例如:user_name->userName + * 驼峰式命名法 例如:user_name->userName */ - public static String toCamelCase(String s) - { - if (s == null) - { - return null; - } - if (s.indexOf(SEPARATOR) == -1) - { - return s; - } - s = s.toLowerCase(); - StringBuilder sb = new StringBuilder(s.length()); - boolean upperCase = false; - for (int i = 0; i < s.length(); i++) - { - char c = s.charAt(i); - - if (c == SEPARATOR) - { - upperCase = true; - } - else if (upperCase) - { - sb.append(Character.toUpperCase(c)); - upperCase = false; - } - else - { - sb.append(c); - } - } - return sb.toString(); + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); } /** * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 - * + * * @param str 指定字符串 * @param strs 需要检查的字符串数组 * @return 是否匹配 @@ -543,11 +491,11 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } /** - * 判断url是否与规则配置: - * ? 表示单个字符; - * * 表示一层路径内的任意字符串,不可跨层级; + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; * ** 表示任意层路径; - * + * * @param pattern 匹配规则 * @param url 需要匹配的url * @return @@ -566,7 +514,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 - * + * * @param num 数字对象 * @param size 字符串指定长度 * @return 返回数字的字符串格式,该字符串为指定长度。 @@ -578,7 +526,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils /** * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 - * + * * @param s 原始字符串 * @param size 字符串指定长度 * @param c 用于补齐的字符 @@ -612,4 +560,55 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } return sb.toString(); } -} \ No newline at end of file + + /** + * 切分字符串(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @return 分割后的数据列表 + */ + public static List splitList(String str) { + return splitTo(str, Convert::toStr); + } + + /** + * 切分字符串 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @return 分割后的数据列表 + */ + public static List splitList(String str, String separator) { + return splitTo(str, separator, Convert::toStr); + } + + /** + * 切分字符串自定义转换(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, Function mapper) { + return splitTo(str, SEPARATOR, mapper); + } + + /** + * 切分字符串自定义转换 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, String separator, Function mapper) { + if (isBlank(str)) { + return new ArrayList<>(0); + } + return StrUtil.split(str, separator) + .stream() + .filter(Objects::nonNull) + .map(mapper) + .collect(Collectors.toList()); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java index 088ae0b..8812a08 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java @@ -5,6 +5,9 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,10 +16,10 @@ import org.slf4j.LoggerFactory; * * @author ruoyi */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class Threads { - private static final Logger logger = LoggerFactory.getLogger(Threads.class); - + private static final Logger log = LoggerFactory.getLogger(Threads.class); /** * sleep等待,单位为毫秒 */ @@ -51,7 +54,7 @@ public class Threads pool.shutdownNow(); if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { - logger.info("Pool did not terminate"); + log.info("Pool did not terminate"); } } } @@ -93,7 +96,7 @@ public class Threads } if (t != null) { - logger.error(t.getMessage(), t); + log.error(t.getMessage(), t); } } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java new file mode 100644 index 0000000..7b331f0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.core.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; +import java.util.Set; + +/** + * Validator 校验框架工具 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ValidatorUtils { + + private static final Validator VALID = SpringUtils.getBean(Validator.class); + + public static void validate(T object, Class... groups) { + Set> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("参数校验异常", validate); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java index afe8115..2e4a79c 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java @@ -20,12 +20,17 @@ import org.apache.commons.lang3.ArrayUtils; import com.ruoyi.common.core.config.RuoYiConfig; import org.apache.commons.io.FilenameUtils; +import cn.hutool.core.io.FileUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + /** * 文件处理工具类 * * @author ruoyi */ -public class FileUtils +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class FileUtils extends FileUtil { public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; @@ -74,7 +79,7 @@ public class FileUtils */ public static String writeImportBytes(byte[] data) throws IOException { - return writeBytes(data, RuoYiConfig.getImportPath()); + return writeByte(data, RuoYiConfig.getImportPath()); } /** @@ -85,7 +90,7 @@ public class FileUtils * @return 目标文件 * @throws IOException IO异常 */ - public static String writeBytes(byte[] data, String uploadDir) throws IOException + public static String writeByte(byte[] data, String uploadDir) throws IOException { FileOutputStream fos = null; String pathName = ""; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java index 1b8345c..93aacdb 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java @@ -78,7 +78,6 @@ import org.slf4j.LoggerFactory; import com.ruoyi.common.core.config.RuoYiConfig; import com.ruoyi.common.core.exception.UtilException; import com.ruoyi.common.core.utils.DateUtils; -import com.ruoyi.common.core.utils.DictUtils; import com.ruoyi.common.core.utils.file.FileTypeUtils; import com.ruoyi.common.core.utils.file.FileUtils; import com.ruoyi.common.core.utils.file.ImageUtils; @@ -86,7 +85,7 @@ import com.ruoyi.common.core.utils.reflect.ReflectUtils; /** * Excel相关处理 - * + * * @author ruoyi */ public class ExcelUtil @@ -283,7 +282,7 @@ public class ExcelUtil /** * 对excel表单默认第一个索引名转换成list - * + * * @param is 输入流 * @return 转换后集合 */ @@ -294,7 +293,7 @@ public class ExcelUtil /** * 对excel表单默认第一个索引名转换成list - * + * * @param is 输入流 * @param titleNum 标题占用行数 * @return 转换后集合 @@ -306,7 +305,7 @@ public class ExcelUtil /** * 对excel表单指定表格索引名转换成list - * + * * @param sheetName 表格索引名 * @param titleNum 标题占用行数 * @param is 输入流 @@ -486,7 +485,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param list 导出数据集合 * @param sheetName 工作表的名称 * @return 结果 @@ -498,7 +497,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param list 导出数据集合 * @param sheetName 工作表的名称 * @param title 标题 @@ -512,7 +511,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param response 返回数据 * @param list 导出数据集合 * @param sheetName 工作表的名称 @@ -525,7 +524,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param response 返回数据 * @param list 导出数据集合 * @param sheetName 工作表的名称 @@ -542,7 +541,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param sheetName 工作表的名称 * @return 结果 */ @@ -553,7 +552,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param sheetName 工作表的名称 * @param title 标题 * @return 结果 @@ -566,7 +565,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param sheetName 工作表的名称 * @return 结果 */ @@ -577,7 +576,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param sheetName 工作表的名称 * @param title 标题 * @return 结果 @@ -592,7 +591,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @return 结果 */ public void exportExcel(HttpServletResponse response) @@ -614,7 +613,7 @@ public class ExcelUtil /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @return 结果 */ public AjaxResult exportExcel() @@ -682,7 +681,7 @@ public class ExcelUtil /** * 填充excel数据 - * + * * @param index 序号 * @param row 单元格行 */ @@ -753,7 +752,7 @@ public class ExcelUtil /** * 创建表格样式 - * + * * @param wb 工作薄对象 * @return 样式列表 */ @@ -806,7 +805,7 @@ public class ExcelUtil /** * 根据Excel注解创建表格头样式 - * + * * @param wb 工作薄对象 * @return 自定义样式列表 */ @@ -839,7 +838,7 @@ public class ExcelUtil /** * 根据Excel注解创建表格列样式 - * + * * @param wb 工作薄对象 * @return 自定义样式列表 */ @@ -901,7 +900,7 @@ public class ExcelUtil /** * 设置单元格信息 - * + * * @param value 单元格值 * @param attr 注解相关 * @param cell 单元格信息 @@ -1070,7 +1069,7 @@ public class ExcelUtil /** * 设置 POI XSSFSheet 单元格提示或选择框 - * + * * @param sheet 表单 * @param textlist 下拉框显示的内容 * @param promptContent 提示内容 @@ -1107,7 +1106,7 @@ public class ExcelUtil /** * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). - * + * * @param sheet 要设置的sheet. * @param textlist 下拉框显示的内容 * @param promptContent 提示内容 @@ -1159,7 +1158,7 @@ public class ExcelUtil /** * 解析导出值 0=男,1=女,2=未知 - * + * * @param propertyValue 参数值 * @param converterExp 翻译注解 * @param separator 分隔符 @@ -1196,7 +1195,7 @@ public class ExcelUtil /** * 反向解析值 男=0,女=1,未知=2 - * + * * @param propertyValue 参数值 * @param converterExp 翻译注解 * @param separator 分隔符 @@ -1233,7 +1232,7 @@ public class ExcelUtil /** * 解析字典值 - * + * * @param dictValue 字典值 * @param dictType 字典类型 * @param separator 分隔符 @@ -1241,12 +1240,13 @@ public class ExcelUtil */ public static String convertDictByExp(String dictValue, String dictType, String separator) { - return DictUtils.getDictLabel(dictType, dictValue, separator); + //return DictUtils.getDictLabel(dictType, dictValue, separator); + return ""; } /** * 反向解析值字典值 - * + * * @param dictLabel 字典标签 * @param dictType 字典类型 * @param separator 分隔符 @@ -1254,12 +1254,13 @@ public class ExcelUtil */ public static String reverseDictByExp(String dictLabel, String dictType, String separator) { - return DictUtils.getDictValue(dictType, dictLabel, separator); + //return DictUtils.getDictValue(dictType, dictLabel, separator); + return ""; } /** * 数据处理器 - * + * * @param value 数据值 * @param excel 数据注解 * @return @@ -1336,7 +1337,7 @@ public class ExcelUtil /** * 获取下载路径 - * + * * @param filename 文件名称 */ public String getAbsoluteFile(String filename) @@ -1352,7 +1353,7 @@ public class ExcelUtil /** * 获取bean中的属性值 - * + * * @param vo 实体对象 * @param field 字段 * @param excel 注解 @@ -1383,7 +1384,7 @@ public class ExcelUtil /** * 以类的属性的get方法方法形式获取值 - * + * * @param o * @param name * @return value @@ -1489,7 +1490,7 @@ public class ExcelUtil /** * 创建工作表 - * + * * @param sheetNo sheet数量 * @param index 序号 */ @@ -1506,7 +1507,7 @@ public class ExcelUtil /** * 获取单元格值 - * + * * @param row 获取的行 * @param column 获取单元格列号 * @return 单元格值 @@ -1566,7 +1567,7 @@ public class ExcelUtil /** * 判断是否是空行 - * + * * @param row 判断的行 * @return */ @@ -1654,7 +1655,7 @@ public class ExcelUtil /** * 格式化不同类型的日期对象 - * + * * @param dateFormat 日期格式 * @param val 被格式化的日期对象 * @return 格式化后的日期字符 @@ -1720,7 +1721,7 @@ public class ExcelUtil /** * 获取对象的子列表方法 - * + * * @param name 名称 * @param pojoClass 类对象 * @return 子列表方法 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java index d2e0bf1..8909ada 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java @@ -1,5 +1,6 @@ package com.ruoyi.common.core.utils.reflect; +import cn.hutool.core.util.ReflectUtil; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -18,11 +19,11 @@ import org.slf4j.LoggerFactory; /** * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. - * + * * @author ruoyi */ @SuppressWarnings("rawtypes") -public class ReflectUtils +public class ReflectUtils extends ReflectUtil { private static final String SETTER_PREFIX = "set"; @@ -71,51 +72,51 @@ public class ReflectUtils } } - /** - * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. - */ - @SuppressWarnings("unchecked") - public static E getFieldValue(final Object obj, final String fieldName) - { - Field field = getAccessibleField(obj, fieldName); - if (field == null) - { - logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); - return null; - } - E result = null; - try - { - result = (E) field.get(obj); - } - catch (IllegalAccessException e) - { - logger.error("不可能抛出的异常{}", e.getMessage()); - } - return result; - } - - /** - * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. - */ - public static void setFieldValue(final Object obj, final String fieldName, final E value) - { - Field field = getAccessibleField(obj, fieldName); - if (field == null) - { - // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); - logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); - return; - } - try - { - field.set(obj, value); - } - catch (IllegalAccessException e) - { - logger.error("不可能抛出的异常: {}", e.getMessage()); - } - } +// /** +// * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. +// */ +// @SuppressWarnings("unchecked") +// public static E getFieldValue(final Object obj, final String fieldName) +// { +// Field field = getAccessibleField(obj, fieldName); +// if (field == null) +// { +// logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); +// return null; +// } +// E result = null; +// try +// { +// result = (E) field.get(obj); +// } +// catch (IllegalAccessException e) +// { +// logger.error("不可能抛出的异常{}", e.getMessage()); +// } +// return result; +// } +// +// /** +// * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. +// */ +// public static void setFieldValue(final Object obj, final String fieldName, final E value) +// { +// Field field = getAccessibleField(obj, fieldName); +// if (field == null) +// { +// // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); +// logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); +// return; +// } +// try +// { +// field.set(obj, value); +// } +// catch (IllegalAccessException e) +// { +// logger.error("不可能抛出的异常: {}", e.getMessage()); +// } +// } /** * 直接调用对象方法, 无视private/protected修饰符. diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java deleted file mode 100644 index 23ec675..0000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.ruoyi.common.core.utils.spring; - -import com.ruoyi.common.core.utils.StringUtils; -import org.springframework.aop.framework.AopContext; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -/** - * spring工具类 方便在非spring管理环境中获取bean - * - * @author ruoyi - */ -@Component -public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware -{ - /** Spring应用上下文环境 */ - private static ConfigurableListableBeanFactory beanFactory; - - private static ApplicationContext applicationContext; - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException - { - SpringUtils.beanFactory = beanFactory; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - SpringUtils.applicationContext = applicationContext; - } - - /** - * 获取对象 - * - * @param name - * @return Object 一个以所给名字注册的bean的实例 - * @throws org.springframework.beans.BeansException - * - */ - @SuppressWarnings("unchecked") - public static T getBean(String name) throws BeansException - { - return (T) beanFactory.getBean(name); - } - - /** - * 获取类型为requiredType的对象 - * - * @param clz - * @return - * @throws org.springframework.beans.BeansException - * - */ - public static T getBean(Class clz) throws BeansException - { - T result = (T) beanFactory.getBean(clz); - return result; - } - - /** - * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true - * - * @param name - * @return boolean - */ - public static boolean containsBean(String name) - { - return beanFactory.containsBean(name); - } - - /** - * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) - * - * @param name - * @return boolean - * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException - * - */ - public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException - { - return beanFactory.isSingleton(name); - } - - /** - * @param name - * @return Class 注册对象的类型 - * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException - * - */ - public static Class getType(String name) throws NoSuchBeanDefinitionException - { - return beanFactory.getType(name); - } - - /** - * 如果给定的bean名字在bean定义中有别名,则返回这些别名 - * - * @param name - * @return - * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException - * - */ - public static String[] getAliases(String name) throws NoSuchBeanDefinitionException - { - return beanFactory.getAliases(name); - } - - /** - * 获取aop代理对象 - * - * @param invoker - * @return - */ - @SuppressWarnings("unchecked") - public static T getAopProxy(T invoker) - { - return (T) AopContext.currentProxy(); - } - - /** - * 获取当前的环境配置,无配置返回null - * - * @return 当前的环境配置 - */ - public static String[] getActiveProfiles() - { - return applicationContext.getEnvironment().getActiveProfiles(); - } - - /** - * 获取当前的环境配置,当有多个环境配置时,只获取第一个 - * - * @return 当前的环境配置 - */ - public static String getActiveProfile() - { - final String[] activeProfiles = getActiveProfiles(); - return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; - } - - /** - * 获取配置文件中的值 - * - * @param key 配置文件的key - * @return 当前的配置文件的值 - * - */ - public static String getRequiredProperty(String key) - { - return applicationContext.getEnvironment().getRequiredProperty(key); - } -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java new file mode 100644 index 0000000..e1934e1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java @@ -0,0 +1,9 @@ +package com.ruoyi.common.core.validate; + +/** + * 校验分组 add + * + * @author Lion Li + */ +public interface AddGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java new file mode 100644 index 0000000..3c6ca7f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java @@ -0,0 +1,9 @@ +package com.ruoyi.common.core.validate; + +/** + * 校验分组 edit + * + * @author Lion Li + */ +public interface EditGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java new file mode 100644 index 0000000..bbbfe03 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java @@ -0,0 +1,9 @@ +package com.ruoyi.common.core.validate; + +/** + * 校验分组 query + * + * @author Lion Li + */ +public interface QueryGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java new file mode 100644 index 0000000..536a85b --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java @@ -0,0 +1,7 @@ +package com.ruoyi.common.core.validate.auth; + +/** + * @Author Michelle.Chung + */ +public interface EmailGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java new file mode 100644 index 0000000..2dba18e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java @@ -0,0 +1,7 @@ +package com.ruoyi.common.core.validate.auth; + +/** + * @Author Michelle.Chung + */ +public interface PasswordGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java new file mode 100644 index 0000000..660609f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java @@ -0,0 +1,7 @@ +package com.ruoyi.common.core.validate.auth; + +/** + * @Author Michelle.Chung + */ +public interface SmsGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java new file mode 100644 index 0000000..5a6a59a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java @@ -0,0 +1,4 @@ +package com.ruoyi.common.core.validate.auth; + +public interface SocialGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java new file mode 100644 index 0000000..3f792f8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java @@ -0,0 +1,7 @@ +package com.ruoyi.common.core.validate.auth; + +/** + * @Author Michelle.Chung + */ +public interface WechatGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..11c007c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,5 @@ +com.ruoyi.common.core.config.ApplicationConfig +com.ruoyi.common.core.config.AsyncConfig +com.ruoyi.common.core.config.RuoYiConfig +com.ruoyi.common.core.config.ThreadPoolConfig +com.ruoyi.common.core.config.ValidatorConfig diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml new file mode 100644 index 0000000..1b91b7b --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/pom.xml @@ -0,0 +1,30 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-excel + + + ruoyi-common-excel excel表格模块 + + + + + com.ruoyi + ruoyi-common-json + + + + com.alibaba + easyexcel + + + + diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java new file mode 100644 index 0000000..5c0f552 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java @@ -0,0 +1,24 @@ +package com.ruoyi.common.excel.annotation; + +import com.ruoyi.common.excel.core.CellMergeStrategy; + +import java.lang.annotation.*; + +/** + * excel 列单元格合并(合并列相同项) + * + * 需搭配 {@link CellMergeStrategy} 策略使用 + * + * @author Lion Li + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java new file mode 100644 index 0000000..162dc79 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java @@ -0,0 +1,32 @@ +package com.ruoyi.common.excel.annotation; + +import com.ruoyi.common.core.utils.StringUtils; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * @author Lion Li + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default StringUtils.SEPARATOR; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java new file mode 100644 index 0000000..d5fda7c --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.excel.annotation; + +import java.lang.annotation.*; + +/** + * 枚举格式化 + * + * @author Liang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelEnumFormat { + + /** + * 字典枚举类型 + */ + Class> enumClass(); + + /** + * 字典枚举类中对应的code属性名称,默认为code + */ + String codeField() default "code"; + + /** + * 字典枚举类中对应的text属性名称,默认为text + */ + String textField() default "text"; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java new file mode 100644 index 0000000..1e10334 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java @@ -0,0 +1,52 @@ +package com.ruoyi.common.excel.convert; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * 大数值转换 + * Excel 数值长度位15位 大于15位的数值转换位字符串 + * + * @author Lion Li + */ +@Slf4j +public class ExcelBigNumberConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Convert.toLong(cellData.getData()); + } + + @Override + public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNotNull(object)) { + String str = Convert.toStr(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } + } + WriteCellData cellData = new WriteCellData<>(new BigDecimal(object)); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java new file mode 100644 index 0000000..5d69355 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java @@ -0,0 +1,73 @@ +package com.ruoyi.common.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.utils.ExcelUtil; +import com.ruoyi.common.core.service.DictService; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 字典格式化转换处理 + * + * @author Lion Li + */ +@Slf4j +public class ExcelDictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String label = cellData.getStringValue(); + String value; + if (StringUtils.isBlank(type)) { + value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); + } else { + value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator()); + } + return Convert.convert(contentProperty.getField().getType(), value); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String value = Convert.toStr(object); + String label; + if (StringUtils.isBlank(type)) { + label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); + } else { + label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator()); + } + return new WriteCellData<>(label); + } + + private ExcelDictFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java new file mode 100644 index 0000000..2fb1d32 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java @@ -0,0 +1,87 @@ +package com.ruoyi.common.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.ruoyi.common.core.utils.reflect.ReflectUtils; +import com.ruoyi.common.excel.annotation.ExcelEnumFormat; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 枚举格式化转换处理 + * + * @author Liang + */ +@Slf4j +public class ExcelEnumConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + cellData.checkEmpty(); + // Excel中填入的是枚举中指定的描述 + Object textValue = switch (cellData.getType()) { + case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue(); + case NUMBER -> cellData.getNumberValue(); + case BOOLEAN -> cellData.getBooleanValue(); + default -> throw new IllegalArgumentException("单元格类型异常!"); + }; + // 如果是空值 + if (ObjectUtil.isNull(textValue)) { + return null; + } + Map enumCodeToTextMap = beforeConvert(contentProperty); + // 从Java输出至Excel是code转text + // 因此从Excel转Java应该将text与code对调 + Map enumTextToCodeMap = new HashMap<>(); + enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key)); + // 应该从text -> code中查找 + Object codeValue = enumTextToCodeMap.get(textValue); + return Convert.convert(contentProperty.getField().getType(), codeValue); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + Map enumValueMap = beforeConvert(contentProperty); + String value = Convert.toStr(enumValueMap.get(object), ""); + return new WriteCellData<>(value); + } + + private Map beforeConvert(ExcelContentProperty contentProperty) { + ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); + Map enumValueMap = new HashMap<>(); + Enum[] enumConstants = anno.enumClass().getEnumConstants(); + for (Enum enumConstant : enumConstants) { + Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); + String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); + enumValueMap.put(codeValue, textValue); + } + return enumValueMap; + } + + private ExcelEnumFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class); + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java new file mode 100644 index 0000000..2e7e4d9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java @@ -0,0 +1,121 @@ +package com.ruoyi.common.excel.core; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import com.ruoyi.common.core.utils.reflect.ReflectUtils; +import com.ruoyi.common.excel.annotation.CellMerge; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 列值重复合并策略 + * + * @author Lion Li + */ +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy { + + private final List cellList; + private final boolean hasTitle; + private int rowIndex; + + public CellMergeStrategy(List list, boolean hasTitle) { + this.hasTitle = hasTitle; + // 行合并开始下标 + this.rowIndex = hasTitle ? 1 : 0; + this.cellList = handle(list, hasTitle); + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + // judge the list is not null + if (CollUtil.isNotEmpty(cellList)) { + // the judge is necessary + if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) { + for (CellRangeAddress item : cellList) { + sheet.addMergedRegion(item); + } + } + } + } + + @SneakyThrows + private List handle(List list, boolean hasTitle) { + List cellList = new ArrayList<>(); + if (CollUtil.isEmpty(list)) { + return cellList; + } + Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName())); + + // 有注解的字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + if (hasTitle) { + ExcelProperty property = field.getAnnotation(ExcelProperty.class); + rowIndex = Math.max(rowIndex, property.value().length); + } + } + } + + Map map = new HashMap<>(); + // 生成两两合并单元格 + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); + Object val = ReflectUtils.invokeGetter(list.get(i), field.getName()); + + int colNum = mergeFieldsIndex.get(j); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object cellValue = repeatCell.getValue(); + if (cellValue == null || "".equals(cellValue)) { + // 空值跳过不合并 + continue; + } + if (!cellValue.equals(val)) { + if (i - repeatCell.getCurrent() > 1) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent()) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); + } + } + } + } + } + return cellList; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java new file mode 100644 index 0000000..1cf6426 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java @@ -0,0 +1,104 @@ +package com.ruoyi.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.ruoyi.common.core.utils.StreamUtils; +import com.ruoyi.common.core.utils.ValidatorUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; +import java.util.Set; + +/** + * Excel 导入监听 + * + * @author Yjoioooo + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + + /** + * 是否Validator检验,默认为是 + */ + private Boolean isValidate = Boolean.TRUE; + + /** + * excel 表头数据 + */ + private Map headMap; + + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefaultExcelResult<>(); + this.isValidate = isValidate; + } + + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context Excel 上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException excelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException constraintViolationException) { + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); + errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("所有数据解析完成!"); + } + + @Override + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java new file mode 100644 index 0000000..e57b2a5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java @@ -0,0 +1,73 @@ +package com.ruoyi.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认excel返回对象 + * + * @author Yjoioooo + * @author Lion Li + */ +public class DefaultExcelResult implements ExcelResult { + + /** + * 数据对象list + */ + @Setter + private List list; + + /** + * 错误信息列表 + */ + @Setter + private List errorList; + + public DefaultExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefaultExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefaultExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + + /** + * 获取导入回执 + * + * @return 导入回执 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return ""; + } + } + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java new file mode 100644 index 0000000..1caf9bb --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java @@ -0,0 +1,149 @@ +package com.ruoyi.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import com.ruoyi.common.core.exception.ServiceException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + *

Excel下拉可选项

+ * 注意:为确保下拉框解析正确,传值务必使用createOptionValue()做为值的拼接 + * + * @author Emil.Zhang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuppressWarnings("unused") +public class DropDownOptions { + /** + * 一级下拉所在列index,从0开始算 + */ + private int index = 0; + /** + * 二级下拉所在的index,从0开始算,不能与一级相同 + */ + private int nextIndex = 0; + /** + * 一级下拉所包含的数据 + */ + private List options = new ArrayList<>(); + /** + * 二级下拉所包含的数据Map + *

以每一个一级选项值为Key,每个一级选项对应的二级数据为Value

+ */ + private Map> nextOptions = new HashMap<>(); + /** + * 分隔符 + */ + private static final String DELIMITER = "_"; + + /** + * 创建只有一级的下拉选 + */ + public DropDownOptions(int index, List options) { + this.index = index; + this.options = options; + } + + /** + *

创建每个选项可选值

+ *

注意:不能以数字,特殊符号开头,选项中不可以包含任何运算符号

+ * + * @param vars 可选值内包含的参数 + * @return 合规的可选值 + */ + public static String createOptionValue(Object... vars) { + StringBuilder stringBuffer = new StringBuilder(); + String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$"; + for (int i = 0; i < vars.length; i++) { + String var = StrUtil.trimToEmpty(String.valueOf(vars[i])); + if (!var.matches(regex)) { + throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字"); + } + stringBuffer.append(var); + if (i < vars.length - 1) { + // 直至最后一个前,都以_作为切割线 + stringBuffer.append(DELIMITER); + } + } + if (stringBuffer.toString().matches("^\\d_*$")) { + throw new ServiceException("禁止以数字开头"); + } + return stringBuffer.toString(); + } + + /** + * 将处理后合理的可选值解析为原始的参数 + * + * @param option 经过处理后的合理的可选项 + * @return 原始的参数 + */ + public static List analyzeOptionValue(String option) { + return StrUtil.split(option, DELIMITER, true, true); + } + + /** + * 创建级联下拉选项 + * + * @param parentList 父实体可选项原始数据 + * @param parentIndex 父下拉选位置 + * @param sonList 子实体可选项原始数据 + * @param sonIndex 子下拉选位置 + * @param parentHowToGetIdFunction 父类如何获取唯一标识 + * @param sonHowToGetParentIdFunction 子类如何获取父类的唯一标识 + * @param howToBuildEveryOption 如何生成下拉选内容 + * @return 级联下拉选项 + */ + public static DropDownOptions buildLinkedOptions(List parentList, + int parentIndex, + List sonList, + int sonIndex, + Function parentHowToGetIdFunction, + Function sonHowToGetParentIdFunction, + Function howToBuildEveryOption) { + DropDownOptions parentLinkSonOptions = new DropDownOptions(); + // 先创建父类的下拉 + parentLinkSonOptions.setIndex(parentIndex); + parentLinkSonOptions.setOptions( + parentList.stream() + .map(howToBuildEveryOption) + .collect(Collectors.toList()) + ); + // 提取父-子级联下拉 + Map> sonOptions = new HashMap<>(); + // 父级依据自己的ID分组 + Map> parentGroupByIdMap = + parentList.stream().collect(Collectors.groupingBy(parentHowToGetIdFunction)); + // 遍历每个子集,提取到Map中 + sonList.forEach(everySon -> { + if (parentGroupByIdMap.containsKey(sonHowToGetParentIdFunction.apply(everySon))) { + // 找到对应的上级 + T parentObj = parentGroupByIdMap.get(sonHowToGetParentIdFunction.apply(everySon)).get(0); + // 提取名称和ID作为Key + String key = howToBuildEveryOption.apply(parentObj); + // Key对应的Value + List thisParentSonOptionList; + if (sonOptions.containsKey(key)) { + thisParentSonOptionList = sonOptions.get(key); + } else { + thisParentSonOptionList = new ArrayList<>(); + sonOptions.put(key, thisParentSonOptionList); + } + // 往Value中添加当前子集选项 + thisParentSonOptionList.add(howToBuildEveryOption.apply(everySon)); + } + }); + parentLinkSonOptions.setNextIndex(sonIndex); + parentLinkSonOptions.setNextOptions(sonOptions); + return parentLinkSonOptions; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelDownHandler.java new file mode 100644 index 0000000..53a96ed --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelDownHandler.java @@ -0,0 +1,371 @@ +package com.ruoyi.common.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.EnumUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.metadata.FieldCache; +import com.alibaba.excel.metadata.FieldWrapper; +import com.alibaba.excel.util.ClassUtils; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.ss.util.WorkbookUtil; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.service.DictService; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StreamUtils; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.annotation.ExcelEnumFormat; + +import java.lang.reflect.Field; +import java.util.*; + +/** + *

Excel表格下拉选操作

+ * 考虑到下拉选过多可能导致Excel打开缓慢的问题,只校验前1000行 + *

+ * 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出 + * + * @author Emil.Zhang + */ +@Slf4j +public class ExcelDownHandler implements SheetWriteHandler { + + /** + * Excel表格中的列名英文 + * 仅为了解析列英文,禁止修改 + */ + private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * 单选数据Sheet名 + */ + private static final String OPTIONS_SHEET_NAME = "options"; + /** + * 联动选择数据Sheet名的头 + */ + private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions"; + /** + * 下拉可选项 + */ + private final List dropDownOptions; + /** + * 当前单选进度 + */ + private int currentOptionsColumnIndex; + /** + * 当前联动选择进度 + */ + private int currentLinkedOptionsSheetIndex; + private final DictService dictService; + + public ExcelDownHandler(List options) { + this.dropDownOptions = options; + this.currentOptionsColumnIndex = 0; + this.currentLinkedOptionsSheetIndex = 0; + this.dictService = SpringUtils.getBean(DictService.class); + } + + /** + *

开始创建下拉数据

+ * 1.通过解析传入的@ExcelProperty同级是否标注有@DropDown选项 + * 如果有且设置了value值,则将其直接置为下拉可选项 + *

+ * 2.或者在调用ExcelUtil时指定了可选项,将依据传入的可选项做下拉 + *

+ * 3.二者并存,注意调用方式 + */ + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + // 开始设置下拉框 HSSFWorkbook + DataValidationHelper helper = sheet.getDataValidationHelper(); + Workbook workbook = writeWorkbookHolder.getWorkbook(); + FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder); + for (Map.Entry entry : fieldCache.getSortedFieldMap().entrySet()) { + Integer index = entry.getKey(); + FieldWrapper wrapper = entry.getValue(); + Field field = wrapper.getField(); + // 循环实体中的每个属性 + // 可选的下拉值 + List options = new ArrayList<>(); + if (field.isAnnotationPresent(ExcelDictFormat.class)) { + // 如果指定了@ExcelDictFormat,则使用字典的逻辑 + ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class); + String dictType = format.dictType(); + String converterExp = format.readConverterExp(); + if (StrUtil.isNotBlank(dictType)) { + // 如果传递了字典名,则依据字典建立下拉 + Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType)) + .orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType))) + .values(); + options = new ArrayList<>(values); + } else if (StrUtil.isNotBlank(converterExp)) { + // 如果指定了确切的值,则直接解析确切的值 + options = StrUtil.split(converterExp, format.separator(), true, true); + } + } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) { + // 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑 + ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class); + List values = EnumUtil.getFieldValues(format.enumClass(), format.textField()); + options = StreamUtils.toList(values, String::valueOf); + } + if (ObjectUtil.isNotEmpty(options)) { + // 仅当下拉可选项不为空时执行 + if (options.size() > 20) { + // 这里限制如果可选项大于20,则使用额外表形式 + dropDownWithSheet(helper, workbook, sheet, index, options); + } else { + // 否则使用固定值形式 + dropDownWithSimple(helper, sheet, index, options); + } + } + } + if (CollUtil.isEmpty(dropDownOptions)) { + return; + } + dropDownOptions.forEach(everyOptions -> { + // 如果传递了下拉框选择器参数 + if (!everyOptions.getNextOptions().isEmpty()) { + // 当二级选项不为空时,使用额外关联表的形式 + dropDownLinkedOptions(helper, workbook, sheet, everyOptions); + } else if (everyOptions.getOptions().size() > 10) { + // 当一级选项参数个数大于10,使用额外表的形式 + dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } else if (everyOptions.getOptions().size() != 0) { + // 当一级选项个数不为空,使用默认形式 + dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } + }); + } + + /** + *

简单下拉框

+ * 直接将可选项拼接为指定列的数据校验值 + * + * @param celIndex 列index + * @param value 下拉选可选值 + */ + private void dropDownWithSimple(DataValidationHelper helper, Sheet sheet, Integer celIndex, List value) { + if (ObjectUtil.isEmpty(value)) { + return; + } + this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class))); + } + + /** + *

额外表格形式的级联下拉框

+ * + * @param options 额外表格形式存储的下拉可选项 + */ + private void dropDownLinkedOptions(DataValidationHelper helper, Workbook workbook, Sheet sheet, DropDownOptions options) { + String linkedOptionsSheetName = String.format("%s_%d", LINKED_OPTIONS_SHEET_NAME, currentLinkedOptionsSheetIndex); + // 创建联动下拉数据表 + Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName)); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true); + // 完善横向的一级选项数据表 + List firstOptions = options.getOptions(); + Map> secoundOptionsMap = options.getNextOptions(); + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + name.setNameName(linkedOptionsSheetName); + // 以横向第一行创建一级下拉拼接引用位置 + String firstOptionsFunction = String.format("%s!$%s$1:$%s$1", + linkedOptionsSheetName, + getExcelColumnName(0), + getExcelColumnName(firstOptions.size()) + ); + // 设置名称管理器的引用位置 + name.setRefersToFormula(firstOptionsFunction); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName)); + + for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) { + // 先提取主表中一级下拉的列名 + String firstOptionsColumnName = getExcelColumnName(columIndex); + // 一次循环是每一个一级选项 + int finalI = columIndex; + // 本次循环的一级选项值 + String thisFirstOptionsValue = firstOptions.get(columIndex); + // 创建第一行的数据 + Optional.ofNullable(linkedOptionsDataSheet.getRow(0)) + // 如果不存在则创建第一行 + .orElseGet(() -> linkedOptionsDataSheet.createRow(finalI)) + // 第一行当前列 + .createCell(columIndex) + // 设置值为当前一级选项值 + .setCellValue(thisFirstOptionsValue); + + // 第二行开始,设置第二级别选项参数 + List secondOptions = secoundOptionsMap.get(thisFirstOptionsValue); + if (CollUtil.isEmpty(secondOptions)) { + // 必须保证至少有一个关联选项,否则将导致Excel解析错误 + secondOptions = Collections.singletonList("暂无_0"); + } + + // 以该一级选项值创建子名称管理器 + Name sonName = workbook.createName(); + // 设置名称管理器的别名 + sonName.setNameName(thisFirstOptionsValue); + // 以第二行该列数据拼接引用位置 + String sonFunction = String.format("%s!$%s$2:$%s$%d", + linkedOptionsSheetName, + firstOptionsColumnName, + firstOptionsColumnName, + secondOptions.size() + 1 + ); + // 设置名称管理器的引用位置 + sonName.setRefersToFormula(sonFunction); + // 数据验证为序列模式,引用到每一个主表中的二级选项位置 + // 创建子项的名称管理器,只是为了使得Excel可以识别到数据 + String mainSheetFirstOptionsColumnName = getExcelColumnName(options.getIndex()); + for (int i = 0; i < 100; i++) { + // 以一级选项对应的主体所在位置创建二级下拉 + String secondOptionsFunction = String.format("=INDIRECT(%s%d)", mainSheetFirstOptionsColumnName, i + 1); + // 二级只能主表每一行的每一列添加二级校验 + markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction)); + } + + for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) { + // 从第二行开始填充二级选项 + int finalRowIndex = rowIndex + 1; + int finalColumIndex = columIndex; + + Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex)) + // 没有则创建 + .orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex)); + Optional + // 在本级一级选项所在的列 + .ofNullable(row.getCell(finalColumIndex)) + // 不存在则创建 + .orElseGet(() -> row.createCell(finalColumIndex)) + // 设置二级选项值 + .setCellValue(secondOptions.get(rowIndex)); + } + } + + currentLinkedOptionsSheetIndex++; + } + + /** + *

额外表格形式的普通下拉框

+ * 由于下拉框可选值数量过多,为提升Excel打开效率,使用额外表格形式做下拉 + * + * @param celIndex 下拉选 + * @param value 下拉选可选值 + */ + private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List value) { + // 创建下拉数据表 + Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))) + .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true); + // 完善纵向的一级选项数据表 + for (int i = 0; i < value.size(); i++) { + int finalI = i; + // 获取每一选项行,如果没有则创建 + Row row = Optional.ofNullable(simpleDataSheet.getRow(i)) + .orElseGet(() -> simpleDataSheet.createRow(finalI)); + // 获取本级选项对应的选项列,如果没有则创建 + Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex)) + .orElseGet(() -> row.createCell(currentOptionsColumnIndex)); + // 设置值 + cell.setCellValue(value.get(i)); + } + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex); + name.setNameName(nameName); + // 以纵向第一列创建一级下拉拼接引用位置 + String function = String.format("%s!$%s$1:$%s$%d", + OPTIONS_SHEET_NAME, + getExcelColumnName(currentOptionsColumnIndex), + getExcelColumnName(currentOptionsColumnIndex), + value.size()); + // 设置名称管理器的引用位置 + name.setRefersToFormula(function); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName)); + currentOptionsColumnIndex++; + } + + /** + * 挂载下拉的列,仅限一级选项 + */ + private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex, + DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 挂载下拉的列,仅限二级选项 + */ + private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex, + Integer celIndex, DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 应用数据校验 + */ + private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet, + DataValidationConstraint constraint, CellRangeAddressList addressList) { + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, addressList); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + //数据校验 + dataValidation.setSuppressDropDownArrow(true); + //错误提示 + dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP); + dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致"); + dataValidation.setShowErrorBox(true); + //选定提示 + dataValidation.createPromptBox("填写说明:", "填写内容只能为下拉中数据,其他数据将导致导入失败"); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + *

依据列index获取列名英文

+ * 依据列index转换为Excel中的列名英文 + *

例如第1列,index为0,解析出来为A列

+ * 第27列,index为26,解析为AA列 + *

第28列,index为27,解析为AB列

+ * + * @param columnIndex 列index + * @return 列index所在得英文名 + */ + private String getExcelColumnName(int columnIndex) { + // 26一循环的次数 + int columnCircleCount = columnIndex / 26; + // 26一循环内的位置 + int thisCircleColumnIndex = columnIndex % 26; + // 26一循环的次数大于0,则视为栏名至少两位 + String columnPrefix = columnCircleCount == 0 + ? StrUtil.EMPTY + : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1); + // 从26一循环内取对应的栏位名 + String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1); + // 将二者拼接即为最终的栏位名 + return columnPrefix + columnNext; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelListener.java new file mode 100644 index 0000000..093b94f --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelListener.java @@ -0,0 +1,14 @@ +package com.ruoyi.common.excel.core; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + * @author Lion Li + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelResult.java new file mode 100644 index 0000000..81aab5d --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/ExcelResult.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.excel.core; + +import java.util.List; + +/** + * excel返回对象 + * + * @author Lion Li + */ +public interface ExcelResult { + + /** + * 对象列表 + */ + List getList(); + + /** + * 错误列表 + */ + List getErrorList(); + + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/utils/ExcelUtil.java new file mode 100644 index 0000000..e3ceb60 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/utils/ExcelUtil.java @@ -0,0 +1,380 @@ +package com.ruoyi.common.excel.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.ruoyi.common.excel.convert.ExcelBigNumberConvert; +import com.ruoyi.common.excel.core.*; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.file.FileUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Excel相关处理 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ExcelUtil { + + /** + * 同步导入(适用于小数据量) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static List importExcel(InputStream is, Class clazz) { + return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); + } + + + /** + * 使用校验监听器 异步导入 同步返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param isValidate 是否 Validator 检验 默认为是 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate) { + DefaultExcelListener listener = new DefaultExcelListener<>(isValidate); + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 使用自定义监听器 异步导入 自定义返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param listener 自定义监听器 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, ExcelListener listener) { + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, false, os, null); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + * @param options 级联下拉选 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response, List options) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, false, os, options); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, os, null); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + * @param options 级联下拉选 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response, List options) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, os, options); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os) { + exportExcel(list, sheetName, clazz, false, os, null); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + * @param options 级联下拉选内容 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os, List options) { + exportExcel(list, sheetName, clazz, false, os, options); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, + OutputStream os, List options) { + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(list, true)); + } + // 添加下拉框操作 + builder.registerWriteHandler(new ExcelDownHandler(options)); + builder.doWrite(list); + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplate(List data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplate(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplate(List data, String templatePath, OutputStream os) { + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + // 单表多数据导出 模板格式为 {.属性} + for (Object d : data) { + excelWriter.fill(d, writeSheet); + } + excelWriter.finish(); + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplateMultiList(Map data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplateMultiList(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplateMultiList(Map data, String templatePath, OutputStream os) { + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + for (Map.Entry map : data.entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + excelWriter.finish(); + } + + /** + * 重置响应体 + */ + private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException { + String filename = encodingFilename(sheetName); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1] + separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0] + separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 编码文件名 + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } + +} diff --git a/ruoyi-common/ruoyi-common-json/pom.xml b/ruoyi-common/ruoyi-common-json/pom.xml new file mode 100644 index 0000000..5491e3a --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/pom.xml @@ -0,0 +1,37 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-json + + + ruoyi-common-json 序列化模块 + + + + + com.ruoyi + ruoyi-common-core + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/config/JacksonConfig.java b/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/config/JacksonConfig.java new file mode 100644 index 0000000..6b09b47 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/config/JacksonConfig.java @@ -0,0 +1,47 @@ +package com.ruoyi.common.json.config; + +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.ruoyi.common.json.handler.BigNumberSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * jackson 配置 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration(before = JacksonAutoConfiguration.class) +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + // 全局配置序列化返回 JSON 处理 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + builder.modules(javaTimeModule); + builder.timeZone(TimeZone.getDefault()); + log.info("初始化 jackson 配置"); + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/handler/BigNumberSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/handler/BigNumberSerializer.java new file mode 100644 index 0000000..bb797b3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/handler/BigNumberSerializer.java @@ -0,0 +1,42 @@ +package com.ruoyi.common.json.handler; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 超出 JS 最大最小值 处理 + * + * @author Lion Li + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + + /** + * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化位字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/utils/JsonUtils.java b/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/utils/JsonUtils.java new file mode 100644 index 0000000..66a63a2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/com/ruoyi/common/json/utils/JsonUtils.java @@ -0,0 +1,113 @@ +package com.ruoyi.common.json.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 类型不匹配说明不是json + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static List parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..6847712 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.ruoyi.common.json.config.JacksonConfig diff --git a/ruoyi-common/ruoyi-common-log/pom.xml b/ruoyi-common/ruoyi-common-log/pom.xml new file mode 100644 index 0000000..f64a27e --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/pom.xml @@ -0,0 +1,37 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-log + + + ruoyi-common-log 日志记录 + + + + + + com.ruoyi + ruoyi-common-security + + + + com.ruoyi + ruoyi-common-json + + + + com.alibaba + transmittable-thread-local + + + + + diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java new file mode 100644 index 0000000..4e5fc58 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java @@ -0,0 +1,48 @@ +package com.ruoyi.common.log.annotation; + +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.log.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author ruoyi + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log { + /** + * 模块 + */ + String title() default ""; + + /** + * 功能 + */ + BusinessType businessType() default BusinessType.OTHER; + + /** + * 操作人类别 + */ + OperatorType operatorType() default OperatorType.MANAGE; + + /** + * 是否保存请求的参数 + */ + boolean isSaveRequestData() default true; + + /** + * 是否保存响应的参数 + */ + boolean isSaveResponseData() default true; + + + /** + * 排除指定的请求参数 + */ + String[] excludeParamNames() default {}; + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java similarity index 52% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java rename to ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java index 752113c..ee5fc3e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java @@ -1,59 +1,65 @@ -package com.ruoyi.framework.aspectj; +package com.ruoyi.common.log.aspect; -import java.util.Collection; -import java.util.Map; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.ttl.TransmittableThreadLocal; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessStatus; +import com.ruoyi.common.log.event.OperLogEvent; +import com.ruoyi.common.security.utils.LoginHelper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.apache.commons.lang3.ArrayUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.NamedThreadLocal; -import org.springframework.stereotype.Component; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.http.HttpMethod; import org.springframework.validation.BindingResult; import org.springframework.web.multipart.MultipartFile; -import com.alibaba.fastjson2.JSON; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.enums.BusinessStatus; -import com.ruoyi.common.core.enums.HttpMethod; -import com.ruoyi.common.core.filter.PropertyPreExcludeFilter; -import com.ruoyi.common.core.utils.SecurityUtils; -import com.ruoyi.common.core.utils.ServletUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.ip.IpUtils; -import com.ruoyi.framework.manager.AsyncManager; -import com.ruoyi.framework.manager.factory.AsyncFactory; -import com.ruoyi.system.domain.SysOperLog; + +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; /** * 操作日志记录处理 - * - * @author ruoyi + * + * @author Lion Li */ +@Slf4j @Aspect -@Component -public class LogAspect -{ - private static final Logger log = LoggerFactory.getLogger(LogAspect.class); +@AutoConfiguration +public class LogAspect { - /** 排除敏感属性字段 */ + /** + * 排除敏感属性字段 + */ public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; - /** 计算操作消耗时间 */ - private static final ThreadLocal TIME_THREADLOCAL = new NamedThreadLocal<>("Cost Time"); + + /** + * 计算操作消耗时间 + */ + private static final ThreadLocal TIME_THREADLOCAL = new TransmittableThreadLocal<>(); /** * 处理请求前执行 */ @Before(value = "@annotation(controllerLog)") - public void boBefore(JoinPoint joinPoint, Log controllerLog) - { - TIME_THREADLOCAL.set(System.currentTimeMillis()); + public void boBefore(JoinPoint joinPoint, Log controllerLog) { + StopWatch stopWatch = new StopWatch(); + TIME_THREADLOCAL.set(stopWatch); + stopWatch.start(); } /** @@ -62,44 +68,35 @@ public class LogAspect * @param joinPoint 切点 */ @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") - public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) - { + public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { handleLog(joinPoint, controllerLog, null, jsonResult); } /** * 拦截异常操作 - * + * * @param joinPoint 切点 - * @param e 异常 + * @param e 异常 */ @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") - public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) - { + public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) { handleLog(joinPoint, controllerLog, e, null); } - protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) - { - try - { - // 获取当前的用户 - LoginUser loginUser = SecurityUtils.getLoginUser(); + protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) { + try { // *========数据库日志=========*// - SysOperLog operLog = new SysOperLog(); + OperLogEvent operLog = new OperLogEvent(); + operLog.setTenantId(LoginHelper.getTenantId()); operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); // 请求的地址 - String ip = IpUtils.getIpAddr(); + String ip = ServletUtils.getClientIP(); operLog.setOperIp(ip); operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); - if (loginUser != null) - { - operLog.setOperName(loginUser.getUsername()); - } + operLog.setOperName(LoginHelper.getUsername()); - if (e != null) - { + if (e != null) { operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); } @@ -112,31 +109,28 @@ public class LogAspect // 处理设置注解上的参数 getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); // 设置消耗时间 - operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get()); - // 保存数据库 - AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); - } - catch (Exception exp) - { + StopWatch stopWatch = TIME_THREADLOCAL.get(); + stopWatch.stop(); + operLog.setCostTime(stopWatch.getTime()); + // 发布事件保存数据库 + SpringUtils.context().publishEvent(operLog); + } catch (Exception exp) { // 记录本地异常日志 log.error("异常信息:{}", exp.getMessage()); exp.printStackTrace(); - } - finally - { + } finally { TIME_THREADLOCAL.remove(); } } /** * 获取注解中对方法的描述信息 用于Controller层注解 - * - * @param log 日志 + * + * @param log 日志 * @param operLog 操作日志 * @throws Exception */ - public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception - { + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception { // 设置action动作 operLog.setBusinessType(log.businessType().ordinal()); // 设置标题 @@ -144,106 +138,82 @@ public class LogAspect // 设置操作人类别 operLog.setOperatorType(log.operatorType().ordinal()); // 是否需要保存request,参数和值 - if (log.isSaveRequestData()) - { + if (log.isSaveRequestData()) { // 获取参数的信息,传入到数据库中。 setRequestValue(joinPoint, operLog, log.excludeParamNames()); } // 是否需要保存response,参数和值 - if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) - { - operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000)); + if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { + operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000)); } } /** * 获取请求的参数,放到log中 - * + * * @param operLog 操作日志 * @throws Exception 异常 */ - private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception - { - Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); String requestMethod = operLog.getRequestMethod(); - if (StringUtils.isEmpty(paramsMap) - && (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))) - { + if (MapUtil.isEmpty(paramsMap) + && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); operLog.setOperParam(StringUtils.substring(params, 0, 2000)); - } - else - { - operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000)); + } else { + MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); + MapUtil.removeAny(paramsMap, excludeParamNames); + operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000)); } } /** * 参数拼装 */ - private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) - { - String params = ""; - if (paramsArray != null && paramsArray.length > 0) - { - for (Object o : paramsArray) - { - if (StringUtils.isNotNull(o) && !isFilterObject(o)) - { - try - { - String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames)); - params += jsonObj.toString() + " "; - } - catch (Exception e) - { - } + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + String str = JsonUtils.toJsonString(o); + Dict dict = JsonUtils.parseMap(str); + if (MapUtil.isNotEmpty(dict)) { + MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); + MapUtil.removeAny(dict, excludeParamNames); + str = JsonUtils.toJsonString(dict); } + params.add(str); } } - return params.trim(); - } - - /** - * 忽略敏感属性 - */ - public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) - { - return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames)); + return params.toString(); } /** * 判断是否需要过滤的对象。 - * + * * @param o 对象信息。 * @return 如果是需要过滤的对象,则返回true;否则返回false。 */ @SuppressWarnings("rawtypes") - public boolean isFilterObject(final Object o) - { + public boolean isFilterObject(final Object o) { Class clazz = o.getClass(); - if (clazz.isArray()) - { + if (clazz.isArray()) { return clazz.getComponentType().isAssignableFrom(MultipartFile.class); - } - else if (Collection.class.isAssignableFrom(clazz)) - { + } else if (Collection.class.isAssignableFrom(clazz)) { Collection collection = (Collection) o; - for (Object value : collection) - { + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.values()) { return value instanceof MultipartFile; } } - else if (Map.class.isAssignableFrom(clazz)) - { - Map map = (Map) o; - for (Object value : map.entrySet()) - { - Map.Entry entry = (Map.Entry) value; - return entry.getValue() instanceof MultipartFile; - } - } return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse - || o instanceof BindingResult; + || o instanceof BindingResult; } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/BusinessStatus.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessStatus.java similarity index 65% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/BusinessStatus.java rename to ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessStatus.java index ba54ba7..716c4cc 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/BusinessStatus.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessStatus.java @@ -1,13 +1,11 @@ -package com.ruoyi.common.core.enums; +package com.ruoyi.common.log.enums; /** * 操作状态 - * - * @author ruoyi * + * @author ruoyi */ -public enum BusinessStatus -{ +public enum BusinessStatus { /** * 成功 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/BusinessType.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessType.java similarity index 86% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/BusinessType.java rename to ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessType.java index 5d3fac2..7314de5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/BusinessType.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessType.java @@ -1,12 +1,11 @@ -package com.ruoyi.common.core.enums; +package com.ruoyi.common.log.enums; /** * 业务操作类型 - * + * * @author ruoyi */ -public enum BusinessType -{ +public enum BusinessType { /** * 其它 */ @@ -51,7 +50,7 @@ public enum BusinessType * 生成代码 */ GENCODE, - + /** * 清空数据 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/OperatorType.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/OperatorType.java similarity index 73% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/OperatorType.java rename to ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/OperatorType.java index f153876..a93394a 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/OperatorType.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/OperatorType.java @@ -1,12 +1,11 @@ -package com.ruoyi.common.core.enums; +package com.ruoyi.common.log.enums; /** * 操作人类别 - * + * * @author ruoyi */ -public enum OperatorType -{ +public enum OperatorType { /** * 其它 */ diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/LogininforEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/LogininforEvent.java new file mode 100644 index 0000000..d1e2153 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/LogininforEvent.java @@ -0,0 +1,52 @@ +package com.ruoyi.common.log.event; + +import lombok.Data; + +import jakarta.servlet.http.HttpServletRequest; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 登录事件 + * + * @author Lion Li + */ + +@Data +public class LogininforEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 用户账号 + */ + private String username; + + /** + * 登录状态 0成功 1失败 + */ + private String status; + + /** + * 提示消息 + */ + private String message; + + /** + * 请求体 + */ + private HttpServletRequest request; + + /** + * 其他参数 + */ + private Object[] args; + +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/OperLogEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/OperLogEvent.java new file mode 100644 index 0000000..683cb41 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/event/OperLogEvent.java @@ -0,0 +1,115 @@ +package com.ruoyi.common.log.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 操作日志事件 + * + * @author Lion Li + */ + +@Data +public class OperLogEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + private Long operId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..b8e3223 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.ruoyi.common.log.aspect.LogAspect diff --git a/ruoyi-common/ruoyi-common-orm/mybatis-flex.config b/ruoyi-common/ruoyi-common-orm/mybatis-flex.config new file mode 100644 index 0000000..2f68734 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/mybatis-flex.config @@ -0,0 +1,13 @@ +# 自定义 TableDef 的字段风格,upperCamelCase为首字母大写的驼峰命名,例如:UserName +# upperCase, lowerCase, upperCamelCase, lowerCamelCase +processor.tableDef.propertiesNameStyle = upperCamelCase + +# APT开启Mapper生成, 从 v1.1.9 开始, APT 的 Mapper 自动生成 功能是关闭的 +processor.mappersGenerateEnable = false + +# 自定义 Mapper 的父类 +#processor.mapper.baseClass = com.ruoyi.mapper.FlexBaseMapper + + + + diff --git a/ruoyi-common/ruoyi-common-orm/pom.xml b/ruoyi-common/ruoyi-common-orm/pom.xml new file mode 100644 index 0000000..2b97bb6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/pom.xml @@ -0,0 +1,45 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-orm + + + ruoyi-common-orm 数据库映射服务 + + + + + com.ruoyi + ruoyi-common-core + + + + com.ruoyi + ruoyi-common-security + + + + + com.mybatis-flex + mybatis-flex-spring-boot-starter + + + + + com.github.pagehelper + pagehelper + + + + + + + diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataColumn.java new file mode 100644 index 0000000..287a3c7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataColumn.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.orm.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限 + * + * 一个注解只能对应一个模板 + * + * @author Lion Li + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataColumn { + + /** + * 占位符关键字 + */ + String[] key() default "deptName"; + + /** + * 占位符替换值 + */ + String[] value() default "dept_id"; + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataPermission.java new file mode 100644 index 0000000..e2f473d --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/annotation/DataPermission.java @@ -0,0 +1,17 @@ +package com.ruoyi.common.orm.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限组 + * + * @author Lion Li + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + DataColumn[] value(); + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexConfig.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexConfig.java new file mode 100644 index 0000000..39ecee2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexConfig.java @@ -0,0 +1,118 @@ +package com.ruoyi.common.orm.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.extension.plugins.MybatisPlusInterceptor; +//import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +//import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +//import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler; +//import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor; +import com.mybatisflex.core.audit.AuditManager; +import com.mybatisflex.core.datasource.DataSourceDecipher; +import com.ruoyi.common.orm.decipher.Decipher; +import org.mybatis.spring.annotation.MapperScan; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +/** + * mybatis-flex配置 + * + * @author dataprince数据小王子 + */ +//@EnableTransactionManagement(proxyTargetClass = true) +@Configuration +@MapperScan("${mybatis-flex.mapperPackage}") +public class MyBatisFlexConfig { + + private static final Logger logger = LoggerFactory.getLogger("mybatis-flex-sql"); + + /** + * SQL 打印 + */ + public MyBatisFlexConfig() { + //开启审计功能 + AuditManager.setAuditEnable(true); + + //设置 SQL 审计收集器 + AuditManager.setMessageCollector(auditMessage -> + logger.info("{},{}ms", auditMessage.getFullSql() + , auditMessage.getElapsedTime()) + ); + } + + /** + * 数据源解密 + */ + @Bean + public DataSourceDecipher decipher(){ + DataSourceDecipher decipher = new Decipher(); + return decipher; + } + + //TODO:动态表名 + + //TODO:多租户配置 + + + +// @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(); +// } +// +// /** +// * 分页插件,自动识别数据库类型 +// */ +// public PaginationInnerInterceptor paginationInnerInterceptor() { +// PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); +// // 设置最大单页限制数量,默认 500 条,-1 不受限制 +// paginationInnerInterceptor.setMaxLimit(-1L); +// // 分页合理化 +// paginationInnerInterceptor.setOverflow(true); +// return paginationInnerInterceptor; +// } +// +// /** +// * 乐观锁插件 +// */ +// public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { +// return new OptimisticLockerInnerInterceptor(); +// } +// +// /** +// * 元对象字段填充控制器 +// */ +// @Bean +// public MetaObjectHandler metaObjectHandler() { +// return new InjectionMetaObjectHandler(); +// } +// +// /** +// * 使用网卡信息绑定雪花生成器 +// * 防止集群雪花ID重复 +// */ +// @Bean +// public IdentifierGenerator idGenerator() { +// return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); +// } + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexInitConfig.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexInitConfig.java new file mode 100644 index 0000000..7a56fd6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyBatisFlexInitConfig.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.orm.config; + +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.core.FlexGlobalConfig; +import com.mybatisflex.core.keygen.KeyGenerators; +import com.mybatisflex.spring.boot.MyBatisFlexCustomizer; +import org.springframework.context.annotation.Configuration; + +/** + * Mybatis-Flex自定义初始化配置 + * + * @author dataprince数据小王子 + */ +@Configuration +public class MyBatisFlexInitConfig implements MyBatisFlexCustomizer { + + @Override + public void customize(FlexGlobalConfig globalConfig) { + //我们可以在这里进行一些初始化配置 + + //统一设置数据库表主键为雪花算法 + FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig(); + keyConfig.setKeyType(KeyType.Generator); + keyConfig.setValue(KeyGenerators.snowFlakeId); + //keyConfig.setBefore(true); + globalConfig.setKeyConfig(keyConfig); + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyConfigurationCustomizer.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyConfigurationCustomizer.java new file mode 100644 index 0000000..c2a63e9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/MyConfigurationCustomizer.java @@ -0,0 +1,19 @@ +package com.ruoyi.common.orm.config; + +import com.mybatisflex.core.mybatis.FlexConfiguration; +import com.mybatisflex.spring.boot.ConfigurationCustomizer; +import org.apache.ibatis.logging.stdout.StdOutImpl; +import org.springframework.context.annotation.Configuration; + +/** + * 指定输出日志 + * + * @author dataprince数据小王子 + */ +@Configuration +public class MyConfigurationCustomizer implements ConfigurationCustomizer { + @Override + public void customize(FlexConfiguration configuration) { + configuration.setLogImpl(StdOutImpl.class); + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/PagehelperConfig.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/PagehelperConfig.java new file mode 100644 index 0000000..bc404b3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/config/PagehelperConfig.java @@ -0,0 +1,19 @@ +package com.ruoyi.common.orm.config; + +import com.github.pagehelper.PageInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Pagehelper分页,兼用老项目 + * + * @author dataprince数据小王子 + */ +@Configuration +public class PagehelperConfig { + @Bean + public PageInterceptor pageInterceptor(){ + PageInterceptor pageInterceptor = new PageInterceptor(); + return pageInterceptor; + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/BaseEntity.java new file mode 100644 index 0000000..632ae50 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/BaseEntity.java @@ -0,0 +1,73 @@ +package com.ruoyi.common.orm.core.domain; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.mybatisflex.annotation.Column; +import lombok.Data; + +/** + * Entity基类 + * + * @author dataprince数据小王子 + */ + +@Data +public class BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 搜索值 + */ + @JsonIgnore + @Column(ignore = true) + private String searchValue; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + /** + * 备注 + */ + private String remark; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Column(ignore = true) + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/TreeEntity.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/TreeEntity.java similarity index 96% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/TreeEntity.java rename to ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/TreeEntity.java index bd539a9..49513ae 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/TreeEntity.java +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/domain/TreeEntity.java @@ -1,4 +1,4 @@ -package com.ruoyi.common.core.core.domain; +package com.ruoyi.common.orm.core.domain; import com.mybatisflex.annotation.Column; @@ -7,7 +7,7 @@ import java.util.List; /** * Tree基类 - * + * * @author ruoyi */ public class TreeEntity extends BaseEntity diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/mapper/BaseMapperFlex.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/mapper/BaseMapperFlex.java new file mode 100644 index 0000000..e2bef7e --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/mapper/BaseMapperFlex.java @@ -0,0 +1,192 @@ +package com.ruoyi.common.orm.core.mapper; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.mybatisflex.core.BaseMapper; +import com.ruoyi.common.core.utils.MapstructUtils; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param table 泛型 + * @param vo 泛型 + * @author Lion Li + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperFlex extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperFlex.class); + +// default Class currentVoClass() { +// return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperFlex.class, 1); +// } +// +// default Class currentModelClass() { +// return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperFlex.class, 0); +// } +// +// default List selectList() { +// return this.selectList(new QueryWrapper<>()); +// } +// +// /** +// * 批量插入 +// */ +// default boolean insertBatch(Collection entityList) { +// return Db.saveBatch(entityList); +// } +// +// /** +// * 批量更新 +// */ +// default boolean updateBatchById(Collection entityList) { +// return Db.updateBatchById(entityList); +// } +// +// /** +// * 批量插入或更新 +// */ +// default boolean insertOrUpdateBatch(Collection entityList) { +// return Db.saveOrUpdateBatch(entityList); +// } +// +// /** +// * 批量插入(包含限制条数) +// */ +// default boolean insertBatch(Collection entityList, int batchSize) { +// return Db.saveBatch(entityList, batchSize); +// } +// +// /** +// * 批量更新(包含限制条数) +// */ +// default boolean updateBatchById(Collection entityList, int batchSize) { +// return Db.updateBatchById(entityList, batchSize); +// } +// +// /** +// * 批量插入或更新(包含限制条数) +// */ +// default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { +// return Db.saveOrUpdateBatch(entityList, batchSize); +// } +// +// /** +// * 插入或更新(包含限制条数) +// */ +// default boolean insertOrUpdate(T entity) { +// return Db.saveOrUpdate(entity); +// } +// +// default V selectVoById(Serializable id) { +// return selectVoById(id, this.currentVoClass()); +// } +// +// /** +// * 根据 ID 查询 +// */ +// default C selectVoById(Serializable id, Class voClass) { +// T obj = this.selectById(id); +// if (ObjectUtil.isNull(obj)) { +// return null; +// } +// return MapstructUtils.convert(obj, voClass); +// } +// +// default List selectVoBatchIds(Collection idList) { +// return selectVoBatchIds(idList, this.currentVoClass()); +// } +// +// /** +// * 查询(根据ID 批量查询) +// */ +// default List selectVoBatchIds(Collection idList, Class voClass) { +// List list = this.selectBatchIds(idList); +// if (CollUtil.isEmpty(list)) { +// return CollUtil.newArrayList(); +// } +// return MapstructUtils.convert(list, voClass); +// } +// +// default List selectVoByMap(Map map) { +// return selectVoByMap(map, this.currentVoClass()); +// } +// +// /** +// * 查询(根据 columnMap 条件) +// */ +// default List selectVoByMap(Map map, Class voClass) { +// List list = this.selectByMap(map); +// if (CollUtil.isEmpty(list)) { +// return CollUtil.newArrayList(); +// } +// return MapstructUtils.convert(list, voClass); +// } +// +// default V selectVoOne(Wrapper wrapper) { +// return selectVoOne(wrapper, this.currentVoClass()); +// } +// +// /** +// * 根据 entity 条件,查询一条记录 +// */ +// default C selectVoOne(Wrapper wrapper, Class voClass) { +// T obj = this.selectOne(wrapper); +// if (ObjectUtil.isNull(obj)) { +// return null; +// } +// return MapstructUtils.convert(obj, voClass); +// } +// +// default List selectVoList() { +// return selectVoList(new QueryWrapper<>(), this.currentVoClass()); +// } +// +// default List selectVoList(Wrapper wrapper) { +// return selectVoList(wrapper, this.currentVoClass()); +// } +// +// /** +// * 根据 entity 条件,查询全部记录 +// */ +// default List selectVoList(Wrapper wrapper, Class voClass) { +// List list = this.selectList(wrapper); +// if (CollUtil.isEmpty(list)) { +// return CollUtil.newArrayList(); +// } +// return MapstructUtils.convert(list, voClass); +// } +// +// default

> P selectVoPage(IPage page, Wrapper wrapper) { +// return selectVoPage(page, wrapper, this.currentVoClass()); +// } +// +// /** +// * 分页查询VO +// */ +// default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { +// IPage pageData = this.selectPage(page, wrapper); +// IPage voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()); +// if (CollUtil.isEmpty(pageData.getRecords())) { +// return (P) voPage; +// } +// voPage.setRecords(MapstructUtils.convert(pageData.getRecords(), voClass)); +// return (P) voPage; +// } +// +// default List selectObjs(Wrapper wrapper, Function mapper) { +// return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList()); +// } + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/PageQuery.java new file mode 100644 index 0000000..203a6c2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/PageQuery.java @@ -0,0 +1,112 @@ +package com.ruoyi.common.orm.core.page; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.sql.SqlUtil; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 分页查询实体类 + * + * @author Lion Li + */ + +@Data +public class PageQuery implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 分页大小 + */ + private Integer pageSize; + + /** + * 当前页数 + */ + private Integer pageNum; + + /** + * 排序列 + */ + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + private String isAsc; + + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + + /** + * 每页显示记录数 默认值 默认查全部 + */ + public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + +// public Page 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 page = new Page<>(pageNum, pageSize); +// List orderItems = buildOrderItem(); +// if (CollUtil.isNotEmpty(orderItems)) { +// page.addOrder(orderItems); +// } +// return page; +// } + + /** + * 构建排序 + * + * 支持的用法如下: + * {isAsc:"asc",orderByColumn:"id"} order by id asc + * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc + * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc + * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc + */ +// private List buildOrderItem() { +// if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { +// return null; +// } +// String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); +// orderBy = StringUtils.toUnderScoreCase(orderBy); +// +// // 兼容前端排序类型 +// isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); +// +// String[] orderByArr = orderBy.split(StringUtils.SEPARATOR); +// String[] isAscArr = isAsc.split(StringUtils.SEPARATOR); +// if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { +// throw new ServiceException("排序参数有误"); +// } +// +// List list = new ArrayList<>(); +// // 每个字段各自排序 +// for (int i = 0; i < orderByArr.length; i++) { +// String orderByStr = orderByArr[i]; +// String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; +// if ("asc".equals(isAscStr)) { +// list.add(OrderItem.asc(orderByStr)); +// } else if ("desc".equals(isAscStr)) { +// list.add(OrderItem.desc(orderByStr)); +// } else { +// throw new ServiceException("排序参数有误"); +// } +// } +// return list; +// } + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/TableDataInfo.java new file mode 100644 index 0000000..daa38ad --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/core/page/TableDataInfo.java @@ -0,0 +1,80 @@ +package com.ruoyi.common.orm.core.page; + +import cn.hutool.http.HttpStatus; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class TableDataInfo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总记录数 + */ + private long total; + + /** + * 列表数据 + */ + private List rows; + + /** + * 消息状态码 + */ + private int code; + + /** + * 消息内容 + */ + private String msg; + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, long total) { + this.rows = list; + this.total = total; + } + +// public static TableDataInfo build(IPage page) { +// TableDataInfo rspData = new TableDataInfo<>(); +// rspData.setCode(HttpStatus.HTTP_OK); +// rspData.setMsg("查询成功"); +// rspData.setRows(page.getRecords()); +// rspData.setTotal(page.getTotal()); +// return rspData; +// } + + public static TableDataInfo build(List list) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); + return rspData; + } + + public static TableDataInfo build() { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + return rspData; + } + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/decipher/Decipher.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/decipher/Decipher.java new file mode 100644 index 0000000..ad007f0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/decipher/Decipher.java @@ -0,0 +1,24 @@ +package com.ruoyi.common.orm.decipher; + +import com.mybatisflex.core.datasource.DataSourceDecipher; +import com.mybatisflex.core.datasource.DataSourceProperty; + +/** + * 数据源解密 + * + * @author dataprince数据小王子 + */ +public class Decipher implements DataSourceDecipher { + @Override + public String decrypt(DataSourceProperty property, String value) { + //解密用户名,通过编码支持任意加密方式的解密 + if (property == DataSourceProperty.USERNAME) { + return value.substring(0, 4); + } + //解密密码 + else if (property == DataSourceProperty.PASSWORD) { + return value.substring(0, 8); + } + return value; + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataBaseType.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataBaseType.java new file mode 100644 index 0000000..e3f9f89 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataBaseType.java @@ -0,0 +1,49 @@ +package com.ruoyi.common.orm.enums; + +import com.ruoyi.common.core.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据库类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DataBaseType { + + /** + * MySQL + */ + MY_SQL("MySQL"), + + /** + * Oracle + */ + ORACLE("Oracle"), + + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL"), + + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server"); + + private final String type; + + public static DataBaseType find(String databaseProductName) { + if (StringUtils.isBlank(databaseProductName)) { + return null; + } + for (DataBaseType type : values()) { + if (type.getType().equals(databaseProductName)) { + return type; + } + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataScopeType.java new file mode 100644 index 0000000..ea4af6a --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/enums/DataScopeType.java @@ -0,0 +1,71 @@ +package com.ruoyi.common.orm.enums; + +import com.ruoyi.common.core.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据权限类型 + *

+ * 语法支持 spel 模板表达式 + *

+ * 内置数据 user 当前用户 内容参考 LoginUser + * 如需扩展数据 可使用 {@link DataPermissionHelper} 操作 + * 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService + * 如需扩展更多自定义服务 可以参考 sdss 自行编写 + * + * @author Lion Li + */ +@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; + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/MybatisExceptionHandler.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/MybatisExceptionHandler.java new file mode 100644 index 0000000..2567cab --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/MybatisExceptionHandler.java @@ -0,0 +1,46 @@ +package com.ruoyi.common.orm.handler; + +import com.ruoyi.common.core.core.domain.R; +import lombok.extern.slf4j.Slf4j; +import org.mybatis.spring.MyBatisSystemException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import jakarta.servlet.http.HttpServletRequest; + +/** + * Mybatis异常处理器 + * + * @author Lion Li + */ +@Slf4j +@RestControllerAdvice +public class MybatisExceptionHandler { + + /** + * 主键或UNIQUE索引,数据重复异常 + */ + @ExceptionHandler(DuplicateKeyException.class) + public R handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage()); + return R.fail("数据库中已存在该记录,请联系管理员确认"); + } + + /** + * Mybatis系统异常 通用处理 + */ + @ExceptionHandler(MyBatisSystemException.class) + public R handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String message = e.getMessage(); + if (message.contains("CannotFindDataSourceException")) { + log.error("请求地址'{}', 未找到数据源", requestURI); + return R.fail("未找到数据源,请联系管理员确认"); + } + log.error("请求地址'{}', Mybatis系统异常", requestURI, e); + return R.fail(message); + } + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/PlusDataPermissionHandler.java new file mode 100644 index 0000000..f5a5f49 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/handler/PlusDataPermissionHandler.java @@ -0,0 +1,197 @@ +package com.ruoyi.common.orm.handler; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.collection.CollUtil; +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.core.core.domain.dto.RoleDTO; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StreamUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.orm.annotation.DataColumn; +import com.ruoyi.common.orm.annotation.DataPermission; +import com.ruoyi.common.orm.enums.DataScopeType; +import com.ruoyi.common.orm.helper.DataPermissionHelper; +import com.ruoyi.common.security.utils.LoginHelper; +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.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +/** + * 数据权限过滤 + * + * @author Lion Li + */ +@Slf4j +public class PlusDataPermissionHandler { + + /** + * 方法或类(名称) 与 注解的映射关系缓存 + */ + private final Map dataPermissionCacheMap = new ConcurrentHashMap<>(); + + /** + * 无效注解方法缓存用于快速返回 + */ + private final Set invalidCacheSet = 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)) { + invalidCacheSet.add(mappedStatementId); + return where; + } + LoginUser currentUser = DataPermissionHelper.getVariable("user"); + if (ObjectUtil.isNull(currentUser)) { + currentUser = LoginHelper.getLoginUser(); + DataPermissionHelper.setVariable("user", currentUser); + } + // 如果是超级管理员或租户管理员,则不过滤数据 + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + 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) { + // 更新或删除需满足所有条件 + String joinStr = isSelect ? " OR " : " AND "; + LoginUser user = DataPermissionHelper.getVariable("user"); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setBeanResolver(beanResolver); + DataPermissionHelper.getContext().forEach(context::setVariable); + Set conditions = new HashSet<>(); + for (RoleDTO 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) { + if (dataColumn.key().length != dataColumn.value().length) { + throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); + } + // 不包含 key 变量 则不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), + Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new) + )) { + continue; + } + // 设置注解变量 key 为表达式变量 value 为变量值 + for (int i = 0; i < dataColumn.key().length; i++) { + context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); + } + + // 解析sql模板并填充 + String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class); + conditions.add(joinStr + sql); + isSuccess = true; + } + // 未处理成功则填充兜底方案 + if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { + conditions.add(joinStr + type.getElseSql()); + } + } + + if (CollUtil.isNotEmpty(conditions)) { + String sql = StreamUtils.join(conditions, Function.identity(), ""); + return sql.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 methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz)) + .filter(method -> method.getName().equals(methodName)).toList(); + DataPermission dataPermission; + // 获取方法注解 + for (Method method : methods) { + dataPermission = dataPermissionCacheMap.get(mappedStatementId); + if (ObjectUtil.isNotNull(dataPermission)) { + return dataPermission.value(); + } + if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { + dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); + dataPermissionCacheMap.put(mappedStatementId, 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 invalidCacheSet.contains(mappedStatementId); + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataBaseHelper.java new file mode 100644 index 0000000..4ba3e0b --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataBaseHelper.java @@ -0,0 +1,69 @@ +package com.ruoyi.common.orm.helper; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * 数据库助手 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DataBaseHelper { + + //private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + + /** + * 获取当前数据库类型 + */ +// public static DataBaseType getDataBaseType() { +// DataSource dataSource = DS.determineDataSource(); +// try (Connection conn = dataSource.getConnection()) { +// DatabaseMetaData metaData = conn.getMetaData(); +// String databaseProductName = metaData.getDatabaseProductName(); +// return DataBaseType.find(databaseProductName); +// } catch (SQLException e) { +// throw new ServiceException(e.getMessage()); +// } +// } + +// public static boolean isMySql() { +// return DataBaseType.MY_SQL == getDataBaseType(); +// } +// +// public static boolean isOracle() { +// return DataBaseType.ORACLE == getDataBaseType(); +// } +// +// public static boolean isPostgerSql() { +// return DataBaseType.POSTGRE_SQL == getDataBaseType(); +// } +// +// public static boolean isSqlServer() { +// return DataBaseType.SQL_SERVER == getDataBaseType(); +// } +// +// public static String findInSet(Object var1, String var2) { +// DataBaseType dataBasyType = getDataBaseType(); +// String var = Convert.toStr(var1); +// if (dataBasyType == DataBaseType.SQL_SERVER) { +// // charindex(',100,' , ',0,100,101,') <> 0 +// return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2); +// } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { +// // (select position(',100,' in ',0,100,101,')) <> 0 +// return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2); +// } else if (dataBasyType == DataBaseType.ORACLE) { +// // instr(',0,100,101,' , ',100,') <> 0 +// return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var); +// } +// // find_in_set(100 , '0,100,101') +// return "find_in_set('%s' , %s) <> 0".formatted(var, var2); +// } + + /** + * 获取当前加载的数据库名 + */ +// public static List getDataSourceNameList() { +// return new ArrayList<>(DS.getDataSources().keySet()); +// } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataPermissionHelper.java new file mode 100644 index 0000000..a766a74 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/helper/DataPermissionHelper.java @@ -0,0 +1,90 @@ +package com.ruoyi.common.orm.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.util.ObjectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +/** + * 数据权限助手 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings("unchecked cast") +public class DataPermissionHelper { + + private static final String DATA_PERMISSION_KEY = "data:permission"; + + public static T getVariable(String key) { + Map context = getContext(); + return (T) context.get(key); + } + + + public static void setVariable(String key, Object value) { + Map context = getContext(); + context.put(key, value); + } + + public static Map getContext() { + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); + attribute = saStorage.get(DATA_PERMISSION_KEY); + } + if (attribute instanceof Map map) { + return map; + } + throw new NullPointerException("data permission context type exception"); + } + + /** + * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) + */ +// public static void enableIgnore() { +// InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); +// } + + /** + * 关闭忽略数据权限 + */ +// public static void disableIgnore() { +// InterceptorIgnoreHelper.clearIgnoreStrategy(); +// } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ +// public static void ignore(Runnable handle) { +// enableIgnore(); +// try { +// handle.run(); +// } finally { +// disableIgnore(); +// } +// } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ +// public static T ignore(Supplier handle) { +// enableIgnore(); +// try { +// return handle.get(); +// } finally { +// disableIgnore(); +// } +// } + +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityInsertListener.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityInsertListener.java new file mode 100644 index 0000000..3bee812 --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityInsertListener.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.orm.listener; + +import com.mybatisflex.annotation.InsertListener; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.common.security.utils.LoginHelper; + +import java.util.Date; + +/** + * Entity实体类新增数据监听器 + * + * @author dataprince数据小王子 + */ +public class EntityInsertListener implements InsertListener { + + @Override + public void onInsert(Object entity) { + BaseEntity baseEntity = (BaseEntity) entity; + Long loginUserId = LoginHelper.getUserId(); + Date createTime = new Date(); + baseEntity.setCreateBy(loginUserId); + baseEntity.setCreateTime(createTime); + baseEntity.setUpdateBy(loginUserId); + baseEntity.setUpdateTime(createTime); + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityUpdateListener.java b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityUpdateListener.java new file mode 100644 index 0000000..aeb465f --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/java/com/ruoyi/common/orm/listener/EntityUpdateListener.java @@ -0,0 +1,21 @@ +package com.ruoyi.common.orm.listener; + +import com.mybatisflex.annotation.UpdateListener; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.common.security.utils.LoginHelper; + +import java.util.Date; + +/** + * Entity实体类更新数据监听器 + * + * @author dataprince数据小王子 + */ +public class EntityUpdateListener implements UpdateListener { + @Override + public void onUpdate(Object entity) { + BaseEntity baseEntity = (BaseEntity) entity; + baseEntity.setUpdateBy(LoginHelper.getUserId()); + baseEntity.setUpdateTime(new Date()); + } +} diff --git a/ruoyi-common/ruoyi-common-orm/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-orm/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..82153bd --- /dev/null +++ b/ruoyi-common/ruoyi-common-orm/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,4 @@ +com.ruoyi.common.orm.config.PagehelperConfig +com.ruoyi.common.orm.config.MyBatisFlexInitConfig +com.ruoyi.common.orm.config.MyConfigurationCustomizer +com.ruoyi.common.orm.config.MyBatisFlexConfig diff --git a/ruoyi-common/ruoyi-common-ratelimiter/pom.xml b/ruoyi-common/ruoyi-common-ratelimiter/pom.xml new file mode 100644 index 0000000..b0c6f41 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/pom.xml @@ -0,0 +1,30 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-ratelimiter + + + ruoyi-common-ratelimiter 限流功能 + + + + + com.ruoyi + ruoyi-common-core + + + + com.ruoyi + ruoyi-common-redis + + + + diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java new file mode 100644 index 0000000..87a946b --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/annotation/RateLimiter.java @@ -0,0 +1,41 @@ +package com.ruoyi.common.ratelimiter.annotation; + +import com.ruoyi.common.ratelimiter.enums.LimitType; + +import java.lang.annotation.*; + +/** + * 限流注解 + * + * @author Lion Li + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter { + /** + * 限流key,支持使用Spring el表达式来动态获取方法上的参数值 + * 格式类似于 #code.id #{#code} + */ + String key() default ""; + + /** + * 限流时间,单位秒 + */ + int time() default 60; + + /** + * 限流次数 + */ + int count() default 100; + + /** + * 限流类型 + */ + LimitType limitType() default LimitType.DEFAULT; + + /** + * 提示消息 支持国际化 格式为 {code} + */ + String message() default "{rate.limiter.message}"; +} diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java new file mode 100644 index 0000000..7d13bc6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/aspectj/RateLimiterAspect.java @@ -0,0 +1,127 @@ +package com.ruoyi.common.ratelimiter.aspectj; + +import cn.hutool.core.util.ArrayUtil; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.ratelimiter.annotation.RateLimiter; +import com.ruoyi.common.ratelimiter.enums.LimitType; +import com.ruoyi.common.redis.utils.RedisUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RateType; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +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; + +/** + * 限流处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +public class RateLimiterAspect { + + /** + * 定义spel表达式解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); + /** + * 定义spel解析模版 + */ + private final ParserContext parserContext = new TemplateParserContext(); + /** + * 定义spel上下文对象进行解析 + */ + private final EvaluationContext context = new StandardEvaluationContext(); + /** + * 方法参数解析器 + */ + private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); + + @Before("@annotation(rateLimiter)") + public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable { + int time = rateLimiter.time(); + int count = rateLimiter.count(); + String combineKey = getCombineKey(rateLimiter, point); + try { + RateType rateType = RateType.OVERALL; + if (rateLimiter.limitType() == LimitType.CLUSTER) { + rateType = RateType.PER_CLIENT; + } + long number = RedisUtils.rateLimiter(combineKey, rateType, count, time); + if (number == -1) { + String message = rateLimiter.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey); + } catch (Exception e) { + if (e instanceof ServiceException) { + throw e; + } else { + throw new RuntimeException("服务器限流异常,请稍候再试"); + } + } + } + + public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { + String key = rateLimiter.key(); + // 获取方法(通过方法签名来获取) + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + Class targetClass = method.getDeclaringClass(); + // 判断是否是spel格式 + if (StringUtils.containsAny(key, "#")) { + // 获取参数值 + Object[] args = point.getArgs(); + // 获取方法上参数的名称 + String[] parameterNames = pnd.getParameterNames(method); + if (ArrayUtil.isEmpty(parameterNames)) { + throw new ServiceException("限流key解析异常!请联系管理员!"); + } + for (int i = 0; i < parameterNames.length; i++) { + context.setVariable(parameterNames[i], args[i]); + } + // 解析返回给key + try { + Expression expression; + if (StringUtils.startsWith(key, parserContext.getExpressionPrefix()) + && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { + expression = parser.parseExpression(key, parserContext); + } else { + expression = parser.parseExpression(key); + } + key = expression.getValue(context, String.class) + ":"; + } catch (Exception e) { + throw new ServiceException("限流key解析异常!请联系管理员!"); + } + } + StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY); + stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":"); + if (rateLimiter.limitType() == LimitType.IP) { + // 获取请求ip + stringBuffer.append(ServletUtils.getClientIP()).append(":"); + } else if (rateLimiter.limitType() == LimitType.CLUSTER) { + // 获取客户端实例id + stringBuffer.append(RedisUtils.getClient().getId()).append(":"); + } + return stringBuffer.append(key).toString(); + } +} diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/config/RateLimiterConfig.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/config/RateLimiterConfig.java new file mode 100644 index 0000000..f55a1f7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/config/RateLimiterConfig.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.ratelimiter.config; + +import com.ruoyi.common.ratelimiter.aspectj.RateLimiterAspect; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConfiguration; + +/** + * @author guangxin + * @date 2023/1/18 + */ +@AutoConfiguration(after = RedisConfiguration.class) +public class RateLimiterConfig { + + @Bean + public RateLimiterAspect rateLimiterAspect() { + return new RateLimiterAspect(); + } + +} diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/enums/LimitType.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/enums/LimitType.java new file mode 100644 index 0000000..1ff05d1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/com/ruoyi/common/ratelimiter/enums/LimitType.java @@ -0,0 +1,24 @@ +package com.ruoyi.common.ratelimiter.enums; + +/** + * 限流类型 + * + * @author ruoyi + */ + +public enum LimitType { + /** + * 默认策略全局限流 + */ + DEFAULT, + + /** + * 根据请求者IP进行限流 + */ + IP, + + /** + * 实例限流(集群多后端实例) + */ + CLUSTER +} diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..68afe55 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.ruoyi.common.ratelimiter.config.RateLimiterConfig diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml new file mode 100644 index 0000000..bf59aec --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -0,0 +1,51 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + jar + + ruoyi-common-redis + + + ruoyi-common-redis 缓存服务 + + + + + + com.ruoyi + ruoyi-common-core + + + + + org.redisson + redisson-spring-boot-starter + + + + com.baomidou + lock4j-redisson-spring-boot-starter + + + + + org.projectlombok + lombok + + + + + org.springframework.boot + spring-boot-configuration-processor + + + + + diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java new file mode 100644 index 0000000..ea1ef22 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/RedisConfig.java @@ -0,0 +1,142 @@ +package com.ruoyi.common.redis.config; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.ruoyi.common.redis.handler.KeyPrefixHandler; +import com.ruoyi.common.redis.manager.FlexSpringCacheManager; +import com.ruoyi.common.redis.config.properties.RedissonProperties; +import jakarta.annotation.Resource; +import org.redisson.client.codec.StringCodec; +import org.redisson.codec.CompositeCodec; +import org.redisson.codec.TypedJsonJacksonCodec; +import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * redis配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableCaching +@EnableConfigurationProperties(RedissonProperties.class) +public class RedisConfig { + private static final Logger log = LoggerFactory.getLogger(RedisConfig.class); + @Autowired + private RedissonProperties redissonProperties; + @Resource + private ObjectMapper objectMapper; + + @Bean + public RedissonAutoConfigurationCustomizer redissonCustomizer() { + return config -> { + ObjectMapper om = objectMapper.copy(); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来 + om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); + TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om); + // 组合序列化 key 使用 String 内容使用通用 json 格式 + CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec); + config.setThreads(redissonProperties.getThreads()) + .setNettyThreads(redissonProperties.getNettyThreads()) + .setCodec(codec); + RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); + if (ObjectUtil.isNotNull(singleServerConfig)) { + // 使用单机模式 + config.useSingleServer() + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(singleServerConfig.getTimeout()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); + } + // 集群配置方式 参考下方注释 + RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); + if (ObjectUtil.isNotNull(clusterServersConfig)) { + config.useClusterServers() + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(clusterServersConfig.getTimeout()) + .setClientName(clusterServersConfig.getClientName()) + .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) + .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) + .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) + .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) + .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) + .setReadMode(clusterServersConfig.getReadMode()) + .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); + } + log.info("初始化 redis 配置"); + }; + } + + /** + * 自定义缓存管理器 整合spring-cache + */ + @Bean + public CacheManager cacheManager() { + return new FlexSpringCacheManager(); + } + + /** + * 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 + * # 集群配置 + * clusterServersConfig: + * # 客户端名称 + * clientName: ${ruoyi.name} + * # master最小空闲连接数 + * masterConnectionMinimumIdleSize: 32 + * # master连接池大小 + * masterConnectionPoolSize: 64 + * # slave最小空闲连接数 + * slaveConnectionMinimumIdleSize: 32 + * # slave连接池大小 + * slaveConnectionPoolSize: 64 + * # 连接空闲超时,单位:毫秒 + * idleConnectionTimeout: 10000 + * # 命令等待超时,单位:毫秒 + * timeout: 3000 + * # 发布和订阅连接池大小 + * subscriptionConnectionPoolSize: 50 + * # 读取模式 + * readMode: "SLAVE" + * # 订阅模式 + * subscriptionMode: "MASTER" + */ + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/properties/RedissonProperties.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/properties/RedissonProperties.java new file mode 100644 index 0000000..c4814d7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/config/properties/RedissonProperties.java @@ -0,0 +1,135 @@ +package com.ruoyi.common.redis.config.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.redisson.config.ReadMode; +import org.redisson.config.SubscriptionMode; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Redisson 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "redisson") +public class RedissonProperties { + + /** + * redis缓存key前缀 + */ + private String keyPrefix; + + /** + * 线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int threads; + + /** + * Netty线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int nettyThreads; + + /** + * 单机服务配置 + */ + private SingleServerConfig singleServerConfig; + + /** + * 集群服务配置 + */ + private ClusterServersConfig clusterServersConfig; + + @Data + @NoArgsConstructor + public static class SingleServerConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * 最小空闲连接数 + */ + private int connectionMinimumIdleSize; + + /** + * 连接池大小 + */ + private int connectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + } + + @Data + @NoArgsConstructor + public static class ClusterServersConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * master最小空闲连接数 + */ + private int masterConnectionMinimumIdleSize; + + /** + * master连接池大小 + */ + private int masterConnectionPoolSize; + + /** + * slave最小空闲连接数 + */ + private int slaveConnectionMinimumIdleSize; + + /** + * slave连接池大小 + */ + private int slaveConnectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + /** + * 读取模式 + */ + private ReadMode readMode; + + /** + * 订阅模式 + */ + private SubscriptionMode subscriptionMode; + + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/handler/KeyPrefixHandler.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/handler/KeyPrefixHandler.java new file mode 100644 index 0000000..900cc02 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/handler/KeyPrefixHandler.java @@ -0,0 +1,49 @@ +package com.ruoyi.common.redis.handler; + +import com.ruoyi.common.core.utils.StringUtils; +import org.redisson.api.NameMapper; + +/** + * redis缓存key前缀处理 + * + * @author ye + * @date 2022/7/14 17:44 + */ +public class KeyPrefixHandler implements NameMapper { + + private final String keyPrefix; + + public KeyPrefixHandler(String keyPrefix) { + //前缀为空 则返回空前缀 + this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":"; + } + + /** + * 增加前缀 + */ + @Override + public String map(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) { + return keyPrefix + name; + } + return name; + } + + /** + * 去除前缀 + */ + @Override + public String unmap(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) { + return name.substring(keyPrefix.length()); + } + return name; + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java new file mode 100644 index 0000000..405a495 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/manager/FlexSpringCacheManager.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2013-2021 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ruoyi.common.redis.manager; + +import com.ruoyi.common.redis.utils.RedisUtils; +import org.redisson.api.RMap; +import org.redisson.api.RMapCache; +import org.redisson.spring.cache.CacheConfig; +import org.redisson.spring.cache.RedissonCache; +import org.springframework.boot.convert.DurationStyle; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.transaction.TransactionAwareCacheDecorator; +import org.springframework.util.StringUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A {@link org.springframework.cache.CacheManager} implementation + * backed by Redisson instance. + *

+ * 修改 RedissonSpringCacheManager 源码 + * 重写 cacheName 处理方法 支持多参数 + * + * @author Nikita Koksharov + * + */ +@SuppressWarnings("unchecked") +public class FlexSpringCacheManager implements CacheManager { + + private boolean dynamic = true; + + private boolean allowNullValues = true; + + private boolean transactionAware = true; + + Map configMap = new ConcurrentHashMap<>(); + ConcurrentMap instanceMap = new ConcurrentHashMap<>(); + + /** + * Creates CacheManager supplied by Redisson instance + */ + public FlexSpringCacheManager() { + } + + + /** + * Defines possibility of storing {@code null} values. + *

+ * Default is true + * + * @param allowNullValues stores if true + */ + public void setAllowNullValues(boolean allowNullValues) { + this.allowNullValues = allowNullValues; + } + + /** + * Defines if cache aware of Spring-managed transactions. + * If {@code true} put/evict operations are executed only for successful transaction in after-commit phase. + *

+ * Default is false + * + * @param transactionAware cache is transaction aware if true + */ + public void setTransactionAware(boolean transactionAware) { + this.transactionAware = transactionAware; + } + + /** + * Defines 'fixed' cache names. + * A new cache instance will not be created in dynamic for non-defined names. + *

+ * `null` parameter setups dynamic mode + * + * @param names of caches + */ + public void setCacheNames(Collection names) { + if (names != null) { + for (String name : names) { + getCache(name); + } + dynamic = false; + } else { + dynamic = true; + } + } + + /** + * Set cache config mapped by cache name + * + * @param config object + */ + public void setConfig(Map config) { + this.configMap = (Map) config; + } + + protected CacheConfig createDefaultConfig() { + return new CacheConfig(); + } + + @Override + public Cache getCache(String name) { + // 重写 cacheName 支持多参数 + String[] array = StringUtils.delimitedListToStringArray(name, "#"); + name = array[0]; + + Cache cache = instanceMap.get(name); + if (cache != null) { + return cache; + } + if (!dynamic) { + return cache; + } + + CacheConfig config = configMap.get(name); + if (config == null) { + config = createDefaultConfig(); + configMap.put(name, config); + } + + if (array.length > 1) { + config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis()); + } + if (array.length > 2) { + config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis()); + } + if (array.length > 3) { + config.setMaxSize(Integer.parseInt(array[3])); + } + + if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) { + return createMap(name, config); + } + + return createMapCache(name, config); + } + + private Cache createMap(String name, CacheConfig config) { + RMap map = RedisUtils.getClient().getMap(name); + + Cache cache = new RedissonCache(map, allowNullValues); + if (transactionAware) { + cache = new TransactionAwareCacheDecorator(cache); + } + Cache oldCache = instanceMap.putIfAbsent(name, cache); + if (oldCache != null) { + cache = oldCache; + } + return cache; + } + + private Cache createMapCache(String name, CacheConfig config) { + RMapCache map = RedisUtils.getClient().getMapCache(name); + + Cache cache = new RedissonCache(map, config, allowNullValues); + if (transactionAware) { + cache = new TransactionAwareCacheDecorator(cache); + } + Cache oldCache = instanceMap.putIfAbsent(name, cache); + if (oldCache != null) { + cache = oldCache; + } else { + map.setMaxSize(config.getMaxSize()); + } + return cache; + } + + @Override + public Collection getCacheNames() { + return Collections.unmodifiableSet(configMap.keySet()); + } + + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/CacheUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/CacheUtils.java new file mode 100644 index 0000000..e953d03 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/CacheUtils.java @@ -0,0 +1,75 @@ +package com.ruoyi.common.redis.utils; + +import com.ruoyi.common.core.utils.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.RMap; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +import java.util.Set; + +/** + * 缓存操作工具类 {@link } + * + * @author Michelle.Chung + * @date 2022/8/13 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings(value = {"unchecked"}) +public class CacheUtils { + + private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class); + + /** + * 获取缓存组内所有的KEY + * + * @param cacheNames 缓存组名称 + */ + public static Set keys(String cacheNames) { + RMap rmap = (RMap) CACHE_MANAGER.getCache(cacheNames).getNativeCache(); + return rmap.keySet(); + } + + /** + * 获取缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + */ + public static T get(String cacheNames, Object key) { + Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key); + return wrapper != null ? (T) wrapper.get() : null; + } + + /** + * 保存缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + * @param value 缓存值 + */ + public static void put(String cacheNames, Object key, Object value) { + CACHE_MANAGER.getCache(cacheNames).put(key, value); + } + + /** + * 删除缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + */ + public static void evict(String cacheNames, Object key) { + CACHE_MANAGER.getCache(cacheNames).evict(key); + } + + /** + * 清空缓存值 + * + * @param cacheNames 缓存组名称 + */ + public static void clear(String cacheNames) { + CACHE_MANAGER.getCache(cacheNames).clear(); + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/QueueUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/QueueUtils.java new file mode 100644 index 0000000..29ddd98 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/QueueUtils.java @@ -0,0 +1,179 @@ +package com.ruoyi.common.redis.utils; + +import com.ruoyi.common.core.utils.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.*; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * 分布式队列工具 + * 轻量级队列 重量级数据量 请使用 MQ + * 要求 redis 5.X 以上 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class QueueUtils { + + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + + + /** + * 获取客户端实例 + */ + public static RedissonClient getClient() { + return CLIENT; + } + + /** + * 添加普通队列数据 + * + * @param queueName 队列名 + * @param data 数据 + */ + public static boolean addQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.offer(data); + } + + /** + * 通用获取一个队列数据 没有数据返回 null(不支持延迟队列) + * + * @param queueName 队列名 + */ + public static T getQueueObject(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.poll(); + } + + /** + * 通用删除队列数据(不支持延迟队列) + */ + public static boolean removeQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.remove(data); + } + + /** + * 通用销毁队列 所有阻塞监听 报错(不支持延迟队列) + */ + public static boolean destroyQueue(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.delete(); + } + + /** + * 添加延迟队列数据 默认毫秒 + * + * @param queueName 队列名 + * @param data 数据 + * @param time 延迟时间 + */ + public static void addDelayedQueueObject(String queueName, T data, long time) { + addDelayedQueueObject(queueName, data, time, TimeUnit.MILLISECONDS); + } + + /** + * 添加延迟队列数据 + * + * @param queueName 队列名 + * @param data 数据 + * @param time 延迟时间 + * @param timeUnit 单位 + */ + public static void addDelayedQueueObject(String queueName, T data, long time, TimeUnit timeUnit) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + delayedQueue.offer(data, time, timeUnit); + } + + /** + * 获取一个延迟队列数据 没有数据返回 null + * + * @param queueName 队列名 + */ + public static T getDelayedQueueObject(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + return delayedQueue.poll(); + } + + /** + * 删除延迟队列数据 + */ + public static boolean removeDelayedQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + return delayedQueue.remove(data); + } + + /** + * 销毁延迟队列 所有阻塞监听 报错 + */ + public static void destroyDelayedQueue(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + delayedQueue.destroy(); + } + + /** + * 添加优先队列数据 + * + * @param queueName 队列名 + * @param data 数据 + */ + public static boolean addPriorityQueueObject(String queueName, T data) { + RPriorityBlockingQueue priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName); + return priorityBlockingQueue.offer(data); + } + + /** + * 尝试设置 有界队列 容量 用于限制数量 + * + * @param queueName 队列名 + * @param capacity 容量 + */ + public static boolean trySetBoundedQueueCapacity(String queueName, int capacity) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + return boundedBlockingQueue.trySetCapacity(capacity); + } + + /** + * 尝试设置 有界队列 容量 用于限制数量 + * + * @param queueName 队列名 + * @param capacity 容量 + * @param destroy 已存在是否销毁 + */ + public static boolean trySetBoundedQueueCapacity(String queueName, int capacity, boolean destroy) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + if (boundedBlockingQueue.isExists() && destroy) { + destroyQueue(queueName); + } + return boundedBlockingQueue.trySetCapacity(capacity); + } + + /** + * 添加有界队列数据 + * + * @param queueName 队列名 + * @param data 数据 + * @return 添加成功 true 已达到界限 false + */ + public static boolean addBoundedQueueObject(String queueName, T data) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + return boundedBlockingQueue.offer(data); + } + + /** + * 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 等) + */ + public static void subscribeBlockingQueue(String queueName, Consumer consumer) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + queue.subscribeOnElements(consumer); + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/RedisUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/RedisUtils.java new file mode 100644 index 0000000..3d434ec --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/utils/RedisUtils.java @@ -0,0 +1,489 @@ +package com.ruoyi.common.redis.utils; + +import com.ruoyi.common.core.utils.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.*; + +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * redis 工具类 + * + * @author Lion Li + * @version 3.1.0 新增 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings(value = {"unchecked", "rawtypes"}) +public class RedisUtils { + + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + + /** + * 限流 + * + * @param key 限流key + * @param rateType 限流类型 + * @param rate 速率 + * @param rateInterval 速率间隔 + * @return -1 表示失败 + */ + public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) { + RRateLimiter rateLimiter = CLIENT.getRateLimiter(key); + rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS); + if (rateLimiter.tryAcquire()) { + return rateLimiter.availablePermits(); + } else { + return -1L; + } + } + + /** + * 获取客户端实例 + */ + public static RedissonClient getClient() { + return CLIENT; + } + + /** + * 发布通道消息 + * + * @param channelKey 通道key + * @param msg 发送数据 + * @param consumer 自定义处理 + */ + public static void publish(String channelKey, T msg, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + consumer.accept(msg); + } + + public static void publish(String channelKey, T msg) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + } + + /** + * 订阅通道接收消息 + * + * @param channelKey 通道key + * @param clazz 消息类型 + * @param consumer 自定义处理 + */ + public static void subscribe(String channelKey, Class clazz, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public static void setCacheObject(final String key, final T value) { + setCacheObject(key, value, false); + } + + /** + * 缓存基本的对象,保留当前对象 TTL 有效期 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param isSaveTtl 是否保留TTL有效期(例如: set之前ttl剩余90 set之后还是为90) + * @since Redis 6.X 以上使用 setAndKeepTTL 兼容 5.X 方案 + */ + public static void setCacheObject(final String key, final T value, final boolean isSaveTtl) { + RBucket bucket = CLIENT.getBucket(key); + if (isSaveTtl) { + try { + bucket.setAndKeepTTL(value); + } catch (Exception e) { + long timeToLive = bucket.remainTimeToLive(); + setCacheObject(key, value, Duration.ofMillis(timeToLive)); + } + } else { + bucket.set(value); + } + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param duration 时间 + */ + public static void setCacheObject(final String key, final T value, final Duration duration) { + RBatch batch = CLIENT.createBatch(); + RBucketAsync bucket = batch.getBucket(key); + bucket.setAsync(value); + bucket.expireAsync(duration); + batch.execute(); + } + + /** + * 如果不存在则设置 并返回 true 如果存在则返回 false + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @return set成功或失败 + */ + public static boolean setObjectIfAbsent(final String key, final T value, final Duration duration) { + RBucket bucket = CLIENT.getBucket(key); + return bucket.setIfAbsent(value, duration); + } + + /** + * 注册对象监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addObjectListener(final String key, final ObjectListener listener) { + RBucket result = CLIENT.getBucket(key); + result.addListener(listener); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public static boolean expire(final String key, final long timeout) { + return expire(key, Duration.ofSeconds(timeout)); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param duration 超时时间 + * @return true=设置成功;false=设置失败 + */ + public static boolean expire(final String key, final Duration duration) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.expire(duration); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public static T getCacheObject(final String key) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.get(); + } + + /** + * 获得key剩余存活时间 + * + * @param key 缓存键值 + * @return 剩余存活时间 + */ + public static long getTimeToLive(final String key) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.remainTimeToLive(); + } + + /** + * 删除单个对象 + * + * @param key 缓存的键值 + */ + public static boolean deleteObject(final String key) { + return CLIENT.getBucket(key).delete(); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + */ + public static void deleteObject(final Collection collection) { + RBatch batch = CLIENT.createBatch(); + collection.forEach(t -> { + batch.getBucket(t.toString()).deleteAsync(); + }); + batch.execute(); + } + + /** + * 检查缓存对象是否存在 + * + * @param key 缓存的键值 + */ + public static boolean isExistsObject(final String key) { + return CLIENT.getBucket(key).isExists(); + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public static boolean setCacheList(final String key, final List dataList) { + RList rList = CLIENT.getList(key); + return rList.addAll(dataList); + } + + /** + * 注册List监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addListListener(final String key, final ObjectListener listener) { + RList rList = CLIENT.getList(key); + rList.addListener(listener); + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public static List getCacheList(final String key) { + RList rList = CLIENT.getList(key); + return rList.readAll(); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public static boolean setCacheSet(final String key, final Set dataSet) { + RSet rSet = CLIENT.getSet(key); + return rSet.addAll(dataSet); + } + + /** + * 注册Set监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addSetListener(final String key, final ObjectListener listener) { + RSet rSet = CLIENT.getSet(key); + rSet.addListener(listener); + } + + /** + * 获得缓存的set + * + * @param key 缓存的key + * @return set对象 + */ + public static Set getCacheSet(final String key) { + RSet rSet = CLIENT.getSet(key); + return rSet.readAll(); + } + + /** + * 缓存Map + * + * @param key 缓存的键值 + * @param dataMap 缓存的数据 + */ + public static void setCacheMap(final String key, final Map dataMap) { + if (dataMap != null) { + RMap rMap = CLIENT.getMap(key); + rMap.putAll(dataMap); + } + } + + /** + * 注册Map监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addMapListener(final String key, final ObjectListener listener) { + RMap rMap = CLIENT.getMap(key); + rMap.addListener(listener); + } + + /** + * 获得缓存的Map + * + * @param key 缓存的键值 + * @return map对象 + */ + public static Map getCacheMap(final String key) { + RMap rMap = CLIENT.getMap(key); + return rMap.getAll(rMap.keySet()); + } + + /** + * 获得缓存Map的key列表 + * + * @param key 缓存的键值 + * @return key列表 + */ + public static Set getCacheMapKeySet(final String key) { + RMap rMap = CLIENT.getMap(key); + return rMap.keySet(); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public static void setCacheMapValue(final String key, final String hKey, final T value) { + RMap rMap = CLIENT.getMap(key); + rMap.put(hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public static T getCacheMapValue(final String key, final String hKey) { + RMap rMap = CLIENT.getMap(key); + return rMap.get(hKey); + } + + /** + * 删除Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public static T delCacheMapValue(final String key, final String hKey) { + RMap rMap = CLIENT.getMap(key); + return rMap.remove(hKey); + } + + /** + * 删除Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键 + */ + public static void delMultiCacheMapValue(final String key, final Set hKeys) { + RBatch batch = CLIENT.createBatch(); + RMapAsync rMap = batch.getMap(key); + for (String hKey : hKeys) { + rMap.removeAsync(hKey); + } + batch.execute(); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public static Map getMultiCacheMapValue(final String key, final Set hKeys) { + RMap rMap = CLIENT.getMap(key); + return rMap.getAll(hKeys); + } + + /** + * 设置原子值 + * + * @param key Redis键 + * @param value 值 + */ + public static void setAtomicValue(String key, long value) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + atomic.set(value); + } + + /** + * 获取原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long getAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.get(); + } + + /** + * 递增原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long incrAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.incrementAndGet(); + } + + /** + * 递减原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long decrAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.decrementAndGet(); + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public static Collection keys(final String pattern) { + Stream stream = CLIENT.getKeys().getKeysStreamByPattern(pattern); + return stream.collect(Collectors.toList()); + } + + /** + * 删除缓存的基本对象列表 + * + * @param pattern 字符串前缀 + */ + public static void deleteKeys(final String pattern) { + CLIENT.getKeys().deleteByPattern(pattern); + } + + /** + * 检查redis中是否存在key + * + * @param key 键 + */ + public static Boolean hasKey(String key) { + RKeys rKeys = CLIENT.getKeys(); + return rKeys.countExists(key) > 0; + } +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fe5d8b9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.ruoyi.common.redis.config.RedisConfig diff --git a/ruoyi-common/ruoyi-common-security/pom.xml b/ruoyi-common/ruoyi-common-security/pom.xml new file mode 100644 index 0000000..73eca43 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/pom.xml @@ -0,0 +1,46 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + jar + + ruoyi-common-security + + + ruoyi-common-security 安全模块 + + + + + + com.ruoyi + ruoyi-common-core + + + + + com.ruoyi + ruoyi-common-redis + + + + + cn.dev33 + sa-token-spring-boot3-starter + + + + + cn.dev33 + sa-token-jwt + + + + + diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SaTokenConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SaTokenConfig.java new file mode 100644 index 0000000..5915baa --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SaTokenConfig.java @@ -0,0 +1,46 @@ +package com.ruoyi.common.security.config; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.jwt.StpLogicJwtForSimple; +import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.stp.StpLogic; +import com.ruoyi.common.core.factory.YmlPropertySourceFactory; +import com.ruoyi.common.security.core.dao.FlexSaTokenDao; +import com.ruoyi.common.security.core.service.SaPermissionImpl; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * sa-token 配置 + * + * @author Lion Li + */ +@AutoConfiguration +@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class) +public class SaTokenConfig implements WebMvcConfigurer { + + @Bean + public StpLogic getStpLogicJwt() { + // Sa-Token 整合 jwt (简单模式) + return new StpLogicJwtForSimple(); + } + + /** + * 权限接口实现(使用bean注入方便用户替换) + */ + @Bean + public StpInterface stpInterface() { + return new SaPermissionImpl(); + } + + /** + * 自定义dao层存储 + */ + @Bean + public SaTokenDao saTokenDao() { + return new FlexSaTokenDao(); + } + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java new file mode 100644 index 0000000..e2cf40e --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java @@ -0,0 +1,59 @@ +package com.ruoyi.common.security.config; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpUtil; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.security.config.properties.SecurityProperties; +import com.ruoyi.common.security.handler.AllUrlHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 权限安全配置 + * + * @author Lion Li + */ + +@Slf4j +@AutoConfiguration +@EnableConfigurationProperties(SecurityProperties.class) +@RequiredArgsConstructor +public class SecurityConfig implements WebMvcConfigurer { + + private final SecurityProperties securityProperties; + + /** + * 注册 Sa-Token 路由拦截器 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册路由拦截器,自定义验证规则 + registry.addInterceptor(new SaInterceptor(handler -> { + AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); + // 登录验证 -- 排除多个路径 + SaRouter + // 获取所有的 + .match(allUrlHandler.getUrls()) + // 对未排除的路径进行检查 + .check(() -> { + // 检查是否登录 是否有token + StpUtil.checkLogin(); + + //TODO :以后完善多平台登录校验clientID功能 + + }); + })).addPathPatterns("/**") + // 排除不需要拦截的路径 + .excludePathPatterns(securityProperties.getExcludes()); + + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/properties/SecurityProperties.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/properties/SecurityProperties.java new file mode 100644 index 0000000..109a89c --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/properties/SecurityProperties.java @@ -0,0 +1,21 @@ +package com.ruoyi.common.security.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Security 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "security") +public class SecurityProperties { + + /** + * 排除路径 + */ + private String[] excludes; + + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java new file mode 100644 index 0000000..3736e96 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/dao/FlexSaTokenDao.java @@ -0,0 +1,176 @@ +package com.ruoyi.common.security.core.dao; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.util.SaFoxUtil; +import com.ruoyi.common.redis.utils.RedisUtils; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) + * + * @author Lion Li + */ +public class FlexSaTokenDao implements SaTokenDao { + + /** + * 获取Value,如无返空 + */ + @Override + public String get(String key) { + return RedisUtils.getCacheObject(key); + } + + /** + * 写入Value,并设定存活时间 (单位: 秒) + */ + @Override + public void set(String key, String value, long timeout) { + if (timeout == 0 || timeout <= NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == NEVER_EXPIRE) { + RedisUtils.setCacheObject(key, value); + } else { + RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout)); + } + } + + /** + * 修修改指定key-value键值对 (过期时间不变) + */ + @Override + public void update(String key, String value) { + long expire = getTimeout(key); + // -2 = 无此键 + if (expire == NOT_VALUE_EXPIRE) { + return; + } + this.set(key, value, expire); + } + + /** + * 删除Value + */ + @Override + public void delete(String key) { + RedisUtils.deleteObject(key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + long timeout = RedisUtils.getTimeToLive(key); + return timeout < 0 ? timeout : timeout / 1000; + } + + /** + * 修改Value的剩余存活时间 (单位: 秒) + */ + @Override + public void updateTimeout(String key, long timeout) { + // 判断是否想要设置为永久 + if (timeout == NEVER_EXPIRE) { + long expire = getTimeout(key); + if (expire == NEVER_EXPIRE) { + // 如果其已经被设置为永久,则不作任何处理 + } else { + // 如果尚未被设置为永久,那么再次set一次 + this.set(key, this.get(key), timeout); + } + return; + } + RedisUtils.expire(key, Duration.ofSeconds(timeout)); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return RedisUtils.getCacheObject(key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + if (timeout == 0 || timeout <= NOT_VALUE_EXPIRE) { + return; + } + // 判断是否为永不过期 + if (timeout == NEVER_EXPIRE) { + RedisUtils.setCacheObject(key, object); + } else { + RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout)); + } + } + + /** + * 更新Object (过期时间不变) + */ + @Override + public void updateObject(String key, Object object) { + long expire = getObjectTimeout(key); + // -2 = 无此键 + if (expire == NOT_VALUE_EXPIRE) { + return; + } + this.setObject(key, object, expire); + } + + /** + * 删除Object + */ + @Override + public void deleteObject(String key) { + RedisUtils.deleteObject(key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + long timeout = RedisUtils.getTimeToLive(key); + return timeout < 0 ? timeout : timeout / 1000; + } + + /** + * 修改Object的剩余存活时间 (单位: 秒) + */ + @Override + public void updateObjectTimeout(String key, long timeout) { + // 判断是否想要设置为永久 + if (timeout == NEVER_EXPIRE) { + long expire = getObjectTimeout(key); + if (expire == NEVER_EXPIRE) { + // 如果其已经被设置为永久,则不作任何处理 + } else { + // 如果尚未被设置为永久,那么再次set一次 + this.setObject(key, this.getObject(key), timeout); + } + return; + } + RedisUtils.expire(key, Duration.ofSeconds(timeout)); + } + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + Collection keys = RedisUtils.keys(prefix + "*" + keyword + "*"); + List list = new ArrayList<>(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/service/SaPermissionImpl.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/service/SaPermissionImpl.java new file mode 100644 index 0000000..488515d --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/core/service/SaPermissionImpl.java @@ -0,0 +1,47 @@ +package com.ruoyi.common.security.core.service; + +import cn.dev33.satoken.stp.StpInterface; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.enums.UserType; +import com.ruoyi.common.security.utils.LoginHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + * sa-token 权限管理实现类 + * + * @author Lion Li + */ +public class SaPermissionImpl implements StpInterface { + + /** + * 获取菜单权限列表 + */ + @Override + public List getPermissionList(Object loginId, String loginType) { + LoginUser loginUser = LoginHelper.getLoginUser(); + UserType userType = UserType.getUserType(loginUser.getUserType()); + if (userType == UserType.SYS_USER) { + return new ArrayList<>(loginUser.getMenuPermission()); + } else if (userType == UserType.APP_USER) { + // 其他端 自行根据业务编写 + } + return new ArrayList<>(); + } + + /** + * 获取角色权限列表 + */ + @Override + public List getRoleList(Object loginId, String loginType) { + LoginUser loginUser = LoginHelper.getLoginUser(); + UserType userType = UserType.getUserType(loginUser.getUserType()); + if (userType == UserType.SYS_USER) { + return new ArrayList<>(loginUser.getRolePermission()); + } else if (userType == UserType.APP_USER) { + // 其他端 自行根据业务编写 + } + return new ArrayList<>(); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/AllUrlHandler.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/AllUrlHandler.java new file mode 100644 index 0000000..cf58172 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/AllUrlHandler.java @@ -0,0 +1,39 @@ +package com.ruoyi.common.security.handler; + +import cn.hutool.core.util.ReUtil; +import com.ruoyi.common.core.utils.SpringUtils; +import lombok.Data; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * 获取所有Url配置 + * + * @author Lion Li + */ +@Data +public class AllUrlHandler implements InitializingBean { + + private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); + + private List urls = new ArrayList<>(); + + @Override + public void afterPropertiesSet() { + Set set = new HashSet<>(); + RequestMappingHandlerMapping mapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); + Map map = mapping.getHandlerMethods(); + map.keySet().forEach(info -> { + // 获取注解上边的 path 替代 path variable 为 * + Objects.requireNonNull(info.getPathPatternsCondition().getPatterns()) + .forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*"))); + }); + urls.addAll(set); + } + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..8d4687e --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java @@ -0,0 +1,172 @@ +package com.ruoyi.common.security.handler; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; +import cn.dev33.satoken.exception.NotRoleException; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpStatus; +import com.ruoyi.common.core.exception.base.BaseException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.core.domain.R; +import com.ruoyi.common.core.exception.DemoModeException; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.StreamUtils; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingPathVariableException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +/** + * 全局异常处理器 + * + * @author Lion Li + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 权限码异常 + */ + @ExceptionHandler(NotPermissionException.class) + public R handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + + /** + * 角色权限异常 + */ + @ExceptionHandler(NotRoleException.class) + public R handleNotRoleException(NotRoleException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + + /** + * 认证失败 + */ + @ExceptionHandler(NotLoginException.class) + public R handleNotLoginException(NotLoginException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"); + } + + /** + * 请求方式不支持 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public R handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, + HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); + return R.fail(e.getMessage()); + } + + /** + * 业务异常 + */ + @ExceptionHandler(ServiceException.class) + public R handleServiceException(ServiceException e, HttpServletRequest request) { + log.error(e.getMessage()); + Integer code = e.getCode(); + return ObjectUtil.isNotNull(code) ? R.fail(code,e.getMessage()) : R.fail(e.getMessage()); + } + + /** + * 业务异常 + */ + @ExceptionHandler(BaseException.class) + public R handleBaseException(BaseException e, HttpServletRequest request) { + log.error(e.getMessage()); + return R.fail(e.getMessage()); + } + + /** + * 请求路径中缺少必需的路径变量 + */ + @ExceptionHandler(MissingPathVariableException.class) + public R handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI); + return R.fail(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); + } + + /** + * 请求参数类型不匹配 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public R handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI); + return R.fail(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue())); + } + + /** + * 拦截未知的运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + public R handleRuntimeException(RuntimeException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生未知异常.", requestURI, e); + return R.fail(e.getMessage()); + } + + /** + * 系统异常 + */ + @ExceptionHandler(Exception.class) + public R handleException(Exception e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',发生系统异常.", requestURI, e); + return R.fail(e.getMessage()); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public R handleBindException(BindException e) { + log.error(e.getMessage()); + String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", "); + return R.fail(message); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(ConstraintViolationException.class) + public R constraintViolationException(ConstraintViolationException e) { + log.error(e.getMessage()); + String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", "); + return R.fail(message); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.error(e.getMessage()); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + return R.fail(message); + } + + /** + * 演示模式异常 + */ + @ExceptionHandler(DemoModeException.class) + public R handleDemoModeException(DemoModeException e) { + return R.fail("演示模式,不允许操作"); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/listener/UserActionListener.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/listener/UserActionListener.java new file mode 100644 index 0000000..2614890 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/listener/UserActionListener.java @@ -0,0 +1,139 @@ +package com.ruoyi.common.security.listener; + +import cn.dev33.satoken.config.SaTokenConfig; +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.core.domain.dto.UserOnlineDTO; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.enums.UserType; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.core.utils.ip.AddressUtils; +import com.ruoyi.common.core.utils.ServletUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 用户行为 自定义侦听器 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class UserActionListener implements SaTokenListener { + + private final SaTokenConfig tokenConfig; + + /** + * 每次登录时触发 + */ + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + UserType userType = UserType.getUserType(loginId.toString()); + if (userType == UserType.SYS_USER) { + UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = ServletUtils.getClientIP(); + LoginUser user = LoginHelper.getLoginUser(); + UserOnlineDTO dto = new UserOnlineDTO(); + dto.setIpaddr(ip); + dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + dto.setBrowser(userAgent.getBrowser().getName()); + dto.setOs(userAgent.getOs().getName()); + dto.setLoginTime(System.currentTimeMillis()); + dto.setTokenId(tokenValue); + dto.setUserName(user.getUsername()); + dto.setDeptName(user.getDeptName()); + if(tokenConfig.getTimeout() == -1) { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); + } else { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); + } + log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); + } else if (userType == UserType.APP_USER) { + // app端 自行根据业务编写 + } + } + + /** + * 每次注销时触发 + */ + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被踢下线时触发 + */ + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被顶下线时触发 + */ + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { + } + + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId, String service) { + } + + /** + * 每次打开二级认证时触发 + */ + @Override + public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCloseSafe(String loginType, String tokenValue, String service) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + } + + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + } + + /** + * 每次Token续期时触发 + */ + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/LoginHelper.java new file mode 100644 index 0000000..314256a --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/LoginHelper.java @@ -0,0 +1,172 @@ +package com.ruoyi.common.security.utils; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import com.ruoyi.common.core.constant.TenantConstants; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.enums.UserType; + +import java.util.Set; + +/** + * 登录鉴权助手 + *

+ * user_type 为 用户类型 同一个用户表 可以有多种用户类型 例如 pc,app + * deivce 为 设备类型 同一个用户类型 可以有 多种设备类型 例如 web,ios + * 可以组成 用户类型与设备类型多对多的 权限灵活控制 + *

+ * 多用户体系 针对 多种用户类型 但权限控制不一致 + * 可以组成 多用户类型表与多设备类型 分别控制权限 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LoginHelper { + + public static final String LOGIN_USER_KEY = "loginUser"; + public static final String TENANT_KEY = "tenantId"; + public static final String USER_KEY = "userId"; + public static final String CLIENT_KEY = "clientid"; + + /** + * 登录系统 基于 设备类型 + * 针对相同用户体系不同设备 + * + * @param loginUser 登录用户信息 + * @param model 配置参数 + */ + public static void login(LoginUser loginUser, SaLoginModel model) { + SaStorage storage = SaHolder.getStorage(); + storage.set(LOGIN_USER_KEY, loginUser); + storage.set(TENANT_KEY, loginUser.getTenantId()); + storage.set(USER_KEY, loginUser.getUserId()); + model = ObjectUtil.defaultIfNull(model, new SaLoginModel()); + //登录,生成token + StpUtil.login(loginUser.getLoginId(), + model.setExtra(TENANT_KEY, loginUser.getTenantId()) + .setExtra(USER_KEY, loginUser.getUserId())); + StpUtil.getSession().set(LOGIN_USER_KEY, loginUser); + } + + /** + * 获取用户(多级缓存) + */ + public static LoginUser getLoginUser() { + LoginUser loginUser = (LoginUser) SaHolder.getStorage().get(LOGIN_USER_KEY); + if (loginUser != null) { + return loginUser; + } + SaSession session = StpUtil.getSession(); + if (ObjectUtil.isNull(session)) { + return null; + } + loginUser = (LoginUser) session.get(LOGIN_USER_KEY); + SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); + return loginUser; + } + + /** + * 获取用户基于token + */ + public static LoginUser getLoginUser(String token) { + Object loginId = StpUtil.getLoginIdByToken(token); + SaSession session = StpUtil.getSessionByLoginId(loginId); + if (ObjectUtil.isNull(session)) { + return null; + } + return (LoginUser) session.get(LOGIN_USER_KEY); + } + + /** + * 获取用户id + */ + public static Long getUserId() { + Long userId; + try { + userId = Convert.toLong(SaHolder.getStorage().get(USER_KEY)); + if (ObjectUtil.isNull(userId)) { + userId = Convert.toLong(StpUtil.getExtra(USER_KEY)); + SaHolder.getStorage().set(USER_KEY, userId); + } + } catch (Exception e) { + return null; + } + return userId; + } + + /** + * 获取租户ID + */ + public static String getTenantId() { + String tenantId; + try { + tenantId = (String) SaHolder.getStorage().get(TENANT_KEY); + if (ObjectUtil.isNull(tenantId)) { + tenantId = (String) StpUtil.getExtra(TENANT_KEY); + SaHolder.getStorage().set(TENANT_KEY, tenantId); + } + } catch (Exception e) { + return null; + } + return tenantId; + } + + /** + * 获取部门ID + */ + public static Long getDeptId() { + return getLoginUser().getDeptId(); + } + + /** + * 获取用户账户 + */ + public static String getUsername() { + return getLoginUser().getUsername(); + } + + /** + * 获取用户类型 + */ + public static UserType getUserType() { + String loginType = StpUtil.getLoginIdAsString(); + return UserType.getUserType(loginType); + } + + /** + * 是否为超级管理员 + * + * @param userId 用户ID + * @return 结果 + */ + public static boolean isSuperAdmin(Long userId) { + return UserConstants.SUPER_ADMIN_ID.equals(userId); + } + + public static boolean isSuperAdmin() { + return isSuperAdmin(getUserId()); + } + + /** + * 是否为超级管理员 + * + * @param rolePermission 角色权限标识组 + * @return 结果 + */ + public static boolean isTenantAdmin(Set rolePermission) { + return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY); + } + + public static boolean isTenantAdmin() { + return isTenantAdmin(getLoginUser().getRolePermission()); + } + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..5f8dc63 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,4 @@ +com.ruoyi.common.security.config.SaTokenConfig +com.ruoyi.common.security.handler.GlobalExceptionHandler +com.ruoyi.common.security.handler.AllUrlHandler +com.ruoyi.common.security.config.SecurityConfig \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-security/src/main/resources/common-satoken.yml b/ruoyi-common/ruoyi-common-security/src/main/resources/common-satoken.yml new file mode 100644 index 0000000..95e1b41 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/resources/common-satoken.yml @@ -0,0 +1,13 @@ +# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖 +# Sa-Token配置 +sa-token: + # 允许动态设置 token 有效期 + dynamic-active-timeout: true + # 允许从 请求参数 读取 token + is-read-body: true + # 允许从 header 读取 token + is-read-header: true + # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险 + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" diff --git a/ruoyi-common/ruoyi-common-springdoc/pom.xml b/ruoyi-common/ruoyi-common-springdoc/pom.xml index 54a8bf8..b5a6d90 100644 --- a/ruoyi-common/ruoyi-common-springdoc/pom.xml +++ b/ruoyi-common/ruoyi-common-springdoc/pom.xml @@ -3,11 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - ruoyi-common com.ruoyi + ruoyi-common ${revision} 4.0.0 + jar ruoyi-common-springdoc @@ -37,7 +38,7 @@ com.github.therapi therapi-runtime-javadoc - + - \ No newline at end of file + diff --git a/ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/springdoc/SpringDocConfig.java b/ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/security/SpringDocConfig.java similarity index 98% rename from ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/springdoc/SpringDocConfig.java rename to ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/security/SpringDocConfig.java index 3a1daec..5e33463 100644 --- a/ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/springdoc/SpringDocConfig.java +++ b/ruoyi-common/ruoyi-common-springdoc/src/main/java/com/ruoyi/common/security/SpringDocConfig.java @@ -1,4 +1,4 @@ -package com.ruoyi.common.springdoc; +package com.ruoyi.common.security; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.ExternalDocumentation; diff --git a/ruoyi-common/ruoyi-common-tenant/pom.xml b/ruoyi-common/ruoyi-common-tenant/pom.xml new file mode 100644 index 0000000..d5999de --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/pom.xml @@ -0,0 +1,36 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-tenant + + + ruoyi-common-tenant 租户模块 + + + + + com.ruoyi + ruoyi-common-orm + + + + com.ruoyi + ruoyi-common-redis + + + + com.alibaba + transmittable-thread-local + + + + + diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantEntity.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantEntity.java new file mode 100644 index 0000000..bfb724d --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantEntity.java @@ -0,0 +1,24 @@ +package com.ruoyi.common.tenant.core; + +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 租户基类 + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TenantEntity extends BaseEntity { + + /** + * 租户编号 + */ + //@NotNull(message = "id不能为空", groups = { EditGroup.class }) + private Long tenantId; + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java new file mode 100644 index 0000000..ad93f62 --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/core/TenantSaTokenDao.java @@ -0,0 +1,148 @@ +package com.ruoyi.common.tenant.core; + +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.core.dao.FlexSaTokenDao; + +import java.time.Duration; +import java.util.List; + +/** + * SaToken 认证数据持久层 适配多租户 + * + * @author Lion Li + */ +public class TenantSaTokenDao extends FlexSaTokenDao { + + @Override + public String get(String key) { + return super.get(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + @Override + public void set(String key, String value, long timeout) { + super.set(GlobalConstants.GLOBAL_REDIS_KEY + key, value, timeout); + } + + /** + * 修修改指定key-value键值对 (过期时间不变) + */ + @Override + public void update(String key, String value) { + long expire = getTimeout(key); + // -2 = 无此键 + if (expire == NOT_VALUE_EXPIRE) { + return; + } + this.set(key, value, expire); + } + + /** + * 删除Value + */ + @Override + public void delete(String key) { + super.delete(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 获取Value的剩余存活时间 (单位: 秒) + */ + @Override + public long getTimeout(String key) { + return super.getTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 修改Value的剩余存活时间 (单位: 秒) + */ + @Override + public void updateTimeout(String key, long timeout) { + // 判断是否想要设置为永久 + if (timeout == NEVER_EXPIRE) { + long expire = getTimeout(key); + if (expire == NEVER_EXPIRE) { + // 如果其已经被设置为永久,则不作任何处理 + } else { + // 如果尚未被设置为永久,那么再次set一次 + this.set(key, this.get(key), timeout); + } + return; + } + RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout)); + } + + + /** + * 获取Object,如无返空 + */ + @Override + public Object getObject(String key) { + return super.getObject(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 写入Object,并设定存活时间 (单位: 秒) + */ + @Override + public void setObject(String key, Object object, long timeout) { + super.setObject(GlobalConstants.GLOBAL_REDIS_KEY + key, object, timeout); + } + + /** + * 更新Object (过期时间不变) + */ + @Override + public void updateObject(String key, Object object) { + long expire = getObjectTimeout(key); + // -2 = 无此键 + if (expire == NOT_VALUE_EXPIRE) { + return; + } + this.setObject(key, object, expire); + } + + /** + * 删除Object + */ + @Override + public void deleteObject(String key) { + super.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 获取Object的剩余存活时间 (单位: 秒) + */ + @Override + public long getObjectTimeout(String key) { + return super.getObjectTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 修改Object的剩余存活时间 (单位: 秒) + */ + @Override + public void updateObjectTimeout(String key, long timeout) { + // 判断是否想要设置为永久 + if (timeout == NEVER_EXPIRE) { + long expire = getObjectTimeout(key); + if (expire == NEVER_EXPIRE) { + // 如果其已经被设置为永久,则不作任何处理 + } else { + // 如果尚未被设置为永久,那么再次set一次 + this.setObject(key, this.getObject(key), timeout); + } + return; + } + RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout)); + } + + + /** + * 搜索数据 + */ + @Override + public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { + return super.searchData(GlobalConstants.GLOBAL_REDIS_KEY + prefix, keyword, start, size, sortType); + } +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/exception/TenantException.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/exception/TenantException.java new file mode 100644 index 0000000..371bc12 --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/exception/TenantException.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.tenant.exception; + +import com.ruoyi.common.core.exception.base.BaseException; + +import java.io.Serial; + +/** + * 租户异常类 + * + * @author Lion Li + */ +public class TenantException extends BaseException { + + @Serial + private static final long serialVersionUID = 1L; + + public TenantException(String code, Object... args) { + super("tenant", code, args, null); + } +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/PlusTenantLineHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/PlusTenantLineHandler.java new file mode 100644 index 0000000..c67a22a --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/PlusTenantLineHandler.java @@ -0,0 +1,57 @@ +package com.ruoyi.common.tenant.handle; + +import cn.hutool.core.collection.ListUtil; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.common.tenant.properties.TenantProperties; +import lombok.AllArgsConstructor; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.NullValue; +import net.sf.jsqlparser.expression.StringValue; + +import java.util.List; + +/** + * 自定义租户处理器 + * + * @author Lion Li + */ +@AllArgsConstructor +//public class PlusTenantLineHandler implements TenantLineHandler { +public class PlusTenantLineHandler { + + private final TenantProperties tenantProperties; + + public Expression getTenantId() { + String tenantId = LoginHelper.getTenantId(); + if (StringUtils.isBlank(tenantId)) { + return new NullValue(); + } + String dynamicTenantId = TenantHelper.getDynamic(); + if (StringUtils.isNotBlank(dynamicTenantId)) { + // 返回动态租户 + return new StringValue(dynamicTenantId); + } + // 返回固定租户 + return new StringValue(tenantId); + } + + public boolean ignoreTable(String tableName) { + String tenantId = LoginHelper.getTenantId(); + // 判断是否有租户 + if (StringUtils.isNotBlank(tenantId)) { + // 不需要过滤租户的表 + List excludes = tenantProperties.getExcludes(); + // 非业务表 + List tables = ListUtil.toList( + "gen_table", + "gen_table_column" + ); + tables.addAll(excludes); + return tables.contains(tableName); + } + return true; + } + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java new file mode 100644 index 0000000..729702d --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/handle/TenantKeyPrefixHandler.java @@ -0,0 +1,58 @@ +package com.ruoyi.common.tenant.handle; + +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.handler.KeyPrefixHandler; +import com.ruoyi.common.tenant.helper.TenantHelper; + +/** + * 多租户redis缓存key前缀处理 + * + * @author Lion Li + */ +public class TenantKeyPrefixHandler extends KeyPrefixHandler { + + public TenantKeyPrefixHandler(String keyPrefix) { + super(keyPrefix); + } + + /** + * 增加前缀 + */ + @Override + public String map(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { + return super.map(name); + } + String tenantId = TenantHelper.getTenantId(); + if (StringUtils.startsWith(name, tenantId)) { + // 如果存在则直接返回 + return super.map(name); + } + return super.map(tenantId + ":" + name); + } + + /** + * 去除前缀 + */ + @Override + public String unmap(String name) { + String unmap = super.unmap(name); + if (StringUtils.isBlank(unmap)) { + return null; + } + if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { + return super.unmap(name); + } + String tenantId = TenantHelper.getTenantId(); + if (StringUtils.startsWith(unmap, tenantId)) { + // 如果存在则删除 + return unmap.substring((tenantId + ":").length()); + } + return unmap; + } + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java new file mode 100644 index 0000000..5b04f3d --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/helper/TenantHelper.java @@ -0,0 +1,138 @@ +package com.ruoyi.common.tenant.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.spring.SpringMVCUtil; +import cn.hutool.core.convert.Convert; +import com.alibaba.ttl.TransmittableThreadLocal; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.utils.LoginHelper; + +import java.util.function.Supplier; + +/** + * 租户助手 + * + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TenantHelper { + + private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant"; + + private static final ThreadLocal TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>(); + + /** + * 租户功能是否启用 + */ + public static boolean isEnable() { + return Convert.toBool(SpringUtils.getProperty("tenant.enable"), false); + } + + /** + * 开启忽略租户(开启后需手动调用 {@link #disableIgnore()} 关闭) + */ + public static void enableIgnore() { + //InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build()); + } + + /** + * 关闭忽略租户 + */ + public static void disableIgnore() { + //InterceptorIgnoreHelper.clearIgnoreStrategy(); + } + + /** + * 在忽略租户中执行 + * + * @param handle 处理执行方法 + */ + public static void ignore(Runnable handle) { + enableIgnore(); + try { + handle.run(); + } finally { + disableIgnore(); + } + } + + /** + * 在忽略租户中执行 + * + * @param handle 处理执行方法 + */ + public static T ignore(Supplier handle) { + enableIgnore(); + try { + return handle.get(); + } finally { + disableIgnore(); + } + } + + /** + * 设置动态租户(一直有效 需要手动清理) + *

+ * 如果为非web环境 那么只在当前线程内生效 + */ + public static void setDynamic(String tenantId) { + if (!SpringMVCUtil.isWeb()) { + TEMP_DYNAMIC_TENANT.set(tenantId); + return; + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); + RedisUtils.setCacheObject(cacheKey, tenantId); + SaHolder.getStorage().set(cacheKey, tenantId); + } + + /** + * 获取动态租户(一直有效 需要手动清理) + *

+ * 如果为非web环境 那么只在当前线程内生效 + */ + public static String getDynamic() { + if (!SpringMVCUtil.isWeb()) { + return TEMP_DYNAMIC_TENANT.get(); + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); + String tenantId = (String) SaHolder.getStorage().get(cacheKey); + if (StringUtils.isNotBlank(tenantId)) { + return tenantId; + } + tenantId = RedisUtils.getCacheObject(cacheKey); + SaHolder.getStorage().set(cacheKey, tenantId); + return tenantId; + } + + /** + * 清除动态租户 + */ + public static void clearDynamic() { + if (!SpringMVCUtil.isWeb()) { + TEMP_DYNAMIC_TENANT.remove(); + return; + } + String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); + RedisUtils.deleteObject(cacheKey); + SaHolder.getStorage().delete(cacheKey); + } + + /** + * 获取当前租户id(动态租户优先) + */ + public static String getTenantId() { + String tenantId = TenantHelper.getDynamic(); + if (StringUtils.isBlank(tenantId)) { + tenantId = LoginHelper.getTenantId(); + } + return tenantId; + } + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java new file mode 100644 index 0000000..68e9f70 --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/manager/TenantSpringCacheManager.java @@ -0,0 +1,32 @@ +package com.ruoyi.common.tenant.manager; + +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.manager.FlexSpringCacheManager; +import com.ruoyi.common.tenant.helper.TenantHelper; +import org.springframework.cache.Cache; + +/** + * 重写 cacheName 处理方法 支持多租户 + * + * @author Lion Li + */ +public class TenantSpringCacheManager extends FlexSpringCacheManager { + + public TenantSpringCacheManager() { + } + + @Override + public Cache getCache(String name) { + if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { + return super.getCache(name); + } + String tenantId = TenantHelper.getTenantId(); + if (StringUtils.startsWith(name, tenantId)) { + // 如果存在则直接返回 + return super.getCache(name); + } + return super.getCache(tenantId + ":" + name); + } + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/properties/TenantProperties.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/properties/TenantProperties.java new file mode 100644 index 0000000..473ea77 --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/com/ruoyi/common/tenant/properties/TenantProperties.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.tenant.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.List; + +/** + * 租户 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "tenant") +public class TenantProperties { + + /** + * 是否启用 + */ + private Boolean enable; + + /** + * 排除表 + */ + private List excludes; + +} diff --git a/ruoyi-common/ruoyi-common-translation/pom.xml b/ruoyi-common/ruoyi-common-translation/pom.xml new file mode 100644 index 0000000..51199d5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/pom.xml @@ -0,0 +1,27 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-translation + + + ruoyi-common-translation 通用翻译功能 + + + + + + com.ruoyi + ruoyi-common-json + + + + + diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/Translation.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/Translation.java new file mode 100644 index 0000000..1a74001 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/Translation.java @@ -0,0 +1,39 @@ +package com.ruoyi.common.translation.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.ruoyi.common.translation.core.handler.TranslationHandler; + +import java.lang.annotation.*; + +/** + * 通用翻译注解 + * + * @author Lion Li + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@Documented +@JacksonAnnotationsInside +@JsonSerialize(using = TranslationHandler.class) +public @interface Translation { + + /** + * 类型 (需与实现类上的 {@link TranslationType} 注解type对应) + *

+ * 默认取当前字段的值 如果设置了 @{@link Translation#mapper()} 则取映射字段的值 + */ + String type(); + + /** + * 映射字段 (如果不为空则取此字段的值) + */ + String mapper() default ""; + + /** + * 其他条件 例如: 字典type(sys_user_sex) + */ + String other() default ""; + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/TranslationType.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/TranslationType.java new file mode 100644 index 0000000..e90ee38 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/annotation/TranslationType.java @@ -0,0 +1,23 @@ +package com.ruoyi.common.translation.annotation; + +import com.ruoyi.common.translation.core.TranslationInterface; + +import java.lang.annotation.*; + +/** + * 翻译类型注解 (标注到{@link TranslationInterface} 的实现类) + * + * @author Lion Li + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +public @interface TranslationType { + + /** + * 类型 + */ + String type(); + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/config/TranslationConfig.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/config/TranslationConfig.java new file mode 100644 index 0000000..a9aefe5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/config/TranslationConfig.java @@ -0,0 +1,50 @@ +package com.ruoyi.common.translation.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ruoyi.common.translation.annotation.TranslationType; +import com.ruoyi.common.translation.core.TranslationInterface; +import com.ruoyi.common.translation.core.handler.TranslationBeanSerializerModifier; +import com.ruoyi.common.translation.core.handler.TranslationHandler; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 翻译模块配置类 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration +public class TranslationConfig { + + @Autowired + private List> list; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public void init() { + Map> map = new HashMap<>(list.size()); + for (TranslationInterface trans : list) { + if (trans.getClass().isAnnotationPresent(TranslationType.class)) { + TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class); + map.put(annotation.type(), trans); + } else { + log.warn(trans.getClass().getName() + " 翻译实现类未标注 TranslationType 注解!"); + } + } + TranslationHandler.TRANSLATION_MAPPER.putAll(map); + // 设置 Bean 序列化修改器 + objectMapper.setSerializerFactory( + objectMapper.getSerializerFactory() + .withSerializerModifier(new TranslationBeanSerializerModifier())); + } + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/constant/TransConstant.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/constant/TransConstant.java new file mode 100644 index 0000000..1cfec58 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/constant/TransConstant.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.translation.constant; + +/** + * 翻译常量 + * + * @author Lion Li + */ +public interface TransConstant { + + /** + * 用户id转账号 + */ + String USER_ID_TO_NAME = "user_id_to_name"; + + /** + * 部门id转名称 + */ + String DEPT_ID_TO_NAME = "dept_id_to_name"; + + /** + * 字典type转label + */ + String DICT_TYPE_TO_LABEL = "dict_type_to_label"; + + /** + * ossId转url + */ + String OSS_ID_TO_URL = "oss_id_to_url"; + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/TranslationInterface.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/TranslationInterface.java new file mode 100644 index 0000000..d5c9ec7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/TranslationInterface.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.translation.core; + +import com.ruoyi.common.translation.annotation.TranslationType; + +/** + * 翻译接口 (实现类需标注 {@link TranslationType} 注解标明翻译类型) + * + * @author Lion Li + */ +public interface TranslationInterface { + + /** + * 翻译 + * + * @param key 需要被翻译的键(不为空) + * @param other 其他参数 + * @return 返回键对应的值 + */ + T translation(Object key, String other); +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationBeanSerializerModifier.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationBeanSerializerModifier.java new file mode 100644 index 0000000..fb3f6f7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationBeanSerializerModifier.java @@ -0,0 +1,29 @@ +package com.ruoyi.common.translation.core.handler; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; + +import java.util.List; + +/** + * Bean 序列化修改器 解决 Null 被单独处理问题 + * + * @author Lion Li + */ +public class TranslationBeanSerializerModifier extends BeanSerializerModifier { + + @Override + public List changeProperties(SerializationConfig config, BeanDescription beanDesc, + List beanProperties) { + for (BeanPropertyWriter writer : beanProperties) { + // 如果序列化器为 TranslationHandler 的话 将 Null 值也交给他处理 + if (writer.getSerializer() instanceof TranslationHandler serializer) { + writer.assignNullSerializer(serializer); + } + } + return beanProperties; + } + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationHandler.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationHandler.java new file mode 100644 index 0000000..ac10ee5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/handler/TranslationHandler.java @@ -0,0 +1,65 @@ +package com.ruoyi.common.translation.core.handler; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.ruoyi.common.translation.annotation.Translation; +import com.ruoyi.common.translation.core.TranslationInterface; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.reflect.ReflectUtils; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 翻译处理器 + * + * @author Lion Li + */ +@Slf4j +public class TranslationHandler extends JsonSerializer implements ContextualSerializer { + + /** + * 全局翻译实现类映射器 + */ + public static final Map> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); + + private Translation translation; + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + TranslationInterface trans = TRANSLATION_MAPPER.get(translation.type()); + if (ObjectUtil.isNotNull(trans)) { + // 如果映射字段不为空 则取映射字段的值 + if (StringUtils.isNotBlank(translation.mapper())) { + value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper()); + } + // 如果为 null 直接写出 + if (ObjectUtil.isNull(value)) { + gen.writeNull(); + return; + } + Object result = trans.translation(value, translation.other()); + gen.writeObject(result); + } else { + gen.writeObject(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + Translation translation = property.getAnnotation(Translation.class); + if (Objects.nonNull(translation)) { + this.translation = translation; + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DeptNameTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DeptNameTranslationImpl.java new file mode 100644 index 0000000..0acf8b6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DeptNameTranslationImpl.java @@ -0,0 +1,29 @@ +package com.ruoyi.common.translation.core.impl; + +import com.ruoyi.common.translation.annotation.TranslationType; +import com.ruoyi.common.core.service.DeptService; +import com.ruoyi.common.translation.constant.TransConstant; +import com.ruoyi.common.translation.core.TranslationInterface; +import lombok.AllArgsConstructor; + +/** + * 部门翻译实现 + * + * @author Lion Li + */ +@AllArgsConstructor +@TranslationType(type = TransConstant.DEPT_ID_TO_NAME) +public class DeptNameTranslationImpl implements TranslationInterface { + + private final DeptService deptService; + + @Override + public String translation(Object key, String other) { + if (key instanceof String ids) { + return deptService.selectDeptNameByIds(ids); + } else if (key instanceof Long id) { + return deptService.selectDeptNameByIds(id.toString()); + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DictTypeTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DictTypeTranslationImpl.java new file mode 100644 index 0000000..5e54441 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/DictTypeTranslationImpl.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.translation.core.impl; + +import com.ruoyi.common.translation.annotation.TranslationType; +import com.ruoyi.common.translation.constant.TransConstant; +import com.ruoyi.common.translation.core.TranslationInterface; +import com.ruoyi.common.core.service.DictService; +import com.ruoyi.common.core.utils.StringUtils; +import lombok.AllArgsConstructor; + +/** + * 字典翻译实现 + * + * @author Lion Li + */ +@AllArgsConstructor +@TranslationType(type = TransConstant.DICT_TYPE_TO_LABEL) +public class DictTypeTranslationImpl implements TranslationInterface { + + private final DictService dictService; + + @Override + public String translation(Object key, String other) { + if (key instanceof String dictValue && StringUtils.isNotBlank(other)) { + return dictService.getDictLabel(other, dictValue); + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/UserNameTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/UserNameTranslationImpl.java new file mode 100644 index 0000000..1ae09c6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/com/ruoyi/common/translation/core/impl/UserNameTranslationImpl.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.translation.core.impl; + +import com.ruoyi.common.translation.annotation.TranslationType; +import com.ruoyi.common.translation.constant.TransConstant; +import com.ruoyi.common.translation.core.TranslationInterface; +import com.ruoyi.common.core.service.UserService; +import lombok.AllArgsConstructor; + +/** + * 用户名翻译实现 + * + * @author Lion Li + */ +@AllArgsConstructor +@TranslationType(type = TransConstant.USER_ID_TO_NAME) +public class UserNameTranslationImpl implements TranslationInterface { + + private final UserService userService; + + @Override + public String translation(Object key, String other) { + if (key instanceof Long id) { + return userService.selectUserNameById(id); + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..0f983f7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,4 @@ +com.ruoyi.common.translation.config.TranslationConfig +com.ruoyi.common.translation.core.impl.DeptNameTranslationImpl +com.ruoyi.common.translation.core.impl.DictTypeTranslationImpl +com.ruoyi.common.translation.core.impl.UserNameTranslationImpl diff --git a/ruoyi-framework/pom.xml b/ruoyi-common/ruoyi-common-web/pom.xml similarity index 54% rename from ruoyi-framework/pom.xml rename to ruoyi-common/ruoyi-common-web/pom.xml index c68fe8c..073d667 100644 --- a/ruoyi-framework/pom.xml +++ b/ruoyi-common/ruoyi-common-web/pom.xml @@ -3,19 +3,43 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - ruoyi-flex com.ruoyi + ruoyi-common ${revision} 4.0.0 - ruoyi-framework + ruoyi-common-web - framework框架核心 + ruoyi-common-web web服务 + + com.ruoyi + ruoyi-common-core + + + + com.ruoyi + ruoyi-common-json + + + + com.ruoyi + ruoyi-common-orm + + + + com.ruoyi + ruoyi-common-redis + + + + com.ruoyi + ruoyi-common-security + @@ -28,47 +52,31 @@ - + org.springframework.boot spring-boot-starter-undertow - org.springframework.boot - spring-boot-starter-aop - - - - - pro.fessional - kaptcha - - - servlet-api - jakarta.servlet - - + spring-boot-starter-actuator - com.google.guava - guava + cn.hutool + hutool-captcha - - com.github.oshi - oshi-core + cn.hutool + hutool-crypto - - com.ruoyi - ruoyi-system + com.alibaba + transmittable-thread-local - - \ No newline at end of file + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/RepeatSubmit.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/annotation/RepeatSubmit.java similarity index 69% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/RepeatSubmit.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/annotation/RepeatSubmit.java index d9b2326..de8cac4 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/RepeatSubmit.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/annotation/RepeatSubmit.java @@ -1,4 +1,4 @@ -package com.ruoyi.common.core.annotation; +package com.ruoyi.common.web.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -6,10 +6,11 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; /** * 自定义注解防止表单重复提交 - * + * * @author ruoyi * */ @@ -24,8 +25,10 @@ public @interface RepeatSubmit */ public int interval() default 5000; + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + /** - * 提示消息 + * 提示消息 支持国际化 格式为 {code} */ - public String message() default "不允许重复提交,请稍候再试"; + String message() default "{repeat.submit.message}"; } diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/aspectj/RepeatSubmitAspect.java new file mode 100644 index 0000000..589d825 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/aspectj/RepeatSubmitAspect.java @@ -0,0 +1,146 @@ +package com.ruoyi.common.web.aspectj; + +import cn.dev33.satoken.SaManager; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.core.domain.R; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.web.annotation.RepeatSubmit; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.time.Duration; +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; + +/** + * 防止重复提交(参考美团GTIS防重系统) + * + * @author Lion Li + */ +@Aspect +public class RepeatSubmitAspect { + + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + @Before("@annotation(repeatSubmit)") + public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { + // 如果注解不为0 则使用注解数值 + long interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval()); + + if (interval < 1000) { + throw new ServiceException("重复提交间隔时间不能小于'1'秒"); + } + HttpServletRequest request = ServletUtils.getRequest(); + String nowParams = argsArrayToString(point.getArgs()); + + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + + // 唯一值(没有消息头则使用请求地址) + String submitKey = StringUtils.trimToEmpty(request.getHeader(SaManager.getConfig().getTokenName())); + + submitKey = SecureUtil.md5(submitKey + ":" + nowParams); + // 唯一标识(指定key + url + 消息头) + String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey; + if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) { + KEY_CACHE.set(cacheRepeatKey); + } else { + String message = repeatSubmit.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) { + if (jsonResult instanceof R r) { + try { + // 成功则不删除redis数据 保证在有效时间内无法重复提交 + if (r.getCode() == R.SUCCESS) { + return; + } + RedisUtils.deleteObject(KEY_CACHE.get()); + } finally { + KEY_CACHE.remove(); + } + } + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) { + RedisUtils.deleteObject(KEY_CACHE.get()); + KEY_CACHE.remove(); + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + params.add(JsonUtils.toJsonString(o)); + } + } + return params.toString(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.values()) { + return value instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } + +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/CaptchaConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/CaptchaConfig.java new file mode 100644 index 0000000..5b2eba6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/CaptchaConfig.java @@ -0,0 +1,65 @@ +package com.ruoyi.common.web.config; + +import cn.hutool.captcha.CaptchaUtil; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import com.ruoyi.common.web.config.properties.CaptchaProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; + +import java.awt.*; + +/** + * 验证码配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableConfigurationProperties(CaptchaProperties.class) +public class CaptchaConfig { + + private static final int WIDTH = 160; + private static final int HEIGHT = 60; + private static final Color BACKGROUND = Color.PINK; + private static final Font FONT = new Font("Arial", Font.BOLD, 48); + + /** + * 圆圈干扰验证码 + */ + @Lazy + @Bean + public CircleCaptcha circleCaptcha() { + CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + + /** + * 线段干扰的验证码 + */ + @Lazy + @Bean + public LineCaptcha lineCaptcha() { + LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + + /** + * 扭曲干扰验证码 + */ + @Lazy + @Bean + public ShearCaptcha shearCaptcha() { + ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/FilterConfig.java similarity index 58% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/FilterConfig.java index e459d3b..d35ea52 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/FilterConfig.java @@ -1,52 +1,47 @@ -package com.ruoyi.framework.config; +package com.ruoyi.common.web.config; + +import com.ruoyi.common.web.config.properties.XssProperties; +import com.ruoyi.common.web.filter.XssFilter; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.web.filter.RepeatableFilter; +import jakarta.servlet.DispatcherType; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; import java.util.HashMap; import java.util.Map; -import jakarta.servlet.DispatcherType; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import com.ruoyi.common.core.filter.RepeatableFilter; -import com.ruoyi.common.core.filter.XssFilter; -import com.ruoyi.common.core.utils.StringUtils; /** * Filter配置 * - * @author ruoyi + * @author Lion Li */ -@Configuration -public class FilterConfig -{ - @Value("${xss.excludes}") - private String excludes; +@AutoConfiguration +@EnableConfigurationProperties(XssProperties.class) +public class FilterConfig { - @Value("${xss.urlPatterns}") - private String urlPatterns; - - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) @Bean @ConditionalOnProperty(value = "xss.enabled", havingValue = "true") - public FilterRegistrationBean xssFilterRegistration() - { + public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setFilter(new XssFilter()); - registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); + registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR)); registration.setName("xssFilter"); registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); Map initParameters = new HashMap<>(); - initParameters.put("excludes", excludes); + initParameters.put("excludes", xssProperties.getExcludes()); registration.setInitParameters(initParameters); return registration; } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) @Bean - public FilterRegistrationBean someFilterRegistration() - { + public FilterRegistrationBean someFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new RepeatableFilter()); registration.addUrlPatterns("/*"); diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java new file mode 100644 index 0000000..dd76619 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java @@ -0,0 +1,22 @@ +package com.ruoyi.common.web.config; + +import com.ruoyi.common.web.core.I18nLocaleResolver; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.servlet.LocaleResolver; + +/** + * 国际化配置 + * + * @author Lion Li + */ +@AutoConfiguration(before = WebMvcAutoConfiguration.class) +public class I18nConfig { + + @Bean + public LocaleResolver localeResolver() { + return new I18nLocaleResolver(); + } + +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/RepeatSubmitConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/RepeatSubmitConfig.java new file mode 100644 index 0000000..19b584c --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/RepeatSubmitConfig.java @@ -0,0 +1,21 @@ +package com.ruoyi.common.web.config; + +import com.ruoyi.common.web.aspectj.RepeatSubmitAspect; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConfiguration; + +/** + * 幂等功能配置 + * + * @author Lion Li + */ +@AutoConfiguration(after = RedisConfiguration.class) +public class RepeatSubmitConfig { + + @Bean + public RepeatSubmitAspect repeatSubmitAspect() { + return new RepeatSubmitAspect(); + } + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/ResourcesConfig.java similarity index 51% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/ResourcesConfig.java index 0f82201..6e34038 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/ResourcesConfig.java @@ -1,61 +1,39 @@ -package com.ruoyi.framework.config; +package com.ruoyi.common.web.config; -import java.util.concurrent.TimeUnit; - -import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; +import com.ruoyi.common.web.interceptor.FlexWebInvokeTimeInterceptor; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.CacheControl; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import com.ruoyi.common.core.config.RuoYiConfig; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /** * 通用配置 - * - * @author ruoyi + * + * @author Lion Li */ -@Configuration +@AutoConfiguration public class ResourcesConfig implements WebMvcConfigurer { - @Resource - private RepeatSubmitInterceptor repeatSubmitInterceptor; @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) - { - /** 本地文件上传路径 */ - registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**") - .addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); - - /** swagger配置 */ - registry.addResourceHandler("/swagger-ui/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") - .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic()); + public void addInterceptors(InterceptorRegistry registry) { + // 全局访问性能拦截 + registry.addInterceptor(new FlexWebInvokeTimeInterceptor()); } - /** - * 自定义拦截规则 - */ @Override - public void addInterceptors(InterceptorRegistry registry) - { - registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + public void addResourceHandlers(ResourceHandlerRegistry registry) { } /** * 跨域配置 */ @Bean - public CorsFilter corsFilter() - { + public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // 设置访问源地址 @@ -72,4 +50,4 @@ public class ResourcesConfig implements WebMvcConfigurer // 返回新的CorsFilter return new CorsFilter(source); } -} \ No newline at end of file +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/UndertowConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/UndertowConfig.java new file mode 100644 index 0000000..6659c3c --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/UndertowConfig.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.web.config; + +import io.undertow.server.DefaultByteBufferPool; +import io.undertow.websockets.jsr.WebSocketDeploymentInfo; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; + +/** + * Undertow 自定义配置 + * + * @author Lion Li + */ +@AutoConfiguration +public class UndertowConfig implements WebServerFactoryCustomizer { + + /** + * 设置 Undertow 的 websocket 缓冲池 + */ + @Override + public void customize(UndertowServletWebServerFactory factory) { + // 默认不直接分配内存 如果项目中使用了 websocket 建议直接分配 + factory.addDeploymentInfoCustomizers(deploymentInfo -> { + WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); + webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(false, 512)); + deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo); + }); + } + +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/CaptchaProperties.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/CaptchaProperties.java new file mode 100644 index 0000000..e4b8e15 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/CaptchaProperties.java @@ -0,0 +1,38 @@ +package com.ruoyi.common.web.config.properties; + +import com.ruoyi.common.web.enums.CaptchaCategory; +import com.ruoyi.common.web.enums.CaptchaType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 验证码 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "captcha") +public class CaptchaProperties { + + private Boolean enable; + + /** + * 验证码类型 + */ + private CaptchaType type; + + /** + * 验证码类别 + */ + private CaptchaCategory category; + + /** + * 数字验证码位数 + */ + private Integer numberLength; + + /** + * 字符验证码长度 + */ + private Integer charLength; +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/XssProperties.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/XssProperties.java new file mode 100644 index 0000000..1978236 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/properties/XssProperties.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.web.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * xss过滤 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "xss") +public class XssProperties { + + /** + * 过滤开关 + */ + private String enabled; + + /** + * 排除链接(多个用逗号分隔) + */ + private String excludes; + + /** + * 匹配链接 + */ + private String urlPatterns; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/controller/BaseController.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/BaseController.java similarity index 84% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/controller/BaseController.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/BaseController.java index 5bb476a..206ea72 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/controller/BaseController.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/BaseController.java @@ -1,4 +1,4 @@ -package com.ruoyi.common.core.core.controller; +package com.ruoyi.common.web.core; import java.beans.PropertyEditorSupport; import java.util.Date; @@ -15,17 +15,15 @@ import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.ruoyi.common.core.constant.HttpStatus; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.model.LoginUser; import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.PageUtils; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.sql.SqlUtil; import com.mybatisflex.core.paginate.Page; /** * web层通用数据处理 - * + * * @author ruoyi */ public class BaseController @@ -50,7 +48,7 @@ public class BaseController } /** - * 设置请求分页数据 + * PageHelper设置请求分页数据 */ protected void startPage() { @@ -93,7 +91,7 @@ public class BaseController } /** - * 响应请求分页数据 + * 响应请求分页数据(mybatis-flex版本) */ protected TableDataInfo getFlexTable(Page page) { @@ -128,7 +126,7 @@ public class BaseController { return AjaxResult.success(message); } - + /** * 返回成功消息 */ @@ -155,7 +153,7 @@ public class BaseController /** * 响应返回结果 - * + * * @param rows 影响行数 * @return 操作结果 */ @@ -164,9 +162,13 @@ public class BaseController return rows > 0 ? AjaxResult.success() : AjaxResult.error(); } +// protected R toAjax(int rows) { +// return rows > 0 ? R.ok() : R.fail(); +// } + /** * 响应返回结果 - * + * * @param result 结果 * @return 操作结果 */ @@ -175,6 +177,10 @@ public class BaseController return result ? success() : error(); } +// protected R toAjax(boolean result) { +// return result ? R.ok() : R.fail(); +// } + /** * 页面跳转 */ @@ -183,35 +189,5 @@ public class BaseController return StringUtils.format("redirect:{}", url); } - /** - * 获取用户缓存信息 - */ - public LoginUser getLoginUser() - { - return SecurityUtils.getLoginUser(); - } - /** - * 获取登录用户id - */ - public Long getUserId() - { - return getLoginUser().getUserId(); - } - - /** - * 获取登录部门id - */ - public Long getDeptId() - { - return getLoginUser().getDeptId(); - } - - /** - * 获取登录用户名 - */ - public String getUsername() - { - return getLoginUser().getUsername(); - } } diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java new file mode 100644 index 0000000..6b741de --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java @@ -0,0 +1,31 @@ +package com.ruoyi.common.web.core; + +import org.springframework.web.servlet.LocaleResolver; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Locale; + +/** + * 获取请求头国际化信息 + * + * @author Lion Li + */ +public class I18nLocaleResolver implements LocaleResolver { + + @Override + public Locale resolveLocale(HttpServletRequest httpServletRequest) { + String language = httpServletRequest.getHeader("content-language"); + Locale locale = Locale.getDefault(); + if (language != null && language.length() > 0) { + String[] split = language.split("_"); + locale = new Locale(split[0], split[1]); + } + return locale; + } + + @Override + public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { + + } +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaCategory.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaCategory.java new file mode 100644 index 0000000..7fca5c2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaCategory.java @@ -0,0 +1,35 @@ +package com.ruoyi.common.web.enums; + +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类别 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum CaptchaCategory { + + /** + * 线段干扰 + */ + LINE(LineCaptcha.class), + + /** + * 圆圈干扰 + */ + CIRCLE(CircleCaptcha.class), + + /** + * 扭曲干扰 + */ + SHEAR(ShearCaptcha.class); + + private final Class clazz; +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaType.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaType.java new file mode 100644 index 0000000..f78d572 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/enums/CaptchaType.java @@ -0,0 +1,29 @@ +package com.ruoyi.common.web.enums; + +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.captcha.generator.RandomGenerator; +import com.ruoyi.common.web.utils.UnsignedMathGenerator; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum CaptchaType { + + /** + * 数字 + */ + MATH(UnsignedMathGenerator.class), + + /** + * 字符 + */ + CHAR(RandomGenerator.class); + + private final Class clazz; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/RepeatableFilter.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/RepeatableFilter.java similarity index 55% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/RepeatableFilter.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/RepeatableFilter.java index ff0e005..60e98ef 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/RepeatableFilter.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/RepeatableFilter.java @@ -1,53 +1,40 @@ -package com.ruoyi.common.core.filter; - -import java.io.IOException; +package com.ruoyi.common.web.filter; import com.ruoyi.common.core.utils.StringUtils; -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; + /** * Repeatable 过滤器 - * + * * @author ruoyi */ -public class RepeatableFilter implements Filter -{ +public class RepeatableFilter implements Filter { @Override - public void init(FilterConfig filterConfig) throws ServletException - { + public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException - { + throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest - && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) - { + && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); } - if (null == requestWrapper) - { + if (null == requestWrapper) { chain.doFilter(request, response); - } - else - { + } else { chain.doFilter(requestWrapper, response); } } @Override - public void destroy() - { + public void destroy() { } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/RepeatedlyRequestWrapper.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/RepeatedlyRequestWrapper.java similarity index 70% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/RepeatedlyRequestWrapper.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/RepeatedlyRequestWrapper.java index 32e6d8e..1451575 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/RepeatedlyRequestWrapper.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/RepeatedlyRequestWrapper.java @@ -1,75 +1,66 @@ -package com.ruoyi.common.core.filter; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; +package com.ruoyi.common.web.filter; +import cn.hutool.core.io.IoUtil; import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.utils.http.HttpHelper; + import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + /** * 构建可重复读取inputStream的request - * + * * @author ruoyi */ -public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper -{ +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; - public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException - { + public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { super(request); request.setCharacterEncoding(Constants.UTF8); response.setCharacterEncoding(Constants.UTF8); - body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8); + body = IoUtil.readBytes(request.getInputStream(), false); } @Override - public BufferedReader getReader() throws IOException - { + public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override - public ServletInputStream getInputStream() throws IOException - { + public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); - return new ServletInputStream() - { + return new ServletInputStream() { @Override - public int read() throws IOException - { + public int read() throws IOException { return bais.read(); } @Override - public int available() throws IOException - { + public int available() throws IOException { return body.length; } @Override - public boolean isFinished() - { + public boolean isFinished() { return false; } @Override - public boolean isReady() - { + public boolean isReady() { return false; } @Override - public void setReadListener(ReadListener readListener) - { + public void setReadListener(ReadListener readListener) { } }; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/XssFilter.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/XssFilter.java similarity index 64% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/XssFilter.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/XssFilter.java index 1898976..5ae7e7d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/XssFilter.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/XssFilter.java @@ -1,41 +1,32 @@ -package com.ruoyi.common.core.filter; +package com.ruoyi.common.web.filter; +import com.ruoyi.common.core.utils.StringUtils; +import org.springframework.http.HttpMethod; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import com.ruoyi.common.core.enums.HttpMethod; -import com.ruoyi.common.core.utils.StringUtils; -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - /** * 防止XSS攻击的过滤器 - * + * * @author ruoyi */ -public class XssFilter implements Filter -{ +public class XssFilter implements Filter { /** * 排除链接 */ public List excludes = new ArrayList<>(); @Override - public void init(FilterConfig filterConfig) throws ServletException - { + public void init(FilterConfig filterConfig) throws ServletException { String tempExcludes = filterConfig.getInitParameter("excludes"); - if (StringUtils.isNotEmpty(tempExcludes)) - { - String[] url = tempExcludes.split(","); - for (int i = 0; url != null && i < url.length; i++) - { + if (StringUtils.isNotEmpty(tempExcludes)) { + String[] url = tempExcludes.split(StringUtils.SEPARATOR); + for (int i = 0; url != null && i < url.length; i++) { excludes.add(url[i]); } } @@ -43,12 +34,10 @@ public class XssFilter implements Filter @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException - { + throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; - if (handleExcludeURL(req, resp)) - { + if (handleExcludeURL(req, resp)) { chain.doFilter(request, response); return; } @@ -56,21 +45,18 @@ public class XssFilter implements Filter chain.doFilter(xssRequest, response); } - private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) - { + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { String url = request.getServletPath(); String method = request.getMethod(); // GET DELETE 不过滤 - if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) - { + if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) { return true; } return StringUtils.matches(url, excludes); } @Override - public void destroy() - { + public void destroy() { } -} \ No newline at end of file +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/XssHttpServletRequestWrapper.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/XssHttpServletRequestWrapper.java similarity index 59% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/XssHttpServletRequestWrapper.java rename to ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/XssHttpServletRequestWrapper.java index ecb9c82..a7d9f1e 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/XssHttpServletRequestWrapper.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/filter/XssHttpServletRequestWrapper.java @@ -1,99 +1,87 @@ -package com.ruoyi.common.core.filter; - -import java.io.ByteArrayInputStream; -import java.io.IOException; +package com.ruoyi.common.web.filter; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HtmlUtil; import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.html.EscapeUtil; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; -import org.apache.commons.io.IOUtils; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; /** * XSS过滤处理 - * + * * @author ruoyi */ -public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper -{ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * @param request */ - public XssHttpServletRequestWrapper(HttpServletRequest request) - { + public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } @Override - public String[] getParameterValues(String name) - { + public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); - if (values != null) - { + if (values != null) { int length = values.length; - String[] escapesValues = new String[length]; - for (int i = 0; i < length; i++) - { + String[] escapseValues = new String[length]; + for (int i = 0; i < length; i++) { // 防xss攻击和过滤前后空格 - escapesValues[i] = EscapeUtil.clean(values[i]).trim(); + escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim(); } - return escapesValues; + return escapseValues; } return super.getParameterValues(name); } @Override - public ServletInputStream getInputStream() throws IOException - { + public ServletInputStream getInputStream() throws IOException { // 非json类型,直接返回 - if (!isJsonRequest()) - { + if (!isJsonRequest()) { return super.getInputStream(); } // 为空,直接返回 - String json = IOUtils.toString(super.getInputStream(), "utf-8"); - if (StringUtils.isEmpty(json)) - { + String json = StrUtil.str(IoUtil.readBytes(super.getInputStream(), false), StandardCharsets.UTF_8); + if (StringUtils.isEmpty(json)) { return super.getInputStream(); } // xss过滤 - json = EscapeUtil.clean(json).trim(); - byte[] jsonBytes = json.getBytes("utf-8"); - final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes); - return new ServletInputStream() - { + json = HtmlUtil.cleanHtmlTag(json).trim(); + byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); + final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes); + return new ServletInputStream() { @Override - public boolean isFinished() - { + public boolean isFinished() { return true; } @Override - public boolean isReady() - { + public boolean isReady() { return true; } @Override - public int available() throws IOException - { + public int available() throws IOException { return jsonBytes.length; } @Override - public void setReadListener(ReadListener readListener) - { + public void setReadListener(ReadListener readListener) { } @Override - public int read() throws IOException - { + public int read() throws IOException { return bis.read(); } }; @@ -101,12 +89,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper /** * 是否是Json请求 - * - * @param request */ - public boolean isJsonRequest() - { + public boolean isJsonRequest() { String header = super.getHeader(HttpHeaders.CONTENT_TYPE); return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); } -} \ No newline at end of file +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/interceptor/FlexWebInvokeTimeInterceptor.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/interceptor/FlexWebInvokeTimeInterceptor.java new file mode 100644 index 0000000..05c5057 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/interceptor/FlexWebInvokeTimeInterceptor.java @@ -0,0 +1,93 @@ +package com.ruoyi.common.web.interceptor; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import com.alibaba.ttl.TransmittableThreadLocal; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import com.ruoyi.common.web.filter.RepeatedlyRequestWrapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +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 java.io.BufferedReader; +import java.util.Map; + +/** + * web的调用时间统计拦截器 + * dev环境有效 + * + * @author Lion Li + */ +@Slf4j +public class FlexWebInvokeTimeInterceptor implements HandlerInterceptor { + + private final String prodProfile = "prod"; + + private final TransmittableThreadLocal invokeTimeTL = new TransmittableThreadLocal<>(); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (!prodProfile.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 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 (!prodProfile.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; + } + +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/utils/UnsignedMathGenerator.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/utils/UnsignedMathGenerator.java new file mode 100644 index 0000000..06c3f3c --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/utils/UnsignedMathGenerator.java @@ -0,0 +1,88 @@ +package com.ruoyi.common.web.utils; + +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.math.Calculator; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.RandomUtil; +import com.ruoyi.common.core.utils.StringUtils; + +import java.io.Serial; + +/** + * 无符号计算生成器 + * + * @author Lion Li + */ +public class UnsignedMathGenerator implements CodeGenerator { + + @Serial + private static final long serialVersionUID = -5514819971774091076L; + + private static final String OPERATORS = "+-*"; + + /** + * 参与计算数字最大长度 + */ + private final int numberLength; + + /** + * 构造 + */ + public UnsignedMathGenerator() { + this(2); + } + + /** + * 构造 + * + * @param numberLength 参与计算最大数字位数 + */ + public UnsignedMathGenerator(int numberLength) { + this.numberLength = numberLength; + } + + @Override + public String generate() { + final int limit = getLimit(); + int a = RandomUtil.randomInt(limit); + int b = RandomUtil.randomInt(limit); + String max = Integer.toString(Math.max(a,b)); + String min = Integer.toString(Math.min(a,b)); + max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE); + min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE); + + return max + RandomUtil.randomChar(OPERATORS) + min + '='; + } + + @Override + public boolean verify(String code, String userInputCode) { + int result; + try { + result = Integer.parseInt(userInputCode); + } catch (NumberFormatException e) { + // 用户输入非数字 + return false; + } + + final int calculateResult = (int) Calculator.conversion(code); + return result == calculateResult; + } + + /** + * 获取验证码长度 + * + * @return 验证码长度 + */ + public int getLength() { + return this.numberLength * 2 + 2; + } + + /** + * 根据长度获取参与计算数字最大值 + * + * @return 最大值 + */ + private int getLimit() { + return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength)); + } +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..ec9a3d9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +com.ruoyi.common.web.config.CaptchaConfig +com.ruoyi.common.web.config.FilterConfig +com.ruoyi.common.web.config.I18nConfig +com.ruoyi.common.web.config.ResourcesConfig +com.ruoyi.common.web.config.UndertowConfig +com.ruoyi.common.web.config.RepeatSubmitConfig diff --git a/ruoyi-extra/pom.xml b/ruoyi-extra/pom.xml new file mode 100644 index 0000000..c37b8e9 --- /dev/null +++ b/ruoyi-extra/pom.xml @@ -0,0 +1,19 @@ + + + + ruoyi-flex + com.ruoyi + ${revision} + + 4.0.0 + pom + + ruoyi-extra + + + + + + diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java deleted file mode 100644 index 5a4beea..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.ruoyi.framework.aspectj; - -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.reflect.MethodSignature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.script.RedisScript; -import org.springframework.stereotype.Component; -import com.ruoyi.common.core.annotation.RateLimiter; -import com.ruoyi.common.core.enums.LimitType; -import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.ip.IpUtils; - -/** - * 限流处理 - * - * @author ruoyi - */ -@Aspect -@Component -public class RateLimiterAspect -{ - private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class); - - private RedisTemplate redisTemplate; - - private RedisScript limitScript; - - @Autowired - public void setRedisTemplate1(RedisTemplate redisTemplate) - { - this.redisTemplate = redisTemplate; - } - - @Autowired - public void setLimitScript(RedisScript limitScript) - { - this.limitScript = limitScript; - } - - @Before("@annotation(rateLimiter)") - public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable - { - int time = rateLimiter.time(); - int count = rateLimiter.count(); - - String combineKey = getCombineKey(rateLimiter, point); - List keys = Collections.singletonList(combineKey); - try - { - Long number = redisTemplate.execute(limitScript, keys, count, time); - if (StringUtils.isNull(number) || number.intValue() > count) - { - throw new ServiceException("访问过于频繁,请稍候再试"); - } - log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey); - } - catch (ServiceException e) - { - throw e; - } - catch (Exception e) - { - throw new RuntimeException("服务器限流异常,请稍候再试"); - } - } - - public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) - { - StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); - if (rateLimiter.limitType() == LimitType.IP) - { - stringBuffer.append(IpUtils.getIpAddr()).append("-"); - } - MethodSignature signature = (MethodSignature) point.getSignature(); - Method method = signature.getMethod(); - Class targetClass = method.getDeclaringClass(); - stringBuffer.append(targetClass.getName()).append("-").append(method.getName()); - return stringBuffer.toString(); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java deleted file mode 100644 index 1d4dc1f..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.ruoyi.framework.config; - -import java.util.TimeZone; -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.EnableAspectJAutoProxy; - -/** - * 程序注解配置 - * - * @author ruoyi - */ -@Configuration -// 表示通过aop框架暴露该代理对象,AopContext能够访问 -@EnableAspectJAutoProxy(exposeProxy = true) -// 指定要扫描的Mapper类的包的路径 -@MapperScan("com.ruoyi.**.mapper") -public class ApplicationConfig -{ - /** - * 时区配置 - */ - @Bean - public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() - { - return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault()); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java deleted file mode 100644 index 43e78ae..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.ruoyi.framework.config; - -import java.util.Properties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import com.google.code.kaptcha.impl.DefaultKaptcha; -import com.google.code.kaptcha.util.Config; -import static com.google.code.kaptcha.Constants.*; - -/** - * 验证码配置 - * - * @author ruoyi - */ -@Configuration -public class CaptchaConfig -{ - @Bean(name = "captchaProducer") - public DefaultKaptcha getKaptchaBean() - { - DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); - Properties properties = new Properties(); - // 是否有边框 默认为true 我们可以自己设置yes,no - properties.setProperty(KAPTCHA_BORDER, "yes"); - // 验证码文本字符颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); - // 验证码图片宽度 默认为200 - properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); - // 验证码图片高度 默认为50 - properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); - // 验证码文本字符大小 默认为40 - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); - // KAPTCHA_SESSION_KEY - properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); - // 验证码文本字符长度 默认为5 - properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); - // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); - // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy - properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); - Config config = new Config(properties); - defaultKaptcha.setConfig(config); - return defaultKaptcha; - } - - @Bean(name = "captchaProducerMath") - public DefaultKaptcha getKaptchaBeanMath() - { - DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); - Properties properties = new Properties(); - // 是否有边框 默认为true 我们可以自己设置yes,no - properties.setProperty(KAPTCHA_BORDER, "yes"); - // 边框颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); - // 验证码文本字符颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); - // 验证码图片宽度 默认为200 - properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); - // 验证码图片高度 默认为50 - properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); - // 验证码文本字符大小 默认为40 - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); - // KAPTCHA_SESSION_KEY - properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); - // 验证码文本生成器 - properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator"); - // 验证码文本字符间距 默认为2 - properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); - // 验证码文本字符长度 默认为5 - properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); - // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) - properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); - // 验证码噪点颜色 默认为Color.BLACK - properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); - // 干扰实现类 - properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); - // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy - properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); - Config config = new Config(properties); - defaultKaptcha.setConfig(config); - return defaultKaptcha; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java deleted file mode 100644 index b6d6110..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.ruoyi.framework.config; - -import java.nio.charset.Charset; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.serializer.SerializationException; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONReader; -import com.alibaba.fastjson2.JSONWriter; - -/** - * Redis使用FastJson序列化 - * - * @author ruoyi - */ -public class FastJson2JsonRedisSerializer implements RedisSerializer -{ - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); - - private Class clazz; - - public FastJson2JsonRedisSerializer(Class clazz) - { - super(); - this.clazz = clazz; - } - - @Override - public byte[] serialize(T t) throws SerializationException - { - if (t == null) - { - return new byte[0]; - } - return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET); - } - - @Override - public T deserialize(byte[] bytes) throws SerializationException - { - if (bytes == null || bytes.length <= 0) - { - return null; - } - String str = new String(bytes, DEFAULT_CHARSET); - - return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java deleted file mode 100644 index 7f8e1d5..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.ruoyi.framework.config; - -import java.util.Random; -import com.google.code.kaptcha.text.impl.DefaultTextCreator; - -/** - * 验证码文本生成器 - * - * @author ruoyi - */ -public class KaptchaTextCreator extends DefaultTextCreator -{ - private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); - - @Override - public String getText() - { - Integer result = 0; - Random random = new Random(); - int x = random.nextInt(10); - int y = random.nextInt(10); - StringBuilder suChinese = new StringBuilder(); - int randomoperands = random.nextInt(3); - if (randomoperands == 0) - { - result = x * y; - suChinese.append(CNUMBERS[x]); - suChinese.append("*"); - suChinese.append(CNUMBERS[y]); - } - else if (randomoperands == 1) - { - if ((x != 0) && y % x == 0) - { - result = y / x; - suChinese.append(CNUMBERS[y]); - suChinese.append("/"); - suChinese.append(CNUMBERS[x]); - } - else - { - result = x + y; - suChinese.append(CNUMBERS[x]); - suChinese.append("+"); - suChinese.append(CNUMBERS[y]); - } - } - else - { - if (x >= y) - { - result = x - y; - suChinese.append(CNUMBERS[x]); - suChinese.append("-"); - suChinese.append(CNUMBERS[y]); - } - else - { - result = y - x; - suChinese.append(CNUMBERS[y]); - suChinese.append("-"); - suChinese.append(CNUMBERS[x]); - } - } - suChinese.append("=?@" + result); - return suChinese.toString(); - } -} \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java deleted file mode 100644 index f364964..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.ruoyi.framework.config; - -import com.mybatisflex.annotation.KeyType; -import com.mybatisflex.core.keygen.KeyGenerators; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import com.mybatisflex.core.FlexGlobalConfig; -import org.mybatis.spring.annotation.MapperScan; -import jakarta.annotation.PostConstruct; -import com.github.pagehelper.PageInterceptor; - -/** - * Mybatis支持*匹配扫描包 - * Mybatis-Flex配置 - * - * @author dataprince数据小王子 - */ -@Configuration -@MapperScan("com.ruoyi.**.mapper") -public class MyBatisConfig -{ - @Bean - public PageInterceptor pageInterceptor(){ - PageInterceptor pageInterceptor = new PageInterceptor(); - return pageInterceptor; - } - - @PostConstruct - public void setFlexConfig() - { - FlexGlobalConfig globalConfig = FlexGlobalConfig.getDefaultConfig(); - // 关闭banner - globalConfig.setPrintBanner(false); - - //统一设置数据库表主键为雪花算法 - FlexGlobalConfig.KeyConfig keyConfig = new FlexGlobalConfig.KeyConfig(); - keyConfig.setKeyType(KeyType.Generator); - keyConfig.setValue(KeyGenerators.snowFlakeId); - //keyConfig.setBefore(true); - FlexGlobalConfig.getDefaultConfig().setKeyConfig(keyConfig); - - //设置数据库正常时的值 - globalConfig.setNormalValueOfLogicDelete("0"); - //设置数据已被删除时的值 - globalConfig.setDeletedValueOfLogicDelete("1"); - } -} \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java deleted file mode 100644 index 3f4f485..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.ruoyi.framework.config; - -import org.springframework.cache.annotation.CachingConfigurerSupport; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.script.DefaultRedisScript; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -/** - * redis配置 - * - * @author ruoyi - */ -@Configuration -@EnableCaching -public class RedisConfig extends CachingConfigurerSupport -{ - @Bean - @SuppressWarnings(value = { "unchecked", "rawtypes" }) - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) - { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - - FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); - - // 使用StringRedisSerializer来序列化和反序列化redis的key值 - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(serializer); - - // Hash的key也采用StringRedisSerializer的序列化方式 - template.setHashKeySerializer(new StringRedisSerializer()); - template.setHashValueSerializer(serializer); - - template.afterPropertiesSet(); - return template; - } - - @Bean - public DefaultRedisScript limitScript() - { - DefaultRedisScript redisScript = new DefaultRedisScript<>(); - redisScript.setScriptText(limitScriptText()); - redisScript.setResultType(Long.class); - return redisScript; - } - - /** - * 限流脚本 - */ - private String limitScriptText() - { - return "local key = KEYS[1]\n" + - "local count = tonumber(ARGV[1])\n" + - "local time = tonumber(ARGV[2])\n" + - "local current = redis.call('get', key);\n" + - "if current and tonumber(current) > count then\n" + - " return tonumber(current);\n" + - "end\n" + - "current = redis.call('incr', key)\n" + - "if tonumber(current) == 1 then\n" + - " redis.call('expire', key, time)\n" + - "end\n" + - "return tonumber(current);"; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java deleted file mode 100644 index 1bee220..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.ruoyi.framework.config; - -import jakarta.annotation.Resource; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -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.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.logout.LogoutFilter; -import org.springframework.web.filter.CorsFilter; -import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter; -import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl; -import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import jakarta.annotation.security.PermitAll; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition; -import org.springframework.web.servlet.mvc.method.RequestMappingInfo; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; -import org.springframework.context.ApplicationContext; -import java.util.Map; -import java.util.Set; - -/** - * spring security配置 - * - * @author dataprince数据小王子 - */ -@Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -public class SecurityConfig -{ - /** - * 自定义用户认证逻辑 - */ - @Resource - private UserDetailsService userDetailsService; - - /** - * 认证失败处理类 - */ - @Resource - private AuthenticationEntryPointImpl unauthorizedHandler; - - /** - * 退出处理类 - */ - @Resource - private LogoutSuccessHandlerImpl logoutSuccessHandler; - - /** - * token认证过滤器 - */ - @Resource - private JwtAuthenticationTokenFilter authenticationTokenFilter; - - /** - * 跨域过滤器 - */ - @Resource - private CorsFilter corsFilter; - - @Resource - private ApplicationContext applicationContext; - - /** - * anyRequest | 匹配所有请求路径 - * access | SpringEl表达式结果为true时可以访问 - * anonymous | 匿名可以访问 - * denyAll | 用户不能访问 - * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) - * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 - * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 - * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 - * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 - * hasRole | 如果有参数,参数表示角色,则其角色可以访问 - * permitAll | 用户可以任意访问 - * rememberMe | 允许通过remember-me登录的用户访问 - * authenticated | 用户登录后可访问 - */ - @Bean - protected SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception - { - // 注解标记允许匿名访问的url - Multimap permitAllUrls = getPermitAllUrlsFromAnnotations(); - - httpSecurity - // CSRF禁用,因为不使用session - .csrf().disable() - // 禁用HTTP响应标头 - .headers().cacheControl().disable().and() - // 认证失败处理类 - .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() - .headers().frameOptions().disable().and() - // 基于token,所以不需要session - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - // 过滤请求 - .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests - // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - .requestMatchers("/login", "/register", "/captchaImage","/captcha/get", "/captcha/check").permitAll() - // 静态资源,可匿名访问 - .requestMatchers(HttpMethod.GET, "/*.html", "/*/*.html", "/*/*.css", "/*/*.js", "/profile/**").permitAll() - .requestMatchers("/swagger-resources/**", "/webjars/**", "/*/api-docs").permitAll() - .requestMatchers("/swagger-ui.html","/swagger-ui/**", "/v3/api-docs/**").permitAll() - //设置 @PermitAll 无需认证 - .requestMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll() - .requestMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll() - .requestMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll() - .requestMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll() - - ); - - // 除上面外的所有请求全部需要鉴权认证 - httpSecurity.authorizeHttpRequests() - .anyRequest() - .authenticated(); - - - // 添加Logout filter - httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); - // 添加JWT filter - httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); - // 添加CORS filter - httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); - httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); - - return httpSecurity.build(); - } - - private Multimap getPermitAllUrlsFromAnnotations() { - Multimap result = HashMultimap.create(); - // 获得接口对应的 HandlerMethod 集合 - RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) - applicationContext.getBean("requestMappingHandlerMapping"); - Map handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); - // 获得有 @PermitAll 注解的接口 - for (Map.Entry entry : handlerMethodMap.entrySet()) { - HandlerMethod handlerMethod = entry.getValue(); - if (!handlerMethod.hasMethodAnnotation(PermitAll.class)) { - continue; - } - PathPatternsRequestCondition pathPatternsCondition = entry.getKey().getPathPatternsCondition(); - if (pathPatternsCondition == null) { - continue; - } - Set urls = pathPatternsCondition.getPatternValues(); - // 根据请求方法,添加到 result 结果 - entry.getKey().getMethodsCondition().getMethods().forEach(requestMethod -> { - switch (requestMethod) { - case GET -> result.putAll(HttpMethod.GET, urls); - case POST -> result.putAll(HttpMethod.POST, urls); - case PUT -> result.putAll(HttpMethod.PUT, urls); - case DELETE -> result.putAll(HttpMethod.DELETE, urls); - } - }); - } - return result; - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - /** - * 解决 无法直接注入 AuthenticationManager - * - */ - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { - return config.getAuthenticationManager(); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java deleted file mode 100644 index 68eb524..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ruoyi.framework.config; - -import com.ruoyi.common.core.utils.Threads; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor; - -/** - * 线程池配置 - * - * @author ruoyi - **/ -@Configuration -public class ThreadPoolConfig -{ - // 核心线程池大小 - private int corePoolSize = 50; - - // 最大可创建的线程数 - private int maxPoolSize = 200; - - // 队列最大长度 - private int queueCapacity = 1000; - - // 线程池维护线程所允许的空闲时间 - private int keepAliveSeconds = 300; - - @Bean(name = "threadPoolTaskExecutor") - public ThreadPoolTaskExecutor threadPoolTaskExecutor() - { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setMaxPoolSize(maxPoolSize); - executor.setCorePoolSize(corePoolSize); - executor.setQueueCapacity(queueCapacity); - executor.setKeepAliveSeconds(keepAliveSeconds); - // 线程池对拒绝任务(无线程可用)的处理策略 - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); - return executor; - } - - /** - * 执行周期性或定时任务 - */ - @Bean(name = "scheduledExecutorService") - protected ScheduledExecutorService scheduledExecutorService() - { - return new ScheduledThreadPoolExecutor(corePoolSize, - new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), - new ThreadPoolExecutor.CallerRunsPolicy()) - { - @Override - protected void afterExecute(Runnable r, Throwable t) - { - super.afterExecute(r, t); - Threads.printException(r, t); - } - }; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java deleted file mode 100644 index 8620b4b..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ruoyi.framework.config.properties; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.regex.Pattern; -import org.apache.commons.lang3.RegExUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.mvc.method.RequestMappingInfo; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; -import com.ruoyi.common.core.annotation.Anonymous; - -/** - * 设置Anonymous注解允许匿名访问的url - * - * @author ruoyi - */ -@Configuration -public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware -{ - private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); - - private ApplicationContext applicationContext; - - private List urls = new ArrayList<>(); - - public String ASTERISK = "*"; - - @Override - public void afterPropertiesSet() - { - RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class); - Map map = mapping.getHandlerMethods(); - - map.keySet().forEach(info -> { - HandlerMethod handlerMethod = map.get(info); - - // 获取方法上边的注解 替代path variable 为 * - Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class); - Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns()) - .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); - - // 获取类上边的注解, 替代path variable 为 * - Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class); - Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns()) - .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); - }); - } - - @Override - public void setApplicationContext(ApplicationContext context) throws BeansException - { - this.applicationContext = context; - } - - public List getUrls() - { - return urls; - } - - public void setUrls(List urls) - { - this.urls = urls; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java deleted file mode 100644 index 88ca8e6..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.ruoyi.framework.interceptor; - -import java.lang.reflect.Method; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerInterceptor; -import com.alibaba.fastjson2.JSON; -import com.ruoyi.common.core.annotation.RepeatSubmit; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.utils.ServletUtils; - -/** - * 防止重复提交拦截器 - * - * @author ruoyi - */ -@Component -public abstract class RepeatSubmitInterceptor implements HandlerInterceptor -{ - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception - { - if (handler instanceof HandlerMethod) - { - HandlerMethod handlerMethod = (HandlerMethod) handler; - Method method = handlerMethod.getMethod(); - RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); - if (annotation != null) - { - if (this.isRepeatSubmit(request, annotation)) - { - AjaxResult ajaxResult = AjaxResult.error(annotation.message()); - ServletUtils.renderString(response, JSON.toJSONString(ajaxResult)); - return false; - } - } - return true; - } - else - { - return true; - } - } - - /** - * 验证是否重复提交由子类实现具体的防重复提交的规则 - * - * @param request - * @return - * @throws Exception - */ - public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation); -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java deleted file mode 100644 index 0f43659..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.ruoyi.framework.interceptor.impl; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import com.alibaba.fastjson2.JSON; -import com.ruoyi.common.core.annotation.RepeatSubmit; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.filter.RepeatedlyRequestWrapper; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.http.HttpHelper; -import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; - -/** - * 判断请求url和数据是否和上一次相同, - * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 - * - * @author ruoyi - */ -@Component -public class SameUrlDataInterceptor extends RepeatSubmitInterceptor -{ - public final String REPEAT_PARAMS = "repeatParams"; - - public final String REPEAT_TIME = "repeatTime"; - - // 令牌自定义标识 - @Value("${token.header}") - private String header; - - @Autowired - private RedisCache redisCache; - - @SuppressWarnings("unchecked") - @Override - public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) - { - String nowParams = ""; - if (request instanceof RepeatedlyRequestWrapper) - { - RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request; - nowParams = HttpHelper.getBodyString(repeatedlyRequest); - } - - // body参数为空,获取Parameter的数据 - if (StringUtils.isEmpty(nowParams)) - { - nowParams = JSON.toJSONString(request.getParameterMap()); - } - Map nowDataMap = new HashMap<>(); - nowDataMap.put(REPEAT_PARAMS, nowParams); - nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); - - // 请求地址(作为存放cache的key值) - String url = request.getRequestURI(); - - // 唯一值(没有消息头则使用请求地址) - String submitKey = StringUtils.trimToEmpty(request.getHeader(header)); - - // 唯一标识(指定key + url + 消息头) - String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey; - - Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); - if (sessionObj != null) - { - Map sessionMap = (Map) sessionObj; - if (sessionMap.containsKey(url)) - { - Map preDataMap = (Map) sessionMap.get(url); - if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) - { - return true; - } - } - } - Map cacheMap = new HashMap<>(); - cacheMap.put(url, nowDataMap); - redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS); - return false; - } - - /** - * 判断参数是否相同 - */ - private boolean compareParams(Map nowMap, Map preMap) - { - String nowParams = (String) nowMap.get(REPEAT_PARAMS); - String preParams = (String) preMap.get(REPEAT_PARAMS); - return nowParams.equals(preParams); - } - - /** - * 判断两次间隔时间 - */ - private boolean compareTime(Map nowMap, Map preMap, int interval) - { - long time1 = (Long) nowMap.get(REPEAT_TIME); - long time2 = (Long) preMap.get(REPEAT_TIME); - if ((time1 - time2) < interval) - { - return true; - } - return false; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java deleted file mode 100644 index 2dcf5ab..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.ruoyi.framework.manager; - -import java.util.TimerTask; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import com.ruoyi.common.core.utils.Threads; -import com.ruoyi.common.core.utils.spring.SpringUtils; - -/** - * 异步任务管理器 - * - * @author ruoyi - */ -public class AsyncManager -{ - /** - * 操作延迟10毫秒 - */ - private final int OPERATE_DELAY_TIME = 10; - - /** - * 异步操作任务调度线程池 - */ - private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); - - /** - * 单例模式 - */ - private AsyncManager(){} - - private static AsyncManager me = new AsyncManager(); - - public static AsyncManager me() - { - return me; - } - - /** - * 执行任务 - * - * @param task 任务 - */ - public void execute(TimerTask task) - { - executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); - } - - /** - * 停止任务线程池 - */ - public void shutdown() - { - Threads.shutdownAndAwaitTermination(executor); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java deleted file mode 100644 index 095b865..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.ruoyi.framework.manager; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import jakarta.annotation.PreDestroy; - -/** - * 确保应用退出时能关闭后台线程 - * - * @author ruoyi - */ -@Component -public class ShutdownManager -{ - private static final Logger logger = LoggerFactory.getLogger("sys-user"); - - @PreDestroy - public void destroy() - { - shutdownAsyncManager(); - } - - /** - * 停止异步执行任务 - */ - private void shutdownAsyncManager() - { - try - { - logger.info("====关闭后台任务任务线程池===="); - AsyncManager.me().shutdown(); - } - catch (Exception e) - { - logger.error(e.getMessage(), e); - } - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java deleted file mode 100644 index 18d5b27..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ruoyi.framework.manager.factory; - -import java.util.TimerTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.utils.LogUtils; -import com.ruoyi.common.core.utils.ServletUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.ip.AddressUtils; -import com.ruoyi.common.core.utils.ip.IpUtils; -import com.ruoyi.common.core.utils.spring.SpringUtils; -import com.ruoyi.system.domain.SysLogininfor; -import com.ruoyi.system.domain.SysOperLog; -import com.ruoyi.system.service.ISysLogininforService; -import com.ruoyi.system.service.ISysOperLogService; -import eu.bitwalker.useragentutils.UserAgent; - -/** - * 异步工厂(产生任务用) - * - * @author ruoyi - */ -public class AsyncFactory -{ - private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); - - /** - * 记录登录信息 - * - * @param username 用户名 - * @param status 状态 - * @param message 消息 - * @param args 列表 - * @return 任务task - */ - public static TimerTask recordLogininfor(final String username, final String status, final String message, - final Object... args) - { - final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); - final String ip = IpUtils.getIpAddr(); - return new TimerTask() - { - @Override - public void run() - { - String address = AddressUtils.getRealAddressByIP(ip); - StringBuilder s = new StringBuilder(); - s.append(LogUtils.getBlock(ip)); - s.append(address); - s.append(LogUtils.getBlock(username)); - s.append(LogUtils.getBlock(status)); - s.append(LogUtils.getBlock(message)); - // 打印信息到日志 - sys_user_logger.info(s.toString(), args); - // 获取客户端操作系统 - String os = userAgent.getOperatingSystem().getName(); - // 获取客户端浏览器 - String browser = userAgent.getBrowser().getName(); - // 封装对象 - SysLogininfor logininfor = new SysLogininfor(); - logininfor.setUserName(username); - logininfor.setIpaddr(ip); - logininfor.setLoginLocation(address); - logininfor.setBrowser(browser); - logininfor.setOs(os); - logininfor.setMsg(message); - // 日志状态 - if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) - { - logininfor.setStatus(Constants.SUCCESS); - } - else if (Constants.LOGIN_FAIL.equals(status)) - { - logininfor.setStatus(Constants.FAIL); - } - // 插入数据 - SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor); - } - }; - } - - /** - * 操作日志记录 - * - * @param operLog 操作日志信息 - * @return 任务task - */ - public static TimerTask recordOper(final SysOperLog operLog) - { - return new TimerTask() - { - @Override - public void run() - { - // 远程查询操作地点 - operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); - SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); - } - }; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java deleted file mode 100644 index 6c776ce..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ruoyi.framework.security.context; - -import org.springframework.security.core.Authentication; - -/** - * 身份验证信息 - * - * @author ruoyi - */ -public class AuthenticationContextHolder -{ - private static final ThreadLocal contextHolder = new ThreadLocal<>(); - - public static Authentication getContext() - { - return contextHolder.get(); - } - - public static void setContext(Authentication context) - { - contextHolder.set(context); - } - - public static void clearContext() - { - contextHolder.remove(); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java deleted file mode 100644 index eda3827..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ruoyi.framework.security.context; - -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; -import com.ruoyi.common.core.core.text.Convert; - -/** - * 权限信息 - * - * @author ruoyi - */ -public class PermissionContextHolder -{ - private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT"; - - public static void setContext(String permission) - { - RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission, - RequestAttributes.SCOPE_REQUEST); - } - - public static String getContext() - { - return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES, - RequestAttributes.SCOPE_REQUEST)); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java deleted file mode 100644 index a700d8b..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ruoyi.framework.security.filter; - -import java.io.IOException; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.utils.SecurityUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.framework.web.service.TokenService; - -/** - * token过滤器 验证token有效性 - * - * @author ruoyi - */ -@Component -public class JwtAuthenticationTokenFilter extends OncePerRequestFilter -{ - @Autowired - private TokenService tokenService; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) - throws ServletException, IOException - { - LoginUser loginUser = tokenService.getLoginUser(request); - if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) - { - tokenService.verifyToken(loginUser); - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); - authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - } - chain.doFilter(request, response); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java deleted file mode 100644 index 2e8d746..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ruoyi.framework.security.handle; - -import java.io.IOException; -import java.io.Serializable; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; -import com.alibaba.fastjson2.JSON; -import com.ruoyi.common.core.constant.HttpStatus; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.utils.ServletUtils; -import com.ruoyi.common.core.utils.StringUtils; - -/** - * 认证失败处理类 返回未授权 - * - * @author ruoyi - */ -@Component -public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable -{ - private static final long serialVersionUID = -8970718410437077606L; - - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) - throws IOException - { - int code = HttpStatus.UNAUTHORIZED; - String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); - ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg))); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java deleted file mode 100644 index 10fce36..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.ruoyi.framework.security.handle; - -import java.io.IOException; - -import jakarta.annotation.Resource; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; -import com.alibaba.fastjson2.JSON; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.utils.ServletUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.framework.manager.AsyncManager; -import com.ruoyi.framework.manager.factory.AsyncFactory; -import com.ruoyi.framework.web.service.TokenService; - -/** - * 自定义退出处理类 返回成功 - * - * @author ruoyi - */ -@Configuration -public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler -{ - @Resource - private TokenService tokenService; - - /** - * 退出处理 - * - * - */ - @Override - public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) - throws IOException, ServletException - { - LoginUser loginUser = tokenService.getLoginUser(request); - if (StringUtils.isNotNull(loginUser)) - { - String userName = loginUser.getUsername(); - // 删除用户缓存记录 - tokenService.delLoginUser(loginUser.getToken()); - // 记录用户退出日志 - AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); - } - ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功"))); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java deleted file mode 100644 index 546e206..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.ruoyi.framework.web.exception; - -import javax.servlet.http.HttpServletRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.validation.BindException; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.MissingPathVariableException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -import com.ruoyi.common.core.constant.HttpStatus; -import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.exception.DemoModeException; -import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.StringUtils; - -/** - * 全局异常处理器 - * - * @author ruoyi - */ -@RestControllerAdvice -public class GlobalExceptionHandler -{ - private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); - - /** - * 权限校验异常 - */ - @ExceptionHandler(AccessDeniedException.class) - public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) - { - String requestURI = request.getRequestURI(); - log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage()); - return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权"); - } - - /** - * 请求方式不支持 - */ - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, - HttpServletRequest request) - { - String requestURI = request.getRequestURI(); - log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); - return AjaxResult.error(e.getMessage()); - } - - /** - * 业务异常 - */ - @ExceptionHandler(ServiceException.class) - public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) - { - log.error(e.getMessage(), e); - Integer code = e.getCode(); - return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); - } - - /** - * 请求路径中缺少必需的路径变量 - */ - @ExceptionHandler(MissingPathVariableException.class) - public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) - { - String requestURI = request.getRequestURI(); - log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e); - return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); - } - - /** - * 请求参数类型不匹配 - */ - @ExceptionHandler(MethodArgumentTypeMismatchException.class) - public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) - { - String requestURI = request.getRequestURI(); - log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e); - return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue())); - } - - /** - * 拦截未知的运行时异常 - */ - @ExceptionHandler(RuntimeException.class) - public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) - { - String requestURI = request.getRequestURI(); - log.error("请求地址'{}',发生未知异常.", requestURI, e); - return AjaxResult.error(e.getMessage()); - } - - /** - * 系统异常 - */ - @ExceptionHandler(Exception.class) - public AjaxResult handleException(Exception e, HttpServletRequest request) - { - String requestURI = request.getRequestURI(); - log.error("请求地址'{}',发生系统异常.", requestURI, e); - return AjaxResult.error(e.getMessage()); - } - - /** - * 自定义验证异常 - */ - @ExceptionHandler(BindException.class) - public AjaxResult handleBindException(BindException e) - { - log.error(e.getMessage(), e); - String message = e.getAllErrors().get(0).getDefaultMessage(); - return AjaxResult.error(message); - } - - /** - * 自定义验证异常 - */ - @ExceptionHandler(MethodArgumentNotValidException.class) - public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) - { - log.error(e.getMessage(), e); - String message = e.getBindingResult().getFieldError().getDefaultMessage(); - return AjaxResult.error(message); - } - - /** - * 演示模式异常 - */ - @ExceptionHandler(DemoModeException.class) - public AjaxResult handleDemoModeException(DemoModeException e) - { - return AjaxResult.error("演示模式,不允许操作"); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java deleted file mode 100644 index 786956c..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.ruoyi.framework.web.service; - -import java.util.Set; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.utils.SecurityUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.framework.security.context.PermissionContextHolder; - -/** - * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母 - * - * @author ruoyi - */ -@Service("ss") -public class PermissionService -{ - /** 所有权限标识 */ - private static final String ALL_PERMISSION = "*:*:*"; - - /** 管理员角色权限标识 */ - private static final String SUPER_ADMIN = "admin"; - - private static final String ROLE_DELIMETER = ","; - - private static final String PERMISSION_DELIMETER = ","; - - /** - * 验证用户是否具备某权限 - * - * @param permission 权限字符串 - * @return 用户是否具备某权限 - */ - public boolean hasPermi(String permission) - { - if (StringUtils.isEmpty(permission)) - { - return false; - } - LoginUser loginUser = SecurityUtils.getLoginUser(); - if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) - { - return false; - } - PermissionContextHolder.setContext(permission); - return hasPermissions(loginUser.getPermissions(), permission); - } - - /** - * 验证用户是否不具备某权限,与 hasPermi逻辑相反 - * - * @param permission 权限字符串 - * @return 用户是否不具备某权限 - */ - public boolean lacksPermi(String permission) - { - return hasPermi(permission) != true; - } - - /** - * 验证用户是否具有以下任意一个权限 - * - * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表 - * @return 用户是否具有以下任意一个权限 - */ - public boolean hasAnyPermi(String permissions) - { - if (StringUtils.isEmpty(permissions)) - { - return false; - } - LoginUser loginUser = SecurityUtils.getLoginUser(); - if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) - { - return false; - } - PermissionContextHolder.setContext(permissions); - Set authorities = loginUser.getPermissions(); - for (String permission : permissions.split(PERMISSION_DELIMETER)) - { - if (permission != null && hasPermissions(authorities, permission)) - { - return true; - } - } - return false; - } - - /** - * 判断用户是否拥有某个角色 - * - * @param role 角色字符串 - * @return 用户是否具备某角色 - */ - public boolean hasRole(String role) - { - if (StringUtils.isEmpty(role)) - { - return false; - } - LoginUser loginUser = SecurityUtils.getLoginUser(); - if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) - { - return false; - } - for (SysRole sysRole : loginUser.getUser().getRoles()) - { - String roleKey = sysRole.getRoleKey(); - if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) - { - return true; - } - } - return false; - } - - /** - * 验证用户是否不具备某角色,与 isRole逻辑相反。 - * - * @param role 角色名称 - * @return 用户是否不具备某角色 - */ - public boolean lacksRole(String role) - { - return hasRole(role) != true; - } - - /** - * 验证用户是否具有以下任意一个角色 - * - * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 - * @return 用户是否具有以下任意一个角色 - */ - public boolean hasAnyRoles(String roles) - { - if (StringUtils.isEmpty(roles)) - { - return false; - } - LoginUser loginUser = SecurityUtils.getLoginUser(); - if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) - { - return false; - } - for (String role : roles.split(ROLE_DELIMETER)) - { - if (hasRole(role)) - { - return true; - } - } - return false; - } - - /** - * 判断是否包含权限 - * - * @param permissions 权限列表 - * @param permission 权限字符串 - * @return 用户是否具备某权限 - */ - private boolean hasPermissions(Set permissions, String permission) - { - return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission)); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java deleted file mode 100644 index ff6bc28..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.ruoyi.framework.web.service; - -import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.exception.user.BlackListException; -import com.ruoyi.common.core.exception.user.CaptchaException; -import com.ruoyi.common.core.exception.user.CaptchaExpireException; -import com.ruoyi.common.core.exception.user.UserNotExistsException; -import com.ruoyi.common.core.exception.user.UserPasswordNotMatchException; -import com.ruoyi.common.core.utils.DateUtils; -import com.ruoyi.common.core.utils.MessageUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.ip.IpUtils; -import com.ruoyi.framework.manager.AsyncManager; -import com.ruoyi.framework.manager.factory.AsyncFactory; -import com.ruoyi.framework.security.context.AuthenticationContextHolder; -import com.ruoyi.system.service.ISysConfigService; -import com.ruoyi.system.service.ISysUserService; - -/** - * 登录校验方法 - * - * @author ruoyi - */ -@Component -public class SysLoginService -{ - @Autowired - private TokenService tokenService; - - @Resource - private AuthenticationManager authenticationManager; - - @Autowired - private RedisCache redisCache; - - @Autowired - private ISysUserService userService; - - @Autowired - private ISysConfigService configService; - - /** - * 登录验证 - * - * @param username 用户名 - * @param password 密码 - * @param code 验证码 - * @param uuid 唯一标识 - * @return 结果 - */ - public String login(String username, String password, String code, String uuid) - { - // 验证码校验 - validateCaptcha(username, code, uuid); - // 登录前置校验 - loginPreCheck(username, password); - // 用户验证 - Authentication authentication = null; - try - { - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); - AuthenticationContextHolder.setContext(authenticationToken); - // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername - authentication = authenticationManager.authenticate(authenticationToken); - } - catch (Exception e) - { - if (e instanceof BadCredentialsException) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); - throw new UserPasswordNotMatchException(); - } - else - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); - throw new ServiceException(e.getMessage()); - } - } - finally - { - AuthenticationContextHolder.clearContext(); - } - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); - LoginUser loginUser = (LoginUser) authentication.getPrincipal(); - recordLoginInfo(loginUser.getUserId()); - // 生成token - return tokenService.createToken(loginUser); - } - - /** - * 校验验证码 - * - * @param username 用户名 - * @param code 验证码 - * @param uuid 唯一标识 - * @return 结果 - */ - public void validateCaptcha(String username, String code, String uuid) - { - boolean captchaEnabled = configService.selectCaptchaEnabled(); - if (captchaEnabled) - { - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); - String captcha = redisCache.getCacheObject(verifyKey); - redisCache.deleteObject(verifyKey); - if (captcha == null) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); - throw new CaptchaExpireException(); - } - if (!code.equalsIgnoreCase(captcha)) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); - throw new CaptchaException(); - } - } - } - - /** - * 登录前置校验 - * @param username 用户名 - * @param password 用户密码 - */ - public void loginPreCheck(String username, String password) - { - // 用户名或密码为空 错误 - if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); - throw new UserNotExistsException(); - } - // 密码如果不在指定范围内 错误 - if (password.length() < UserConstants.PASSWORD_MIN_LENGTH - || password.length() > UserConstants.PASSWORD_MAX_LENGTH) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); - throw new UserPasswordNotMatchException(); - } - // 用户名不在指定范围内 错误 - if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); - throw new UserPasswordNotMatchException(); - } - // IP黑名单校验 - String blackStr = configService.selectConfigByKey("sys.login.blackIPList"); - if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked"))); - throw new BlackListException(); - } - } - - /** - * 记录登录信息 - * - * @param userId 用户ID - */ - public void recordLoginInfo(Long userId) - { - SysUser sysUser = new SysUser(); - sysUser.setUserId(userId); - sysUser.setLoginIp(IpUtils.getIpAddr()); - sysUser.setLoginDate(DateUtils.getNowDate()); - userService.updateUserProfile(sysUser); - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java deleted file mode 100644 index e4806cc..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.ruoyi.framework.web.service; - -import java.util.concurrent.TimeUnit; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.exception.user.UserPasswordNotMatchException; -import com.ruoyi.common.core.exception.user.UserPasswordRetryLimitExceedException; -import com.ruoyi.common.core.utils.MessageUtils; -import com.ruoyi.common.core.utils.SecurityUtils; -import com.ruoyi.framework.manager.AsyncManager; -import com.ruoyi.framework.manager.factory.AsyncFactory; -import com.ruoyi.framework.security.context.AuthenticationContextHolder; - -/** - * 登录密码方法 - * - * @author ruoyi - */ -@Component -public class SysPasswordService -{ - @Autowired - private RedisCache redisCache; - - @Value(value = "${user.password.maxRetryCount}") - private int maxRetryCount; - - @Value(value = "${user.password.lockTime}") - private int lockTime; - - /** - * 登录账户密码错误次数缓存键名 - * - * @param username 用户名 - * @return 缓存键key - */ - private String getCacheKey(String username) - { - return CacheConstants.PWD_ERR_CNT_KEY + username; - } - - public void validate(SysUser user) - { - Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext(); - String username = usernamePasswordAuthenticationToken.getName(); - String password = usernamePasswordAuthenticationToken.getCredentials().toString(); - - Integer retryCount = redisCache.getCacheObject(getCacheKey(username)); - - if (retryCount == null) - { - retryCount = 0; - } - - if (retryCount >= Integer.valueOf(maxRetryCount).intValue()) - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, - MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime))); - throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime); - } - - if (!matches(user, password)) - { - retryCount = retryCount + 1; - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, - MessageUtils.message("user.password.retry.limit.count", retryCount))); - redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES); - throw new UserPasswordNotMatchException(); - } - else - { - clearLoginRecordCache(username); - } - } - - public boolean matches(SysUser user, String rawPassword) - { - return SecurityUtils.matchesPassword(rawPassword, user.getPassword()); - } - - public void clearLoginRecordCache(String loginName) - { - if (redisCache.hasKey(getCacheKey(loginName))) - { - redisCache.deleteObject(getCacheKey(loginName)); - } - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java deleted file mode 100644 index 75c94e2..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.ruoyi.framework.web.service; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.system.service.ISysMenuService; -import com.ruoyi.system.service.ISysRoleService; - -/** - * 用户权限处理 - * - * @author ruoyi - */ -@Component -public class SysPermissionService -{ - @Autowired - private ISysRoleService roleService; - - @Autowired - private ISysMenuService menuService; - - /** - * 获取角色数据权限 - * - * @param user 用户信息 - * @return 角色权限信息 - */ - public Set getRolePermission(SysUser user) - { - Set roles = new HashSet<>(); - // 管理员拥有所有权限 - if (user.isAdmin()) - { - roles.add("admin"); - } - else - { - roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId())); - } - return roles; - } - - /** - * 获取菜单数据权限 - * - * @param user 用户信息 - * @return 菜单权限信息 - */ - public Set getMenuPermission(SysUser user) - { - Set perms = new HashSet<>(); - // 管理员拥有所有权限 - if (user.isAdmin()) - { - perms.add("*:*:*"); - } - else - { - List roles = user.getRoles(); - if (!CollectionUtils.isEmpty(roles)) - { - // 多角色设置permissions属性,以便数据权限匹配权限 - for (SysRole role : roles) - { - Set rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); - role.setPermissions(rolePerms); - perms.addAll(rolePerms); - } - } - else - { - perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); - } - } - return perms; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java deleted file mode 100644 index ad2329f..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.ruoyi.framework.web.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.common.core.core.domain.model.RegisterBody; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.exception.user.CaptchaException; -import com.ruoyi.common.core.exception.user.CaptchaExpireException; -import com.ruoyi.common.core.utils.MessageUtils; -import com.ruoyi.common.core.utils.SecurityUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.framework.manager.AsyncManager; -import com.ruoyi.framework.manager.factory.AsyncFactory; -import com.ruoyi.system.service.ISysConfigService; -import com.ruoyi.system.service.ISysUserService; - -/** - * 注册校验方法 - * - * @author ruoyi - */ -@Component -public class SysRegisterService -{ - @Autowired - private ISysUserService userService; - - @Autowired - private ISysConfigService configService; - - @Autowired - private RedisCache redisCache; - - /** - * 注册 - */ - public String register(RegisterBody registerBody) - { - String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(); - SysUser sysUser = new SysUser(); - sysUser.setUserName(username); - - // 验证码开关 - boolean captchaEnabled = configService.selectCaptchaEnabled(); - if (captchaEnabled) - { - validateCaptcha(username, registerBody.getCode(), registerBody.getUuid()); - } - - if (StringUtils.isEmpty(username)) - { - msg = "用户名不能为空"; - } - else if (StringUtils.isEmpty(password)) - { - msg = "用户密码不能为空"; - } - else if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) - { - msg = "账户长度必须在2到20个字符之间"; - } - else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH - || password.length() > UserConstants.PASSWORD_MAX_LENGTH) - { - msg = "密码长度必须在5到20个字符之间"; - } - else if (!userService.checkUserNameUnique(sysUser)) - { - msg = "保存用户'" + username + "'失败,注册账号已存在"; - } - else - { - sysUser.setNickName(username); - sysUser.setPassword(SecurityUtils.encryptPassword(password)); - boolean regFlag = userService.registerUser(sysUser); - if (!regFlag) - { - msg = "注册失败,请联系系统管理人员"; - } - else - { - AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success"))); - } - } - return msg; - } - - /** - * 校验验证码 - * - * @param username 用户名 - * @param code 验证码 - * @param uuid 唯一标识 - */ - public void validateCaptcha(String username, String code, String uuid) - { - String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); - String captcha = redisCache.getCacheObject(verifyKey); - redisCache.deleteObject(verifyKey); - if (captcha == null) - { - throw new CaptchaExpireException(); - } - if (!code.equalsIgnoreCase(captcha)) - { - throw new CaptchaException(); - } - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java deleted file mode 100644 index 5536541..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java +++ /dev/null @@ -1,226 +0,0 @@ -package com.ruoyi.framework.web.service; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import com.ruoyi.common.core.constant.CacheConstants; -import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.core.redis.RedisCache; -import com.ruoyi.common.core.utils.ServletUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.ip.AddressUtils; -import com.ruoyi.common.core.utils.ip.IpUtils; -import com.ruoyi.common.core.utils.uuid.IdUtils; -import eu.bitwalker.useragentutils.UserAgent; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; - -/** - * token验证处理 - * - * @author ruoyi - */ -@Component -public class TokenService -{ - // 令牌自定义标识 - @Value("${token.header}") - private String header; - - // 令牌秘钥 - @Value("${token.secret}") - private String secret; - - // 令牌有效期(默认30分钟) - @Value("${token.expireTime}") - private int expireTime; - - protected static final long MILLIS_SECOND = 1000; - - protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; - - private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L; - - @Autowired - private RedisCache redisCache; - - /** - * 获取用户身份信息 - * - * @return 用户信息 - */ - public LoginUser getLoginUser(HttpServletRequest request) - { - // 获取请求携带的令牌 - String token = getToken(request); - if (StringUtils.isNotEmpty(token)) - { - try - { - Claims claims = parseToken(token); - // 解析对应的权限以及用户信息 - String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); - String userKey = getTokenKey(uuid); - LoginUser user = redisCache.getCacheObject(userKey); - return user; - } - catch (Exception e) - { - } - } - return null; - } - - /** - * 设置用户身份信息 - */ - public void setLoginUser(LoginUser loginUser) - { - if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) - { - refreshToken(loginUser); - } - } - - /** - * 删除用户身份信息 - */ - public void delLoginUser(String token) - { - if (StringUtils.isNotEmpty(token)) - { - String userKey = getTokenKey(token); - redisCache.deleteObject(userKey); - } - } - - /** - * 创建令牌 - * - * @param loginUser 用户信息 - * @return 令牌 - */ - public String createToken(LoginUser loginUser) - { - String token = IdUtils.fastUUID(); - loginUser.setToken(token); - setUserAgent(loginUser); - refreshToken(loginUser); - - Map claims = new HashMap<>(); - claims.put(Constants.LOGIN_USER_KEY, token); - return createToken(claims); - } - - /** - * 验证令牌有效期,相差不足20分钟,自动刷新缓存 - * - * @param loginUser - * @return 令牌 - */ - public void verifyToken(LoginUser loginUser) - { - long expireTime = loginUser.getExpireTime(); - long currentTime = System.currentTimeMillis(); - if (expireTime - currentTime <= MILLIS_MINUTE_TEN) - { - refreshToken(loginUser); - } - } - - /** - * 刷新令牌有效期 - * - * @param loginUser 登录信息 - */ - public void refreshToken(LoginUser loginUser) - { - loginUser.setLoginTime(System.currentTimeMillis()); - loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); - // 根据uuid将loginUser缓存 - String userKey = getTokenKey(loginUser.getToken()); - redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); - } - - /** - * 设置用户代理信息 - * - * @param loginUser 登录信息 - */ - public void setUserAgent(LoginUser loginUser) - { - UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); - String ip = IpUtils.getIpAddr(); - loginUser.setIpaddr(ip); - loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); - loginUser.setBrowser(userAgent.getBrowser().getName()); - loginUser.setOs(userAgent.getOperatingSystem().getName()); - } - - /** - * 从数据声明生成令牌 - * - * @param claims 数据声明 - * @return 令牌 - */ - private String createToken(Map claims) - { - String token = Jwts.builder() - .setClaims(claims) - .signWith(SignatureAlgorithm.HS512, secret).compact(); - return token; - } - - /** - * 从令牌中获取数据声明 - * - * @param token 令牌 - * @return 数据声明 - */ - private Claims parseToken(String token) - { - return Jwts.parser() - .setSigningKey(secret) - .parseClaimsJws(token) - .getBody(); - } - - /** - * 从令牌中获取用户名 - * - * @param token 令牌 - * @return 用户名 - */ - public String getUsernameFromToken(String token) - { - Claims claims = parseToken(token); - return claims.getSubject(); - } - - /** - * 获取请求token - * - * @param request - * @return token - */ - private String getToken(HttpServletRequest request) - { - String token = request.getHeader(header); - if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) - { - token = token.replace(Constants.TOKEN_PREFIX, ""); - } - return token; - } - - private String getTokenKey(String uuid) - { - return CacheConstants.LOGIN_TOKEN_KEY + uuid; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java deleted file mode 100644 index ef8b16e..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.ruoyi.framework.web.service; - -import com.ruoyi.common.core.utils.MessageUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.enums.UserStatus; -import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.system.service.ISysUserService; - -/** - * 用户验证处理 - * - * @author ruoyi - */ -@Service -public class UserDetailsServiceImpl implements UserDetailsService -{ - private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class); - - @Autowired - private ISysUserService userService; - - @Autowired - private SysPasswordService passwordService; - - @Autowired - private SysPermissionService permissionService; - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException - { - SysUser user = userService.selectUserByUserName(username); - if (StringUtils.isNull(user)) - { - log.info("登录用户:{} 不存在.", username); - throw new ServiceException(MessageUtils.message("user.not.exists")); - } - else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) - { - log.info("登录用户:{} 已被删除.", username); - throw new ServiceException(MessageUtils.message("user.password.delete")); - } - else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) - { - log.info("登录用户:{} 已被停用.", username); - throw new ServiceException(MessageUtils.message("user.blocked")); - } - - passwordService.validate(user); - - return createLoginUser(user); - } - - public UserDetails createLoginUser(SysUser user) - { - return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); - } -} diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml index 8a4011c..8cdb302 100644 --- a/ruoyi-modules/pom.xml +++ b/ruoyi-modules/pom.xml @@ -8,6 +8,7 @@ ${revision} 4.0.0 + pom ruoyi-demo @@ -17,7 +18,7 @@ ruoyi-modules - pom + ruoyi-modules 业务模块 diff --git a/ruoyi-modules/ruoyi-demo/pom.xml b/ruoyi-modules/ruoyi-demo/pom.xml index 5948627..ccc3b57 100644 --- a/ruoyi-modules/ruoyi-demo/pom.xml +++ b/ruoyi-modules/ruoyi-demo/pom.xml @@ -8,6 +8,7 @@ ${revision} 4.0.0 + jar ruoyi-demo @@ -21,6 +22,11 @@ ruoyi-common-core + + com.ruoyi + ruoyi-common-web + + com.ruoyi ruoyi-common-springdoc diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoCustomerController.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoCustomerController.java index f9d92d7..d28015f 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoCustomerController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoCustomerController.java @@ -1,8 +1,9 @@ package com.ruoyi.demo.controller; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.access.prepost.PreAuthorize; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -12,10 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.demo.domain.DemoCustomer; import com.ruoyi.demo.service.IDemoCustomerService; import com.ruoyi.common.core.utils.poi.ExcelUtil; @@ -24,7 +23,7 @@ import com.ruoyi.common.core.core.page.TableDataInfo; /** * 客户主表(mb)Controller - * + * * @author 数据小王子 * 2023-07-11 */ @@ -38,7 +37,7 @@ public class DemoCustomerController extends BaseController /** * 查询客户主表(mb)列表 */ - @PreAuthorize("@ss.hasPermi('demo:customer:list')") + @SaCheckPermission("demo:customer:list") @GetMapping("/list") public TableDataInfo list(DemoCustomer demoCustomer) { @@ -50,8 +49,7 @@ public class DemoCustomerController extends BaseController /** * 导出客户主表(mb)列表 */ - @PreAuthorize("@ss.hasPermi('demo:customer:export')") - @Log(title = "客户主表(mb)", businessType = BusinessType.EXPORT) + @SaCheckPermission("demo:customer:export") @PostMapping("/export") public void export(HttpServletResponse response, DemoCustomer demoCustomer) { @@ -63,7 +61,7 @@ public class DemoCustomerController extends BaseController /** * 获取客户主表(mb)详细信息 */ - @PreAuthorize("@ss.hasPermi('demo:customer:query')") + @SaCheckPermission("demo:customer:query") @GetMapping(value = "/{customerId}") public AjaxResult getInfo(@PathVariable("customerId") Long customerId) { @@ -73,8 +71,7 @@ public class DemoCustomerController extends BaseController /** * 新增客户主表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:customer:add')") - @Log(title = "客户主表(mb)", businessType = BusinessType.INSERT) + @SaCheckPermission("demo:customer:add") @PostMapping public AjaxResult add(@RequestBody DemoCustomer demoCustomer) { @@ -84,8 +81,7 @@ public class DemoCustomerController extends BaseController /** * 修改客户主表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:customer:edit')") - @Log(title = "客户主表(mb)", businessType = BusinessType.UPDATE) + @SaCheckPermission("demo:customer:edit") @PutMapping public AjaxResult edit(@RequestBody DemoCustomer demoCustomer) { @@ -95,9 +91,8 @@ public class DemoCustomerController extends BaseController /** * 删除客户主表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:customer:remove')") - @Log(title = "客户主表(mb)", businessType = BusinessType.DELETE) - @DeleteMapping("/{customerIds}") + @SaCheckPermission("demo:customer:remove") + @DeleteMapping("/{customerIds}") public AjaxResult remove(@PathVariable Long[] customerIds) { return toAjax(demoCustomerService.deleteDemoCustomerByCustomerIds(customerIds)); diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoProductController.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoProductController.java index 0009c87..0e01c5e 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoProductController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoProductController.java @@ -1,8 +1,9 @@ package com.ruoyi.demo.controller; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.access.prepost.PreAuthorize; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -12,10 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.demo.domain.DemoProduct; import com.ruoyi.demo.service.IDemoProductService; import com.ruoyi.common.core.utils.poi.ExcelUtil; @@ -23,7 +22,7 @@ import com.ruoyi.common.core.utils.poi.ExcelUtil; /** * 产品树表(mb)Controller - * + * * @author 数据小王子 * 2023-07-11 */ @@ -37,7 +36,7 @@ public class DemoProductController extends BaseController /** * 查询产品树表(mb)列表 */ - @PreAuthorize("@ss.hasPermi('demo:product:list')") + @SaCheckPermission("demo:product:list") @GetMapping("/list") public AjaxResult list(DemoProduct demoProduct) { @@ -48,8 +47,7 @@ public class DemoProductController extends BaseController /** * 导出产品树表(mb)列表 */ - @PreAuthorize("@ss.hasPermi('demo:product:export')") - @Log(title = "产品树表(mb)", businessType = BusinessType.EXPORT) + @SaCheckPermission("demo:product:export") @PostMapping("/export") public void export(HttpServletResponse response, DemoProduct demoProduct) { @@ -61,7 +59,7 @@ public class DemoProductController extends BaseController /** * 获取产品树表(mb)详细信息 */ - @PreAuthorize("@ss.hasPermi('demo:product:query')") + @SaCheckPermission("demo:product:query") @GetMapping(value = "/{productId}") public AjaxResult getInfo(@PathVariable("productId") Long productId) { @@ -71,8 +69,7 @@ public class DemoProductController extends BaseController /** * 新增产品树表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:product:add')") - @Log(title = "产品树表(mb)", businessType = BusinessType.INSERT) + @SaCheckPermission("demo:product:add") @PostMapping public AjaxResult add(@RequestBody DemoProduct demoProduct) { @@ -82,8 +79,7 @@ public class DemoProductController extends BaseController /** * 修改产品树表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:product:edit')") - @Log(title = "产品树表(mb)", businessType = BusinessType.UPDATE) + @SaCheckPermission("demo:product:edit") @PutMapping public AjaxResult edit(@RequestBody DemoProduct demoProduct) { @@ -93,9 +89,8 @@ public class DemoProductController extends BaseController /** * 删除产品树表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:product:remove')") - @Log(title = "产品树表(mb)", businessType = BusinessType.DELETE) - @DeleteMapping("/{productIds}") + @SaCheckPermission("demo:product:remove") + @DeleteMapping("/{productIds}") public AjaxResult remove(@PathVariable Long[] productIds) { return toAjax(demoProductService.deleteDemoProductByProductIds(productIds)); diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoStudentController.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoStudentController.java index 3645e8e..178faf6 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoStudentController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/DemoStudentController.java @@ -1,8 +1,9 @@ package com.ruoyi.demo.controller; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.access.prepost.PreAuthorize; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -12,10 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.demo.domain.DemoStudent; import com.ruoyi.demo.service.IDemoStudentService; import com.ruoyi.common.core.utils.poi.ExcelUtil; @@ -24,7 +23,7 @@ import com.ruoyi.common.core.core.page.TableDataInfo; /** * 学生信息单表(mb)Controller - * + * * @author 数据小王子 * 2023-07-11 */ @@ -38,7 +37,7 @@ public class DemoStudentController extends BaseController /** * 查询学生信息单表(mb)列表 */ - @PreAuthorize("@ss.hasPermi('demo:student:list')") + @SaCheckPermission("demo:student:list") @GetMapping("/list") public TableDataInfo list(DemoStudent demoStudent) { @@ -50,8 +49,7 @@ public class DemoStudentController extends BaseController /** * 导出学生信息单表(mb)列表 */ - @PreAuthorize("@ss.hasPermi('demo:student:export')") - @Log(title = "学生信息单表(mb)", businessType = BusinessType.EXPORT) + @SaCheckPermission("demo:student:export") @PostMapping("/export") public void export(HttpServletResponse response, DemoStudent demoStudent) { @@ -63,7 +61,7 @@ public class DemoStudentController extends BaseController /** * 获取学生信息单表(mb)详细信息 */ - @PreAuthorize("@ss.hasPermi('demo:student:query')") + @SaCheckPermission("demo:student:query") @GetMapping(value = "/{studentId}") public AjaxResult getInfo(@PathVariable("studentId") Long studentId) { @@ -73,8 +71,7 @@ public class DemoStudentController extends BaseController /** * 新增学生信息单表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:student:add')") - @Log(title = "学生信息单表(mb)", businessType = BusinessType.INSERT) + @SaCheckPermission("demo:student:add") @PostMapping public AjaxResult add(@RequestBody DemoStudent demoStudent) { @@ -84,8 +81,7 @@ public class DemoStudentController extends BaseController /** * 修改学生信息单表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:student:edit')") - @Log(title = "学生信息单表(mb)", businessType = BusinessType.UPDATE) + @SaCheckPermission("demo:student:edit") @PutMapping public AjaxResult edit(@RequestBody DemoStudent demoStudent) { @@ -95,9 +91,8 @@ public class DemoStudentController extends BaseController /** * 删除学生信息单表(mb) */ - @PreAuthorize("@ss.hasPermi('demo:student:remove')") - @Log(title = "学生信息单表(mb)", businessType = BusinessType.DELETE) - @DeleteMapping("/{studentIds}") + @SaCheckPermission("demo:student:remove") + @DeleteMapping("/{studentIds}") public AjaxResult remove(@PathVariable Long[] studentIds) { return toAjax(demoStudentService.deleteDemoStudentByStudentIds(studentIds)); diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoCustomer.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoCustomer.java index f42c09e..22f895b 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoCustomer.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoCustomer.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.annotation.JsonFormat; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 客户主表(mb)对象 demo_customer - * + * * @author 数据小王子 * 2023-07-11 */ @@ -41,48 +41,48 @@ public class DemoCustomer extends BaseEntity /** 商品子信息 */ private List demoGoodsList; - public void setCustomerId(Long customerId) + public void setCustomerId(Long customerId) { this.customerId = customerId; } - public Long getCustomerId() + public Long getCustomerId() { return customerId; } - public void setCustomerName(String customerName) + public void setCustomerName(String customerName) { this.customerName = customerName; } - public String getCustomerName() + public String getCustomerName() { return customerName; } - public void setPhonenumber(String phonenumber) + public void setPhonenumber(String phonenumber) { this.phonenumber = phonenumber; } - public String getPhonenumber() + public String getPhonenumber() { return phonenumber; } - public void setSex(String sex) + public void setSex(String sex) { this.sex = sex; } - public String getSex() + public String getSex() { return sex; } - public void setBirthday(Date birthday) + public void setBirthday(Date birthday) { this.birthday = birthday; } - public Date getBirthday() + public Date getBirthday() { return birthday; } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoGoods.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoGoods.java index 180fe35..a4948ad 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoGoods.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoGoods.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.annotation.JsonFormat; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 商品子对象 demo_goods - * + * * @author 数据小王子 * 2023-07-11 */ @@ -46,66 +46,66 @@ public class DemoGoods extends BaseEntity @Excel(name = "商品种类") private String type; - public void setGoodsId(Long goodsId) + public void setGoodsId(Long goodsId) { this.goodsId = goodsId; } - public Long getGoodsId() + public Long getGoodsId() { return goodsId; } - public void setCustomerId(Long customerId) + public void setCustomerId(Long customerId) { this.customerId = customerId; } - public Long getCustomerId() + public Long getCustomerId() { return customerId; } - public void setName(String name) + public void setName(String name) { this.name = name; } - public String getName() + public String getName() { return name; } - public void setWeight(Long weight) + public void setWeight(Long weight) { this.weight = weight; } - public Long getWeight() + public Long getWeight() { return weight; } - public void setPrice(BigDecimal price) + public void setPrice(BigDecimal price) { this.price = price; } - public BigDecimal getPrice() + public BigDecimal getPrice() { return price; } - public void setDate(Date date) + public void setDate(Date date) { this.date = date; } - public Date getDate() + public Date getDate() { return date; } - public void setType(String type) + public void setType(String type) { this.type = type; } - public String getType() + public String getType() { return type; } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoProduct.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoProduct.java index e2f7fbb..5f6a7ae 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoProduct.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoProduct.java @@ -3,11 +3,11 @@ package com.ruoyi.demo.domain; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.TreeEntity; +import com.ruoyi.common.orm.core.domain.TreeEntity; /** * 产品树表(mb)对象 demo_product - * + * * @author 数据小王子 * 2023-07-11 */ @@ -26,30 +26,30 @@ public class DemoProduct extends TreeEntity @Excel(name = "产品状态", readConverterExp = "0=正常,1=停用") private String status; - public void setProductId(Long productId) + public void setProductId(Long productId) { this.productId = productId; } - public Long getProductId() + public Long getProductId() { return productId; } - public void setProductName(String productName) + public void setProductName(String productName) { this.productName = productName; } - public String getProductName() + public String getProductName() { return productName; } - public void setStatus(String status) + public void setStatus(String status) { this.status = status; } - public String getStatus() + public String getStatus() { return status; } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoStudent.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoStudent.java index 248fefb..965b48d 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoStudent.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/DemoStudent.java @@ -5,11 +5,11 @@ import com.fasterxml.jackson.annotation.JsonFormat; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 学生信息单表(mb)对象 demo_student - * + * * @author 数据小王子 * 2023-07-11 */ @@ -45,66 +45,66 @@ public class DemoStudent extends BaseEntity @Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd") private Date studentBirthday; - public void setStudentId(Long studentId) + public void setStudentId(Long studentId) { this.studentId = studentId; } - public Long getStudentId() + public Long getStudentId() { return studentId; } - public void setStudentName(String studentName) + public void setStudentName(String studentName) { this.studentName = studentName; } - public String getStudentName() + public String getStudentName() { return studentName; } - public void setStudentAge(Long studentAge) + public void setStudentAge(Long studentAge) { this.studentAge = studentAge; } - public Long getStudentAge() + public Long getStudentAge() { return studentAge; } - public void setStudentHobby(String studentHobby) + public void setStudentHobby(String studentHobby) { this.studentHobby = studentHobby; } - public String getStudentHobby() + public String getStudentHobby() { return studentHobby; } - public void setStudentSex(String studentSex) + public void setStudentSex(String studentSex) { this.studentSex = studentSex; } - public String getStudentSex() + public String getStudentSex() { return studentSex; } - public void setStudentStatus(String studentStatus) + public void setStudentStatus(String studentStatus) { this.studentStatus = studentStatus; } - public String getStudentStatus() + public String getStudentStatus() { return studentStatus; } - public void setStudentBirthday(Date studentBirthday) + public void setStudentBirthday(Date studentBirthday) { this.studentBirthday = studentBirthday; } - public Date getStudentBirthday() + public Date getStudentBirthday() { return studentBirthday; } diff --git a/ruoyi-modules/ruoyi-generator/pom.xml b/ruoyi-modules/ruoyi-generator/pom.xml index b5a761b..b0974e2 100644 --- a/ruoyi-modules/ruoyi-generator/pom.xml +++ b/ruoyi-modules/ruoyi-generator/pom.xml @@ -8,6 +8,7 @@ ${revision} 4.0.0 + jar ruoyi-generator @@ -35,6 +36,11 @@ ruoyi-common-core + + com.ruoyi + ruoyi-common-web + + - \ No newline at end of file + diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java index ec41eed..c667289 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java @@ -4,10 +4,11 @@ import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -17,12 +18,10 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; import com.ruoyi.common.core.core.text.Convert; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTableColumn; import com.ruoyi.generator.service.IGenTableColumnService; @@ -30,23 +29,23 @@ import com.ruoyi.generator.service.IGenTableService; /** * 代码生成 操作处理 - * + * * @author ruoyi */ @RestController @RequestMapping("/tool/gen") public class GenController extends BaseController { - @Autowired + @Resource private IGenTableService genTableService; - @Autowired + @Resource private IGenTableColumnService genTableColumnService; /** * 查询代码生成列表 */ - @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @SaCheckPermission("tool:gen:list") @GetMapping("/list") public TableDataInfo genList(GenTable genTable) { @@ -58,7 +57,7 @@ public class GenController extends BaseController /** * 修改代码生成业务 */ - @PreAuthorize("@ss.hasPermi('tool:gen:query')") + @SaCheckPermission("tool:gen:query") @GetMapping(value = "/{tableId}") public AjaxResult getInfo(@PathVariable Long tableId) { @@ -75,7 +74,7 @@ public class GenController extends BaseController /** * 查询数据库列表 */ - @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @SaCheckPermission("tool:gen:list") @GetMapping("/db/list") public TableDataInfo dataList(GenTable genTable) { @@ -87,7 +86,7 @@ public class GenController extends BaseController /** * 查询数据表字段列表 */ - @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @SaCheckPermission("tool:gen:list") @GetMapping(value = "/column/{tableId}") public TableDataInfo columnList(Long tableId) { @@ -101,8 +100,7 @@ public class GenController extends BaseController /** * 导入表结构(保存) */ - @PreAuthorize("@ss.hasPermi('tool:gen:import')") - @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @SaCheckPermission("tool:gen:import") @PostMapping("/importTable") public AjaxResult importTableSave(String tables) { @@ -116,8 +114,7 @@ public class GenController extends BaseController /** * 修改保存代码生成业务 */ - @PreAuthorize("@ss.hasPermi('tool:gen:edit')") - @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @SaCheckPermission("tool:gen:edit") @PutMapping public AjaxResult editSave(@Validated @RequestBody GenTable genTable) { @@ -129,8 +126,7 @@ public class GenController extends BaseController /** * 删除代码生成 */ - @PreAuthorize("@ss.hasPermi('tool:gen:remove')") - @Log(title = "代码生成", businessType = BusinessType.DELETE) + @SaCheckPermission("tool:gen:remove") @DeleteMapping("/{tableIds}") public AjaxResult remove(@PathVariable Long[] tableIds) { @@ -141,7 +137,7 @@ public class GenController extends BaseController /** * 预览代码 */ - @PreAuthorize("@ss.hasPermi('tool:gen:preview')") + @SaCheckPermission("tool:gen:preview") @GetMapping("/preview/{tableId}") public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException { @@ -152,8 +148,7 @@ public class GenController extends BaseController /** * 生成代码(下载方式) */ - @PreAuthorize("@ss.hasPermi('tool:gen:code')") - @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @SaCheckPermission("tool:gen:code") @GetMapping("/download/{tableName}") public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException { @@ -164,8 +159,7 @@ public class GenController extends BaseController /** * 生成代码(自定义路径) */ - @PreAuthorize("@ss.hasPermi('tool:gen:code')") - @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @SaCheckPermission("tool:gen:code") @GetMapping("/genCode/{tableName}") public AjaxResult genCode(@PathVariable("tableName") String tableName) { @@ -176,8 +170,7 @@ public class GenController extends BaseController /** * 同步数据库 */ - @PreAuthorize("@ss.hasPermi('tool:gen:edit')") - @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @SaCheckPermission("tool:gen:edit") @GetMapping("/synchDb/{tableName}") public AjaxResult synchDb(@PathVariable("tableName") String tableName) { @@ -188,8 +181,7 @@ public class GenController extends BaseController /** * 批量生成代码 */ - @PreAuthorize("@ss.hasPermi('tool:gen:code')") - @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @SaCheckPermission("tool:gen:code") @GetMapping("/batchGenCode") public void batchGenCode(HttpServletResponse response, String tables) throws IOException { @@ -211,4 +203,4 @@ public class GenController extends BaseController response.setContentType("application/octet-stream; charset=UTF-8"); IOUtils.write(data, response.getOutputStream()); } -} \ No newline at end of file +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java index c15f7d6..4c33b36 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java @@ -1,20 +1,22 @@ package com.ruoyi.generator.domain; +import java.io.Serial; import java.util.List; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import org.apache.commons.lang3.ArrayUtils; import com.ruoyi.common.core.constant.GenConstants; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; import com.ruoyi.common.core.utils.StringUtils; /** * 业务表 gen_table - * + * * @author ruoyi */ public class GenTable extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 编号 */ @@ -369,4 +371,4 @@ public class GenTable extends BaseEntity } return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); } -} \ No newline at end of file +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java index 7ac88f7..2b6d2e1 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java @@ -1,16 +1,19 @@ package com.ruoyi.generator.domain; import jakarta.validation.constraints.NotBlank; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; import com.ruoyi.common.core.utils.StringUtils; +import java.io.Serial; + /** * 代码生成业务字段表 gen_table_column - * + * * @author ruoyi */ public class GenTableColumn extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 编号 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java index 2095350..e83f47a 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java @@ -3,7 +3,6 @@ package com.ruoyi.generator.service; import java.util.List; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.common.core.core.text.Convert; import com.ruoyi.generator.domain.GenTableColumn; @@ -11,18 +10,18 @@ import com.ruoyi.generator.mapper.GenTableColumnMapper; /** * 业务字段 服务层实现 - * + * * @author ruoyi */ @Service -public class GenTableColumnServiceImpl implements IGenTableColumnService +public class GenTableColumnServiceImpl implements IGenTableColumnService { @Resource private GenTableColumnMapper genTableColumnMapper; /** * 查询业务字段列表 - * + * * @param tableId 业务字段编号 * @return 业务字段集合 */ @@ -31,10 +30,10 @@ public class GenTableColumnServiceImpl implements IGenTableColumnService { return genTableColumnMapper.selectGenTableColumnListByTableId(tableId); } - + /** * 新增业务字段 - * + * * @param genTableColumn 业务字段信息 * @return 结果 */ @@ -43,10 +42,10 @@ public class GenTableColumnServiceImpl implements IGenTableColumnService { return genTableColumnMapper.insertGenTableColumn(genTableColumn); } - + /** * 修改业务字段 - * + * * @param genTableColumn 业务字段信息 * @return 结果 */ @@ -58,7 +57,7 @@ public class GenTableColumnServiceImpl implements IGenTableColumnService /** * 删除业务字段对象 - * + * * @param ids 需要删除的数据ID * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java index f2f7e42..c07854b 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java @@ -1,9 +1,6 @@ package com.ruoyi.generator.service; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; +import java.io.*; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -20,7 +17,6 @@ import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.alibaba.fastjson2.JSON; @@ -29,7 +25,6 @@ import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.GenConstants; import com.ruoyi.common.core.core.text.CharsetKit; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTableColumn; @@ -41,12 +36,13 @@ import com.ruoyi.generator.util.VelocityUtils; /** * 业务 服务层实现 - * + * * @author ruoyi */ @Service public class GenTableServiceImpl implements IGenTableService { + @Serial private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class); @Resource @@ -57,7 +53,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 查询业务信息 - * + * * @param id 业务ID * @return 业务信息 */ @@ -71,7 +67,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 查询业务列表 - * + * * @param genTable 业务信息 * @return 业务集合 */ @@ -83,7 +79,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 查询据库列表 - * + * * @param genTable 业务信息 * @return 数据库表集合 */ @@ -95,7 +91,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 查询据库列表 - * + * * @param tableNames 表名称组 * @return 数据库表集合 */ @@ -107,7 +103,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 查询所有表信息 - * + * * @return 表信息集合 */ @Override @@ -118,7 +114,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 修改业务 - * + * * @param genTable 业务信息 * 结果 */ @@ -140,7 +136,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 删除业务对象 - * + * * @param tableIds 需要删除的数据ID * 结果 */ @@ -154,20 +150,19 @@ public class GenTableServiceImpl implements IGenTableService /** * 导入表结构 - * + * * @param tableList 导入表列表 */ @Override @Transactional public void importGenTable(List tableList) { - String operName = SecurityUtils.getUsername(); try { for (GenTable table : tableList) { String tableName = table.getTableName(); - GenUtils.initTable(table, operName); + GenUtils.initTable(table); int row = genTableMapper.insertGenTable(table); if (row > 0) { @@ -189,7 +184,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 预览代码 - * + * * @param tableId 表编号 * @return 预览数据列表 */ @@ -222,7 +217,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 生成代码(下载方式) - * + * * @param tableName 表名称 * @return 数据 */ @@ -238,7 +233,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 生成代码(自定义路径) - * + * * @param tableName 表名称 */ @Override @@ -280,7 +275,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 同步数据库 - * + * * @param tableName 表名称 */ @Override @@ -335,7 +330,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 批量生成代码(下载方式) - * + * * @param tableNames 表数组 * @return 数据 */ @@ -394,7 +389,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 修改保存参数校验 - * + * * @param genTable 业务信息 */ @Override @@ -432,7 +427,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 设置主键列信息 - * + * * @param table 业务表信息 */ public void setPkColumn(GenTable table) @@ -468,7 +463,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 设置主子表信息 - * + * * @param table 业务表信息 */ public void setSubTable(GenTable table) @@ -482,7 +477,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 设置代码生成其他选项值 - * + * * @param genTable 设置后的生成对象 */ public void setTableFromOptions(GenTable genTable) @@ -506,7 +501,7 @@ public class GenTableServiceImpl implements IGenTableService /** * 获取代码生成地址 - * + * * @param table 业务表信息 * @param template 模板文件路径 * @return 生成地址 @@ -520,4 +515,4 @@ public class GenTableServiceImpl implements IGenTableService } return genPath + File.separator + VelocityUtils.getFileName(template, table); } -} \ No newline at end of file +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java index e77265b..1a42540 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java @@ -1,6 +1,8 @@ package com.ruoyi.generator.util; import java.util.Arrays; + +import com.ruoyi.common.security.utils.LoginHelper; import org.apache.commons.lang3.RegExUtils; import com.ruoyi.common.core.constant.GenConstants; import com.ruoyi.common.core.utils.StringUtils; @@ -10,7 +12,7 @@ import com.ruoyi.generator.domain.GenTableColumn; /** * 代码生成器 工具类 - * + * * @author ruoyi */ public class GenUtils @@ -18,7 +20,7 @@ public class GenUtils /** * 初始化表信息 */ - public static void initTable(GenTable genTable, String operName) + public static void initTable(GenTable genTable) { genTable.setClassName(convertClassName(genTable.getTableName())); genTable.setPackageName(GenConfig.getPackageName()); @@ -26,7 +28,7 @@ public class GenUtils genTable.setBusinessName(getBusinessName(genTable.getTableName())); genTable.setFunctionName(replaceText(genTable.getTableComment())); genTable.setFunctionAuthor(GenConfig.getAuthor()); - genTable.setCreateBy(operName); + genTable.setCreateBy(LoginHelper.getUserId()); } /** @@ -135,7 +137,7 @@ public class GenUtils /** * 校验数组是否包含指定值 - * + * * @param arr 数组 * @param targetValue 值 * @return 是否包含 @@ -147,7 +149,7 @@ public class GenUtils /** * 获取模块名 - * + * * @param packageName 包名 * @return 模块名 */ @@ -160,7 +162,7 @@ public class GenUtils /** * 获取业务名 - * + * * @param tableName 表名 * @return 业务名 */ @@ -173,7 +175,7 @@ public class GenUtils /** * 表名转换成Java类名 - * + * * @param tableName 表名称 * @return 类名 */ @@ -191,7 +193,7 @@ public class GenUtils /** * 批量替换前缀 - * + * * @param replacementm 替换值 * @param searchList 替换列表 */ @@ -211,7 +213,7 @@ public class GenUtils /** * 关键字替换 - * + * * @param text 需要被替换的名字 * @return 替换后的名字 */ @@ -222,7 +224,7 @@ public class GenUtils /** * 获取数据库类型字段 - * + * * @param columnType 列类型 * @return 截取后的列类型 */ @@ -240,7 +242,7 @@ public class GenUtils /** * 获取字段长度 - * + * * @param columnType 列类型 * @return 截取后的列类型 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm index 3374997..360e981 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -2,7 +2,6 @@ package ${packageName}.controller; import java.util.List; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.access.prepost.PreAuthorize; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -13,9 +12,9 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.enums.BusinessType; +import cn.dev33.satoken.annotation.SaCheckPermission; import ${packageName}.domain.${ClassName}; import ${packageName}.service.I${ClassName}Service; import com.ruoyi.common.core.core.utils.poi.ExcelUtil; @@ -27,7 +26,7 @@ import com.ruoyi.common.core.core.page.TableDataInfo; /** * ${functionName}Controller - * + * * @author ${author} * ${datetime} */ @@ -41,7 +40,7 @@ public class ${ClassName}Controller extends BaseController /** * 查询${functionName}列表 */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')") + @SaCheckPermission("${permissionPrefix}:list") @GetMapping("/list") #if($table.crud || $table.sub) public TableDataInfo list(${ClassName} ${className}) @@ -61,7 +60,7 @@ public class ${ClassName}Controller extends BaseController /** * 导出${functionName}列表 */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')") + @SaCheckPermission("${permissionPrefix}:export") @Log(title = "${functionName}", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, ${ClassName} ${className}) @@ -74,7 +73,7 @@ public class ${ClassName}Controller extends BaseController /** * 获取${functionName}详细信息 */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')") + @SaCheckPermission("${permissionPrefix}:query") @GetMapping(value = "/{${pkColumn.javaField}}") public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) { @@ -84,7 +83,7 @@ public class ${ClassName}Controller extends BaseController /** * 新增${functionName} */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')") + @SaCheckPermission("${permissionPrefix}:add") @Log(title = "${functionName}", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody ${ClassName} ${className}) @@ -95,7 +94,7 @@ public class ${ClassName}Controller extends BaseController /** * 修改${functionName} */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')") + @SaCheckPermission("${permissionPrefix}:edit") @Log(title = "${functionName}", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@RequestBody ${ClassName} ${className}) @@ -106,7 +105,7 @@ public class ${ClassName}Controller extends BaseController /** * 删除${functionName} */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')") + @SaCheckPermission("${permissionPrefix}:remove") @Log(title = "${functionName}", businessType = BusinessType.DELETE) @DeleteMapping("/{${pkColumn.javaField}s}") public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm index 7a0e93a..b8fd77b 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm @@ -3,13 +3,11 @@ package ${packageName}.domain; #foreach ($import in $importList) import ${import}; #end -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; +import java.io.Serial; #if($table.crud || $table.sub) -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; #elseif($table.tree) -import com.ruoyi.common.core.core.domain.TreeEntity; #end /** @@ -25,6 +23,7 @@ import com.ruoyi.common.core.core.domain.TreeEntity; #end public class ${ClassName} extends ${Entity} { +@Serial private static final long serialVersionUID = 1L; #foreach ($column in $columns) diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm index efa3606..5a76ca0 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -21,19 +21,19 @@ import ${packageName}.service.I${ClassName}Service; /** * ${functionName}Service业务层处理 - * + * * @author ${author} * ${datetime} */ @Service -public class ${ClassName}ServiceImpl implements I${ClassName}Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service { @Resource private ${ClassName}Mapper ${className}Mapper; /** * 查询${functionName} - * + * * @param ${pkColumn.javaField} ${functionName}主键 * @return ${functionName} */ @@ -45,7 +45,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service /** * 查询${functionName}列表 - * + * * @param ${className} ${functionName} * @return ${functionName} */ @@ -57,7 +57,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service /** * 新增${functionName} - * + * * @param ${className} ${functionName} * @return 结果 */ @@ -83,7 +83,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service /** * 修改${functionName} - * + * * @param ${className} ${functionName} * @return 结果 */ @@ -107,7 +107,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service /** * 批量删除${functionName} - * + * * @param ${pkColumn.javaField}s 需要删除的${functionName}主键 * @return 结果 */ @@ -125,7 +125,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service /** * 删除${functionName}信息 - * + * * @param ${pkColumn.javaField} ${functionName}主键 * @return 结果 */ @@ -144,7 +144,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service /** * 新增${subTable.functionName}信息 - * + * * @param ${className} ${functionName}对象 */ public void insert${subClassName}(${ClassName} ${className}) diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm index 7aae32f..8de9459 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm @@ -7,7 +7,7 @@ import com.ruoyi.common.core.core.annotation.Excel; /** * ${subTable.functionName}对象 ${subTableName} - * + * * @author ${author} * ${datetime} */ @@ -45,12 +45,12 @@ public class ${subClassName} extends BaseEntity #else #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #end - public void set${AttrName}($column.javaType $column.javaField) + public void set${AttrName}($column.javaType $column.javaField) { this.$column.javaField = $column.javaField; } - public $column.javaType get${AttrName}() + public $column.javaType get${AttrName}() { return $column.javaField; } diff --git a/ruoyi-modules/ruoyi-quartz/pom.xml b/ruoyi-modules/ruoyi-quartz/pom.xml index dc916e9..92de027 100644 --- a/ruoyi-modules/ruoyi-quartz/pom.xml +++ b/ruoyi-modules/ruoyi-quartz/pom.xml @@ -35,6 +35,11 @@ ruoyi-common-core + + com.ruoyi + ruoyi-common-web + + - \ No newline at end of file + diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java index dfc9e64..134384f 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java @@ -1,10 +1,13 @@ package com.ruoyi.quartz.controller; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.security.utils.LoginHelper; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -13,12 +16,10 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.exception.job.TaskException; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; @@ -29,20 +30,20 @@ import com.ruoyi.quartz.util.ScheduleUtils; /** * 调度任务信息操作处理 - * + * * @author ruoyi */ @RestController @RequestMapping("/monitor/job") public class SysJobController extends BaseController { - @Autowired + @Resource private ISysJobService jobService; /** * 查询定时任务列表 */ - @PreAuthorize("@ss.hasPermi('monitor:job:list')") + @SaCheckPermission("monitor:job:list") @GetMapping("/list") public TableDataInfo list(SysJob sysJob) { @@ -54,8 +55,7 @@ public class SysJobController extends BaseController /** * 导出定时任务列表 */ - @PreAuthorize("@ss.hasPermi('monitor:job:export')") - @Log(title = "定时任务", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:job:export") @PostMapping("/export") public void export(HttpServletResponse response, SysJob sysJob) { @@ -67,7 +67,7 @@ public class SysJobController extends BaseController /** * 获取定时任务详细信息 */ - @PreAuthorize("@ss.hasPermi('monitor:job:query')") + @SaCheckPermission("monitor:job:query") @GetMapping(value = "/{jobId}") public AjaxResult getInfo(@PathVariable("jobId") Long jobId) { @@ -77,8 +77,7 @@ public class SysJobController extends BaseController /** * 新增定时任务 */ - @PreAuthorize("@ss.hasPermi('monitor:job:add')") - @Log(title = "定时任务", businessType = BusinessType.INSERT) + @SaCheckPermission("monitor:job:add") @PostMapping public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException { @@ -106,15 +105,14 @@ public class SysJobController extends BaseController { return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); } - job.setCreateBy(getUsername()); + job.setCreateBy(LoginHelper.getUserId()); return toAjax(jobService.insertJob(job)); } /** * 修改定时任务 */ - @PreAuthorize("@ss.hasPermi('monitor:job:edit')") - @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @SaCheckPermission("monitor:job:edit") @PutMapping public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException { @@ -142,15 +140,14 @@ public class SysJobController extends BaseController { return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); } - job.setUpdateBy(getUsername()); + job.setUpdateBy(LoginHelper.getUserId()); return toAjax(jobService.updateJob(job)); } /** * 定时任务状态修改 */ - @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')") - @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @SaCheckPermission("monitor:job:changeStatus") @PutMapping("/changeStatus") public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException { @@ -162,8 +159,7 @@ public class SysJobController extends BaseController /** * 定时任务立即执行一次 */ - @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')") - @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @SaCheckPermission("monitor:job:changeStatus") @PutMapping("/run") public AjaxResult run(@RequestBody SysJob job) throws SchedulerException { @@ -174,8 +170,7 @@ public class SysJobController extends BaseController /** * 删除定时任务 */ - @PreAuthorize("@ss.hasPermi('monitor:job:remove')") - @Log(title = "定时任务", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:job:remove") @DeleteMapping("/{jobIds}") public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException { diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java index df0f2f9..f2b6cc0 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java @@ -1,40 +1,44 @@ package com.ruoyi.quartz.controller; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.quartz.domain.SysJobLog; import com.ruoyi.quartz.service.ISysJobLogService; /** * 调度日志操作处理 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/monitor/jobLog") public class SysJobLogController extends BaseController { - @Autowired + @Resource private ISysJobLogService jobLogService; /** * 查询定时任务调度日志列表 */ - @PreAuthorize("@ss.hasPermi('monitor:job:list')") + @SaCheckPermission("monitor:job:list") @GetMapping("/list") public TableDataInfo list(SysJobLog sysJobLog) { @@ -46,8 +50,7 @@ public class SysJobLogController extends BaseController /** * 导出定时任务调度日志列表 */ - @PreAuthorize("@ss.hasPermi('monitor:job:export')") - @Log(title = "任务调度日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:job:export") @PostMapping("/export") public void export(HttpServletResponse response, SysJobLog sysJobLog) { @@ -55,11 +58,11 @@ public class SysJobLogController extends BaseController ExcelUtil util = new ExcelUtil<>(SysJobLog.class); util.exportExcel(response, list, "调度日志"); } - + /** * 根据调度编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('monitor:job:query')") + @SaCheckPermission("monitor:job:query") @GetMapping(value = "/{jobLogId}") public AjaxResult getInfo(@PathVariable Long jobLogId) { @@ -70,8 +73,7 @@ public class SysJobLogController extends BaseController /** * 删除定时任务调度日志 */ - @PreAuthorize("@ss.hasPermi('monitor:job:remove')") - @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:job:remove") @DeleteMapping("/{jobLogIds}") public AjaxResult remove(@PathVariable Long[] jobLogIds) { @@ -81,8 +83,7 @@ public class SysJobLogController extends BaseController /** * 清空定时任务调度日志 */ - @PreAuthorize("@ss.hasPermi('monitor:job:remove')") - @Log(title = "调度日志", businessType = BusinessType.CLEAN) + @SaCheckPermission("monitor:job:remove") @DeleteMapping("/clean") public AjaxResult clean() { diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java index f9d36a3..fbbeed0 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java @@ -1,5 +1,6 @@ package com.ruoyi.quartz.domain; +import java.io.Serial; import java.util.Date; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; @@ -9,17 +10,18 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.core.annotation.Excel; import com.ruoyi.common.core.annotation.Excel.ColumnType; import com.ruoyi.common.core.constant.ScheduleConstants; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.quartz.util.CronUtils; /** * 定时任务调度表 sys_job - * + * * @author ruoyi */ public class SysJob extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 任务ID */ diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java index 7fbde83..4f9be9e 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java @@ -1,18 +1,20 @@ package com.ruoyi.quartz.domain; +import java.io.Serial; import java.util.Date; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 定时任务调度日志表 sys_job_log - * + * * @author ruoyi */ public class SysJobLog extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** ID */ @@ -128,7 +130,7 @@ public class SysJobLog extends BaseEntity { this.startTime = startTime; } - + public Date getStopTime() { return stopTime; diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java index cde15a3..77d1648 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java @@ -11,7 +11,7 @@ import com.ruoyi.common.core.constant.ScheduleConstants; import com.ruoyi.common.core.utils.ExceptionUtil; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.bean.BeanUtils; -import com.ruoyi.common.core.utils.spring.SpringUtils; +import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.quartz.domain.SysJob; import com.ruoyi.quartz.domain.SysJobLog; import com.ruoyi.quartz.service.ISysJobLogService; diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java index 0010c38..6934c3e 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java @@ -5,7 +5,7 @@ import java.lang.reflect.Method; import java.util.LinkedList; import java.util.List; import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.spring.SpringUtils; +import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.quartz.domain.SysJob; /** @@ -64,7 +64,7 @@ public class JobInvokeUtil /** * 校验是否为为class包名 - * + * * @param invokeTarget 名称 * @return true是 false否 */ @@ -75,7 +75,7 @@ public class JobInvokeUtil /** * 获取bean名称 - * + * * @param invokeTarget 目标字符串 * @return bean名称 */ @@ -87,7 +87,7 @@ public class JobInvokeUtil /** * 获取bean方法 - * + * * @param invokeTarget 目标字符串 * @return method方法 */ @@ -99,7 +99,7 @@ public class JobInvokeUtil /** * 获取method方法参数相关列表 - * + * * @param invokeTarget 目标字符串 * @return method方法相关参数列表 */ @@ -146,7 +146,7 @@ public class JobInvokeUtil /** * 获取参数类型 - * + * * @param methodParams 参数相关列表 * @return 参数类型列表 */ @@ -164,7 +164,7 @@ public class JobInvokeUtil /** * 获取参数值 - * + * * @param methodParams 参数相关列表 * @return 参数值列表 */ diff --git a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java index befb60f..b7a70be 100644 --- a/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java +++ b/ruoyi-modules/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java @@ -15,12 +15,12 @@ import com.ruoyi.common.core.constant.ScheduleConstants; import com.ruoyi.common.core.exception.job.TaskException; import com.ruoyi.common.core.exception.job.TaskException.Code; import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.spring.SpringUtils; +import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.quartz.domain.SysJob; /** * 定时任务工具类 - * + * * @author ruoyi * */ @@ -121,7 +121,7 @@ public class ScheduleUtils /** * 检查包名是否为白名单配置 - * + * * @param invokeTarget 目标字符串 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml index a57fb51..1b1ac9c 100644 --- a/ruoyi-modules/ruoyi-system/pom.xml +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -8,6 +8,7 @@ ${revision} 4.0.0 + jar ruoyi-system @@ -17,12 +18,68 @@ + + + com.github.oshi + oshi-core + + com.ruoyi ruoyi-common-core + + com.ruoyi + ruoyi-common-excel + + + + com.ruoyi + ruoyi-common-json + + + + com.ruoyi + ruoyi-common-log + + + + com.ruoyi + ruoyi-common-orm + + + + com.ruoyi + ruoyi-common-redis + + + + com.ruoyi + ruoyi-common-security + + + + com.ruoyi + ruoyi-common-springdoc + + + + com.ruoyi + ruoyi-common-tenant + + + + com.ruoyi + ruoyi-common-translation + + + + com.ruoyi + ruoyi-common-web + + - \ No newline at end of file + diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/aspectj/DataScopeAspect.java similarity index 64% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/aspectj/DataScopeAspect.java index 7ab4811..e5697c1 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/aspectj/DataScopeAspect.java @@ -1,20 +1,25 @@ -package com.ruoyi.framework.aspectj; +package com.ruoyi.system.aspectj; -import java.util.ArrayList; -import java.util.List; +import java.lang.reflect.Method; + +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysRole; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.mapper.SysUserMapper; +import jakarta.annotation.Resource; import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import java.util.ArrayList; +import java.util.List; import org.springframework.stereotype.Component; import com.ruoyi.common.core.annotation.DataScope; -import com.ruoyi.common.core.core.domain.BaseEntity; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; +import com.ruoyi.common.orm.core.domain.BaseEntity; import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.core.text.Convert; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.framework.security.context.PermissionContextHolder; /** * 数据过滤处理 @@ -55,30 +60,68 @@ public class DataScopeAspect */ public static final String DATA_SCOPE = "dataScope"; - @Before("@annotation(controllerDataScope)") - public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable + @Resource + private SysUserMapper userMapper; + + // 配置织入点 + @Pointcut("@annotation(com.ruoyi.common.core.annotation.DataScope)") + public void dataScopePointCut() { - clearDataScope(point); - handleDataScope(point, controllerDataScope); } - protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) + @Before("dataScopePointCut()") + public void doBefore(JoinPoint point) throws Throwable { + clearDataScope(point); + handleDataScope(point); + } + + protected void handleDataScope(final JoinPoint joinPoint) + { + // 获得注解 + DataScope controllerDataScope = getAnnotationLog(joinPoint); + if (controllerDataScope == null) + { + return; + } + // 获取当前的用户 - LoginUser loginUser = SecurityUtils.getLoginUser(); + LoginUser loginUser = LoginHelper.getLoginUser(); if (StringUtils.isNotNull(loginUser)) { - SysUser currentUser = loginUser.getUser(); - // 如果是超级管理员,则不过滤数据 - if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) - { - String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext()); - dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), - controllerDataScope.userAlias(), permission); + Long usetId=loginUser.getUserId(); + if (usetId>0){ + SysUser currentUser = userMapper.selectUserById(usetId); + // 如果是超级管理员,则不过滤数据 + if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) + { +// String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext()); +// dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), +// controllerDataScope.userAlias(), permission); + dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), + controllerDataScope.userAlias()); + } } + } } + /** + * 是否存在注解,如果存在就获取 + */ + private DataScope getAnnotationLog(JoinPoint joinPoint) + { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + + if (method != null) + { + return method.getAnnotation(DataScope.class); + } + return null; + } + /** * 数据范围过滤 * @@ -86,9 +129,8 @@ public class DataScopeAspect * @param user 用户 * @param deptAlias 部门别名 * @param userAlias 用户别名 - * @param permission 权限字符 */ - public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission) + public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) { StringBuilder sqlString = new StringBuilder(); List conditions = new ArrayList<>(); @@ -100,11 +142,11 @@ public class DataScopeAspect { continue; } - if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions()) - && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) - { - continue; - } +// if (StringUtils.isNotEmpty(role.getPermissions()) +// && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) +// { +// continue; +// } if (DATA_SCOPE_ALL.equals(dataScope)) { sqlString = new StringBuilder(); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/config/ServerConfig.java similarity index 94% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/config/ServerConfig.java index f663c37..eecae41 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/config/ServerConfig.java @@ -1,4 +1,4 @@ -package com.ruoyi.framework.config; +package com.ruoyi.system.config; import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; @@ -6,7 +6,7 @@ import com.ruoyi.common.core.utils.ServletUtils; /** * 服务相关配置 - * + * * @author ruoyi */ @Component @@ -14,7 +14,7 @@ public class ServerConfig { /** * 获取完整的请求路径,包括:域名,端口,上下文访问路径 - * + * * @return 服务地址 */ public String getUrl() diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java new file mode 100644 index 0000000..681ef9f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/CacheController.java @@ -0,0 +1,143 @@ +package com.ruoyi.system.controller.monitor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.core.core.domain.R; +import com.ruoyi.system.domain.vo.CacheListInfoVo; +import lombok.RequiredArgsConstructor; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.utils.StringUtils; + +/** + * 缓存监控 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/cache") +public class CacheController +{ + private final RedissonConnectionFactory connectionFactory; + + /** + * 获取缓存监控列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping() + public R getInfo() throws Exception { + RedisConnection connection = connectionFactory.getConnection(); + Properties commandStats = connection.commands().info("commandstats"); + + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + } + + CacheListInfoVo infoVo = new CacheListInfoVo(); + infoVo.setInfo(connection.commands().info()); + infoVo.setDbSize(connection.commands().dbSize()); + infoVo.setCommandStats(pieList); + return R.ok(infoVo); + } + +// private final static List caches = new ArrayList(); +// { +// caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); +// caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息")); +// caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典")); +// caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); +// caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); +// caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); +// caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); +// } +// +// @SaCheckPermission("monitor:cache:list") +// @GetMapping() +// public AjaxResult getInfo() throws Exception +// { +// Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); +// Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); +// Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); +// +// Map result = new HashMap<>(3); +// result.put("info", info); +// result.put("dbSize", dbSize); +// +// List> pieList = new ArrayList<>(); +// commandStats.stringPropertyNames().forEach(key -> { +// Map data = new HashMap<>(2); +// String property = commandStats.getProperty(key); +// data.put("name", StringUtils.removeStart(key, "cmdstat_")); +// data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); +// pieList.add(data); +// }); +// result.put("commandStats", pieList); +// return AjaxResult.success(result); +// } +// +// @PreAuthorize("@ss.hasPermi('monitor:cache:list')") +// @GetMapping("/getNames") +// public AjaxResult cache() +// { +// return AjaxResult.success(caches); +// } +// +// @PreAuthorize("@ss.hasPermi('monitor:cache:list')") +// @GetMapping("/getKeys/{cacheName}") +// public AjaxResult getCacheKeys(@PathVariable String cacheName) +// { +// Set cacheKeys = redisTemplate.keys(cacheName + "*"); +// return AjaxResult.success(cacheKeys); +// } +// +// @PreAuthorize("@ss.hasPermi('monitor:cache:list')") +// @GetMapping("/getValue/{cacheName}/{cacheKey}") +// public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) +// { +// String cacheValue = redisTemplate.opsForValue().get(cacheKey); +// SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue); +// return AjaxResult.success(sysCache); +// } +// +// @PreAuthorize("@ss.hasPermi('monitor:cache:list')") +// @DeleteMapping("/clearCacheName/{cacheName}") +// public AjaxResult clearCacheName(@PathVariable String cacheName) +// { +// Collection cacheKeys = redisTemplate.keys(cacheName + "*"); +// redisTemplate.delete(cacheKeys); +// return AjaxResult.success(); +// } +// +// @PreAuthorize("@ss.hasPermi('monitor:cache:list')") +// @DeleteMapping("/clearCacheKey/{cacheKey}") +// public AjaxResult clearCacheKey(@PathVariable String cacheKey) +// { +// redisTemplate.delete(cacheKey); +// return AjaxResult.success(); +// } +// +// @PreAuthorize("@ss.hasPermi('monitor:cache:list')") +// @DeleteMapping("/clearCacheAll") +// public AjaxResult clearCacheAll() +// { +// Collection cacheKeys = redisTemplate.keys("*"); +// redisTemplate.delete(cacheKeys); +// return AjaxResult.success(); +// } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/ServerController.java similarity index 72% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/ServerController.java index aad37f3..371f29c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/ServerController.java @@ -1,22 +1,22 @@ -package com.ruoyi.web.controller.monitor; +package com.ruoyi.system.controller.monitor; -import org.springframework.security.access.prepost.PreAuthorize; +import cn.dev33.satoken.annotation.SaCheckPermission; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.framework.web.domain.Server; +import com.ruoyi.system.domain.Server; /** * 服务器监控 - * + * * @author ruoyi */ @RestController @RequestMapping("/monitor/server") public class ServerController { - @PreAuthorize("@ss.hasPermi('monitor:server:list')") + @SaCheckPermission("monitor:server:list") @GetMapping() public AjaxResult getInfo() throws Exception { diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java similarity index 64% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java index a9d326d..1b8e8de 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysLogininforController.java @@ -1,30 +1,35 @@ -package com.ruoyi.web.controller.monitor; +package com.ruoyi.system.controller.monitor; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.redis.utils.RedisUtils; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.poi.ExcelUtil; -import com.ruoyi.framework.web.service.SysPasswordService; +//import com.ruoyi.framework.web.service.SysPasswordService; import com.ruoyi.system.domain.SysLogininfor; import com.ruoyi.system.service.ISysLogininforService; /** * 系统访问记录 - * + * * @author ruoyi */ +@Validated @RestController @RequestMapping("/monitor/logininfor") public class SysLogininforController extends BaseController @@ -32,10 +37,10 @@ public class SysLogininforController extends BaseController @Autowired private ISysLogininforService logininforService; - @Autowired - private SysPasswordService passwordService; +// @Autowired +// private SysPasswordService passwordService; - @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") + @SaCheckPermission("monitor:logininfor:list") @GetMapping("/list") public TableDataInfo list(SysLogininfor logininfor) { @@ -44,8 +49,11 @@ public class SysLogininforController extends BaseController return getDataTable(list); } + /** + * 导出系统访问记录列表 + */ @Log(title = "登录日志", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") + @SaCheckPermission("monitor:logininfor:export") @PostMapping("/export") public void export(HttpServletResponse response, SysLogininfor logininfor) { @@ -54,15 +62,21 @@ public class SysLogininforController extends BaseController util.exportExcel(response, list, "登录日志"); } - @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + /** + * 批量删除登录日志 + * @param infoIds 日志ids + */ + @SaCheckPermission("monitor:logininfor:remove") @Log(title = "登录日志", businessType = BusinessType.DELETE) - @DeleteMapping("/{infoIds}") public AjaxResult remove(@PathVariable Long[] infoIds) { return toAjax(logininforService.deleteLogininforByIds(infoIds)); } - @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + /** + * 清理系统访问记录 + */ + @SaCheckPermission("monitor:logininfor:remove") @Log(title = "登录日志", businessType = BusinessType.CLEAN) @DeleteMapping("/clean") public AjaxResult clean() @@ -71,12 +85,17 @@ public class SysLogininforController extends BaseController return success(); } - @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')") + @SaCheckPermission("monitor:logininfor:unlock") @Log(title = "账户解锁", businessType = BusinessType.OTHER) @GetMapping("/unlock/{userName}") public AjaxResult unlock(@PathVariable("userName") String userName) { - passwordService.clearLoginRecordCache(userName); +// passwordService.clearLoginRecordCache(userName); +// return success(); + String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName; + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } return success(); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysOperlogController.java similarity index 71% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysOperlogController.java index e240dde..32baad0 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysOperlogController.java @@ -1,29 +1,34 @@ -package com.ruoyi.web.controller.monitor; +package com.ruoyi.system.controller.monitor; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.service.ISysOperLogService; /** * 操作日志记录 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/monitor/operlog") public class SysOperlogController extends BaseController @@ -31,7 +36,10 @@ public class SysOperlogController extends BaseController @Autowired private ISysOperLogService operLogService; - @PreAuthorize("@ss.hasPermi('monitor:operlog:list')") + /** + * 获取操作日志记录列表 + */ + @SaCheckPermission("monitor:operlog:list") @GetMapping("/list") public TableDataInfo list(SysOperLog operLog) { @@ -40,8 +48,11 @@ public class SysOperlogController extends BaseController return getDataTable(list); } + /** + * 导出操作日志记录列表 + */ @Log(title = "操作日志", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('monitor:operlog:export')") + @SaCheckPermission("monitor:operlog:export") @PostMapping("/export") public void export(HttpServletResponse response, SysOperLog operLog) { @@ -50,16 +61,23 @@ public class SysOperlogController extends BaseController util.exportExcel(response, list, "操作日志"); } + /** + * 批量删除操作日志记录 + * @param operIds 日志ids + */ @Log(title = "操作日志", businessType = BusinessType.DELETE) - @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @SaCheckPermission("monitor:operlog:remove") @DeleteMapping("/{operIds}") public AjaxResult remove(@PathVariable Long[] operIds) { return toAjax(operLogService.deleteOperLogByIds(operIds)); } + /** + * 清理操作日志记录 + */ @Log(title = "操作日志", businessType = BusinessType.CLEAN) - @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @SaCheckPermission("monitor:operlog:remove") @DeleteMapping("/clean") public AjaxResult clean() { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..5905188 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,85 @@ +package com.ruoyi.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.core.utils.StreamUtils; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.system.domain.SysUserOnline; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.web.core.BaseController; +import com.ruoyi.common.core.core.domain.AjaxResult; +import com.ruoyi.common.core.core.page.TableDataInfo; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.core.domain.dto.UserOnlineDTO; + +/** + * 在线用户监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController +{ + @SaCheckPermission("monitor:online:list") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) + { + // 获取所有未过期的 token + List keys = StpUtil.searchTokenValue("", 0, -1, false); + List userOnlineDTOList = new ArrayList<>(); + for (String key : keys) { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + continue; + } + userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)); + } + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退用户 + */ + @SaCheckPermission("monitor:online:forceLogout") + @DeleteMapping("/{tokenId}") + public AjaxResult forceLogout(@PathVariable String tokenId) + { + try { + StpUtil.kickoutByTokenValue(tokenId); + } catch (NotLoginException ignored) { + } + return AjaxResult.success(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysClientController.java new file mode 100644 index 0000000..a0c0f5b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysClientController.java @@ -0,0 +1,101 @@ +package com.ruoyi.system.controller.system; + +import com.mybatisflex.core.paginate.Page; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import com.ruoyi.system.service.ISysClientService; +import com.ruoyi.system.domain.SysClient; +import org.springframework.web.bind.annotation.RestController; + +import java.io.Serializable; +import java.util.List; + +/** + * 系统授权表 控制层。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@RestController +@RequestMapping("/sysClient") +public class SysClientController { + + @Resource + private ISysClientService sysClientService; + + /** + * 添加 系统授权表 + * + * @param sysClient 系统授权表 + * @return {@code true} 添加成功,{@code false} 添加失败 + */ + @PostMapping("/save") + public boolean save(@RequestBody SysClient sysClient) { + return sysClientService.save(sysClient); + } + + + /** + * 根据主键删除系统授权表 + * + * @param id 主键 + * @return {@code true} 删除成功,{@code false} 删除失败 + */ + @DeleteMapping("/remove/{id}") + public boolean remove(@PathVariable Serializable id) { + return sysClientService.removeById(id); + } + + + /** + * 根据主键更新系统授权表 + * + * @param sysClient 系统授权表 + * @return {@code true} 更新成功,{@code false} 更新失败 + */ + @PutMapping("/update") + public boolean update(@RequestBody SysClient sysClient) { + return sysClientService.updateById(sysClient); + } + + + /** + * 查询所有系统授权表 + * + * @return 所有数据 + */ + @GetMapping("/list") + public List list() { + return sysClientService.list(); + } + + + /** + * 根据系统授权表主键获取详细信息。 + * + * @param id sysClient主键 + * @return 系统授权表详情 + */ + @GetMapping("/getInfo/{id}") + public SysClient getInfo(@PathVariable Serializable id) { + return sysClientService.getById(id); + } + + + /** + * 分页查询系统授权表 + * + * @param page 分页对象 + * @return 分页对象 + */ + @GetMapping("/page") + public Page page(Page page) { + return sysClientService.page(page); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysConfigController.java similarity index 81% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysConfigController.java index e9b583d..f3140eb 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysConfigController.java @@ -1,9 +1,13 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,31 +17,31 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.service.ISysConfigService; /** * 参数配置 信息操作处理 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/config") public class SysConfigController extends BaseController { - @Autowired + @Resource private ISysConfigService configService; /** * 获取参数配置列表 */ - @PreAuthorize("@ss.hasPermi('system:config:list')") + @SaCheckPermission("system:config:list") @GetMapping("/list") public TableDataInfo list(SysConfig config) { @@ -46,8 +50,11 @@ public class SysConfigController extends BaseController return getDataTable(list); } + /** + * 导出参数配置列表 + */ @Log(title = "参数管理", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('system:config:export')") + @SaCheckPermission("system:config:export") @PostMapping("/export") public void export(HttpServletResponse response, SysConfig config) { @@ -59,7 +66,7 @@ public class SysConfigController extends BaseController /** * 根据参数编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:config:query')") + @SaCheckPermission("system:config:query") @GetMapping(value = "/{configId}") public AjaxResult getInfo(@PathVariable Long configId) { @@ -69,6 +76,7 @@ public class SysConfigController extends BaseController /** * 根据参数键名查询参数值 */ + @SaCheckPermission("system:config:query") @GetMapping(value = "/configKey/{configKey}") public AjaxResult getConfigKey(@PathVariable String configKey) { @@ -78,7 +86,7 @@ public class SysConfigController extends BaseController /** * 新增参数配置 */ - @PreAuthorize("@ss.hasPermi('system:config:add')") + @SaCheckPermission("system:config:add") @Log(title = "参数管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysConfig config) @@ -87,14 +95,13 @@ public class SysConfigController extends BaseController { return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); } - config.setCreateBy(getUsername()); return toAjax(configService.insertConfig(config)); } /** * 修改参数配置 */ - @PreAuthorize("@ss.hasPermi('system:config:edit')") + @SaCheckPermission("system:config:edit") @Log(title = "参数管理", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysConfig config) @@ -103,14 +110,13 @@ public class SysConfigController extends BaseController { return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); } - config.setUpdateBy(getUsername()); return toAjax(configService.updateConfig(config)); } /** * 删除参数配置 */ - @PreAuthorize("@ss.hasPermi('system:config:remove')") + @SaCheckPermission("system:config:remove") @Log(title = "参数管理", businessType = BusinessType.DELETE) @DeleteMapping("/{configIds}") public AjaxResult remove(@PathVariable Long[] configIds) @@ -122,7 +128,7 @@ public class SysConfigController extends BaseController /** * 刷新参数缓存 */ - @PreAuthorize("@ss.hasPermi('system:config:remove')") + @SaCheckPermission("system:config:remove") @Log(title = "参数管理", businessType = BusinessType.CLEAN) @DeleteMapping("/refreshCache") public AjaxResult refreshCache() diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDeptController.java similarity index 62% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDeptController.java index e31634d..470aa9d 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDeptController.java @@ -1,9 +1,15 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysDept; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.ArrayUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,34 +19,31 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysDept; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.service.ISysDeptService; /** * 部门信息 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/dept") -public class SysDeptController extends BaseController -{ - @Autowired +public class SysDeptController extends BaseController { + @Resource private ISysDeptService deptService; /** * 获取部门列表 */ - @PreAuthorize("@ss.hasPermi('system:dept:list')") + @SaCheckPermission("system:dept:list") @GetMapping("/list") - public AjaxResult list(SysDept dept) - { + public AjaxResult list(SysDept dept) { List depts = deptService.selectDeptList(dept); return success(depts); } @@ -48,10 +51,9 @@ public class SysDeptController extends BaseController /** * 查询部门列表(排除节点) */ - @PreAuthorize("@ss.hasPermi('system:dept:list')") + @SaCheckPermission("system:dept:list") @GetMapping("/list/exclude/{deptId}") - public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) - { + public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { List depts = deptService.selectDeptList(new SysDept()); depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); return success(depts); @@ -60,10 +62,10 @@ public class SysDeptController extends BaseController /** * 根据部门编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:dept:query')") + @SaCheckPermission("system:dept:query") + @Log(title = "部门管理", businessType = BusinessType.INSERT) @GetMapping(value = "/{deptId}") - public AjaxResult getInfo(@PathVariable Long deptId) - { + public AjaxResult getInfo(@PathVariable Long deptId) { deptService.checkDeptDataScope(deptId); return success(deptService.selectDeptById(deptId)); } @@ -71,59 +73,51 @@ public class SysDeptController extends BaseController /** * 新增部门 */ - @PreAuthorize("@ss.hasPermi('system:dept:add')") - @Log(title = "部门管理", businessType = BusinessType.INSERT) + @SaCheckPermission("system:dept:add") @PostMapping - public AjaxResult add(@Validated @RequestBody SysDept dept) - { - if (!deptService.checkDeptNameUnique(dept)) - { + public AjaxResult add(@Validated @RequestBody SysDept dept) { + if (!deptService.checkDeptNameUnique(dept)) { return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); } - dept.setCreateBy(getUsername()); + dept.setCreateBy(LoginHelper.getUserId()); return toAjax(deptService.insertDept(dept)); } /** * 修改部门 */ - @PreAuthorize("@ss.hasPermi('system:dept:edit')") + @SaCheckPermission("system:dept:edit") @Log(title = "部门管理", businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult edit(@Validated @RequestBody SysDept dept) - { + public AjaxResult edit(@Validated @RequestBody SysDept dept) { Long deptId = dept.getDeptId(); deptService.checkDeptDataScope(deptId); - if (!deptService.checkDeptNameUnique(dept)) - { + if (!deptService.checkDeptNameUnique(dept)) { return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); - } - else if (dept.getParentId().equals(deptId)) - { + } else if (dept.getParentId().equals(deptId)) { return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) { + if (deptService.selectNormalChildrenDeptById(deptId) > 0) { + return error("该部门包含未停用的子部门!"); + } else if (deptService.checkDeptExistUser(deptId)) { + return error("该部门下存在已分配用户,不能禁用!"); + } } - else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) - { - return error("该部门包含未停用的子部门!"); - } - dept.setUpdateBy(getUsername()); + dept.setUpdateBy(LoginHelper.getUserId()); return toAjax(deptService.updateDept(dept)); } /** * 删除部门 */ - @PreAuthorize("@ss.hasPermi('system:dept:remove')") + @SaCheckPermission("system:dept:remove") @Log(title = "部门管理", businessType = BusinessType.DELETE) @DeleteMapping("/{deptId}") - public AjaxResult remove(@PathVariable Long deptId) - { - if (deptService.hasChildByDeptId(deptId)) - { + public AjaxResult remove(@PathVariable Long deptId) { + if (deptService.hasChildByDeptId(deptId)) { return warn("存在下级部门,不允许删除"); } - if (deptService.checkDeptExistUser(deptId)) - { + if (deptService.checkDeptExistUser(deptId)) { return warn("部门存在用户,不允许删除"); } deptService.checkDeptDataScope(deptId); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictDataController.java similarity index 77% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictDataController.java index edc2dd1..9e53306 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictDataController.java @@ -1,10 +1,18 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.ArrayList; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.stp.StpUtil; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysDictData; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -14,12 +22,9 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysDictData; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.system.service.ISysDictDataService; @@ -27,20 +32,22 @@ import com.ruoyi.system.service.ISysDictTypeService; /** * 数据字典信息 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/dict/data") public class SysDictDataController extends BaseController { - @Autowired + @Resource private ISysDictDataService dictDataService; - @Autowired + @Resource private ISysDictTypeService dictTypeService; - @PreAuthorize("@ss.hasPermi('system:dict:list')") + @SaCheckPermission("system:dict:list") @GetMapping("/list") public TableDataInfo list(SysDictData dictData) { @@ -49,8 +56,11 @@ public class SysDictDataController extends BaseController return getDataTable(list); } + /** + * 导出字典数据列表 + */ + @SaCheckPermission("system:dict:export") @Log(title = "字典数据", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('system:dict:export')") @PostMapping("/export") public void export(HttpServletResponse response, SysDictData dictData) { @@ -62,7 +72,7 @@ public class SysDictDataController extends BaseController /** * 查询字典数据详细 */ - @PreAuthorize("@ss.hasPermi('system:dict:query')") + @SaCheckPermission("system:dict:query") @GetMapping(value = "/{dictCode}") public AjaxResult getInfo(@PathVariable Long dictCode) { @@ -72,6 +82,7 @@ public class SysDictDataController extends BaseController /** * 根据字典类型查询字典数据信息 */ + @SaIgnore @GetMapping(value = "/type/{dictType}") public AjaxResult dictType(@PathVariable String dictType) { @@ -86,31 +97,31 @@ public class SysDictDataController extends BaseController /** * 新增字典类型 */ - @PreAuthorize("@ss.hasPermi('system:dict:add')") + @SaCheckPermission("system:dict:add") @Log(title = "字典数据", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysDictData dict) { - dict.setCreateBy(getUsername()); + dict.setCreateBy(LoginHelper.getUserId()); return toAjax(dictDataService.insertDictData(dict)); } /** * 修改保存字典类型 */ - @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @SaCheckPermission("system:dict:edit") @Log(title = "字典数据", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysDictData dict) { - dict.setUpdateBy(getUsername()); + dict.setUpdateBy(LoginHelper.getUserId()); return toAjax(dictDataService.updateDictData(dict)); } /** * 删除字典类型 */ - @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @SaCheckPermission("system:dict:remove") @Log(title = "字典类型", businessType = BusinessType.DELETE) @DeleteMapping("/{dictCodes}") public AjaxResult remove(@PathVariable Long[] dictCodes) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictTypeController.java similarity index 80% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictTypeController.java index a760db7..8be15f3 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysDictTypeController.java @@ -1,9 +1,16 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysDictType; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,28 +20,27 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysDictType; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.system.service.ISysDictTypeService; /** * 数据字典信息 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/dict/type") public class SysDictTypeController extends BaseController { - @Autowired + @Resource private ISysDictTypeService dictTypeService; - @PreAuthorize("@ss.hasPermi('system:dict:list')") + @SaCheckPermission("system:dict:list") @GetMapping("/list") public TableDataInfo list(SysDictType dictType) { @@ -44,7 +50,7 @@ public class SysDictTypeController extends BaseController } @Log(title = "字典类型", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('system:dict:export')") + @SaCheckPermission("system:dict:export") @PostMapping("/export") public void export(HttpServletResponse response, SysDictType dictType) { @@ -56,7 +62,7 @@ public class SysDictTypeController extends BaseController /** * 查询字典类型详细 */ - @PreAuthorize("@ss.hasPermi('system:dict:query')") + @SaCheckPermission("system:dict:query") @GetMapping(value = "/{dictId}") public AjaxResult getInfo(@PathVariable Long dictId) { @@ -66,7 +72,7 @@ public class SysDictTypeController extends BaseController /** * 新增字典类型 */ - @PreAuthorize("@ss.hasPermi('system:dict:add')") + @SaCheckPermission("system:dict:add") @Log(title = "字典类型", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysDictType dict) @@ -75,14 +81,14 @@ public class SysDictTypeController extends BaseController { return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); } - dict.setCreateBy(getUsername()); + dict.setCreateBy(LoginHelper.getUserId()); return toAjax(dictTypeService.insertDictType(dict)); } /** * 修改字典类型 */ - @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @SaCheckPermission("system:dict:edit") @Log(title = "字典类型", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysDictType dict) @@ -91,14 +97,14 @@ public class SysDictTypeController extends BaseController { return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); } - dict.setUpdateBy(getUsername()); + dict.setUpdateBy(LoginHelper.getUserId()); return toAjax(dictTypeService.updateDictType(dict)); } /** * 删除字典类型 */ - @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @SaCheckPermission("system:dict:remove") @Log(title = "字典类型", businessType = BusinessType.DELETE) @DeleteMapping("/{dictIds}") public AjaxResult remove(@PathVariable Long[] dictIds) @@ -110,7 +116,7 @@ public class SysDictTypeController extends BaseController /** * 刷新字典缓存 */ - @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @SaCheckPermission("system:dict:remove") @Log(title = "字典类型", businessType = BusinessType.CLEAN) @DeleteMapping("/refreshCache") public AjaxResult refreshCache() diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysMenuController.java similarity index 78% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysMenuController.java index 5e950ac..09c42c7 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysMenuController.java @@ -1,8 +1,14 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysMenu; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -12,42 +18,41 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysMenu; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.service.ISysMenuService; /** * 菜单信息 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/menu") public class SysMenuController extends BaseController { - @Autowired + @Resource private ISysMenuService menuService; /** * 获取菜单列表 */ - @PreAuthorize("@ss.hasPermi('system:menu:list')") + @SaCheckPermission("system:menu:list") @GetMapping("/list") public AjaxResult list(SysMenu menu) { - List menus = menuService.selectMenuList(menu, getUserId()); + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); return success(menus); } /** * 根据菜单编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:menu:query')") + @SaCheckPermission("system:menu:query") @GetMapping(value = "/{menuId}") public AjaxResult getInfo(@PathVariable Long menuId) { @@ -57,20 +62,22 @@ public class SysMenuController extends BaseController /** * 获取菜单下拉树列表 */ + @SaCheckPermission("system:menu:query") @GetMapping("/treeselect") public AjaxResult treeselect(SysMenu menu) { - List menus = menuService.selectMenuList(menu, getUserId()); + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); return success(menuService.buildMenuTreeSelect(menus)); } /** * 加载对应角色菜单列表树 */ + @SaCheckPermission("system:menu:query") @GetMapping(value = "/roleMenuTreeselect/{roleId}") public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) { - List menus = menuService.selectMenuList(getUserId()); + List menus = menuService.selectMenuList(LoginHelper.getUserId()); AjaxResult ajax = AjaxResult.success(); ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); ajax.put("menus", menuService.buildMenuTreeSelect(menus)); @@ -80,7 +87,7 @@ public class SysMenuController extends BaseController /** * 新增菜单 */ - @PreAuthorize("@ss.hasPermi('system:menu:add')") + @SaCheckPermission("system:menu:add") @Log(title = "菜单管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysMenu menu) @@ -93,14 +100,14 @@ public class SysMenuController extends BaseController { return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); } - menu.setCreateBy(getUsername()); + menu.setCreateBy(LoginHelper.getUserId()); return toAjax(menuService.insertMenu(menu)); } /** * 修改菜单 */ - @PreAuthorize("@ss.hasPermi('system:menu:edit')") + @SaCheckPermission("system:menu:edit") @Log(title = "菜单管理", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysMenu menu) @@ -117,14 +124,14 @@ public class SysMenuController extends BaseController { return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); } - menu.setUpdateBy(getUsername()); + menu.setUpdateBy(LoginHelper.getUserId()); return toAjax(menuService.updateMenu(menu)); } /** * 删除菜单 */ - @PreAuthorize("@ss.hasPermi('system:menu:remove')") + @SaCheckPermission("system:menu:remove") @Log(title = "菜单管理", businessType = BusinessType.DELETE) @DeleteMapping("/{menuId}") public AjaxResult remove(@PathVariable("menuId") Long menuId) @@ -139,4 +146,4 @@ public class SysMenuController extends BaseController } return toAjax(menuService.deleteMenuById(menuId)); } -} \ No newline at end of file +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysNoticeController.java similarity index 75% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysNoticeController.java index 1476f3d..0e14dd7 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysNoticeController.java @@ -1,8 +1,14 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -12,30 +18,30 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.system.domain.SysNotice; import com.ruoyi.system.service.ISysNoticeService; /** * 公告 信息操作处理 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/notice") public class SysNoticeController extends BaseController { - @Autowired + @Resource private ISysNoticeService noticeService; /** * 获取通知公告列表 */ - @PreAuthorize("@ss.hasPermi('system:notice:list')") + @SaCheckPermission("system:notice:list") @GetMapping("/list") public TableDataInfo list(SysNotice notice) { @@ -47,7 +53,7 @@ public class SysNoticeController extends BaseController /** * 根据通知公告编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:notice:query')") + @SaCheckPermission("system:notice:query") @GetMapping(value = "/{noticeId}") public AjaxResult getInfo(@PathVariable Long noticeId) { @@ -57,31 +63,31 @@ public class SysNoticeController extends BaseController /** * 新增通知公告 */ - @PreAuthorize("@ss.hasPermi('system:notice:add')") + @SaCheckPermission("system:notice:add") @Log(title = "通知公告", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysNotice notice) { - notice.setCreateBy(getUsername()); + notice.setCreateBy(LoginHelper.getUserId()); return toAjax(noticeService.insertNotice(notice)); } /** * 修改通知公告 */ - @PreAuthorize("@ss.hasPermi('system:notice:edit')") + @SaCheckPermission("system:notice:edit") @Log(title = "通知公告", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysNotice notice) { - notice.setUpdateBy(getUsername()); + notice.setUpdateBy(LoginHelper.getUserId()); return toAjax(noticeService.updateNotice(notice)); } /** * 删除通知公告 */ - @PreAuthorize("@ss.hasPermi('system:notice:remove')") + @SaCheckPermission("system:notice:remove") @Log(title = "通知公告", businessType = BusinessType.DELETE) @DeleteMapping("/{noticeIds}") public AjaxResult remove(@PathVariable Long[] noticeIds) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysPostController.java similarity index 74% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysPostController.java index db27691..a620385 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysPostController.java @@ -1,9 +1,16 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,31 +20,31 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.system.domain.SysPost; import com.ruoyi.system.service.ISysPostService; /** * 岗位信息操作处理 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/post") public class SysPostController extends BaseController { - @Autowired + @Resource private ISysPostService postService; /** * 获取岗位列表 */ - @PreAuthorize("@ss.hasPermi('system:post:list')") + @SaCheckPermission("system:post:list") @GetMapping("/list") public TableDataInfo list(SysPost post) { @@ -45,9 +52,9 @@ public class SysPostController extends BaseController List list = postService.selectPostList(post); return getDataTable(list); } - + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('system:post:export')") + @SaCheckPermission("system:post:export") @PostMapping("/export") public void export(HttpServletResponse response, SysPost post) { @@ -59,7 +66,7 @@ public class SysPostController extends BaseController /** * 根据岗位编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:post:query')") + @SaCheckPermission("system:post:query") @GetMapping(value = "/{postId}") public AjaxResult getInfo(@PathVariable Long postId) { @@ -69,7 +76,7 @@ public class SysPostController extends BaseController /** * 新增岗位 */ - @PreAuthorize("@ss.hasPermi('system:post:add')") + @SaCheckPermission("system:post:add") @Log(title = "岗位管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysPost post) @@ -82,14 +89,14 @@ public class SysPostController extends BaseController { return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); } - post.setCreateBy(getUsername()); + post.setCreateBy(LoginHelper.getUserId()); return toAjax(postService.insertPost(post)); } /** * 修改岗位 */ - @PreAuthorize("@ss.hasPermi('system:post:edit')") + @SaCheckPermission("system:post:edit") @Log(title = "岗位管理", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysPost post) @@ -102,14 +109,18 @@ public class SysPostController extends BaseController { return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); } - post.setUpdateBy(getUsername()); + else if (UserConstants.POST_DISABLE.equals(post.getStatus()) + && postService.countUserPostById(post.getPostId()) > 0) { + return error("该岗位下存在已分配用户,不能禁用!"); + } + post.setUpdateBy(LoginHelper.getUserId()); return toAjax(postService.updatePost(post)); } /** * 删除岗位 */ - @PreAuthorize("@ss.hasPermi('system:post:remove')") + @SaCheckPermission("system:post:remove") @Log(title = "岗位管理", businessType = BusinessType.DELETE) @DeleteMapping("/{postIds}") public AjaxResult remove(@PathVariable Long[] postIds) @@ -123,7 +134,9 @@ public class SysPostController extends BaseController @GetMapping("/optionselect") public AjaxResult optionselect() { - List posts = postService.selectPostAll(); + SysPost sysPost = new SysPost(); + sysPost.setStatus(UserConstants.POST_NORMAL); + List posts = postService.selectPostList(sysPost); return success(posts); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java similarity index 66% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java index a213ff5..85671cb 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysProfileController.java @@ -1,6 +1,13 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysUser; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -9,43 +16,38 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.ruoyi.common.core.annotation.Log; import com.ruoyi.common.core.config.RuoYiConfig; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysUser; import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.enums.BusinessType; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.file.FileUploadUtils; import com.ruoyi.common.core.utils.file.MimeTypeUtils; -import com.ruoyi.framework.web.service.TokenService; +import cn.dev33.satoken.secure.BCrypt; import com.ruoyi.system.service.ISysUserService; /** * 个人信息 业务处理 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/user/profile") public class SysProfileController extends BaseController { - @Autowired + @Resource private ISysUserService userService; - @Autowired - private TokenService tokenService; - /** * 个人信息 */ @GetMapping public AjaxResult profile() { - LoginUser loginUser = getLoginUser(); - SysUser user = loginUser.getUser(); + LoginUser loginUser = LoginHelper.getLoginUser(); + SysUser user = userService.selectUserById(loginUser.getUserId()); AjaxResult ajax = AjaxResult.success(user); ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); @@ -59,8 +61,8 @@ public class SysProfileController extends BaseController @PutMapping public AjaxResult updateProfile(@RequestBody SysUser user) { - LoginUser loginUser = getLoginUser(); - SysUser sysUser = loginUser.getUser(); + LoginUser loginUser = LoginHelper.getLoginUser(); + SysUser sysUser = userService.selectUserById(loginUser.getUserId()); user.setUserName(sysUser.getUserName()); if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { @@ -76,12 +78,12 @@ public class SysProfileController extends BaseController user.setDeptId(null); if (userService.updateUserProfile(user) > 0) { - // 更新缓存用户信息 - sysUser.setNickName(user.getNickName()); - sysUser.setPhonenumber(user.getPhonenumber()); - sysUser.setEmail(user.getEmail()); - sysUser.setSex(user.getSex()); - tokenService.setLoginUser(loginUser); +// // 更新缓存用户信息 +// sysUser.setNickName(user.getNickName()); +// sysUser.setPhonenumber(user.getPhonenumber()); +// sysUser.setEmail(user.getEmail()); +// sysUser.setSex(user.getSex()); +// tokenService.setLoginUser(loginUser); return success(); } return error("修改个人信息异常,请联系管理员"); @@ -94,22 +96,17 @@ public class SysProfileController extends BaseController @PutMapping("/updatePwd") public AjaxResult updatePwd(String oldPassword, String newPassword) { - LoginUser loginUser = getLoginUser(); - String userName = loginUser.getUsername(); - String password = loginUser.getPassword(); - if (!SecurityUtils.matchesPassword(oldPassword, password)) - { + SysUser sysUser = userService.selectUserById(LoginHelper.getUserId()); + String userName = sysUser.getUserName(); + String password = sysUser.getPassword(); + if (!BCrypt.checkpw(oldPassword, password)) { return error("修改密码失败,旧密码错误"); } - if (SecurityUtils.matchesPassword(newPassword, password)) - { + if (BCrypt.checkpw(newPassword, password)) { return error("新密码不能与旧密码相同"); } - if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) + if (userService.resetUserPwd(userName, BCrypt.hashpw(newPassword)) > 0) { - // 更新缓存用户密码 - loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); - tokenService.setLoginUser(loginUser); return success(); } return error("修改密码异常,请联系管理员"); @@ -124,15 +121,13 @@ public class SysProfileController extends BaseController { if (!file.isEmpty()) { - LoginUser loginUser = getLoginUser(); + //TODO:需要使用OSS来存储操作用户上传的头像 + SysUser sysUser = userService.selectUserById(LoginHelper.getUserId()); String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); - if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) + if (userService.updateUserAvatar(sysUser.getUserName(), avatar)) { AjaxResult ajax = AjaxResult.success(); ajax.put("imgUrl", avatar); - // 更新缓存用户头像 - loginUser.getUser().setAvatar(avatar); - tokenService.setLoginUser(loginUser); return ajax; } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysRoleController.java similarity index 76% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysRoleController.java index bd9f478..38eb739 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysRoleController.java @@ -1,9 +1,18 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysDept; +import com.ruoyi.system.domain.SysRole; +import com.ruoyi.system.domain.SysUser; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,19 +22,12 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysDept; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; import com.ruoyi.common.core.core.domain.model.LoginUser; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; -import com.ruoyi.framework.web.service.SysPermissionService; -import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.service.ISysRoleService; @@ -33,29 +35,25 @@ import com.ruoyi.system.service.ISysUserService; /** * 角色信息 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/role") public class SysRoleController extends BaseController { - @Autowired + @Resource private ISysRoleService roleService; - @Autowired - private TokenService tokenService; - - @Autowired - private SysPermissionService permissionService; - - @Autowired + @Resource private ISysUserService userService; - @Autowired + @Resource private ISysDeptService deptService; - @PreAuthorize("@ss.hasPermi('system:role:list')") + @SaCheckPermission("system:role:list") @GetMapping("/list") public TableDataInfo list(SysRole role) { @@ -65,7 +63,7 @@ public class SysRoleController extends BaseController } @Log(title = "角色管理", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('system:role:export')") + @SaCheckPermission("system:role:export") @PostMapping("/export") public void export(HttpServletResponse response, SysRole role) { @@ -77,7 +75,7 @@ public class SysRoleController extends BaseController /** * 根据角色编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:role:query')") + @SaCheckPermission("system:role:query") @GetMapping(value = "/{roleId}") public AjaxResult getInfo(@PathVariable Long roleId) { @@ -88,7 +86,7 @@ public class SysRoleController extends BaseController /** * 新增角色 */ - @PreAuthorize("@ss.hasPermi('system:role:add')") + @SaCheckPermission("system:role:add") @Log(title = "角色管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysRole role) @@ -101,7 +99,7 @@ public class SysRoleController extends BaseController { return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); } - role.setCreateBy(getUsername()); + role.setCreateBy(LoginHelper.getUserId()); return toAjax(roleService.insertRole(role)); } @@ -109,7 +107,7 @@ public class SysRoleController extends BaseController /** * 修改保存角色 */ - @PreAuthorize("@ss.hasPermi('system:role:edit')") + @SaCheckPermission("system:role:edit") @Log(title = "角色管理", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysRole role) @@ -124,18 +122,11 @@ public class SysRoleController extends BaseController { return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); } - role.setUpdateBy(getUsername()); - + role.setUpdateBy(LoginHelper.getUserId()); + if (roleService.updateRole(role) > 0) { - // 更新缓存用户权限 - LoginUser loginUser = getLoginUser(); - if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) - { - loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); - loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); - tokenService.setLoginUser(loginUser); - } + roleService.cleanOnlineUserByRole(role.getRoleId()); return success(); } return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); @@ -144,7 +135,7 @@ public class SysRoleController extends BaseController /** * 修改保存数据权限 */ - @PreAuthorize("@ss.hasPermi('system:role:edit')") + @SaCheckPermission("system:role:edit") @Log(title = "角色管理", businessType = BusinessType.UPDATE) @PutMapping("/dataScope") public AjaxResult dataScope(@RequestBody SysRole role) @@ -157,21 +148,21 @@ public class SysRoleController extends BaseController /** * 状态修改 */ - @PreAuthorize("@ss.hasPermi('system:role:edit')") + @SaCheckPermission("system:role:edit") @Log(title = "角色管理", businessType = BusinessType.UPDATE) @PutMapping("/changeStatus") public AjaxResult changeStatus(@RequestBody SysRole role) { roleService.checkRoleAllowed(role); roleService.checkRoleDataScope(role.getRoleId()); - role.setUpdateBy(getUsername()); + role.setUpdateBy(LoginHelper.getUserId()); return toAjax(roleService.updateRoleStatus(role)); } /** * 删除角色 */ - @PreAuthorize("@ss.hasPermi('system:role:remove')") + @SaCheckPermission("system:role:remove") @Log(title = "角色管理", businessType = BusinessType.DELETE) @DeleteMapping("/{roleIds}") public AjaxResult remove(@PathVariable Long[] roleIds) @@ -182,7 +173,7 @@ public class SysRoleController extends BaseController /** * 获取角色选择框列表 */ - @PreAuthorize("@ss.hasPermi('system:role:query')") + @SaCheckPermission("system:role:query") @GetMapping("/optionselect") public AjaxResult optionselect() { @@ -192,7 +183,7 @@ public class SysRoleController extends BaseController /** * 查询已分配用户角色列表 */ - @PreAuthorize("@ss.hasPermi('system:role:list')") + @SaCheckPermission("system:role:list") @GetMapping("/authUser/allocatedList") public TableDataInfo allocatedList(SysUser user) { @@ -204,7 +195,7 @@ public class SysRoleController extends BaseController /** * 查询未分配用户角色列表 */ - @PreAuthorize("@ss.hasPermi('system:role:list')") + @SaCheckPermission("system:role:list") @GetMapping("/authUser/unallocatedList") public TableDataInfo unallocatedList(SysUser user) { @@ -216,7 +207,7 @@ public class SysRoleController extends BaseController /** * 取消授权用户 */ - @PreAuthorize("@ss.hasPermi('system:role:edit')") + @SaCheckPermission("system:role:edit") @Log(title = "角色管理", businessType = BusinessType.GRANT) @PutMapping("/authUser/cancel") public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) @@ -227,7 +218,7 @@ public class SysRoleController extends BaseController /** * 批量取消授权用户 */ - @PreAuthorize("@ss.hasPermi('system:role:edit')") + @SaCheckPermission("system:role:edit") @Log(title = "角色管理", businessType = BusinessType.GRANT) @PutMapping("/authUser/cancelAll") public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) @@ -238,7 +229,7 @@ public class SysRoleController extends BaseController /** * 批量选择用户授权 */ - @PreAuthorize("@ss.hasPermi('system:role:edit')") + @SaCheckPermission("system:role:edit") @Log(title = "角色管理", businessType = BusinessType.GRANT) @PutMapping("/authUser/selectAll") public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) @@ -250,7 +241,7 @@ public class SysRoleController extends BaseController /** * 获取对应角色部门树列表 */ - @PreAuthorize("@ss.hasPermi('system:role:query')") + @SaCheckPermission("system:role:query") @GetMapping(value = "/deptTree/{roleId}") public AjaxResult deptTree(@PathVariable("roleId") Long roleId) { diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysUserController.java similarity index 59% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysUserController.java index bac62b3..b5b4883 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysUserController.java @@ -1,11 +1,26 @@ -package com.ruoyi.web.controller.system; +package com.ruoyi.system.controller.system; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.secure.BCrypt; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.utils.MapstructUtils; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.system.domain.SysDept; +import com.ruoyi.system.domain.SysPost; +import com.ruoyi.system.domain.SysRole; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.service.*; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.ArrayUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -16,167 +31,153 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.ruoyi.common.core.annotation.Log; -import com.ruoyi.common.core.core.controller.BaseController; +import com.ruoyi.common.web.core.BaseController; import com.ruoyi.common.core.core.domain.AjaxResult; -import com.ruoyi.common.core.core.domain.entity.SysDept; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; import com.ruoyi.common.core.core.page.TableDataInfo; -import com.ruoyi.common.core.enums.BusinessType; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; -import com.ruoyi.system.service.ISysDeptService; -import com.ruoyi.system.service.ISysPostService; -import com.ruoyi.system.service.ISysRoleService; -import com.ruoyi.system.service.ISysUserService; /** * 用户信息 - * + * * @author ruoyi */ +@Validated +@RequiredArgsConstructor @RestController @RequestMapping("/system/user") -public class SysUserController extends BaseController -{ - @Autowired +public class SysUserController extends BaseController { + @Resource private ISysUserService userService; - @Autowired + @Resource private ISysRoleService roleService; - @Autowired + @Resource private ISysDeptService deptService; - @Autowired + @Resource private ISysPostService postService; /** * 获取用户列表 */ - @PreAuthorize("@ss.hasPermi('system:user:list')") + @SaCheckPermission("system:user:list") @GetMapping("/list") - public TableDataInfo list(SysUser user) - { + public TableDataInfo list(SysUser user) { startPage(); List list = userService.selectUserList(user); return getDataTable(list); } + /** + * 导出用户列表 + */ @Log(title = "用户管理", businessType = BusinessType.EXPORT) - @PreAuthorize("@ss.hasPermi('system:user:export')") + @SaCheckPermission("system:user:export") @PostMapping("/export") - public void export(HttpServletResponse response, SysUser user) - { + public void export(HttpServletResponse response, SysUser user) { List list = userService.selectUserList(user); ExcelUtil util = new ExcelUtil<>(SysUser.class); util.exportExcel(response, list, "用户数据"); } + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ @Log(title = "用户管理", businessType = BusinessType.IMPORT) - @PreAuthorize("@ss.hasPermi('system:user:import')") + @SaCheckPermission("system:user:import") @PostMapping("/importData") - public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception - { + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { ExcelUtil util = new ExcelUtil<>(SysUser.class); List userList = util.importExcel(file.getInputStream()); - String operName = getUsername(); - String message = userService.importUser(userList, updateSupport, operName); + Long operId = LoginHelper.getUserId(); + //TODO 以后需要改造,使用common-excel工具ExcelUtil.importExcel导出 + String message = userService.importUser(userList, updateSupport, operId); return success(message); } @PostMapping("/importTemplate") - public void importTemplate(HttpServletResponse response) - { + public void importTemplate(HttpServletResponse response) { ExcelUtil util = new ExcelUtil<>(SysUser.class); util.importTemplateExcel(response, "用户数据"); } + /** * 根据用户编号获取详细信息 */ - @PreAuthorize("@ss.hasPermi('system:user:query')") - @GetMapping(value = { "/", "/{userId}" }) - public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) - { - userService.checkUserDataScope(userId); + @SaCheckPermission("system:user:query") + @GetMapping(value = {"/", "/{userId}"}) + public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) { AjaxResult ajax = AjaxResult.success(); - List roles = roleService.selectRoleAll(); + SysRole sysRole = new SysRole(); + sysRole.setStatus(UserConstants.ROLE_NORMAL); + List roles = roleService.selectRoleList(sysRole); + SysPost sysPost = new SysPost(); + sysPost.setStatus(UserConstants.POST_NORMAL); ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); - ajax.put("posts", postService.selectPostAll()); - if (StringUtils.isNotNull(userId)) - { - SysUser sysUser = userService.selectUserById(userId); - ajax.put(AjaxResult.DATA_TAG, sysUser); + ajax.put("posts", postService.selectPostList(sysPost)); + if (StringUtils.isNotNull(userId)) { + ajax.put(AjaxResult.DATA_TAG, userService.selectUserById(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId)); - ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); + ajax.put("roleIds", roleService.selectRoleListByUserId(userId)); } return ajax; } + /** * 新增用户 */ - @PreAuthorize("@ss.hasPermi('system:user:add')") + @SaCheckPermission("system:user:add") @Log(title = "用户管理", businessType = BusinessType.INSERT) @PostMapping - public AjaxResult add(@Validated @RequestBody SysUser user) - { - if (!userService.checkUserNameUnique(user)) - { + public AjaxResult add(@Validated @RequestBody SysUser user) { + if (!userService.checkUserNameUnique(user)) { return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); - } - else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) - { + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); - } - else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) - { + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } - user.setCreateBy(getUsername()); - user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); - return toAjax(userService.insertUser(user)); + user.setCreateBy(LoginHelper.getUserId()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + return toAjax(userService.insertUser(sysUser)); } /** * 修改用户 */ - @PreAuthorize("@ss.hasPermi('system:user:edit')") + @SaCheckPermission("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult edit(@Validated @RequestBody SysUser user) - { + public AjaxResult edit(@Validated @RequestBody SysUser user) { userService.checkUserAllowed(user); userService.checkUserDataScope(user.getUserId()); - if (!userService.checkUserNameUnique(user)) - { + if (!userService.checkUserNameUnique(user)) { return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); - } - else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) - { + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); - } - else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) - { + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } - user.setUpdateBy(getUsername()); + user.setUpdateBy(LoginHelper.getUserId()); return toAjax(userService.updateUser(user)); } /** * 删除用户 */ - @PreAuthorize("@ss.hasPermi('system:user:remove')") + @SaCheckPermission("system:user:remove") @Log(title = "用户管理", businessType = BusinessType.DELETE) @DeleteMapping("/{userIds}") - public AjaxResult remove(@PathVariable Long[] userIds) - { - if (ArrayUtils.contains(userIds, getUserId())) - { + public AjaxResult remove(@PathVariable Long[] userIds) { + if (ArrayUtils.contains(userIds, LoginHelper.getUserId())) { return error("当前用户不能删除"); } return toAjax(userService.deleteUserByIds(userIds)); @@ -185,39 +186,35 @@ public class SysUserController extends BaseController /** * 重置密码 */ - @PreAuthorize("@ss.hasPermi('system:user:resetPwd')") - @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("system:user:resetPwd") @PutMapping("/resetPwd") - public AjaxResult resetPwd(@RequestBody SysUser user) - { + public AjaxResult resetPwd(@RequestBody SysUser user) { userService.checkUserAllowed(user); userService.checkUserDataScope(user.getUserId()); - user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); - user.setUpdateBy(getUsername()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + user.setUpdateBy(LoginHelper.getUserId()); return toAjax(userService.resetPwd(user)); } /** * 状态修改 */ - @PreAuthorize("@ss.hasPermi('system:user:edit')") + @SaCheckPermission("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PutMapping("/changeStatus") - public AjaxResult changeStatus(@RequestBody SysUser user) - { + public AjaxResult changeStatus(@RequestBody SysUser user) { userService.checkUserAllowed(user); userService.checkUserDataScope(user.getUserId()); - user.setUpdateBy(getUsername()); + user.setUpdateBy(LoginHelper.getUserId()); return toAjax(userService.updateUserStatus(user)); } /** * 根据用户编号获取授权角色 */ - @PreAuthorize("@ss.hasPermi('system:user:query')") + @SaCheckPermission("system:user:query") @GetMapping("/authRole/{userId}") - public AjaxResult authRole(@PathVariable("userId") Long userId) - { + public AjaxResult authRole(@PathVariable("userId") Long userId) { AjaxResult ajax = AjaxResult.success(); SysUser user = userService.selectUserById(userId); List roles = roleService.selectRolesByUserId(userId); @@ -229,11 +226,10 @@ public class SysUserController extends BaseController /** * 用户授权角色 */ - @PreAuthorize("@ss.hasPermi('system:user:edit')") + @SaCheckPermission("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.GRANT) @PutMapping("/authRole") - public AjaxResult insertAuthRole(Long userId, Long[] roleIds) - { + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) { userService.checkUserDataScope(userId); userService.insertUserAuth(userId, roleIds); return success(); @@ -242,10 +238,11 @@ public class SysUserController extends BaseController /** * 获取部门树列表 */ - @PreAuthorize("@ss.hasPermi('system:user:list')") + @SaCheckPermission("system:user:list") @GetMapping("/deptTree") - public AjaxResult deptTree(SysDept dept) - { + public AjaxResult deptTree(SysDept dept) { return success(deptService.selectDeptTreeList(dept)); } + + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Server.java similarity index 95% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Server.java index 299b557..2396df6 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Server.java @@ -1,4 +1,4 @@ -package com.ruoyi.framework.web.domain; +package com.ruoyi.system.domain; import java.net.UnknownHostException; import java.util.LinkedList; @@ -6,11 +6,11 @@ import java.util.List; import java.util.Properties; import com.ruoyi.common.core.utils.Arith; import com.ruoyi.common.core.utils.ip.IpUtils; -import com.ruoyi.framework.web.domain.server.Cpu; -import com.ruoyi.framework.web.domain.server.Jvm; -import com.ruoyi.framework.web.domain.server.Mem; -import com.ruoyi.framework.web.domain.server.Sys; -import com.ruoyi.framework.web.domain.server.SysFile; +import com.ruoyi.system.domain.server.Cpu; +import com.ruoyi.system.domain.server.Jvm; +import com.ruoyi.system.domain.server.Mem; +import com.ruoyi.system.domain.server.Sys; +import com.ruoyi.system.domain.server.SysFile; import oshi.SystemInfo; import oshi.hardware.CentralProcessor; import oshi.hardware.CentralProcessor.TickType; @@ -23,13 +23,13 @@ import oshi.util.Util; /** * 服务器相关信息 - * + * * @author ruoyi */ public class Server { private static final int OSHI_WAIT_SECOND = 1000; - + /** * CPU相关信息 */ @@ -209,7 +209,7 @@ public class Server /** * 字节转换 - * + * * @param size 字节大小 * @return 转换后值 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysClient.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysClient.java new file mode 100644 index 0000000..2294e56 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysClient.java @@ -0,0 +1,80 @@ +package com.ruoyi.system.domain; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.common.orm.listener.EntityInsertListener; +import com.ruoyi.common.orm.listener.EntityUpdateListener; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 授权管理对象 sys_client + * + * @author dataprince数据小王子 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Table(value = "sys_client",onInsert = EntityInsertListener.class,onUpdate = EntityUpdateListener.class) +public class SysClient extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @Id() + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + private String clientKey; + + /** + * 客户端秘钥 + */ + private String clientSecret; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @Column(isLogicDelete = true) + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java index 489742a..5d322a4 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java @@ -6,15 +6,18 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; import com.ruoyi.common.core.annotation.Excel.ColumnType; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; + +import java.io.Serial; /** * 参数配置表 sys_config - * + * * @author ruoyi */ public class SysConfig extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 参数主键 */ @@ -92,7 +95,7 @@ public class SysConfig extends BaseEntity { this.configType = configType; } - + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java similarity index 92% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDept.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java index c4be0d9..6500c24 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDept.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java @@ -1,23 +1,23 @@ -package com.ruoyi.common.core.core.domain.entity; +package com.ruoyi.system.domain; +import java.io.Serial; import java.util.ArrayList; import java.util.List; - -import com.ruoyi.common.core.core.domain.BaseEntity; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 部门表 sys_dept - * + * * @author ruoyi */ public class SysDept extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 部门ID */ @@ -33,7 +33,7 @@ public class SysDept extends BaseEntity private String deptName; /** 显示顺序 */ - private Integer orderNum; + private String orderNum; /** 负责人 */ private String leader; @@ -52,7 +52,7 @@ public class SysDept extends BaseEntity /** 父部门名称 */ private String parentName; - + /** 子部门 */ private List children = new ArrayList(); @@ -98,13 +98,13 @@ public class SysDept extends BaseEntity this.deptName = deptName; } - @NotNull(message = "显示顺序不能为空") - public Integer getOrderNum() + @NotBlank(message = "显示顺序不能为空") + public String getOrderNum() { return orderNum; } - public void setOrderNum(Integer orderNum) + public void setOrderNum(String orderNum) { this.orderNum = orderNum; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDictData.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java similarity index 85% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDictData.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java index 2cf28f2..f8d7b74 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDictData.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java @@ -1,28 +1,32 @@ -package com.ruoyi.common.core.core.domain.entity; +package com.ruoyi.system.domain; -import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.core.annotation.Excel; +import com.ruoyi.common.core.annotation.Excel.ColumnType; import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.orm.core.domain.BaseEntity; + +import java.io.Serial; /** * 字典数据表 sys_dict_data - * + * * @author ruoyi */ public class SysDictData extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 字典编码 */ - @Excel(name = "字典编码", cellType = Excel.ColumnType.NUMERIC) + @Excel(name = "字典编码", cellType = ColumnType.NUMERIC) private Long dictCode; /** 字典排序 */ - @Excel(name = "字典排序", cellType = Excel.ColumnType.NUMERIC) + @Excel(name = "字典排序", cellType = ColumnType.NUMERIC) private Long dictSort; /** 字典标签 */ @@ -47,10 +51,6 @@ public class SysDictData extends BaseEntity @Excel(name = "是否默认", readConverterExp = "Y=是,N=否") private String isDefault; - /** 状态(0正常 1停用) */ - @Excel(name = "状态", readConverterExp = "0=正常,1=停用") - private String status; - public Long getDictCode() { return dictCode; @@ -130,7 +130,7 @@ public class SysDictData extends BaseEntity public boolean getDefault() { - return UserConstants.YES.equals(this.isDefault); + return UserConstants.YES.equals(this.isDefault) ? true : false; } public String getIsDefault() @@ -143,16 +143,6 @@ public class SysDictData extends BaseEntity this.isDefault = isDefault; } - public String getStatus() - { - return status; - } - - public void setStatus(String status) - { - this.status = status; - } - @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) @@ -164,7 +154,6 @@ public class SysDictData extends BaseEntity .append("cssClass", getCssClass()) .append("listClass", getListClass()) .append("isDefault", getIsDefault()) - .append("status", getStatus()) .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) .append("updateBy", getUpdateBy()) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDictType.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java similarity index 73% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDictType.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java index 00830ef..6fc0ae0 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysDictType.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java @@ -1,24 +1,27 @@ -package com.ruoyi.common.core.core.domain.entity; +package com.ruoyi.system.domain; -import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.core.annotation.Excel; +import com.ruoyi.common.core.annotation.Excel.ColumnType; +import com.ruoyi.common.orm.core.domain.BaseEntity; + +import java.io.Serial; /** * 字典类型表 sys_dict_type - * + * * @author ruoyi */ public class SysDictType extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 字典主键 */ - @Excel(name = "字典主键", cellType = Excel.ColumnType.NUMERIC) + @Excel(name = "字典主键", cellType = ColumnType.NUMERIC) private Long dictId; /** 字典名称 */ @@ -29,10 +32,6 @@ public class SysDictType extends BaseEntity @Excel(name = "字典类型") private String dictType; - /** 状态(0正常 1停用) */ - @Excel(name = "状态", readConverterExp = "0=正常,1=停用") - private String status; - public Long getDictId() { return dictId; @@ -57,7 +56,6 @@ public class SysDictType extends BaseEntity @NotBlank(message = "字典类型不能为空") @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") - @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") public String getDictType() { return dictType; @@ -68,23 +66,12 @@ public class SysDictType extends BaseEntity this.dictType = dictType; } - public String getStatus() - { - return status; - } - - public void setStatus(String status) - { - this.status = status; - } - @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) .append("dictId", getDictId()) .append("dictName", getDictName()) .append("dictType", getDictType()) - .append("status", getStatus()) .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) .append("updateBy", getUpdateBy()) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java index 506e560..e17bc60 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java @@ -1,18 +1,20 @@ package com.ruoyi.system.domain; +import java.io.Serial; import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.core.annotation.Excel; import com.ruoyi.common.core.annotation.Excel.ColumnType; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 系统访问记录表 sys_logininfor - * + * * @author ruoyi */ public class SysLogininfor extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** ID */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java similarity index 96% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysMenu.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java index 93655d1..4c3a62f 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysMenu.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java @@ -1,22 +1,23 @@ -package com.ruoyi.common.core.core.domain.entity; +package com.ruoyi.system.domain; +import java.io.Serial; import java.util.ArrayList; import java.util.List; - -import com.ruoyi.common.core.core.domain.BaseEntity; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 菜单权限表 sys_menu - * + * * @author ruoyi */ public class SysMenu extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 菜单ID */ @@ -54,8 +55,8 @@ public class SysMenu extends BaseEntity /** 显示状态(0显示 1隐藏) */ private String visible; - - /** 菜单状态(0正常 1停用) */ + + /** 菜单状态(0显示 1隐藏) */ private String status; /** 权限字符串 */ @@ -233,7 +234,7 @@ public class SysMenu extends BaseEntity { this.children = children; } - + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java index be0d2bc..0691d84 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java @@ -4,16 +4,19 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; import com.ruoyi.common.core.xss.Xss; +import java.io.Serial; + /** * 通知公告表 sys_notice - * + * * @author ruoyi */ public class SysNotice extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 公告ID */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java index bbf5c32..ac4b445 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java @@ -4,11 +4,11 @@ import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.core.annotation.Excel; import com.ruoyi.common.core.annotation.Excel.ColumnType; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; /** * 操作日志记录表 oper_log - * + * * @author ruoyi */ public class SysOperLog extends BaseEntity diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java index f67f2ab..531d2bc 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java @@ -7,15 +7,18 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.core.annotation.Excel; import com.ruoyi.common.core.annotation.Excel.ColumnType; -import com.ruoyi.common.core.core.domain.BaseEntity; +import com.ruoyi.common.orm.core.domain.BaseEntity; + +import java.io.Serial; /** * 岗位表 sys_post - * + * * @author ruoyi */ public class SysPost extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 岗位序号 */ @@ -105,7 +108,7 @@ public class SysPost extends BaseEntity { this.flag = flag; } - + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysRole.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java similarity index 93% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysRole.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java index 392666e..5c175e3 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysRole.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java @@ -1,26 +1,28 @@ -package com.ruoyi.common.core.core.domain.entity; +package com.ruoyi.system.domain; -import java.util.Set; - -import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.core.domain.BaseEntity; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.core.annotation.Excel; +import com.ruoyi.common.core.annotation.Excel.ColumnType; +import com.ruoyi.common.orm.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Set; /** * 角色表 sys_role - * + * * @author ruoyi */ public class SysRole extends BaseEntity { + @Serial private static final long serialVersionUID = 1L; /** 角色ID */ - @Excel(name = "角色序号", cellType = Excel.ColumnType.NUMERIC) + @Excel(name = "角色序号", cellType = ColumnType.NUMERIC) private Long roleId; /** 角色名称 */ @@ -33,7 +35,7 @@ public class SysRole extends BaseEntity /** 角色排序 */ @Excel(name = "角色排序") - private Integer roleSort; + private String roleSort; /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */ @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") @@ -118,13 +120,13 @@ public class SysRole extends BaseEntity this.roleKey = roleKey; } - @NotNull(message = "显示顺序不能为空") - public Integer getRoleSort() + @NotBlank(message = "显示顺序不能为空") + public String getRoleSort() { return roleSort; } - public void setRoleSort(Integer roleSort) + public void setRoleSort(String roleSort) { this.roleSort = roleSort; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java similarity index 84% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysUser.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java index 0f2db54..39dbb21 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/entity/SysUser.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java @@ -1,31 +1,36 @@ -package com.ruoyi.common.core.core.domain.entity; +package com.ruoyi.system.domain; import java.util.Date; import java.util.List; -import com.ruoyi.common.core.annotation.Excel; -import com.ruoyi.common.core.annotation.Excels; -import com.ruoyi.common.core.core.domain.BaseEntity; -import com.ruoyi.common.core.xss.Xss; +import com.ruoyi.common.tenant.core.TenantEntity; import jakarta.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.ruoyi.common.core.annotation.Excel; +import com.ruoyi.common.core.annotation.Excel.ColumnType; +import com.ruoyi.common.core.annotation.Excel.Type; +import com.ruoyi.common.core.annotation.Excels; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.common.core.xss.Xss; /** * 用户对象 sys_user - * + * * @author ruoyi */ -public class SysUser extends BaseEntity +public class SysUser extends TenantEntity { private static final long serialVersionUID = 1L; /** 用户ID */ - @Excel(name = "用户序号", cellType = Excel.ColumnType.NUMERIC, prompt = "用户编号") + @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") private Long userId; /** 部门ID */ - @Excel(name = "部门编号", type = Excel.Type.IMPORT) + @Excel(name = "部门编号", type = Type.IMPORT) private Long deptId; /** 用户账号 */ @@ -36,6 +41,11 @@ public class SysUser extends BaseEntity @Excel(name = "用户名称") private String nickName; + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + /** 用户邮箱 */ @Excel(name = "用户邮箱") private String email; @@ -54,6 +64,9 @@ public class SysUser extends BaseEntity /** 密码 */ private String password; + /** 盐加密 */ + private String salt; + /** 帐号状态(0正常 1停用) */ @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") private String status; @@ -62,17 +75,17 @@ public class SysUser extends BaseEntity private String delFlag; /** 最后登录IP */ - @Excel(name = "最后登录IP", type = Excel.Type.EXPORT) + @Excel(name = "最后登录IP", type = Type.EXPORT) private String loginIp; /** 最后登录时间 */ - @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT) + @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) private Date loginDate; /** 部门对象 */ @Excels({ - @Excel(name = "部门名称", targetAttr = "deptName", type = Excel.Type.EXPORT), - @Excel(name = "部门负责人", targetAttr = "leader", type = Excel.Type.EXPORT) + @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), + @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) }) private SysDept dept; @@ -153,6 +166,14 @@ public class SysUser extends BaseEntity this.userName = userName; } + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + @Email(message = "邮箱格式不正确") @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") public String getEmail() @@ -196,6 +217,8 @@ public class SysUser extends BaseEntity this.avatar = avatar; } + @JsonIgnore + @JsonProperty public String getPassword() { return password; @@ -206,6 +229,16 @@ public class SysUser extends BaseEntity this.password = password; } + public String getSalt() + { + return salt; + } + + public void setSalt(String salt) + { + this.salt = salt; + } + public String getStatus() { return status; @@ -303,11 +336,13 @@ public class SysUser extends BaseEntity .append("deptId", getDeptId()) .append("userName", getUserName()) .append("nickName", getNickName()) + .append("userType", getUserType()) .append("email", getEmail()) .append("phonenumber", getPhonenumber()) .append("sex", getSex()) .append("avatar", getAvatar()) .append("password", getPassword()) + .append("salt", getSalt()) .append("status", getStatus()) .append("delFlag", getDelFlag()) .append("loginIp", getLoginIp()) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java index 2bbd318..e8fa5bf 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java @@ -1,113 +1,54 @@ package com.ruoyi.system.domain; +import lombok.Data; + /** * 当前在线会话 - * - * @author ruoyi + * + * @author Lion Li */ -public class SysUserOnline -{ - /** 会话编号 */ + +@Data +public class SysUserOnline { + + /** + * 会话编号 + */ private String tokenId; - /** 部门名称 */ + /** + * 部门名称 + */ private String deptName; - /** 用户名称 */ + /** + * 用户名称 + */ private String userName; - /** 登录IP地址 */ + /** + * 登录IP地址 + */ private String ipaddr; - /** 登录地址 */ + /** + * 登录地址 + */ private String loginLocation; - /** 浏览器类型 */ + /** + * 浏览器类型 + */ private String browser; - /** 操作系统 */ + /** + * 操作系统 + */ private String os; - /** 登录时间 */ + /** + * 登录时间 + */ private Long loginTime; - public String getTokenId() - { - return tokenId; - } - - public void setTokenId(String tokenId) - { - this.tokenId = tokenId; - } - - public String getDeptName() - { - return deptName; - } - - public void setDeptName(String deptName) - { - this.deptName = deptName; - } - - public String getUserName() - { - return userName; - } - - public void setUserName(String userName) - { - this.userName = userName; - } - - public String getIpaddr() - { - return ipaddr; - } - - public void setIpaddr(String ipaddr) - { - this.ipaddr = ipaddr; - } - - public String getLoginLocation() - { - return loginLocation; - } - - public void setLoginLocation(String loginLocation) - { - this.loginLocation = loginLocation; - } - - public String getBrowser() - { - return browser; - } - - public void setBrowser(String browser) - { - this.browser = browser; - } - - public String getOs() - { - return os; - } - - public void setOs(String os) - { - this.os = os; - } - - public Long getLoginTime() - { - return loginTime; - } - - public void setLoginTime(Long loginTime) - { - this.loginTime = loginTime; - } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/TreeSelect.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/TreeSelect.java similarity index 90% rename from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/TreeSelect.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/TreeSelect.java index 3447187..55513a1 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/TreeSelect.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/TreeSelect.java @@ -1,19 +1,19 @@ -package com.ruoyi.common.core.core.domain; +package com.ruoyi.system.domain; +import java.io.Serial; import java.io.Serializable; import java.util.List; import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonInclude; -import com.ruoyi.common.core.core.domain.entity.SysDept; -import com.ruoyi.common.core.core.domain.entity.SysMenu; /** * Treeselect树结构实体类 - * + * * @author ruoyi */ public class TreeSelect implements Serializable { + @Serial private static final long serialVersionUID = 1L; /** 节点ID */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysClientBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysClientBo.java new file mode 100644 index 0000000..00ba71d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysClientBo.java @@ -0,0 +1,79 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.system.domain.SysClient; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.List; + +/** + * 授权管理业务对象 sys_client + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysClient.class, reverseConvertGenerate = false) +public class SysClientBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + @NotBlank(message = "客户端key不能为空", groups = { AddGroup.class, EditGroup.class }) + private String clientKey; + + /** + * 客户端秘钥 + */ + @NotBlank(message = "客户端秘钥不能为空", groups = { AddGroup.class, EditGroup.class }) + private String clientSecret; + + /** + * 授权类型 + */ + @NotNull(message = "授权类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysConfigBo.java new file mode 100644 index 0000000..2cfbca8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysConfigBo.java @@ -0,0 +1,62 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.system.domain.SysConfig; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import com.ruoyi.common.orm.core.domain.BaseEntity; + +/** + * 参数配置业务对象 sys_config + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false) +public class SysConfigBo extends BaseEntity { + + /** + * 参数主键 + */ + @NotNull(message = "参数主键不能为空", groups = { EditGroup.class }) + private Long configId; + + /** + * 参数名称 + */ + @NotBlank(message = "参数名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "参数名称不能超过{max}个字符") + private String configName; + + /** + * 参数键名 + */ + @NotBlank(message = "参数键名不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "参数键名长度不能超过{max}个字符") + private String configKey; + + /** + * 参数键值 + */ + @NotBlank(message = "参数键值不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 500, message = "参数键值长度不能超过{max}个字符") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDeptBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDeptBo.java new file mode 100644 index 0000000..12564cc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDeptBo.java @@ -0,0 +1,73 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysDept; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 部门业务对象 sys_dept + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDept.class, reverseConvertGenerate = false) +public class SysDeptBo extends BaseEntity { + + /** + * 部门id + */ + @NotNull(message = "部门id不能为空", groups = { EditGroup.class }) + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 30, message = "部门名称长度不能超过{max}个字符") + private String deptName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 负责人 + */ + private String leader; + + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过{max}个字符") + private String phone; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictDataBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictDataBo.java new file mode 100644 index 0000000..935f186 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictDataBo.java @@ -0,0 +1,83 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysDictData; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典数据业务对象 sys_dict_data + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDictData.class, reverseConvertGenerate = false) +public class SysDictDataBo extends BaseEntity { + + /** + * 字典编码 + */ + @NotNull(message = "字典编码不能为空", groups = { EditGroup.class }) + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + @NotBlank(message = "字典标签不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "字典标签长度不能超过{max}个字符") + private String dictLabel; + + /** + * 字典键值 + */ + @NotBlank(message = "字典键值不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "字典键值长度不能超过{max}个字符") + private String dictValue; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "字典类型长度不能超过{max}个字符") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过{max}个字符") + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictTypeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictTypeBo.java new file mode 100644 index 0000000..cdb6f68 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysDictTypeBo.java @@ -0,0 +1,53 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysDictType; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典类型业务对象 sys_dict_type + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDictType.class, reverseConvertGenerate = false) +public class SysDictTypeBo extends BaseEntity { + + /** + * 字典主键 + */ + @NotNull(message = "字典主键不能为空", groups = { EditGroup.class }) + private Long dictId; + + /** + * 字典名称 + */ + @NotBlank(message = "字典名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过{max}个字符") + private String dictName; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过{max}个字符") + @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + private String dictType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysLogininforBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysLogininforBo.java new file mode 100644 index 0000000..7209b17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysLogininforBo.java @@ -0,0 +1,77 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.system.domain.SysLogininfor; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 系统访问记录业务对象 sys_logininfor + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysLogininfor.class, reverseConvertGenerate = false) +public class SysLogininforBo { + + /** + * 访问ID + */ + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录状态(0成功 1失败) + */ + private String status; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private Date loginTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysMenuBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysMenuBo.java new file mode 100644 index 0000000..41923d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysMenuBo.java @@ -0,0 +1,111 @@ +package com.ruoyi.system.domain.bo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysMenu; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 菜单权限业务对象 sys_menu + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysMenu.class, reverseConvertGenerate = false) +public class SysMenuBo extends BaseEntity { + + /** + * 菜单ID + */ + @NotNull(message = "菜单ID不能为空", groups = { EditGroup.class }) + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 50, message = "菜单名称长度不能超过{max}个字符") + private String menuName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空", groups = { AddGroup.class, EditGroup.class }) + private Integer orderNum; + + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过{max}个字符") + private String path; + + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过{max}个字符") + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @Size(min = 0, max = 100, message = "权限标识长度不能超过{max}个字符") + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysNoticeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysNoticeBo.java new file mode 100644 index 0000000..8a57be3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysNoticeBo.java @@ -0,0 +1,65 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.xss.Xss; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysNotice; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 通知公告业务对象 sys_notice + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysNotice.class, reverseConvertGenerate = false) +public class SysNoticeBo extends BaseEntity { + + /** + * 公告ID + */ + @NotNull(message = "公告ID不能为空", groups = { EditGroup.class }) + private Long noticeId; + + /** + * 公告标题 + */ + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 50, message = "公告标题不能超过{max}个字符") + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建人名称 + */ + private String createByName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOperLogBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOperLogBo.java new file mode 100644 index 0000000..4ebdb86 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysOperLogBo.java @@ -0,0 +1,127 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.log.event.OperLogEvent; +import com.ruoyi.system.domain.SysOperLog; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMappers; +import lombok.Data; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志记录业务对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ + +@Data +@AutoMappers({ + @AutoMapper(target = SysOperLog.class, reverseConvertGenerate = false), + @AutoMapper(target = OperLogEvent.class) +}) +public class SysOperLogBo { + + /** + * 日志主键 + */ + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 模块标题 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求URL + */ + private String operUrl; + + /** + * 主机地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysPostBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysPostBo.java new file mode 100644 index 0000000..e8a1c0f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysPostBo.java @@ -0,0 +1,62 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysPost; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 岗位信息业务对象 sys_post + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysPost.class, reverseConvertGenerate = false) +public class SysPostBo extends BaseEntity { + + /** + * 岗位ID + */ + @NotNull(message = "岗位ID不能为空", groups = { EditGroup.class }) + private Long postId; + + /** + * 岗位编码 + */ + @NotBlank(message = "岗位编码不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 64, message = "岗位编码长度不能超过{max}个字符") + private String postCode; + + /** + * 岗位名称 + */ + @NotBlank(message = "岗位名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 50, message = "岗位名称长度不能超过{max}个字符") + private String postName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空", groups = { AddGroup.class, EditGroup.class }) + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysRoleBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysRoleBo.java new file mode 100644 index 0000000..34c9751 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysRoleBo.java @@ -0,0 +1,97 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import com.ruoyi.system.domain.SysRole; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 角色信息业务对象 sys_role + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysRole.class, reverseConvertGenerate = false) +public class SysRoleBo extends BaseEntity { + + /** + * 角色ID + */ + @NotNull(message = "角色ID不能为空", groups = { EditGroup.class }) + private Long roleId; + + /** + * 角色名称 + */ + @NotBlank(message = "角色名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 30, message = "角色名称长度不能超过{max}个字符") + private String roleName; + + /** + * 角色权限字符串 + */ + @NotBlank(message = "角色权限字符串不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符") + private String roleKey; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空", groups = { AddGroup.class, EditGroup.class }) + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单组 + */ + private Long[] menuIds; + + /** + * 部门组(数据权限) + */ + private Long[] deptIds; + + public SysRoleBo(Long roleId) { + this.roleId = roleId; + } + + public boolean isSuperAdmin() { + return UserConstants.SUPER_ADMIN_ID.equals(this.roleId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java new file mode 100644 index 0000000..c98146d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserBo.java @@ -0,0 +1,114 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.tenant.core.TenantEntity; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.xss.Xss; +import com.ruoyi.system.domain.SysUser; + +/** + * 用户信息业务对象 sys_user + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysUser.class) +public class SysUserBo extends TenantEntity { + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") + private String userName; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @NotBlank(message = "用户昵称不能为空") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 密码 + */ + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 角色组 + */ + @Size(min = 1, message = "用户角色不能为空") + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + public SysUserBo(Long userId) { + this.userId = userId; + } + + public boolean isSuperAdmin() { + return UserConstants.SUPER_ADMIN_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java new file mode 100644 index 0000000..9879fec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysUserProfileBo.java @@ -0,0 +1,55 @@ +package com.ruoyi.system.domain.bo; + +import com.mybatisflex.annotation.ColumnMask; +import com.mybatisflex.core.mask.Masks; +import com.ruoyi.common.core.xss.Xss; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 个人信息业务处理 + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SysUserProfileBo extends BaseEntity { + + /** + * 用户ID + */ + private Long userId; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户邮箱 + */ + @ColumnMask(Masks.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + @ColumnMask(Masks.MOBILE) + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Cpu.java similarity index 96% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Cpu.java index d9ef7ed..e4d72f2 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Cpu.java @@ -1,10 +1,10 @@ -package com.ruoyi.framework.web.domain.server; +package com.ruoyi.system.domain.server; import com.ruoyi.common.core.utils.Arith; /** * CPU相关信息 - * + * * @author ruoyi */ public class Cpu diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Jvm.java similarity index 97% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Jvm.java index 9c94b9a..bec722f 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Jvm.java @@ -1,4 +1,4 @@ -package com.ruoyi.framework.web.domain.server; +package com.ruoyi.system.domain.server; import java.lang.management.ManagementFactory; import com.ruoyi.common.core.utils.Arith; @@ -6,7 +6,7 @@ import com.ruoyi.common.core.utils.DateUtils; /** * JVM相关信息 - * + * * @author ruoyi */ public class Jvm diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Mem.java similarity index 94% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Mem.java index 349cd30..9d993f1 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Mem.java @@ -1,10 +1,10 @@ -package com.ruoyi.framework.web.domain.server; +package com.ruoyi.system.domain.server; import com.ruoyi.common.core.utils.Arith; /** * 內存相关信息 - * + * * @author ruoyi */ public class Mem diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Sys.java similarity index 95% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Sys.java index 45d64d9..d5f07b5 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/Sys.java @@ -1,8 +1,8 @@ -package com.ruoyi.framework.web.domain.server; +package com.ruoyi.system.domain.server; /** * 系统相关信息 - * + * * @author ruoyi */ public class Sys diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/SysFile.java similarity index 96% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java rename to ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/SysFile.java index 1320cde..5249574 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/server/SysFile.java @@ -1,8 +1,8 @@ -package com.ruoyi.framework.web.domain.server; +package com.ruoyi.system.domain.server; /** * 系统文件相关信息 - * + * * @author ruoyi */ public class SysFile diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AvatarVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AvatarVo.java new file mode 100644 index 0000000..7a2bb16 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AvatarVo.java @@ -0,0 +1,18 @@ +package com.ruoyi.system.domain.vo; + +import lombok.Data; + +/** + * 用户头像信息 + * + * @author Michelle.Chung + */ +@Data +public class AvatarVo { + + /** + * 头像地址 + */ + private String imgUrl; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CacheListInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CacheListInfoVo.java new file mode 100644 index 0000000..a8773a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CacheListInfoVo.java @@ -0,0 +1,23 @@ +package com.ruoyi.system.domain.vo; + +import lombok.Data; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * 缓存监控列表信息 + * + * @author Michelle.Chung + */ +@Data +public class CacheListInfoVo { + + private Properties info; + + private Long dbSize; + + private List> commandStats; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeptTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeptTreeSelectVo.java new file mode 100644 index 0000000..14c00f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeptTreeSelectVo.java @@ -0,0 +1,26 @@ +package com.ruoyi.system.domain.vo; + +import cn.hutool.core.lang.tree.Tree; +import lombok.Data; + +import java.util.List; + +/** + * 角色部门列表树信息 + * + * @author Michelle.Chung + */ +@Data +public class DeptTreeSelectVo { + + /** + * 选中部门列表 + */ + private List checkedKeys; + + /** + * 下拉树结构列表 + */ + private List> depts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuTreeSelectVo.java new file mode 100644 index 0000000..2ddce77 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuTreeSelectVo.java @@ -0,0 +1,26 @@ +package com.ruoyi.system.domain.vo; + +import cn.hutool.core.lang.tree.Tree; +import lombok.Data; + +import java.util.List; + +/** + * 角色菜单列表树信息 + * + * @author Michelle.Chung + */ +@Data +public class MenuTreeSelectVo { + + /** + * 选中菜单列表 + */ + private List checkedKeys; + + /** + * 菜单下拉树结构列表 + */ + private List> menus; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ProfileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ProfileVo.java new file mode 100644 index 0000000..a7f557c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ProfileVo.java @@ -0,0 +1,29 @@ +package com.ruoyi.system.domain.vo; + +import lombok.Data; + +/** + * 用户个人信息 + * + * @author Michelle.Chung + */ +@Data +public class ProfileVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 用户所属角色组 + */ + private String roleGroup; + + /** + * 用户所属岗位组 + */ + private String postGroup; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysClientVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysClientVo.java new file mode 100644 index 0000000..5cb31dc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysClientVo.java @@ -0,0 +1,90 @@ +package com.ruoyi.system.domain.vo; + +import com.ruoyi.system.domain.SysClient; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 授权管理视图对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysClient.class) +public class SysClientVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 客户端id + */ + @ExcelProperty(value = "客户端id") + private String clientId; + + /** + * 客户端key + */ + @ExcelProperty(value = "客户端key") + private String clientKey; + + /** + * 客户端秘钥 + */ + @ExcelProperty(value = "客户端秘钥") + private String clientSecret; + + /** + * 授权类型 + */ + @ExcelProperty(value = "授权类型") + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + @ExcelProperty(value = "token活跃超时时间") + private Long activeTimeout; + + /** + * token固定超时时间 + */ + @ExcelProperty(value = "token固定超时时间") + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysConfigVo.java new file mode 100644 index 0000000..0edaa84 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysConfigVo.java @@ -0,0 +1,72 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysConfig; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 参数配置视图对象 sys_config + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysConfig.class) +public class SysConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 参数主键 + */ + @ExcelProperty(value = "参数主键") + private Long configId; + + /** + * 参数名称 + */ + @ExcelProperty(value = "参数名称") + private String configName; + + /** + * 参数键名 + */ + @ExcelProperty(value = "参数键名") + private String configKey; + + /** + * 参数键值 + */ + @ExcelProperty(value = "参数键值") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + @ExcelProperty(value = "系统内置", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String configType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDeptVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDeptVo.java new file mode 100644 index 0000000..71027e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDeptVo.java @@ -0,0 +1,91 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysDept; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 部门视图对象 sys_dept + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDept.class) +public class SysDeptVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 父部门id + */ + private Long parentId; + + /** + * 父部门名称 + */ + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String leader; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 邮箱 + */ + @ExcelProperty(value = "邮箱") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + @ExcelProperty(value = "部门状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictDataVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictDataVo.java new file mode 100644 index 0000000..56fd6d5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictDataVo.java @@ -0,0 +1,88 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysDictData; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 字典数据视图对象 sys_dict_data + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictData.class) +public class SysDictDataVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + private Long dictCode; + + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + private Integer dictSort; + + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + private String dictLabel; + + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + private String dictValue; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictTypeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictTypeVo.java new file mode 100644 index 0000000..2ff6923 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysDictTypeVo.java @@ -0,0 +1,59 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysDictType; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 字典类型视图对象 sys_dict_type + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictType.class) +public class SysDictTypeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + private Long dictId; + + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + private String dictName; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysLogininforVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysLogininforVo.java new file mode 100644 index 0000000..7cd0e46 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysLogininforVo.java @@ -0,0 +1,92 @@ +package com.ruoyi.system.domain.vo; + +import java.util.Date; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysLogininfor; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + + +/** + * 系统访问记录视图对象 sys_logininfor + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysLogininfor.class) +public class SysLogininforVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 访问ID + */ + @ExcelProperty(value = "序号") + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + + /** + * 登录状态(0成功 1失败) + */ + @ExcelProperty(value = "登录状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; + + /** + * 登录IP地址 + */ + @ExcelProperty(value = "登录地址") + private String ipaddr; + + /** + * 登录地点 + */ + @ExcelProperty(value = "登录地点") + private String loginLocation; + + /** + * 浏览器类型 + */ + @ExcelProperty(value = "浏览器") + private String browser; + + /** + * 操作系统 + */ + @ExcelProperty(value = "操作系统") + private String os; + + + /** + * 提示消息 + */ + @ExcelProperty(value = "提示消息") + private String msg; + + /** + * 访问时间 + */ + @ExcelProperty(value = "访问时间") + private Date loginTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysMenuVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysMenuVo.java new file mode 100644 index 0000000..0131c50 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysMenuVo.java @@ -0,0 +1,116 @@ +package com.ruoyi.system.domain.vo; + +import com.ruoyi.system.domain.SysMenu; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +/** + * 菜单权限视图对象 sys_menu + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysMenu.class) +public class SysMenuVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 子菜单 + */ + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysNoticeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysNoticeVo.java new file mode 100644 index 0000000..57a20d0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysNoticeVo.java @@ -0,0 +1,73 @@ +package com.ruoyi.system.domain.vo; + +import com.ruoyi.common.translation.annotation.Translation; +import com.ruoyi.common.translation.constant.TransConstant; +import com.ruoyi.system.domain.SysNotice; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 通知公告视图对象 sys_notice + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysNotice.class) +public class SysNoticeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVo.java new file mode 100644 index 0000000..3c67c73 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVo.java @@ -0,0 +1,144 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysOperLog; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 操作日志记录视图对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOperLog.class) +public class SysOperLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 模块标题 + */ + @ExcelProperty(value = "操作模块") + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + @ExcelProperty(value = "业务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_oper_type") + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + @ExcelProperty(value = "请求方法") + private String method; + + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @ExcelProperty(value = "操作类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 请求URL + */ + @ExcelProperty(value = "请求地址") + private String operUrl; + + /** + * 主机地址 + */ + @ExcelProperty(value = "操作地址") + private String operIp; + + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private Integer status; + + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private Date operTime; + + /** + * 消耗时间 + */ + @ExcelProperty(value = "消耗时间") + private Long costTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysPostVo.java new file mode 100644 index 0000000..2c9f5e7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysPostVo.java @@ -0,0 +1,73 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysPost; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 岗位信息视图对象 sys_post + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysPost.class) +public class SysPostVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + @ExcelProperty(value = "岗位序号") + private Long postId; + + /** + * 岗位编码 + */ + @ExcelProperty(value = "岗位编码") + private String postCode; + + /** + * 岗位名称 + */ + @ExcelProperty(value = "岗位名称") + private String postName; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "岗位排序") + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysRoleVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysRoleVo.java new file mode 100644 index 0000000..06f97a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysRoleVo.java @@ -0,0 +1,100 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import com.ruoyi.system.domain.SysRole; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 角色信息视图对象 sys_role + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysRole.class) +public class SysRoleVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + private Long roleId; + + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + private String roleName; + + /** + * 角色权限字符串 + */ + @ExcelProperty(value = "角色权限") + private String roleKey; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "角色排序") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + @ExcelProperty(value = "菜单树选择项是否关联显示") + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + @ExcelProperty(value = "部门树选择项是否关联显示") + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 用户是否存在此角色标识 默认不存在 + */ + private boolean flag = false; + + public boolean isSuperAdmin() { + return UserConstants.SUPER_ADMIN_ID.equals(this.roleId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java new file mode 100644 index 0000000..3135cf8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserExportVo.java @@ -0,0 +1,99 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.ReverseAutoMapping; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 用户对象导出VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@AutoMapper(target = SysUserVo.class, convertGenerate = false) +public class SysUserExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 最后登录IP + */ + @ExcelProperty(value = "最后登录IP") + private String loginIp; + + /** + * 最后登录时间 + */ + @ExcelProperty(value = "最后登录时间") + private Date loginDate; + + /** + * 部门名称 + */ + @ReverseAutoMapping(target = "deptName", source = "dept.deptName") + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 负责人 + */ + @ReverseAutoMapping(target = "leader", source = "dept.leader") + @ExcelProperty(value = "部门负责人") + private String leader; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java new file mode 100644 index 0000000..e38a8dd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserImportVo.java @@ -0,0 +1,76 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.excel.annotation.ExcelDictFormat; +import com.ruoyi.common.excel.convert.ExcelDictConvert; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户对象导入VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +// @Accessors(chain = true) // 导入不允许使用 会找不到set方法 +public class SysUserImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 部门ID + */ + @ExcelProperty(value = "部门编号") + private Long deptId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserInfoVo.java new file mode 100644 index 0000000..d675a08 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserInfoVo.java @@ -0,0 +1,40 @@ +package com.ruoyi.system.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 用户信息 + * + * @author Michelle.Chung + */ +@Data +public class SysUserInfoVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 角色ID列表 + */ + private List roleIds; + + /** + * 角色列表 + */ + private List roles; + + /** + * 岗位ID列表 + */ + private List postIds; + + /** + * 岗位列表 + */ + private List posts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java new file mode 100644 index 0000000..616d04f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVo.java @@ -0,0 +1,141 @@ +package com.ruoyi.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.mybatisflex.annotation.ColumnMask; +import com.mybatisflex.core.mask.Masks; +import com.ruoyi.common.translation.annotation.Translation; +import com.ruoyi.common.translation.constant.TransConstant; +import com.ruoyi.system.domain.SysUser; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 用户信息视图对象 sys_user + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysUser.class) +public class SysUserVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户、app_user手机端用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @ColumnMask(Masks.EMAIL) + private String email; + + /** + * 手机号码 + */ + @ColumnMask(Masks.MOBILE) + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 头像地址 + */ + @Translation(type = TransConstant.OSS_ID_TO_URL) + private Long avatar; + + /** + * 密码 + */ + @JsonIgnore + @JsonProperty + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private Date loginDate; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 部门对象 + */ + private SysDeptVo dept; + + /** + * 角色对象 + */ + private List roles; + + /** + * 角色组 + */ + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserInfoVo.java new file mode 100644 index 0000000..a747efb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserInfoVo.java @@ -0,0 +1,30 @@ +package com.ruoyi.system.domain.vo; + +import lombok.Data; + +import java.util.Set; + +/** + * 登录用户信息 + * + * @author Michelle.Chung + */ +@Data +public class UserInfoVo { + + /** + * 用户基本信息 + */ + private SysUserVo user; + + /** + * 菜单权限 + */ + private Set permissions; + + /** + * 角色权限 + */ + private Set roles; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysClientMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysClientMapper.java new file mode 100644 index 0000000..1c45ccf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysClientMapper.java @@ -0,0 +1,17 @@ +package com.ruoyi.system.mapper; + +import com.ruoyi.system.domain.SysClient; +import com.mybatisflex.core.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 系统授权表 映射层。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@Mapper +public interface SysClientMapper extends BaseMapper { + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java index 9930c16..fd40ab6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java @@ -1,19 +1,20 @@ package com.ruoyi.system.mapper; import java.util.List; + +import com.ruoyi.system.domain.SysDept; import org.apache.ibatis.annotations.Param; -import com.ruoyi.common.core.core.domain.entity.SysDept; /** * 部门管理 数据层 - * + * * @author ruoyi */ public interface SysDeptMapper { /** * 查询部门管理数据 - * + * * @param dept 部门信息 * @return 部门信息集合 */ @@ -21,7 +22,7 @@ public interface SysDeptMapper /** * 根据角色ID查询部门树信息 - * + * * @param roleId 角色ID * @param deptCheckStrictly 部门树选择项是否关联显示 * @return 选中部门列表 @@ -30,7 +31,7 @@ public interface SysDeptMapper /** * 根据部门ID查询信息 - * + * * @param deptId 部门ID * @return 部门信息 */ @@ -38,7 +39,7 @@ public interface SysDeptMapper /** * 根据ID查询所有子部门 - * + * * @param deptId 部门ID * @return 部门列表 */ @@ -46,7 +47,7 @@ public interface SysDeptMapper /** * 根据ID查询所有子部门(正常状态) - * + * * @param deptId 部门ID * @return 子部门数 */ @@ -54,7 +55,7 @@ public interface SysDeptMapper /** * 是否存在子节点 - * + * * @param deptId 部门ID * @return 结果 */ @@ -62,7 +63,7 @@ public interface SysDeptMapper /** * 查询部门是否存在用户 - * + * * @param deptId 部门ID * @return 结果 */ @@ -70,7 +71,7 @@ public interface SysDeptMapper /** * 校验部门名称是否唯一 - * + * * @param deptName 部门名称 * @param parentId 父部门ID * @return 结果 @@ -79,7 +80,7 @@ public interface SysDeptMapper /** * 新增部门信息 - * + * * @param dept 部门信息 * @return 结果 */ @@ -87,7 +88,7 @@ public interface SysDeptMapper /** * 修改部门信息 - * + * * @param dept 部门信息 * @return 结果 */ @@ -95,14 +96,14 @@ public interface SysDeptMapper /** * 修改所在部门正常状态 - * + * * @param deptIds 部门ID组 */ void updateDeptStatusNormal(Long[] deptIds); /** * 修改子元素关系 - * + * * @param depts 子元素 * @return 结果 */ @@ -110,7 +111,7 @@ public interface SysDeptMapper /** * 删除部门管理信息 - * + * * @param deptId 部门ID * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java index 1582d8f..4986481 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java @@ -1,19 +1,20 @@ package com.ruoyi.system.mapper; import java.util.List; + +import com.ruoyi.system.domain.SysDictData; import org.apache.ibatis.annotations.Param; -import com.ruoyi.common.core.core.domain.entity.SysDictData; /** * 字典表 数据层 - * + * * @author ruoyi */ public interface SysDictDataMapper { /** * 根据条件分页查询字典数据 - * + * * @param dictData 字典数据信息 * @return 字典数据集合信息 */ @@ -21,7 +22,7 @@ public interface SysDictDataMapper /** * 根据字典类型查询字典数据 - * + * * @param dictType 字典类型 * @return 字典数据集合信息 */ @@ -29,7 +30,7 @@ public interface SysDictDataMapper /** * 根据字典类型和字典键值查询字典数据信息 - * + * * @param dictType 字典类型 * @param dictValue 字典键值 * @return 字典标签 @@ -38,7 +39,7 @@ public interface SysDictDataMapper /** * 根据字典数据ID查询信息 - * + * * @param dictCode 字典数据ID * @return 字典数据 */ @@ -46,7 +47,7 @@ public interface SysDictDataMapper /** * 查询字典数据 - * + * * @param dictType 字典类型 * @return 字典数据 */ @@ -54,7 +55,7 @@ public interface SysDictDataMapper /** * 通过字典ID删除字典数据信息 - * + * * @param dictCode 字典数据ID * @return 结果 */ @@ -62,7 +63,7 @@ public interface SysDictDataMapper /** * 批量删除字典数据信息 - * + * * @param dictCodes 需要删除的字典数据ID * @return 结果 */ @@ -70,7 +71,7 @@ public interface SysDictDataMapper /** * 新增字典数据信息 - * + * * @param dictData 字典数据信息 * @return 结果 */ @@ -78,7 +79,7 @@ public interface SysDictDataMapper /** * 修改字典数据信息 - * + * * @param dictData 字典数据信息 * @return 结果 */ @@ -86,7 +87,7 @@ public interface SysDictDataMapper /** * 同步修改字典类型 - * + * * @param oldDictType 旧字典类型 * @param newDictType 新旧字典类型 * @return 结果 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java index 817e4b8..ae47b41 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java @@ -1,18 +1,19 @@ package com.ruoyi.system.mapper; +import com.ruoyi.system.domain.SysDictType; + import java.util.List; -import com.ruoyi.common.core.core.domain.entity.SysDictType; /** * 字典表 数据层 - * + * * @author ruoyi */ public interface SysDictTypeMapper { /** * 根据条件分页查询字典类型 - * + * * @param dictType 字典类型信息 * @return 字典类型集合信息 */ @@ -20,14 +21,14 @@ public interface SysDictTypeMapper /** * 根据所有字典类型 - * + * * @return 字典类型集合信息 */ List selectDictTypeAll(); /** * 根据字典类型ID查询信息 - * + * * @param dictId 字典类型ID * @return 字典类型 */ @@ -35,7 +36,7 @@ public interface SysDictTypeMapper /** * 根据字典类型查询信息 - * + * * @param dictType 字典类型 * @return 字典类型 */ @@ -43,7 +44,7 @@ public interface SysDictTypeMapper /** * 通过字典ID删除字典信息 - * + * * @param dictId 字典ID * @return 结果 */ @@ -51,7 +52,7 @@ public interface SysDictTypeMapper /** * 批量删除字典类型信息 - * + * * @param dictIds 需要删除的字典ID * @return 结果 */ @@ -59,7 +60,7 @@ public interface SysDictTypeMapper /** * 新增字典类型信息 - * + * * @param dictType 字典类型信息 * @return 结果 */ @@ -67,7 +68,7 @@ public interface SysDictTypeMapper /** * 修改字典类型信息 - * + * * @param dictType 字典类型信息 * @return 结果 */ @@ -75,7 +76,7 @@ public interface SysDictTypeMapper /** * 校验字典类型称是否唯一 - * + * * @param dictType 字典类型 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java index 5e72183..b86aeeb 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java @@ -1,8 +1,9 @@ package com.ruoyi.system.mapper; import java.util.List; + +import com.ruoyi.system.domain.SysMenu; import org.apache.ibatis.annotations.Param; -import com.ruoyi.common.core.core.domain.entity.SysMenu; /** * 菜单表 数据层 @@ -36,7 +37,7 @@ public interface SysMenuMapper /** * 根据角色ID查询权限 - * + * * @param roleId 角色ID * @return 权限列表 */ @@ -67,7 +68,7 @@ public interface SysMenuMapper /** * 根据角色ID查询菜单树信息 - * + * * @param roleId 角色ID * @param menuCheckStrictly 菜单树选择项是否关联显示 * @return 选中菜单列表 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java index a10147e..323cf21 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java @@ -1,18 +1,19 @@ package com.ruoyi.system.mapper; +import com.ruoyi.system.domain.SysRole; + import java.util.List; -import com.ruoyi.common.core.core.domain.entity.SysRole; /** * 角色表 数据层 - * + * * @author ruoyi */ public interface SysRoleMapper { /** * 根据条件分页查询角色数据 - * + * * @param role 角色信息 * @return 角色数据集合信息 */ @@ -20,7 +21,7 @@ public interface SysRoleMapper /** * 根据用户ID查询角色 - * + * * @param userId 用户ID * @return 角色列表 */ @@ -28,14 +29,14 @@ public interface SysRoleMapper /** * 查询所有角色 - * + * * @return 角色列表 */ List selectRoleAll(); /** * 根据用户ID获取角色选择框列表 - * + * * @param userId 用户ID * @return 选中角色ID列表 */ @@ -43,7 +44,7 @@ public interface SysRoleMapper /** * 通过角色ID查询角色 - * + * * @param roleId 角色ID * @return 角色对象信息 */ @@ -51,7 +52,7 @@ public interface SysRoleMapper /** * 根据用户ID查询角色 - * + * * @param userName 用户名 * @return 角色列表 */ @@ -59,7 +60,7 @@ public interface SysRoleMapper /** * 校验角色名称是否唯一 - * + * * @param roleName 角色名称 * @return 角色信息 */ @@ -67,7 +68,7 @@ public interface SysRoleMapper /** * 校验角色权限是否唯一 - * + * * @param roleKey 角色权限 * @return 角色信息 */ @@ -75,7 +76,7 @@ public interface SysRoleMapper /** * 修改角色信息 - * + * * @param role 角色信息 * @return 结果 */ @@ -83,7 +84,7 @@ public interface SysRoleMapper /** * 新增角色信息 - * + * * @param role 角色信息 * @return 结果 */ @@ -91,7 +92,7 @@ public interface SysRoleMapper /** * 通过角色ID删除角色 - * + * * @param roleId 角色ID * @return 结果 */ @@ -99,7 +100,7 @@ public interface SysRoleMapper /** * 批量删除角色信息 - * + * * @param roleIds 需要删除的角色ID * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java index 0cf0198..f4171b8 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java @@ -1,19 +1,21 @@ package com.ruoyi.system.mapper; import java.util.List; + +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.vo.SysUserVo; import org.apache.ibatis.annotations.Param; -import com.ruoyi.common.core.core.domain.entity.SysUser; /** * 用户表 数据层 - * + * * @author ruoyi */ public interface SysUserMapper { /** * 根据条件分页查询用户列表 - * + * * @param sysUser 用户信息 * @return 用户信息集合信息 */ @@ -21,7 +23,7 @@ public interface SysUserMapper /** * 根据条件分页查询已配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -29,7 +31,7 @@ public interface SysUserMapper /** * 根据条件分页查询未分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -37,15 +39,23 @@ public interface SysUserMapper /** * 通过用户名查询用户 - * + * * @param userName 用户名 * @return 用户对象信息 */ SysUser selectUserByUserName(String userName); + /** + * 通过邮箱查询用户 + * + * @param email 邮箱 + * @return 用户对象信息 + */ + SysUser selectUserByEmail(String email); + /** * 通过用户ID查询用户 - * + * * @param userId 用户ID * @return 用户对象信息 */ @@ -53,7 +63,7 @@ public interface SysUserMapper /** * 新增用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -61,7 +71,7 @@ public interface SysUserMapper /** * 修改用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -69,7 +79,7 @@ public interface SysUserMapper /** * 修改用户头像 - * + * * @param userName 用户名 * @param avatar 头像地址 * @return 结果 @@ -78,7 +88,7 @@ public interface SysUserMapper /** * 重置用户密码 - * + * * @param userName 用户名 * @param password 密码 * @return 结果 @@ -87,7 +97,7 @@ public interface SysUserMapper /** * 通过用户ID删除用户 - * + * * @param userId 用户ID * @return 结果 */ @@ -95,7 +105,7 @@ public interface SysUserMapper /** * 批量删除用户信息 - * + * * @param userIds 需要删除的用户ID * @return 结果 */ @@ -103,7 +113,7 @@ public interface SysUserMapper /** * 校验用户名称是否唯一 - * + * * @param userName 用户名称 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysClientService.java new file mode 100644 index 0000000..946b642 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysClientService.java @@ -0,0 +1,15 @@ +package com.ruoyi.system.service; + + +import com.ruoyi.system.domain.SysClient; +import com.mybatisflex.core.service.IService; + +/** + * 系统授权表 服务层。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +public interface ISysClientService extends IService { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java index b307776..ec1e86f 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java @@ -5,14 +5,14 @@ import com.ruoyi.system.domain.SysConfig; /** * 参数配置 服务层 - * + * * @author ruoyi */ public interface ISysConfigService { /** * 查询参数配置信息 - * + * * @param configId 参数配置ID * @return 参数配置信息 */ @@ -20,7 +20,7 @@ public interface ISysConfigService /** * 根据键名查询参数配置信息 - * + * * @param configKey 参数键名 * @return 参数键值 */ @@ -28,14 +28,14 @@ public interface ISysConfigService /** * 获取验证码开关 - * + * * @return true开启,false关闭 */ public boolean selectCaptchaEnabled(); /** * 查询参数配置列表 - * + * * @param config 参数配置信息 * @return 参数配置集合 */ @@ -43,7 +43,7 @@ public interface ISysConfigService /** * 新增参数配置 - * + * * @param config 参数配置信息 * @return 结果 */ @@ -51,7 +51,7 @@ public interface ISysConfigService /** * 修改参数配置 - * + * * @param config 参数配置信息 * @return 结果 */ @@ -59,21 +59,11 @@ public interface ISysConfigService /** * 批量删除参数信息 - * + * * @param configIds 需要删除的参数ID */ public void deleteConfigByIds(Long[] configIds); - /** - * 加载参数缓存数据 - */ - public void loadingConfigCache(); - - /** - * 清空参数缓存数据 - */ - public void clearConfigCache(); - /** * 重置参数缓存数据 */ @@ -81,7 +71,7 @@ public interface ISysConfigService /** * 校验参数键名是否唯一 - * + * * @param config 参数信息 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java index c6e1bc1..f8ef496 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java @@ -1,19 +1,19 @@ package com.ruoyi.system.service; import java.util.List; -import com.ruoyi.common.core.core.domain.TreeSelect; -import com.ruoyi.common.core.core.domain.entity.SysDept; +import com.ruoyi.system.domain.TreeSelect; +import com.ruoyi.system.domain.SysDept; /** * 部门管理 服务层 - * + * * @author ruoyi */ public interface ISysDeptService { /** * 查询部门管理数据 - * + * * @param dept 部门信息 * @return 部门信息集合 */ @@ -21,7 +21,7 @@ public interface ISysDeptService /** * 查询部门树结构信息 - * + * * @param dept 部门信息 * @return 部门树信息集合 */ @@ -29,7 +29,7 @@ public interface ISysDeptService /** * 构建前端所需要树结构 - * + * * @param depts 部门列表 * @return 树结构列表 */ @@ -37,7 +37,7 @@ public interface ISysDeptService /** * 构建前端所需要下拉树结构 - * + * * @param depts 部门列表 * @return 下拉树结构列表 */ @@ -45,7 +45,7 @@ public interface ISysDeptService /** * 根据角色ID查询部门树信息 - * + * * @param roleId 角色ID * @return 选中部门列表 */ @@ -53,7 +53,7 @@ public interface ISysDeptService /** * 根据部门ID查询信息 - * + * * @param deptId 部门ID * @return 部门信息 */ @@ -61,7 +61,7 @@ public interface ISysDeptService /** * 根据ID查询所有子部门(正常状态) - * + * * @param deptId 部门ID * @return 子部门数 */ @@ -69,7 +69,7 @@ public interface ISysDeptService /** * 是否存在部门子节点 - * + * * @param deptId 部门ID * @return 结果 */ @@ -77,7 +77,7 @@ public interface ISysDeptService /** * 查询部门是否存在用户 - * + * * @param deptId 部门ID * @return 结果 true 存在 false 不存在 */ @@ -85,7 +85,7 @@ public interface ISysDeptService /** * 校验部门名称是否唯一 - * + * * @param dept 部门信息 * @return 结果 */ @@ -93,14 +93,14 @@ public interface ISysDeptService /** * 校验部门是否有数据权限 - * + * * @param deptId 部门id */ void checkDeptDataScope(Long deptId); /** * 新增保存部门信息 - * + * * @param dept 部门信息 * @return 结果 */ @@ -108,7 +108,7 @@ public interface ISysDeptService /** * 修改保存部门信息 - * + * * @param dept 部门信息 * @return 结果 */ @@ -116,7 +116,7 @@ public interface ISysDeptService /** * 删除部门管理信息 - * + * * @param deptId 部门ID * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java index 93d0d16..2806d5b 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java @@ -1,18 +1,19 @@ package com.ruoyi.system.service; +import com.ruoyi.system.domain.SysDictData; + import java.util.List; -import com.ruoyi.common.core.core.domain.entity.SysDictData; /** * 字典 业务层 - * + * * @author ruoyi */ public interface ISysDictDataService { /** * 根据条件分页查询字典数据 - * + * * @param dictData 字典数据信息 * @return 字典数据集合信息 */ @@ -20,7 +21,7 @@ public interface ISysDictDataService /** * 根据字典类型和字典键值查询字典数据信息 - * + * * @param dictType 字典类型 * @param dictValue 字典键值 * @return 字典标签 @@ -29,7 +30,7 @@ public interface ISysDictDataService /** * 根据字典数据ID查询信息 - * + * * @param dictCode 字典数据ID * @return 字典数据 */ @@ -37,14 +38,14 @@ public interface ISysDictDataService /** * 批量删除字典数据信息 - * + * * @param dictCodes 需要删除的字典数据ID */ void deleteDictDataByIds(Long[] dictCodes); /** * 新增保存字典数据信息 - * + * * @param dictData 字典数据信息 * @return 结果 */ @@ -52,7 +53,7 @@ public interface ISysDictDataService /** * 修改保存字典数据信息 - * + * * @param dictData 字典数据信息 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java index 8ec28a7..4a98b2f 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java @@ -1,19 +1,20 @@ package com.ruoyi.system.service; +import com.ruoyi.system.domain.SysDictData; +import com.ruoyi.system.domain.SysDictType; + import java.util.List; -import com.ruoyi.common.core.core.domain.entity.SysDictData; -import com.ruoyi.common.core.core.domain.entity.SysDictType; /** * 字典 业务层 - * + * * @author ruoyi */ public interface ISysDictTypeService { /** * 根据条件分页查询字典类型 - * + * * @param dictType 字典类型信息 * @return 字典类型集合信息 */ @@ -21,14 +22,14 @@ public interface ISysDictTypeService /** * 根据所有字典类型 - * + * * @return 字典类型集合信息 */ List selectDictTypeAll(); /** * 根据字典类型查询字典数据 - * + * * @param dictType 字典类型 * @return 字典数据集合信息 */ @@ -36,7 +37,7 @@ public interface ISysDictTypeService /** * 根据字典类型ID查询信息 - * + * * @param dictId 字典类型ID * @return 字典类型 */ @@ -44,7 +45,7 @@ public interface ISysDictTypeService /** * 根据字典类型查询信息 - * + * * @param dictType 字典类型 * @return 字典类型 */ @@ -52,7 +53,7 @@ public interface ISysDictTypeService /** * 批量删除字典信息 - * + * * @param dictIds 需要删除的字典ID */ void deleteDictTypeByIds(Long[] dictIds); @@ -60,12 +61,12 @@ public interface ISysDictTypeService /** * 加载字典缓存数据 */ - void loadingDictCache(); + //void loadingDictCache(); /** * 清空字典缓存数据 */ - void clearDictCache(); + //void clearDictCache(); /** * 重置字典缓存数据 @@ -74,7 +75,7 @@ public interface ISysDictTypeService /** * 新增保存字典类型信息 - * + * * @param dictType 字典类型信息 * @return 结果 */ @@ -82,7 +83,7 @@ public interface ISysDictTypeService /** * 修改保存字典类型信息 - * + * * @param dictType 字典类型信息 * @return 结果 */ @@ -90,9 +91,11 @@ public interface ISysDictTypeService /** * 校验字典类型称是否唯一 - * + * * @param dictType 字典类型 * @return 结果 */ boolean checkDictTypeUnique(SysDictType dictType); + + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java index e15b0ba..e250079 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java @@ -2,20 +2,21 @@ package com.ruoyi.system.service; import java.util.List; import java.util.Set; -import com.ruoyi.common.core.core.domain.TreeSelect; -import com.ruoyi.common.core.core.domain.entity.SysMenu; + +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.TreeSelect; import com.ruoyi.system.domain.vo.RouterVo; /** * 菜单 业务层 - * + * * @author ruoyi */ public interface ISysMenuService { /** * 根据用户查询系统菜单列表 - * + * * @param userId 用户ID * @return 菜单列表 */ @@ -23,7 +24,7 @@ public interface ISysMenuService /** * 根据用户查询系统菜单列表 - * + * * @param menu 菜单信息 * @param userId 用户ID * @return 菜单列表 @@ -32,7 +33,7 @@ public interface ISysMenuService /** * 根据用户ID查询权限 - * + * * @param userId 用户ID * @return 权限列表 */ @@ -40,7 +41,7 @@ public interface ISysMenuService /** * 根据角色ID查询权限 - * + * * @param roleId 角色ID * @return 权限列表 */ @@ -48,7 +49,7 @@ public interface ISysMenuService /** * 根据用户ID查询菜单树信息 - * + * * @param userId 用户ID * @return 菜单列表 */ @@ -56,7 +57,7 @@ public interface ISysMenuService /** * 根据角色ID查询菜单树信息 - * + * * @param roleId 角色ID * @return 选中菜单列表 */ @@ -64,7 +65,7 @@ public interface ISysMenuService /** * 构建前端路由所需要的菜单 - * + * * @param menus 菜单列表 * @return 路由列表 */ @@ -72,7 +73,7 @@ public interface ISysMenuService /** * 构建前端所需要树结构 - * + * * @param menus 菜单列表 * @return 树结构列表 */ @@ -80,7 +81,7 @@ public interface ISysMenuService /** * 构建前端所需要下拉树结构 - * + * * @param menus 菜单列表 * @return 下拉树结构列表 */ @@ -88,7 +89,7 @@ public interface ISysMenuService /** * 根据菜单ID查询信息 - * + * * @param menuId 菜单ID * @return 菜单信息 */ @@ -96,7 +97,7 @@ public interface ISysMenuService /** * 是否存在菜单子节点 - * + * * @param menuId 菜单ID * @return 结果 true 存在 false 不存在 */ @@ -104,7 +105,7 @@ public interface ISysMenuService /** * 查询菜单是否存在角色 - * + * * @param menuId 菜单ID * @return 结果 true 存在 false 不存在 */ @@ -112,7 +113,7 @@ public interface ISysMenuService /** * 新增保存菜单信息 - * + * * @param menu 菜单信息 * @return 结果 */ @@ -120,7 +121,7 @@ public interface ISysMenuService /** * 修改保存菜单信息 - * + * * @param menu 菜单信息 * @return 结果 */ @@ -128,7 +129,7 @@ public interface ISysMenuService /** * 删除菜单管理信息 - * + * * @param menuId 菜单ID * @return 结果 */ @@ -136,7 +137,7 @@ public interface ISysMenuService /** * 校验菜单名称是否唯一 - * + * * @param menu 菜单信息 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java new file mode 100644 index 0000000..1e6d2d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java @@ -0,0 +1,28 @@ +package com.ruoyi.system.service; + +import java.util.Set; + +/** + * 用户权限处理 + * + * @author Lion Li + */ +public interface ISysPermissionService { + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + Set getRolePermission(Long userId); + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + Set getMenuPermission(Long userId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java index e6749e8..1f89b14 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java @@ -2,19 +2,20 @@ package com.ruoyi.system.service; import java.util.List; import java.util.Set; -import com.ruoyi.common.core.core.domain.entity.SysRole; + +import com.ruoyi.system.domain.SysRole; import com.ruoyi.system.domain.SysUserRole; /** * 角色业务层 - * + * * @author ruoyi */ public interface ISysRoleService { /** * 根据条件分页查询角色数据 - * + * * @param role 角色信息 * @return 角色数据集合信息 */ @@ -22,7 +23,7 @@ public interface ISysRoleService /** * 根据用户ID查询角色列表 - * + * * @param userId 用户ID * @return 角色列表 */ @@ -30,7 +31,7 @@ public interface ISysRoleService /** * 根据用户ID查询角色权限 - * + * * @param userId 用户ID * @return 权限列表 */ @@ -38,14 +39,14 @@ public interface ISysRoleService /** * 查询所有角色 - * + * * @return 角色列表 */ List selectRoleAll(); /** * 根据用户ID获取角色选择框列表 - * + * * @param userId 用户ID * @return 选中角色ID列表 */ @@ -53,7 +54,7 @@ public interface ISysRoleService /** * 通过角色ID查询角色 - * + * * @param roleId 角色ID * @return 角色对象信息 */ @@ -61,7 +62,7 @@ public interface ISysRoleService /** * 校验角色名称是否唯一 - * + * * @param role 角色信息 * @return 结果 */ @@ -69,7 +70,7 @@ public interface ISysRoleService /** * 校验角色权限是否唯一 - * + * * @param role 角色信息 * @return 结果 */ @@ -77,21 +78,21 @@ public interface ISysRoleService /** * 校验角色是否允许操作 - * + * * @param role 角色信息 */ void checkRoleAllowed(SysRole role); /** * 校验角色是否有数据权限 - * + * * @param roleId 角色id */ void checkRoleDataScope(Long roleId); /** * 通过角色ID查询角色使用数量 - * + * * @param roleId 角色ID * @return 结果 */ @@ -99,7 +100,7 @@ public interface ISysRoleService /** * 新增保存角色信息 - * + * * @param role 角色信息 * @return 结果 */ @@ -107,7 +108,7 @@ public interface ISysRoleService /** * 修改保存角色信息 - * + * * @param role 角色信息 * @return 结果 */ @@ -115,7 +116,7 @@ public interface ISysRoleService /** * 修改角色状态 - * + * * @param role 角色信息 * @return 结果 */ @@ -123,7 +124,7 @@ public interface ISysRoleService /** * 修改数据权限信息 - * + * * @param role 角色信息 * @return 结果 */ @@ -131,7 +132,7 @@ public interface ISysRoleService /** * 通过角色ID删除角色 - * + * * @param roleId 角色ID * @return 结果 */ @@ -139,7 +140,7 @@ public interface ISysRoleService /** * 批量删除角色信息 - * + * * @param roleIds 需要删除的角色ID * @return 结果 */ @@ -147,7 +148,7 @@ public interface ISysRoleService /** * 取消授权用户角色 - * + * * @param userRole 用户和角色关联信息 * @return 结果 */ @@ -155,7 +156,7 @@ public interface ISysRoleService /** * 批量取消授权用户角色 - * + * * @param roleId 角色ID * @param userIds 需要取消授权的用户数据ID * @return 结果 @@ -164,10 +165,16 @@ public interface ISysRoleService /** * 批量选择授权用户角色 - * + * * @param roleId 角色ID * @param userIds 需要删除的用户数据ID * @return 结果 */ int insertAuthUsers(Long roleId, Long[] userIds); + + /** + * 注销该角色的在线用户 + * @param roleId + */ + void cleanOnlineUserByRole(Long roleId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java deleted file mode 100644 index e7475ce..0000000 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.ruoyi.system.service; - -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.system.domain.SysUserOnline; - -/** - * 在线用户 服务层 - * - * @author ruoyi - */ -public interface ISysUserOnlineService -{ - /** - * 通过登录地址查询信息 - * - * @param ipaddr 登录地址 - * @param user 用户信息 - * @return 在线用户信息 - */ - SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user); - - /** - * 通过用户名称查询信息 - * - * @param userName 用户名称 - * @param user 用户信息 - * @return 在线用户信息 - */ - SysUserOnline selectOnlineByUserName(String userName, LoginUser user); - - /** - * 通过登录地址/用户名称查询信息 - * - * @param ipaddr 登录地址 - * @param userName 用户名称 - * @param user 用户信息 - * @return 在线用户信息 - */ - SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user); - - /** - * 设置在线用户信息 - * - * @param user 用户信息 - * @return 在线用户 - */ - SysUserOnline loginUserToUserOnline(LoginUser user); -} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index d5a6042..e356e5d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -1,18 +1,21 @@ package com.ruoyi.system.service; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.bo.SysUserBo; +import com.ruoyi.system.domain.vo.SysUserVo; + import java.util.List; -import com.ruoyi.common.core.core.domain.entity.SysUser; /** * 用户 业务层 - * + * * @author ruoyi */ public interface ISysUserService { /** * 根据条件分页查询用户列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -20,7 +23,7 @@ public interface ISysUserService /** * 根据条件分页查询已分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -28,7 +31,7 @@ public interface ISysUserService /** * 根据条件分页查询未分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @@ -36,7 +39,7 @@ public interface ISysUserService /** * 通过用户名查询用户 - * + * * @param userName 用户名 * @return 用户对象信息 */ @@ -44,7 +47,7 @@ public interface ISysUserService /** * 通过用户ID查询用户 - * + * * @param userId 用户ID * @return 用户对象信息 */ @@ -52,7 +55,7 @@ public interface ISysUserService /** * 根据用户ID查询用户所属角色组 - * + * * @param userName 用户名 * @return 结果 */ @@ -60,7 +63,7 @@ public interface ISysUserService /** * 根据用户ID查询用户所属岗位组 - * + * * @param userName 用户名 * @return 结果 */ @@ -68,7 +71,7 @@ public interface ISysUserService /** * 校验用户名称是否唯一 - * + * * @param user 用户信息 * @return 结果 */ @@ -92,21 +95,21 @@ public interface ISysUserService /** * 校验用户是否允许操作 - * + * * @param user 用户信息 */ void checkUserAllowed(SysUser user); /** * 校验用户是否有数据权限 - * + * * @param userId 用户id */ void checkUserDataScope(Long userId); /** * 新增用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -114,15 +117,15 @@ public interface ISysUserService /** * 注册用户信息 - * + * * @param user 用户信息 * @return 结果 */ - boolean registerUser(SysUser user); + boolean registerUser(SysUser user, Long tenantId); /** * 修改用户信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -130,7 +133,7 @@ public interface ISysUserService /** * 用户授权角色 - * + * * @param userId 用户ID * @param roleIds 角色组 */ @@ -138,7 +141,7 @@ public interface ISysUserService /** * 修改用户状态 - * + * * @param user 用户信息 * @return 结果 */ @@ -146,7 +149,7 @@ public interface ISysUserService /** * 修改用户基本信息 - * + * * @param user 用户信息 * @return 结果 */ @@ -154,7 +157,7 @@ public interface ISysUserService /** * 修改用户头像 - * + * * @param userName 用户名 * @param avatar 头像地址 * @return 结果 @@ -163,7 +166,7 @@ public interface ISysUserService /** * 重置用户密码 - * + * * @param user 用户信息 * @return 结果 */ @@ -171,7 +174,7 @@ public interface ISysUserService /** * 重置用户密码 - * + * * @param userName 用户名 * @param password 密码 * @return 结果 @@ -180,7 +183,7 @@ public interface ISysUserService /** * 通过用户ID删除用户 - * + * * @param userId 用户ID * @return 结果 */ @@ -188,7 +191,7 @@ public interface ISysUserService /** * 批量删除用户信息 - * + * * @param userIds 需要删除的用户ID * @return 结果 */ @@ -196,11 +199,11 @@ public interface ISysUserService /** * 导入用户数据 - * + * * @param userList 用户数据列表 * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 - * @param operName 操作用户 + * @param operID 操作用户ID * @return 结果 */ - String importUser(List userList, Boolean isUpdateSupport, String operName); + String importUser(List userList, Boolean isUpdateSupport, Long operID); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysClientServiceImpl.java new file mode 100644 index 0000000..1cbd68d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysClientServiceImpl.java @@ -0,0 +1,19 @@ +package com.ruoyi.system.service.impl; + + +import org.springframework.stereotype.Service; +import com.ruoyi.system.service.ISysClientService; +import com.ruoyi.system.domain.SysClient; +import com.ruoyi.system.mapper.SysClientMapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; + +/** + * 系统授权表 服务层实现。 + * + * @author mybatis-flex-helper automatic generation + * @since 1.0 + */ +@Service +public class SysClientServiceImpl extends ServiceImpl implements ISysClientService { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java index 60fe4a1..bf8524c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java @@ -2,12 +2,19 @@ package com.ruoyi.system.service.impl; import java.util.Collection; import java.util.List; + +import com.ruoyi.common.core.constant.CacheNames; +import com.ruoyi.common.core.service.ConfigService; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.redis.utils.CacheUtils; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.redis.RedisCache; import com.ruoyi.common.core.core.text.Convert; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.StringUtils; @@ -17,30 +24,19 @@ import com.ruoyi.system.service.ISysConfigService; /** * 参数配置 服务层实现 - * + * * @author ruoyi */ +@RequiredArgsConstructor @Service -public class SysConfigServiceImpl implements ISysConfigService +public class SysConfigServiceImpl implements ISysConfigService, ConfigService { @Resource private SysConfigMapper configMapper; - @Resource - private RedisCache redisCache; - - /** - * 项目启动时,初始化参数到缓存 - */ - @PostConstruct - public void init() - { - loadingConfigCache(); - } - /** * 查询参数配置信息 - * + * * @param configId 参数配置ID * @return 参数配置信息 */ @@ -54,24 +50,19 @@ public class SysConfigServiceImpl implements ISysConfigService /** * 根据键名查询参数配置信息 - * + * * @param configKey 参数key * @return 参数键值 */ + @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey") @Override public String selectConfigByKey(String configKey) { - String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey))); - if (StringUtils.isNotEmpty(configValue)) - { - return configValue; - } SysConfig config = new SysConfig(); config.setConfigKey(configKey); SysConfig retConfig = configMapper.selectConfig(config); if (StringUtils.isNotNull(retConfig)) { - redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue()); return retConfig.getConfigValue(); } return StringUtils.EMPTY; @@ -79,7 +70,7 @@ public class SysConfigServiceImpl implements ISysConfigService /** * 获取验证码开关 - * + * * @return true开启,false关闭 */ @Override @@ -95,7 +86,7 @@ public class SysConfigServiceImpl implements ISysConfigService /** * 查询参数配置列表 - * + * * @param config 参数配置信息 * @return 参数配置集合 */ @@ -107,47 +98,49 @@ public class SysConfigServiceImpl implements ISysConfigService /** * 新增参数配置 - * + * * @param config 参数配置信息 * @return 结果 */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#config.configKey") @Override public int insertConfig(SysConfig config) { int row = configMapper.insertConfig(config); if (row > 0) { - redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + return row; } - return row; + return 0; } /** * 修改参数配置 - * + * * @param config 参数配置信息 * @return 结果 */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#config.configKey") @Override public int updateConfig(SysConfig config) { SysConfig temp = configMapper.selectConfigById(config.getConfigId()); if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { - redisCache.deleteObject(getCacheKey(temp.getConfigKey())); + CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey()); } int row = configMapper.updateConfig(config); if (row > 0) { - redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + return row; } - return row; + return 0; } /** * 批量删除参数信息 - * + * * @param configIds 需要删除的参数ID */ @Override @@ -161,46 +154,22 @@ public class SysConfigServiceImpl implements ISysConfigService throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey())); } configMapper.deleteConfigById(configId); - redisCache.deleteObject(getCacheKey(config.getConfigKey())); + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); } } - /** - * 加载参数缓存数据 - */ - @Override - public void loadingConfigCache() - { - List configsList = configMapper.selectConfigList(new SysConfig()); - for (SysConfig config : configsList) - { - redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); - } - } - - /** - * 清空参数缓存数据 - */ - @Override - public void clearConfigCache() - { - Collection keys = redisCache.keys(CacheConstants.SYS_CONFIG_KEY + "*"); - redisCache.deleteObject(keys); - } - /** * 重置参数缓存数据 */ @Override public void resetConfigCache() { - clearConfigCache(); - loadingConfigCache(); + CacheUtils.clear(CacheNames.SYS_CONFIG); } /** * 校验参数键名是否唯一 - * + * * @param config 参数配置信息 * @return 结果 */ @@ -216,14 +185,15 @@ public class SysConfigServiceImpl implements ISysConfigService return UserConstants.UNIQUE; } + /** - * 设置cache key - * - * @param configKey 参数键 - * @return 缓存键key + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 */ - private String getCacheKey(String configKey) - { - return CacheConstants.SYS_CONFIG_KEY + configKey; + @Override + public String getConfigValue(String configKey) { + return SpringUtils.getAopProxy(this).selectConfigByKey(configKey); } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java index 17eed6d..f9288de 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java @@ -5,32 +5,33 @@ import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.service.DeptService; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysDept; +import com.ruoyi.system.domain.SysRole; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import com.ruoyi.common.core.annotation.DataScope; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.TreeSelect; -import com.ruoyi.common.core.core.domain.entity.SysDept; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; +import com.ruoyi.system.domain.TreeSelect; import com.ruoyi.common.core.core.text.Convert; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.spring.SpringUtils; +import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.system.mapper.SysDeptMapper; import com.ruoyi.system.mapper.SysRoleMapper; import com.ruoyi.system.service.ISysDeptService; /** * 部门管理 服务实现 - * + * * @author ruoyi */ +@RequiredArgsConstructor @Service -public class SysDeptServiceImpl implements ISysDeptService -{ +public class SysDeptServiceImpl implements ISysDeptService, DeptService { @Resource private SysDeptMapper deptMapper; @@ -39,52 +40,50 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 查询部门管理数据 - * + * * @param dept 部门信息 * @return 部门信息集合 */ @Override @DataScope(deptAlias = "d") - public List selectDeptList(SysDept dept) - { + public List selectDeptList(SysDept dept) { + // 只查询未禁用部门 + dept.setStatus(UserConstants.DEPT_NORMAL); return deptMapper.selectDeptList(dept); } /** * 查询部门树结构信息 - * + * * @param dept 部门信息 * @return 部门树信息集合 */ @Override - public List selectDeptTreeList(SysDept dept) - { + public List selectDeptTreeList(SysDept dept) { + // 只查询未禁用部门 + dept.setStatus(UserConstants.DEPT_NORMAL); List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); return buildDeptTreeSelect(depts); } /** * 构建前端所需要树结构 - * + * * @param depts 部门列表 * @return 树结构列表 */ @Override - public List buildDeptTree(List depts) - { + public List buildDeptTree(List depts) { List returnList = new ArrayList<>(); List tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()); - for (SysDept dept : depts) - { + for (SysDept dept : depts) { // 如果是顶级节点, 遍历该父节点的所有子节点 - if (!tempList.contains(dept.getParentId())) - { + if (!tempList.contains(dept.getParentId())) { recursionFn(depts, dept); returnList.add(dept); } } - if (returnList.isEmpty()) - { + if (returnList.isEmpty()) { returnList = depts; } return returnList; @@ -92,93 +91,85 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 构建前端所需要下拉树结构 - * + * * @param depts 部门列表 * @return 下拉树结构列表 */ @Override - public List buildDeptTreeSelect(List depts) - { + public List buildDeptTreeSelect(List depts) { List deptTrees = buildDeptTree(depts); return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); } /** * 根据角色ID查询部门树信息 - * + * * @param roleId 角色ID * @return 选中部门列表 */ @Override - public List selectDeptListByRoleId(Long roleId) - { + public List selectDeptListByRoleId(Long roleId) { SysRole role = roleMapper.selectRoleById(roleId); return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly()); } /** * 根据部门ID查询信息 - * + * * @param deptId 部门ID * @return 部门信息 */ @Override - public SysDept selectDeptById(Long deptId) - { + public SysDept selectDeptById(Long deptId) { return deptMapper.selectDeptById(deptId); } /** * 根据ID查询所有子部门(正常状态) - * + * * @param deptId 部门ID * @return 子部门数 */ @Override - public int selectNormalChildrenDeptById(Long deptId) - { + public int selectNormalChildrenDeptById(Long deptId) { return deptMapper.selectNormalChildrenDeptById(deptId); } /** * 是否存在子节点 - * + * * @param deptId 部门ID * @return 结果 */ @Override - public boolean hasChildByDeptId(Long deptId) - { + public boolean hasChildByDeptId(Long deptId) { int result = deptMapper.hasChildByDeptId(deptId); return result > 0; } /** * 查询部门是否存在用户 - * + * * @param deptId 部门ID * @return 结果 true 存在 false 不存在 */ @Override - public boolean checkDeptExistUser(Long deptId) - { + public boolean checkDeptExistUser(Long deptId) { int result = deptMapper.checkDeptExistUser(deptId); return result > 0; } /** * 校验部门名称是否唯一 - * + * * @param dept 部门信息 * @return 结果 */ @Override - public boolean checkDeptNameUnique(SysDept dept) - { + public boolean checkDeptNameUnique(SysDept dept) { Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId(); SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId()); - if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -186,37 +177,37 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 校验部门是否有数据权限 - * + * * @param deptId 部门id */ @Override - public void checkDeptDataScope(Long deptId) - { - if (!SysUser.isAdmin(SecurityUtils.getUserId())) - { - SysDept dept = new SysDept(); - dept.setDeptId(deptId); - List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); - if (StringUtils.isEmpty(depts)) - { - throw new ServiceException("没有权限访问部门数据!"); - } + public void checkDeptDataScope(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + + SysDept dept = new SysDept(); + dept.setDeptId(deptId); + List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + if (ObjectUtil.isNull(depts)) { + throw new ServiceException("没有权限访问部门数据!"); } } /** * 新增保存部门信息 - * + * * @param dept 部门信息 * @return 结果 */ @Override - public int insertDept(SysDept dept) - { + public int insertDept(SysDept dept) { SysDept info = deptMapper.selectDeptById(dept.getParentId()); // 如果父节点不为正常状态,则不允许新增子节点 - if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) - { + if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) { throw new ServiceException("部门停用,不允许新增"); } dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); @@ -225,17 +216,15 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 修改保存部门信息 - * + * * @param dept 部门信息 * @return 结果 */ @Override - public int updateDept(SysDept dept) - { + public int updateDept(SysDept dept) { SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId()); SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId()); - if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) - { + if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) { String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId(); String oldAncestors = oldDept.getAncestors(); dept.setAncestors(newAncestors); @@ -243,8 +232,7 @@ public class SysDeptServiceImpl implements ISysDeptService } int result = deptMapper.updateDept(dept); if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) - && !StringUtils.equals("0", dept.getAncestors())) - { + && !StringUtils.equals("0", dept.getAncestors())) { // 如果该部门是启用状态,则启用该部门的所有上级部门 updateParentDeptStatusNormal(dept); } @@ -253,11 +241,10 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 修改该部门的父级部门状态 - * + * * @param dept 当前部门 */ - private void updateParentDeptStatusNormal(SysDept dept) - { + private void updateParentDeptStatusNormal(SysDept dept) { String ancestors = dept.getAncestors(); Long[] deptIds = Convert.toLongArray(ancestors); deptMapper.updateDeptStatusNormal(deptIds); @@ -265,48 +252,41 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 修改子元素关系 - * - * @param deptId 被修改的部门ID + * + * @param deptId 被修改的部门ID * @param newAncestors 新的父ID集合 * @param oldAncestors 旧的父ID集合 */ - public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) - { + public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) { List children = deptMapper.selectChildrenDeptById(deptId); - for (SysDept child : children) - { + for (SysDept child : children) { child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); } - if (children.size() > 0) - { + if (children.size() > 0) { deptMapper.updateDeptChildren(children); } } /** * 删除部门管理信息 - * + * * @param deptId 部门ID * @return 结果 */ @Override - public int deleteDeptById(Long deptId) - { + public int deleteDeptById(Long deptId) { return deptMapper.deleteDeptById(deptId); } /** * 递归列表 */ - private void recursionFn(List list, SysDept t) - { + private void recursionFn(List list, SysDept t) { // 得到子节点列表 List childList = getChildList(list, t); t.setChildren(childList); - for (SysDept tChild : childList) - { - if (hasChild(list, tChild)) - { + for (SysDept tChild : childList) { + if (hasChild(list, tChild)) { recursionFn(list, tChild); } } @@ -315,15 +295,12 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 得到子节点列表 */ - private List getChildList(List list, SysDept t) - { + private List getChildList(List list, SysDept t) { List tlist = new ArrayList<>(); Iterator it = list.iterator(); - while (it.hasNext()) - { + while (it.hasNext()) { SysDept n = (SysDept) it.next(); - if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) - { + if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) { tlist.add(n); } } @@ -333,8 +310,25 @@ public class SysDeptServiceImpl implements ISysDeptService /** * 判断是否有子节点 */ - private boolean hasChild(List list, SysDept t) - { + private boolean hasChild(List list, SysDept t) { return getChildList(list, t).size() > 0; } + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + @Override + public String selectDeptNameByIds(String deptIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) { + SysDept dept = SpringUtils.getAopProxy(this).selectDeptById(id); + if (ObjectUtil.isNotNull(dept)) { + list.add(dept.getDeptName()); + } + } + return String.join(StringUtils.SEPARATOR, list); + } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java index 818c079..123cf4d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java @@ -2,19 +2,22 @@ package com.ruoyi.system.service.impl; import java.util.List; +import com.ruoyi.common.core.constant.CacheNames; +import com.ruoyi.common.redis.utils.CacheUtils; +import com.ruoyi.system.domain.SysDictData; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import com.ruoyi.common.core.core.domain.entity.SysDictData; -import com.ruoyi.common.core.utils.DictUtils; import com.ruoyi.system.mapper.SysDictDataMapper; import com.ruoyi.system.service.ISysDictDataService; +import org.springframework.cache.annotation.CachePut; /** * 字典 业务层处理 - * + * * @author ruoyi */ +@RequiredArgsConstructor @Service public class SysDictDataServiceImpl implements ISysDictDataService { @@ -23,7 +26,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService /** * 根据条件分页查询字典数据 - * + * * @param dictData 字典数据信息 * @return 字典数据集合信息 */ @@ -35,7 +38,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService /** * 根据字典类型和字典键值查询字典数据信息 - * + * * @param dictType 字典类型 * @param dictValue 字典键值 * @return 字典标签 @@ -48,7 +51,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService /** * 根据字典数据ID查询信息 - * + * * @param dictCode 字典数据ID * @return 字典数据 */ @@ -60,7 +63,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService /** * 批量删除字典数据信息 - * + * * @param dictCodes 需要删除的字典数据ID */ @Override @@ -71,16 +74,18 @@ public class SysDictDataServiceImpl implements ISysDictDataService SysDictData data = selectDictDataById(dictCode); dictDataMapper.deleteDictDataById(dictCode); List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); - DictUtils.setDictCache(data.getDictType(), dictDatas); + //DictUtils.setDictCache(data.getDictType(), dictDatas); + CacheUtils.evict(CacheNames.SYS_DICT, data.getDictType()); } } /** * 新增保存字典数据信息 - * + * * @param data 字典数据信息 * @return 结果 */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#data.dictType") @Override public int insertDictData(SysDictData data) { @@ -88,17 +93,18 @@ public class SysDictDataServiceImpl implements ISysDictDataService if (row > 0) { List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); - DictUtils.setDictCache(data.getDictType(), dictDatas); + //DictUtils.setDictCache(data.getDictType(), dictDatas); } return row; } /** * 修改保存字典数据信息 - * + * * @param data 字典数据信息 * @return 结果 */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#data.dictType") @Override public int updateDictData(SysDictData data) { @@ -106,7 +112,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService if (row > 0) { List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); - DictUtils.setDictCache(data.getDictType(), dictDatas); + //DictUtils.setDictCache(data.getDictType(), dictDatas); } return row; } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java index 150d9b5..c9dc70e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java @@ -1,19 +1,27 @@ package com.ruoyi.system.service.impl; -import java.util.Comparator; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import jakarta.annotation.PostConstruct; + +import cn.dev33.satoken.context.SaHolder; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.constant.CacheNames; +import com.ruoyi.common.core.service.DictService; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StreamUtils; +import com.ruoyi.common.redis.utils.CacheUtils; +import com.ruoyi.system.domain.SysDictData; +import com.ruoyi.system.domain.SysDictType; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.entity.SysDictData; -import com.ruoyi.common.core.core.domain.entity.SysDictType; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.DictUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.mapper.SysDictDataMapper; import com.ruoyi.system.mapper.SysDictTypeMapper; @@ -21,11 +29,11 @@ import com.ruoyi.system.service.ISysDictTypeService; /** * 字典 业务层处理 - * + * * @author ruoyi */ @Service -public class SysDictTypeServiceImpl implements ISysDictTypeService +public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService { @Resource private SysDictTypeMapper dictTypeMapper; @@ -36,15 +44,15 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService /** * 项目启动时,初始化字典到缓存 */ - @PostConstruct - public void init() - { - loadingDictCache(); - } +// @PostConstruct +// public void init() +// { +// loadingDictCache(); +// } /** * 根据条件分页查询字典类型 - * + * * @param dictType 字典类型信息 * @return 字典类型集合信息 */ @@ -56,7 +64,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService /** * 根据所有字典类型 - * + * * @return 字典类型集合信息 */ @Override @@ -67,22 +75,18 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService /** * 根据字典类型查询字典数据 - * + * * @param dictType 字典类型 * @return 字典数据集合信息 */ + @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType") @Override public List selectDictDataByType(String dictType) { - List dictDatas = DictUtils.getDictCache(dictType); + List dictDatas = dictDataMapper.selectDictDataByType(dictType); if (StringUtils.isNotEmpty(dictDatas)) { - return dictDatas; - } - dictDatas = dictDataMapper.selectDictDataByType(dictType); - if (StringUtils.isNotEmpty(dictDatas)) - { - DictUtils.setDictCache(dictType, dictDatas); + //DictUtils.setDictCache(dictType, dictDatas); return dictDatas; } return null; @@ -90,7 +94,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService /** * 根据字典类型ID查询信息 - * + * * @param dictId 字典类型ID * @return 字典类型 */ @@ -102,7 +106,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService /** * 根据字典类型查询信息 - * + * * @param dictType 字典类型 * @return 字典类型 */ @@ -114,7 +118,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService /** * 批量删除字典类型信息 - * + * * @param dictIds 需要删除的字典ID */ @Override @@ -128,67 +132,46 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName())); } dictTypeMapper.deleteDictTypeById(dictId); - DictUtils.removeDictCache(dictType.getDictType()); + //DictUtils.removeDictCache(dictType.getDictType()); + CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType()); } } - /** - * 加载字典缓存数据 - */ - @Override - public void loadingDictCache() - { - SysDictData dictData = new SysDictData(); - dictData.setStatus("0"); - Map> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType)); - for (Map.Entry> entry : dictDataMap.entrySet()) - { - DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList())); - } - } - - /** - * 清空字典缓存数据 - */ - @Override - public void clearDictCache() - { - DictUtils.clearDictCache(); - } - /** * 重置字典缓存数据 */ @Override public void resetDictCache() { - clearDictCache(); - loadingDictCache(); + CacheUtils.clear(CacheNames.SYS_DICT); } /** * 新增保存字典类型信息 - * + * * @param dict 字典类型信息 * @return 结果 */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#dict.dictType") @Override public int insertDictType(SysDictType dict) { int row = dictTypeMapper.insertDictType(dict); if (row > 0) { - DictUtils.setDictCache(dict.getDictType(), null); + //DictUtils.setDictCache(dict.getDictType(), null); + return row; } - return row; + return 0; } /** * 修改保存字典类型信息 - * + * * @param dict 字典类型信息 * @return 结果 */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#dict.dictType") @Override @Transactional public int updateDictType(SysDictType dict) @@ -199,14 +182,15 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService if (row > 0) { List dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType()); - DictUtils.setDictCache(dict.getDictType(), dictDatas); + //DictUtils.setDictCache(dict.getDictType(), dictDatas); + CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType()); } return row; } /** * 校验字典类型称是否唯一 - * + * * @param dict 字典类型 * @return 结果 */ @@ -221,4 +205,66 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService } return UserConstants.UNIQUE; } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + @SuppressWarnings("unchecked cast") + @Override + public String getDictLabel(String dictType, String dictValue, String separator) { + // 优先从本地缓存获取 + List datas = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); + if (ObjectUtil.isNull(datas)) { + datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); + } + + Map map = StreamUtils.toMap(datas, SysDictData::getDictValue, SysDictData::getDictLabel); + if (StringUtils.containsAny(dictValue, separator)) { + return Arrays.stream(dictValue.split(separator)) + .map(v -> map.getOrDefault(v, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictValue, StringUtils.EMPTY); + } + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + @SuppressWarnings("unchecked cast") + @Override + public String getDictValue(String dictType, String dictLabel, String separator) { + // 优先从本地缓存获取 + List datas = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); + if (ObjectUtil.isNull(datas)) { + datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); + } + + Map map = StreamUtils.toMap(datas, SysDictData::getDictLabel, SysDictData::getDictValue); + if (StringUtils.containsAny(dictLabel, separator)) { + return Arrays.stream(dictLabel.split(separator)) + .map(l -> map.getOrDefault(l, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictLabel, StringUtils.EMPTY); + } + } + + @Override + public Map getAllDictByDictType(String dictType) { + List list = selectDictDataByType(dictType); + return StreamUtils.toMap(list, SysDictData::getDictValue, SysDictData::getDictLabel); + } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java index 95a3108..1194c73 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java @@ -9,16 +9,15 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.SysRole; +import com.ruoyi.system.domain.SysUser; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.TreeSelect; -import com.ruoyi.common.core.core.domain.entity.SysMenu; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; -import com.ruoyi.common.core.utils.SecurityUtils; +import com.ruoyi.system.domain.TreeSelect; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.domain.vo.MetaVo; import com.ruoyi.system.domain.vo.RouterVo; @@ -29,12 +28,11 @@ import com.ruoyi.system.service.ISysMenuService; /** * 菜单 业务层处理 - * + * * @author ruoyi */ @Service -public class SysMenuServiceImpl implements ISysMenuService -{ +public class SysMenuServiceImpl implements ISysMenuService { public static final String PREMISSION_STRING = "perms[\"{0}\"]"; @Resource @@ -48,33 +46,28 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 根据用户查询系统菜单列表 - * + * * @param userId 用户ID * @return 菜单列表 */ @Override - public List selectMenuList(Long userId) - { + public List selectMenuList(Long userId) { return selectMenuList(new SysMenu(), userId); } /** * 查询系统菜单列表 - * + * * @param menu 菜单信息 * @return 菜单列表 */ @Override - public List selectMenuList(SysMenu menu, Long userId) - { + public List selectMenuList(SysMenu menu, Long userId) { List menuList = null; // 管理员显示所有菜单信息 - if (SysUser.isAdmin(userId)) - { + if (SysUser.isAdmin(userId)) { menuList = menuMapper.selectMenuList(menu); - } - else - { + } else { menu.getParams().put("userId", userId); menuList = menuMapper.selectMenuListByUserId(menu); } @@ -83,19 +76,16 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 根据用户ID查询权限 - * + * * @param userId 用户ID * @return 权限列表 */ @Override - public Set selectMenuPermsByUserId(Long userId) - { + public Set selectMenuPermsByUserId(Long userId) { List perms = menuMapper.selectMenuPermsByUserId(userId); Set permsSet = new HashSet<>(); - for (String perm : perms) - { - if (StringUtils.isNotEmpty(perm)) - { + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { permsSet.addAll(Arrays.asList(perm.trim().split(","))); } } @@ -104,19 +94,16 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 根据角色ID查询权限 - * + * * @param roleId 角色ID * @return 权限列表 */ @Override - public Set selectMenuPermsByRoleId(Long roleId) - { + public Set selectMenuPermsByRoleId(Long roleId) { List perms = menuMapper.selectMenuPermsByRoleId(roleId); Set permsSet = new HashSet<>(); - for (String perm : perms) - { - if (StringUtils.isNotEmpty(perm)) - { + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { permsSet.addAll(Arrays.asList(perm.trim().split(","))); } } @@ -125,20 +112,16 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 根据用户ID查询菜单 - * + * * @param userId 用户名称 * @return 菜单列表 */ @Override - public List selectMenuTreeByUserId(Long userId) - { + public List selectMenuTreeByUserId(Long userId) { List menus = null; - if (SecurityUtils.isAdmin(userId)) - { + if (LoginHelper.isSuperAdmin(userId)) { menus = menuMapper.selectMenuTreeAll(); - } - else - { + } else { menus = menuMapper.selectMenuTreeByUserId(userId); } return getChildPerms(menus, 0); @@ -146,29 +129,26 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 根据角色ID查询菜单树信息 - * + * * @param roleId 角色ID * @return 选中菜单列表 */ @Override - public List selectMenuListByRoleId(Long roleId) - { + public List selectMenuListByRoleId(Long roleId) { SysRole role = roleMapper.selectRoleById(roleId); return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly()); } /** * 构建前端路由所需要的菜单 - * + * * @param menus 菜单列表 * @return 路由列表 */ @Override - public List buildMenus(List menus) - { + public List buildMenus(List menus) { List routers = new LinkedList<>(); - for (SysMenu menu : menus) - { + for (SysMenu menu : menus) { RouterVo router = new RouterVo(); router.setHidden("1".equals(menu.getVisible())); router.setName(getRouteName(menu)); @@ -177,14 +157,11 @@ public class SysMenuServiceImpl implements ISysMenuService router.setQuery(menu.getQuery()); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); List cMenus = menu.getChildren(); - if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) - { + if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) { router.setAlwaysShow(true); router.setRedirect("noRedirect"); router.setChildren(buildMenus(cMenus)); - } - else if (isMenuFrame(menu)) - { + } else if (isMenuFrame(menu)) { router.setMeta(null); List childrenList = new ArrayList<>(); RouterVo children = new RouterVo(); @@ -195,9 +172,7 @@ public class SysMenuServiceImpl implements ISysMenuService children.setQuery(menu.getQuery()); childrenList.add(children); router.setChildren(childrenList); - } - else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) - { + } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) { router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); router.setPath("/"); List childrenList = new ArrayList<>(); @@ -217,27 +192,23 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 构建前端所需要树结构 - * + * * @param menus 菜单列表 * @return 树结构列表 */ @Override - public List buildMenuTree(List menus) - { + public List buildMenuTree(List menus) { List returnList = new ArrayList<>(); List tempList = menus.stream().map(SysMenu::getMenuId).collect(Collectors.toList()); - for (Iterator iterator = menus.iterator(); iterator.hasNext();) - { + for (Iterator iterator = menus.iterator(); iterator.hasNext(); ) { SysMenu menu = (SysMenu) iterator.next(); // 如果是顶级节点, 遍历该父节点的所有子节点 - if (!tempList.contains(menu.getParentId())) - { + if (!tempList.contains(menu.getParentId())) { recursionFn(menus, menu); returnList.add(menu); } } - if (returnList.isEmpty()) - { + if (returnList.isEmpty()) { returnList = menus; } return returnList; @@ -245,104 +216,95 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 构建前端所需要下拉树结构 - * + * * @param menus 菜单列表 * @return 下拉树结构列表 */ @Override - public List buildMenuTreeSelect(List menus) - { + public List buildMenuTreeSelect(List menus) { List menuTrees = buildMenuTree(menus); return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); } /** * 根据菜单ID查询信息 - * + * * @param menuId 菜单ID * @return 菜单信息 */ @Override - public SysMenu selectMenuById(Long menuId) - { + public SysMenu selectMenuById(Long menuId) { return menuMapper.selectMenuById(menuId); } /** * 是否存在菜单子节点 - * + * * @param menuId 菜单ID * @return 结果 */ @Override - public boolean hasChildByMenuId(Long menuId) - { + public boolean hasChildByMenuId(Long menuId) { int result = menuMapper.hasChildByMenuId(menuId); return result > 0; } /** * 查询菜单使用数量 - * + * * @param menuId 菜单ID * @return 结果 */ @Override - public boolean checkMenuExistRole(Long menuId) - { + public boolean checkMenuExistRole(Long menuId) { int result = roleMenuMapper.checkMenuExistRole(menuId); return result > 0; } /** * 新增保存菜单信息 - * + * * @param menu 菜单信息 * @return 结果 */ @Override - public int insertMenu(SysMenu menu) - { + public int insertMenu(SysMenu menu) { return menuMapper.insertMenu(menu); } /** * 修改保存菜单信息 - * + * * @param menu 菜单信息 * @return 结果 */ @Override - public int updateMenu(SysMenu menu) - { + public int updateMenu(SysMenu menu) { return menuMapper.updateMenu(menu); } /** * 删除菜单管理信息 - * + * * @param menuId 菜单ID * @return 结果 */ @Override - public int deleteMenuById(Long menuId) - { + public int deleteMenuById(Long menuId) { return menuMapper.deleteMenuById(menuId); } /** * 校验菜单名称是否唯一 - * + * * @param menu 菜单信息 * @return 结果 */ @Override - public boolean checkMenuNameUnique(SysMenu menu) - { + public boolean checkMenuNameUnique(SysMenu menu) { Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId(); SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId()); - if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -350,16 +312,14 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 获取路由名称 - * + * * @param menu 菜单信息 * @return 路由名称 */ - public String getRouteName(SysMenu menu) - { + public String getRouteName(SysMenu menu) { String routerName = StringUtils.capitalize(menu.getPath()); // 非外链并且是一级目录(类型为目录) - if (isMenuFrame(menu)) - { + if (isMenuFrame(menu)) { routerName = StringUtils.EMPTY; } return routerName; @@ -367,27 +327,23 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 获取路由地址 - * + * * @param menu 菜单信息 * @return 路由地址 */ - public String getRouterPath(SysMenu menu) - { + public String getRouterPath(SysMenu menu) { String routerPath = menu.getPath(); // 内链打开外网方式 - if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) - { + if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) { routerPath = innerLinkReplaceEach(routerPath); } // 非外链并且是一级目录(类型为目录) if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) - && UserConstants.NO_FRAME.equals(menu.getIsFrame())) - { + && UserConstants.NO_FRAME.equals(menu.getIsFrame())) { routerPath = "/" + menu.getPath(); } // 非外链并且是一级目录(类型为菜单) - else if (isMenuFrame(menu)) - { + else if (isMenuFrame(menu)) { routerPath = "/"; } return routerPath; @@ -395,23 +351,17 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 获取组件信息 - * + * * @param menu 菜单信息 * @return 组件信息 */ - public String getComponent(SysMenu menu) - { + public String getComponent(SysMenu menu) { String component = UserConstants.LAYOUT; - if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) - { + if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) { component = menu.getComponent(); - } - else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) - { + } else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) { component = UserConstants.INNER_LINK; - } - else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) - { + } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) { component = UserConstants.PARENT_VIEW; } return component; @@ -419,54 +369,48 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 是否为菜单内部跳转 - * + * * @param menu 菜单信息 * @return 结果 */ - public boolean isMenuFrame(SysMenu menu) - { + public boolean isMenuFrame(SysMenu menu) { return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType()) - && menu.getIsFrame().equals(UserConstants.NO_FRAME); + && menu.getIsFrame().equals(UserConstants.NO_FRAME); } /** * 是否为内链组件 - * + * * @param menu 菜单信息 * @return 结果 */ - public boolean isInnerLink(SysMenu menu) - { + public boolean isInnerLink(SysMenu menu) { return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath()); } /** * 是否为parent_view组件 - * + * * @param menu 菜单信息 * @return 结果 */ - public boolean isParentView(SysMenu menu) - { + public boolean isParentView(SysMenu menu) { return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()); } /** * 根据父节点的ID获取所有子节点 - * - * @param list 分类表 + * + * @param list 分类表 * @param parentId 传入的父节点ID * @return String */ - public List getChildPerms(List list, int parentId) - { + public List getChildPerms(List list, int parentId) { List returnList = new ArrayList<>(); - for (Iterator iterator = list.iterator(); iterator.hasNext();) - { + for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { SysMenu t = (SysMenu) iterator.next(); // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 - if (t.getParentId() == parentId) - { + if (t.getParentId() == parentId) { recursionFn(list, t); returnList.add(t); } @@ -476,19 +420,16 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 递归列表 - * + * * @param list 分类表 - * @param t 子节点 + * @param t 子节点 */ - private void recursionFn(List list, SysMenu t) - { + private void recursionFn(List list, SysMenu t) { // 得到子节点列表 List childList = getChildList(list, t); t.setChildren(childList); - for (SysMenu tChild : childList) - { - if (hasChild(list, tChild)) - { + for (SysMenu tChild : childList) { + if (hasChild(list, tChild)) { recursionFn(list, tChild); } } @@ -497,15 +438,12 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 得到子节点列表 */ - private List getChildList(List list, SysMenu t) - { + private List getChildList(List list, SysMenu t) { List tlist = new ArrayList<>(); Iterator it = list.iterator(); - while (it.hasNext()) - { + while (it.hasNext()) { SysMenu n = (SysMenu) it.next(); - if (n.getParentId().longValue() == t.getMenuId().longValue()) - { + if (n.getParentId().longValue() == t.getMenuId().longValue()) { tlist.add(n); } } @@ -515,19 +453,17 @@ public class SysMenuServiceImpl implements ISysMenuService /** * 判断是否有子节点 */ - private boolean hasChild(List list, SysMenu t) - { + private boolean hasChild(List 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, Constants.WWW, "." }, - new String[] { "", "", "", "/" }); + public String innerLinkReplaceEach(String path) { + return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, "."}, + new String[]{"", "", "", "/"}); } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java new file mode 100644 index 0000000..95bdf61 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java @@ -0,0 +1,61 @@ +package com.ruoyi.system.service.impl; + +import com.ruoyi.common.core.constant.TenantConstants; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.service.ISysMenuService; +import com.ruoyi.system.service.ISysPermissionService; +import com.ruoyi.system.service.ISysRoleService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.Set; + +/** + * 用户权限处理 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@Service +public class SysPermissionServiceImpl implements ISysPermissionService { + + private final ISysRoleService roleService; + private final ISysMenuService menuService; + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + @Override + public Set getRolePermission(Long userId) { + Set roles = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + roles.add(TenantConstants.SUPER_ADMIN_ROLE_KEY); + } else { + roles.addAll(roleService.selectRolePermissionByUserId(userId)); + } + return roles; + } + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + @Override + public Set getMenuPermission(Long userId) { + Set perms = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + perms.add("*:*:*"); + } else { + perms.addAll(menuService.selectMenuPermsByUserId(userId)); + } + return perms; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java index 5b32d0b..8fd0e92 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java @@ -3,7 +3,6 @@ package com.ruoyi.system.service.impl; import java.util.List; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.exception.ServiceException; @@ -15,7 +14,7 @@ import com.ruoyi.system.service.ISysPostService; /** * 岗位信息 服务层处理 - * + * * @author ruoyi */ @Service @@ -29,7 +28,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 查询岗位信息集合 - * + * * @param post 岗位信息 * @return 岗位信息集合 */ @@ -41,7 +40,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 查询所有岗位 - * + * * @return 岗位列表 */ @Override @@ -52,7 +51,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 通过岗位ID查询岗位信息 - * + * * @param postId 岗位ID * @return 角色对象信息 */ @@ -64,7 +63,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 根据用户ID获取岗位选择框列表 - * + * * @param userId 用户ID * @return 选中岗位ID列表 */ @@ -76,7 +75,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 校验岗位名称是否唯一 - * + * * @param post 岗位信息 * @return 结果 */ @@ -94,7 +93,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 校验岗位编码是否唯一 - * + * * @param post 岗位信息 * @return 结果 */ @@ -112,7 +111,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 通过岗位ID查询岗位使用数量 - * + * * @param postId 岗位ID * @return 结果 */ @@ -124,7 +123,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 删除岗位信息 - * + * * @param postId 岗位ID * @return 结果 */ @@ -136,7 +135,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 批量删除岗位信息 - * + * * @param postIds 需要删除的岗位ID * @return 结果 */ @@ -148,7 +147,7 @@ public class SysPostServiceImpl implements ISysPostService SysPost post = selectPostById(postId); if (countUserPostById(postId) > 0) { - throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName())); + throw new ServiceException(String.format("%1$s已分配,不能删除!", post.getPostName())); } } return postMapper.deletePostByIds(postIds); @@ -156,7 +155,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 新增保存岗位信息 - * + * * @param post 岗位信息 * @return 结果 */ @@ -168,7 +167,7 @@ public class SysPostServiceImpl implements ISysPostService /** * 修改保存岗位信息 - * + * * @param post 岗位信息 * @return 结果 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java index 9acde2a..776da39 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java @@ -6,21 +6,21 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.*; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.common.core.annotation.DataScope; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.common.core.utils.spring.SpringUtils; -import com.ruoyi.system.domain.SysRoleDept; -import com.ruoyi.system.domain.SysRoleMenu; -import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.system.mapper.SysRoleDeptMapper; import com.ruoyi.system.mapper.SysRoleMapper; import com.ruoyi.system.mapper.SysRoleMenuMapper; @@ -29,12 +29,11 @@ import com.ruoyi.system.service.ISysRoleService; /** * 角色 业务层处理 - * + * * @author ruoyi */ @Service -public class SysRoleServiceImpl implements ISysRoleService -{ +public class SysRoleServiceImpl implements ISysRoleService { @Resource private SysRoleMapper roleMapper; @@ -49,34 +48,29 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 根据条件分页查询角色数据 - * + * * @param role 角色信息 * @return 角色数据集合信息 */ @Override @DataScope(deptAlias = "d") - public List selectRoleList(SysRole role) - { + public List selectRoleList(SysRole role) { return roleMapper.selectRoleList(role); } /** * 根据用户ID查询角色 - * + * * @param userId 用户ID * @return 角色列表 */ @Override - public List selectRolesByUserId(Long userId) - { + public List selectRolesByUserId(Long userId) { List userRoles = roleMapper.selectRolePermissionByUserId(userId); List roles = selectRoleAll(); - for (SysRole role : roles) - { - for (SysRole userRole : userRoles) - { - if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) - { + for (SysRole role : roles) { + for (SysRole userRole : userRoles) { + if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) { role.setFlag(true); break; } @@ -87,19 +81,16 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 根据用户ID查询权限 - * + * * @param userId 用户ID * @return 权限列表 */ @Override - public Set selectRolePermissionByUserId(Long userId) - { + public Set selectRolePermissionByUserId(Long userId) { List perms = roleMapper.selectRolePermissionByUserId(userId); Set permsSet = new HashSet<>(); - for (SysRole perm : perms) - { - if (StringUtils.isNotNull(perm)) - { + for (SysRole perm : perms) { + if (StringUtils.isNotNull(perm)) { permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(","))); } } @@ -108,52 +99,47 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 查询所有角色 - * + * * @return 角色列表 */ @Override - public List selectRoleAll() - { + public List selectRoleAll() { return SpringUtils.getAopProxy(this).selectRoleList(new SysRole()); } /** * 根据用户ID获取角色选择框列表 - * + * * @param userId 用户ID * @return 选中角色ID列表 */ @Override - public List selectRoleListByUserId(Long userId) - { + public List selectRoleListByUserId(Long userId) { return roleMapper.selectRoleListByUserId(userId); } /** * 通过角色ID查询角色 - * + * * @param roleId 角色ID * @return 角色对象信息 */ @Override - public SysRole selectRoleById(Long roleId) - { + public SysRole selectRoleById(Long roleId) { return roleMapper.selectRoleById(roleId); } /** * 校验角色名称是否唯一 - * + * * @param role 角色信息 * @return 结果 */ @Override - public boolean checkRoleNameUnique(SysRole role) - { + public boolean checkRoleNameUnique(SysRole role) { Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName()); - if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -161,17 +147,15 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 校验角色权限是否唯一 - * + * * @param role 角色信息 * @return 结果 */ @Override - public boolean checkRoleKeyUnique(SysRole role) - { + public boolean checkRoleKeyUnique(SysRole role) { Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey()); - if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -179,60 +163,57 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 校验角色是否允许操作 - * + * * @param role 角色信息 */ @Override - public void checkRoleAllowed(SysRole role) - { - if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) - { + public void checkRoleAllowed(SysRole role) { + if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) { throw new ServiceException("不允许操作超级管理员角色"); } } /** * 校验角色是否有数据权限 - * + * * @param roleId 角色id */ @Override - public void checkRoleDataScope(Long roleId) - { - if (!SysUser.isAdmin(SecurityUtils.getUserId())) - { - SysRole role = new SysRole(); - role.setRoleId(roleId); - List roles = SpringUtils.getAopProxy(this).selectRoleList(role); - if (StringUtils.isEmpty(roles)) - { - throw new ServiceException("没有权限访问角色数据!"); - } + public void checkRoleDataScope(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + SysRole role = new SysRole(); + role.setRoleId(roleId); + List roles = SpringUtils.getAopProxy(this).selectRoleList(role); + if (StringUtils.isEmpty(roles)) { + throw new ServiceException("没有权限访问角色数据!"); } } /** * 通过角色ID查询角色使用数量 - * + * * @param roleId 角色ID * @return 结果 */ @Override - public int countUserRoleByRoleId(Long roleId) - { + public int countUserRoleByRoleId(Long roleId) { return userRoleMapper.countUserRoleByRoleId(roleId); } /** * 新增保存角色信息 - * + * * @param role 角色信息 * @return 结果 */ @Override @Transactional - public int insertRole(SysRole role) - { + public int insertRole(SysRole role) { // 新增角色信息 roleMapper.insertRole(role); return insertRoleMenu(role); @@ -240,14 +221,13 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 修改保存角色信息 - * + * * @param role 角色信息 * @return 结果 */ @Override @Transactional - public int updateRole(SysRole role) - { + public int updateRole(SysRole role) { // 修改角色信息 roleMapper.updateRole(role); // 删除角色与菜单关联 @@ -257,26 +237,29 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 修改角色状态 - * + * * @param role 角色信息 * @return 结果 */ @Override - public int updateRoleStatus(SysRole role) - { + public int updateRoleStatus(SysRole role) { + Long roleId = role.getRoleId(); + String status = role.getStatus(); + if (UserConstants.ROLE_DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } return roleMapper.updateRole(role); } /** * 修改数据权限信息 - * + * * @param role 角色信息 * @return 结果 */ @Override @Transactional - public int authDataScope(SysRole role) - { + public int authDataScope(SysRole role) { // 修改角色信息 roleMapper.updateRole(role); // 删除角色与部门关联 @@ -287,23 +270,20 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 新增角色菜单信息 - * + * * @param role 角色对象 */ - public int insertRoleMenu(SysRole role) - { + public int insertRoleMenu(SysRole role) { int rows = 1; // 新增用户与角色管理 List list = new ArrayList<>(); - for (Long menuId : role.getMenuIds()) - { + for (Long menuId : role.getMenuIds()) { SysRoleMenu rm = new SysRoleMenu(); rm.setRoleId(role.getRoleId()); rm.setMenuId(menuId); list.add(rm); } - if (list.size() > 0) - { + if (list.size() > 0) { rows = roleMenuMapper.batchRoleMenu(list); } return rows; @@ -314,20 +294,17 @@ public class SysRoleServiceImpl implements ISysRoleService * * @param role 角色对象 */ - public int insertRoleDept(SysRole role) - { + public int insertRoleDept(SysRole role) { int rows = 1; // 新增角色与部门(数据权限)管理 List list = new ArrayList<>(); - for (Long deptId : role.getDeptIds()) - { + for (Long deptId : role.getDeptIds()) { SysRoleDept rd = new SysRoleDept(); rd.setRoleId(role.getRoleId()); rd.setDeptId(deptId); list.add(rd); } - if (list.size() > 0) - { + if (list.size() > 0) { rows = roleDeptMapper.batchRoleDept(list); } return rows; @@ -335,14 +312,13 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 通过角色ID删除角色 - * + * * @param roleId 角色ID * @return 结果 */ @Override @Transactional - public int deleteRoleById(Long roleId) - { + public int deleteRoleById(Long roleId) { // 删除角色与菜单关联 roleMenuMapper.deleteRoleMenuByRoleId(roleId); // 删除角色与部门关联 @@ -352,22 +328,19 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 批量删除角色信息 - * + * * @param roleIds 需要删除的角色ID * @return 结果 */ @Override @Transactional - public int deleteRoleByIds(Long[] roleIds) - { - for (Long roleId : roleIds) - { + public int deleteRoleByIds(Long[] roleIds) { + for (Long roleId : roleIds) { checkRoleAllowed(new SysRole(roleId)); checkRoleDataScope(roleId); SysRole role = selectRoleById(roleId); - if (countUserRoleByRoleId(roleId) > 0) - { - throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName())); + if (countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除!", role.getRoleName())); } } // 删除角色与菜单关联 @@ -379,43 +352,39 @@ public class SysRoleServiceImpl implements ISysRoleService /** * 取消授权用户角色 - * + * * @param userRole 用户和角色关联信息 * @return 结果 */ @Override - public int deleteAuthUser(SysUserRole userRole) - { + public int deleteAuthUser(SysUserRole userRole) { return userRoleMapper.deleteUserRoleInfo(userRole); } /** * 批量取消授权用户角色 - * - * @param roleId 角色ID + * + * @param roleId 角色ID * @param userIds 需要取消授权的用户数据ID * @return 结果 */ @Override - public int deleteAuthUsers(Long roleId, Long[] userIds) - { + public int deleteAuthUsers(Long roleId, Long[] userIds) { return userRoleMapper.deleteUserRoleInfos(roleId, userIds); } /** * 批量选择授权用户角色 - * - * @param roleId 角色ID + * + * @param roleId 角色ID * @param userIds 需要授权的用户数据ID * @return 结果 */ @Override - public int insertAuthUsers(Long roleId, Long[] userIds) - { + public int insertAuthUsers(Long roleId, Long[] userIds) { // 新增用户与角色管理 List list = new ArrayList<>(); - for (Long userId : userIds) - { + for (Long userId : userIds) { SysUserRole ur = new SysUserRole(); ur.setUserId(userId); ur.setRoleId(roleId); @@ -423,4 +392,36 @@ public class SysRoleServiceImpl implements ISysRoleService } return userRoleMapper.batchUserRole(list); } + + /** + * 注销该角色的在线用户 + * @param roleId + */ + @Override + public void cleanOnlineUserByRole(Long roleId) { + // 如果角色未绑定用户 直接返回 + int num = userRoleMapper.countUserRoleByRoleId(roleId); + if (num == 0) { + return; + } + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java deleted file mode 100644 index 4ec764b..0000000 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.ruoyi.system.service.impl; - -import org.springframework.stereotype.Service; -import com.ruoyi.common.core.core.domain.model.LoginUser; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.system.domain.SysUserOnline; -import com.ruoyi.system.service.ISysUserOnlineService; - -/** - * 在线用户 服务层处理 - * - * @author ruoyi - */ -@Service -public class SysUserOnlineServiceImpl implements ISysUserOnlineService -{ - /** - * 通过登录地址查询信息 - * - * @param ipaddr 登录地址 - * @param user 用户信息 - * @return 在线用户信息 - */ - @Override - public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user) - { - if (StringUtils.equals(ipaddr, user.getIpaddr())) - { - return loginUserToUserOnline(user); - } - return null; - } - - /** - * 通过用户名称查询信息 - * - * @param userName 用户名称 - * @param user 用户信息 - * @return 在线用户信息 - */ - @Override - public SysUserOnline selectOnlineByUserName(String userName, LoginUser user) - { - if (StringUtils.equals(userName, user.getUsername())) - { - return loginUserToUserOnline(user); - } - return null; - } - - /** - * 通过登录地址/用户名称查询信息 - * - * @param ipaddr 登录地址 - * @param userName 用户名称 - * @param user 用户信息 - * @return 在线用户信息 - */ - @Override - public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user) - { - if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) - { - return loginUserToUserOnline(user); - } - return null; - } - - /** - * 设置在线用户信息 - * - * @param user 用户信息 - * @return 在线用户 - */ - @Override - public SysUserOnline loginUserToUserOnline(LoginUser user) - { - if (StringUtils.isNull(user) || StringUtils.isNull(user.getUser())) - { - return null; - } - SysUserOnline sysUserOnline = new SysUserOnline(); - sysUserOnline.setTokenId(user.getToken()); - sysUserOnline.setUserName(user.getUsername()); - sysUserOnline.setIpaddr(user.getIpaddr()); - sysUserOnline.setLoginLocation(user.getLoginLocation()); - sysUserOnline.setBrowser(user.getBrowser()); - sysUserOnline.setOs(user.getOs()); - sysUserOnline.setLoginTime(user.getLoginTime()); - if (StringUtils.isNotNull(user.getUser().getDept())) - { - sysUserOnline.setDeptName(user.getUser().getDept().getDeptName()); - } - return sysUserOnline; - } -} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index fee0fff..7c087db 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -4,26 +4,28 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.constant.CacheNames; +import com.ruoyi.common.core.service.UserService; +import com.ruoyi.common.core.utils.MapstructUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.*; +import com.ruoyi.system.domain.bo.SysUserBo; import jakarta.annotation.Resource; import jakarta.validation.Validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import com.ruoyi.common.core.annotation.DataScope; import com.ruoyi.common.core.constant.UserConstants; -import com.ruoyi.common.core.core.domain.entity.SysRole; -import com.ruoyi.common.core.core.domain.entity.SysUser; import com.ruoyi.common.core.exception.ServiceException; -import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.bean.BeanValidators; -import com.ruoyi.common.core.utils.spring.SpringUtils; -import com.ruoyi.system.domain.SysPost; -import com.ruoyi.system.domain.SysUserPost; -import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.system.mapper.SysPostMapper; import com.ruoyi.system.mapper.SysRoleMapper; import com.ruoyi.system.mapper.SysUserMapper; @@ -34,12 +36,11 @@ import com.ruoyi.system.service.ISysUserService; /** * 用户 业务层处理 - * + * * @author ruoyi */ @Service -public class SysUserServiceImpl implements ISysUserService -{ +public class SysUserServiceImpl implements ISysUserService, UserService { private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class); @Resource @@ -65,79 +66,72 @@ public class SysUserServiceImpl implements ISysUserService /** * 根据条件分页查询用户列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @Override @DataScope(deptAlias = "d", userAlias = "u") - public List selectUserList(SysUser user) - { + public List selectUserList(SysUser user) { return userMapper.selectUserList(user); } /** * 根据条件分页查询已分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @Override @DataScope(deptAlias = "d", userAlias = "u") - public List selectAllocatedList(SysUser user) - { + public List selectAllocatedList(SysUser user) { return userMapper.selectAllocatedList(user); } /** * 根据条件分页查询未分配用户角色列表 - * + * * @param user 用户信息 * @return 用户信息集合信息 */ @Override @DataScope(deptAlias = "d", userAlias = "u") - public List selectUnallocatedList(SysUser user) - { + public List selectUnallocatedList(SysUser user) { return userMapper.selectUnallocatedList(user); } /** * 通过用户名查询用户 - * + * * @param userName 用户名 * @return 用户对象信息 */ @Override - public SysUser selectUserByUserName(String userName) - { + public SysUser selectUserByUserName(String userName) { return userMapper.selectUserByUserName(userName); } /** * 通过用户ID查询用户 - * + * * @param userId 用户ID * @return 用户对象信息 */ @Override - public SysUser selectUserById(Long userId) - { + public SysUser selectUserById(Long userId) { return userMapper.selectUserById(userId); } /** * 查询用户所属角色组 - * + * * @param userName 用户名 * @return 结果 */ @Override - public String selectUserRoleGroup(String userName) - { + public String selectUserRoleGroup(String userName) { List list = roleMapper.selectRolesByUserName(userName); - if (CollectionUtils.isEmpty(list)) - { + if (CollectionUtils.isEmpty(list)) { return StringUtils.EMPTY; } return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(",")); @@ -145,16 +139,14 @@ public class SysUserServiceImpl implements ISysUserService /** * 查询用户所属岗位组 - * + * * @param userName 用户名 * @return 结果 */ @Override - public String selectUserPostGroup(String userName) - { + public String selectUserPostGroup(String userName) { List list = postMapper.selectPostsByUserName(userName); - if (CollectionUtils.isEmpty(list)) - { + if (CollectionUtils.isEmpty(list)) { return StringUtils.EMPTY; } return list.stream().map(SysPost::getPostName).collect(Collectors.joining(",")); @@ -162,17 +154,15 @@ public class SysUserServiceImpl implements ISysUserService /** * 校验用户名称是否唯一 - * + * * @param user 用户信息 * @return 结果 */ @Override - public boolean checkUserNameUnique(SysUser user) - { + public boolean checkUserNameUnique(SysUser user) { Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); SysUser info = userMapper.checkUserNameUnique(user.getUserName()); - if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -185,12 +175,10 @@ public class SysUserServiceImpl implements ISysUserService * @return */ @Override - public boolean checkPhoneUnique(SysUser user) - { + public boolean checkPhoneUnique(SysUser user) { Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); - if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -203,12 +191,10 @@ public class SysUserServiceImpl implements ISysUserService * @return */ @Override - public boolean checkEmailUnique(SysUser user) - { + public boolean checkEmailUnique(SysUser user) { Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); SysUser info = userMapper.checkEmailUnique(user.getEmail()); - if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) - { + if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; @@ -216,48 +202,47 @@ public class SysUserServiceImpl implements ISysUserService /** * 校验用户是否允许操作 - * + * * @param user 用户信息 */ @Override - public void checkUserAllowed(SysUser user) - { - if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) - { + public void checkUserAllowed(SysUser user) { + if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) { throw new ServiceException("不允许操作超级管理员用户"); } } /** * 校验用户是否有数据权限 - * + * * @param userId 用户id */ @Override - public void checkUserDataScope(Long userId) - { - if (!SysUser.isAdmin(SecurityUtils.getUserId())) - { - SysUser user = new SysUser(); - user.setUserId(userId); - List users = SpringUtils.getAopProxy(this).selectUserList(user); - if (StringUtils.isEmpty(users)) - { - throw new ServiceException("没有权限访问用户数据!"); - } + public void checkUserDataScope(Long userId) { + if (ObjectUtil.isNull(userId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + + SysUser user = new SysUser(); + user.setUserId(userId); + List users = SpringUtils.getAopProxy(this).selectUserList(user); + if (StringUtils.isEmpty(users)) { + throw new ServiceException("没有权限访问用户数据!"); } } /** * 新增保存用户信息 - * + * * @param user 用户信息 * @return 结果 */ @Override @Transactional - public int insertUser(SysUser user) - { + public int insertUser(SysUser user) { // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 @@ -269,26 +254,28 @@ public class SysUserServiceImpl implements ISysUserService /** * 注册用户信息 - * + * * @param user 用户信息 * @return 结果 */ @Override - public boolean registerUser(SysUser user) - { - return userMapper.insertUser(user) > 0; + public boolean registerUser(SysUser user, Long tenantId) { + user.setCreateBy(user.getUserId()); + user.setUpdateBy(user.getUserId()); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + sysUser.setTenantId(Long.valueOf(tenantId)); + return userMapper.insertUser(sysUser) > 0; } /** * 修改保存用户信息 - * + * * @param user 用户信息 * @return 结果 */ @Override @Transactional - public int updateUser(SysUser user) - { + public int updateUser(SysUser user) { Long userId = user.getUserId(); // 删除用户与角色关联 userRoleMapper.deleteUserRoleByUserId(userId); @@ -303,104 +290,94 @@ public class SysUserServiceImpl implements ISysUserService /** * 用户授权角色 - * - * @param userId 用户ID + * + * @param userId 用户ID * @param roleIds 角色组 */ @Override @Transactional - public void insertUserAuth(Long userId, Long[] roleIds) - { + public void insertUserAuth(Long userId, Long[] roleIds) { userRoleMapper.deleteUserRoleByUserId(userId); insertUserRole(userId, roleIds); } /** * 修改用户状态 - * + * * @param user 用户信息 * @return 结果 */ @Override - public int updateUserStatus(SysUser user) - { + public int updateUserStatus(SysUser user) { return userMapper.updateUser(user); } /** * 修改用户基本信息 - * + * * @param user 用户信息 * @return 结果 */ @Override - public int updateUserProfile(SysUser user) - { + public int updateUserProfile(SysUser user) { return userMapper.updateUser(user); } /** * 修改用户头像 - * + * * @param userName 用户名 - * @param avatar 头像地址 + * @param avatar 头像地址 * @return 结果 */ @Override - public boolean updateUserAvatar(String userName, String avatar) - { + public boolean updateUserAvatar(String userName, String avatar) { return userMapper.updateUserAvatar(userName, avatar) > 0; } /** * 重置用户密码 - * + * * @param user 用户信息 * @return 结果 */ @Override - public int resetPwd(SysUser user) - { + public int resetPwd(SysUser user) { return userMapper.updateUser(user); } /** * 重置用户密码 - * + * * @param userName 用户名 * @param password 密码 * @return 结果 */ @Override - public int resetUserPwd(String userName, String password) - { + public int resetUserPwd(String userName, String password) { return userMapper.resetUserPwd(userName, password); } /** * 新增用户角色信息 - * + * * @param user 用户对象 */ - public void insertUserRole(SysUser user) - { + public void insertUserRole(SysUser user) { this.insertUserRole(user.getUserId(), user.getRoleIds()); } /** * 新增用户岗位信息 - * + * * @param user 用户对象 */ - public void insertUserPost(SysUser user) - { + public void insertUserPost(SysUser user) { Long[] posts = user.getPostIds(); - if (StringUtils.isNotEmpty(posts)) - { + if (StringUtils.isNotEmpty(posts)) { // 新增用户与岗位管理 List list = new ArrayList<>(posts.length); - for (Long postId : posts) - { + for (Long postId : posts) { SysUserPost up = new SysUserPost(); up.setUserId(user.getUserId()); up.setPostId(postId); @@ -412,18 +389,15 @@ public class SysUserServiceImpl implements ISysUserService /** * 新增用户角色信息 - * - * @param userId 用户ID + * + * @param userId 用户ID * @param roleIds 角色组 */ - public void insertUserRole(Long userId, Long[] roleIds) - { - if (StringUtils.isNotEmpty(roleIds)) - { + public void insertUserRole(Long userId, Long[] roleIds) { + if (StringUtils.isNotEmpty(roleIds)) { // 新增用户与角色管理 List list = new ArrayList<>(roleIds.length); - for (Long roleId : roleIds) - { + for (Long roleId : roleIds) { SysUserRole ur = new SysUserRole(); ur.setUserId(userId); ur.setRoleId(roleId); @@ -435,14 +409,13 @@ public class SysUserServiceImpl implements ISysUserService /** * 通过用户ID删除用户 - * + * * @param userId 用户ID * @return 结果 */ @Override @Transactional - public int deleteUserById(Long userId) - { + public int deleteUserById(Long userId) { // 删除用户与角色关联 userRoleMapper.deleteUserRoleByUserId(userId); // 删除用户与岗位表 @@ -452,16 +425,14 @@ public class SysUserServiceImpl implements ISysUserService /** * 批量删除用户信息 - * + * * @param userIds 需要删除的用户ID * @return 结果 */ @Override @Transactional - public int deleteUserByIds(Long[] userIds) - { - for (Long userId : userIds) - { + public int deleteUserByIds(Long[] userIds) { + for (Long userId : userIds) { checkUserAllowed(new SysUser(userId)); checkUserDataScope(userId); } @@ -474,73 +445,66 @@ public class SysUserServiceImpl implements ISysUserService /** * 导入用户数据 - * - * @param userList 用户数据列表 + * + * @param userList 用户数据列表 * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 - * @param operName 操作用户 + * @param operID 操作用户ID * @return 结果 */ @Override - public String importUser(List userList, Boolean isUpdateSupport, String operName) - { - if (StringUtils.isNull(userList) || userList.size() == 0) - { + public String importUser(List userList, Boolean isUpdateSupport, Long operID) { + 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 - { + String initPassword = configService.selectConfigByKey("sys.user.initPassword"); + for (SysUser user : userList) { + try { // 验证是否存在这个用户 SysUser u = userMapper.selectUserByUserName(user.getUserName()); - if (StringUtils.isNull(u)) - { + if (StringUtils.isNull(u)) { BeanValidators.validateWithException(validator, user); - user.setPassword(SecurityUtils.encryptPassword(password)); - user.setCreateBy(operName); + user.setPassword(BCrypt.hashpw(initPassword)); + user.setCreateBy(operID); userMapper.insertUser(user); successNum++; successMsg.append("
" + successNum + "、账号 " + user.getUserName() + " 导入成功"); - } - else if (isUpdateSupport) - { + } else if (isUpdateSupport) { BeanValidators.validateWithException(validator, user); checkUserAllowed(u); checkUserDataScope(u.getUserId()); user.setUserId(u.getUserId()); - user.setUpdateBy(operName); + user.setUpdateBy(operID); userMapper.updateUser(user); successNum++; successMsg.append("
" + successNum + "、账号 " + user.getUserName() + " 更新成功"); - } - else - { + } else { failureNum++; failureMsg.append("
" + failureNum + "、账号 " + user.getUserName() + " 已存在"); } - } - catch (Exception e) - { + } catch (Exception e) { failureNum++; String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; failureMsg.append(msg + e.getMessage()); log.error(msg, e); } } - if (failureNum > 0) - { + if (failureNum > 0) { failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); throw new ServiceException(failureMsg.toString()); - } - else - { + } else { successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); } return successMsg.toString(); } + + @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId") + @Override + public String selectUserNameById(Long userId) { + SysUser sysUser=userMapper.selectUserById(userId); + return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName(); + } } diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml new file mode 100644 index 0000000..f7cc143 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + `id`, `client_id`, `client_key`, `client_secret`, `grant_type`, `device_type`, `active_timeout`, `timeout`, + `status`, `del_flag`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time` + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml index 8da9030..a195ee3 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -3,7 +3,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + @@ -13,15 +13,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - + - select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark + select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_by, create_time, remark from sys_dict_data @@ -34,43 +33,40 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND dict_label like concat('%', #{dictLabel}, '%') - - AND status = #{status} - order by dict_sort asc - + - + - + - + - + delete from sys_dict_data where dict_code = #{dictCode} - + delete from sys_dict_data where dict_code in #{dictCode} - + - + update sys_dict_data @@ -81,18 +77,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" css_class = #{cssClass}, list_class = #{listClass}, is_default = #{isDefault}, - status = #{status}, remark = #{remark}, update_by = #{updateBy}, update_time = sysdate() where dict_code = #{dictCode} - + update sys_dict_data set dict_type = #{newDictType} where dict_type = #{oldDictType} - + insert into sys_dict_data( dict_sort, @@ -102,7 +97,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" css_class, list_class, is_default, - status, remark, create_by, create_time @@ -114,11 +108,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{cssClass}, #{listClass}, #{isDefault}, - #{status}, #{remark}, #{createBy}, sysdate() ) - - \ No newline at end of file + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml index 55b4075..5f738b0 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -8,15 +8,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - + - select dict_id, dict_name, dict_type, status, create_by, create_time, remark + select dict_id, dict_name, dict_type, create_by, create_time, remark from sys_dict_type @@ -26,9 +25,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND dict_name like concat('%', #{dictName}, '%') - - AND status = #{status} - AND dict_type like concat('%', #{dictType}, '%') @@ -40,35 +36,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + - + - + - + - + delete from sys_dict_type where dict_id = #{dictId} - + delete from sys_dict_type where dict_id in #{dictId} - + @@ -76,30 +72,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" dict_name = #{dictName}, dict_type = #{dictType}, - status = #{status}, remark = #{remark}, update_by = #{updateBy}, update_time = sysdate() where dict_id = #{dictId} - + insert into sys_dict_type( dict_name, dict_type, - status, remark, create_by, create_time )values( #{dictName}, #{dictType}, - #{status}, #{remark}, #{createBy}, sysdate() ) - - \ No newline at end of file + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml index b16ae05..741f460 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -6,9 +6,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -26,7 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + @@ -36,7 +38,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + @@ -45,9 +47,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + - select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, + select u.user_id, u.tenant_id,u.dept_id, u.user_name, u.nick_name, u.user_type, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status from sys_user u @@ -55,9 +57,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" left join sys_user_role ur on u.user_id = ur.user_id left join sys_role r on r.role_id = ur.role_id - + - + - + - + - + - + - + - + - - + + + insert into sys_user( user_id, dept_id, @@ -173,7 +179,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" sysdate() ) - + update sys_user @@ -194,28 +200,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where user_id = #{userId} - + update sys_user set status = #{status} where user_id = #{userId} - + update sys_user set avatar = #{avatar} where user_name = #{userName} - + update sys_user set password = #{password} where user_name = #{userName} - + update sys_user set del_flag = '1' where user_id = #{userId} - + update sys_user set del_flag = '1' where user_id in #{userId} - + - - \ No newline at end of file + + diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index 143d181..0926cae 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -33,7 +33,7 @@ ], "repository": { "type": "git", - "url": "https://gitee.com/y_project/RuoYi-Vue.git" + "url": "https://gitee.com/dataprince/ruoyi-flex.git" }, "dependencies": { "@riophae/vue-treeselect": "0.4.0", diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js index 649f59c..a0028c2 100644 --- a/ruoyi-ui/src/api/login.js +++ b/ruoyi-ui/src/api/login.js @@ -1,12 +1,18 @@ import request from '@/utils/request' +// pc端固定客户端授权id +const clientId = 'e5cd7e4891bf95d1d19206ce24a7b32e'; + // 登录方法 -export function login(username, password, code, uuid) { - const data = { +export function login(tenantId,username, password, code, uuid) { + const params = { + tenantId, username, password, code, - uuid + uuid, + clientId: clientId, + grantType: 'password' } return request({ url: '/login', @@ -14,7 +20,7 @@ export function login(username, password, code, uuid) { isToken: false }, method: 'post', - data: data + data: params }) } @@ -56,4 +62,4 @@ export function getCodeImg() { method: 'get', timeout: 20000 }) -} \ No newline at end of file +} diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js index ab0a6fe..4f20423 100644 --- a/ruoyi-ui/src/store/modules/user.js +++ b/ruoyi-ui/src/store/modules/user.js @@ -31,12 +31,13 @@ const user = { actions: { // 登录 Login({ commit }, userInfo) { + const tenantId = userInfo.tenantId const username = userInfo.username.trim() const password = userInfo.password const code = userInfo.code const uuid = userInfo.uuid return new Promise((resolve, reject) => { - login(username, password, code, uuid).then(res => { + login(tenantId,username, password, code, uuid).then(res => { setToken(res.token) commit('SET_TOKEN', res.token) resolve() diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue index 1261ec5..862f96e 100644 --- a/ruoyi-ui/src/views/login.vue +++ b/ruoyi-ui/src/views/login.vue @@ -1,7 +1,17 @@