From ddcb9c5334317a6c815ae57a452b450d839dee78 Mon Sep 17 00:00:00 2001 From: rentaiming <806181062@qq.com> Date: 星期二, 25 六月 2024 11:03:55 +0800 Subject: [PATCH] 森林防火框架 --- ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java | 57 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java | 339 ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm | 105 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java | 100 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java | 402 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java | 63 ruoyi-modules/ruoyi-file/src/main/resources/logback.xml | 74 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java | 83 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java | 494 + ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm | 116 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java | 56 ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobMapper.xml | 111 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java | 46 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/utils/HuaWeiSMSUtil.java | 180 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignRequestInterceptor.java | 54 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/SecurityUtils.java | 121 ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml | 74 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java | 374 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresPermissions.java | 27 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ResetPwdDTO.java | 27 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java | 260 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java | 521 + ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java | 123 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java | 370 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java | 270 ruoyi-gateway/src/main/resources/bootstrap.yml | 127 ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 2 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/DictUtils.java | 75 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java | 93 ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java | 52 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer.java | 77 ruoyi-gateway/src/main/resources/banner.txt | 10 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java | 225 ruoyi-common/ruoyi-common-redis/pom.xml | 39 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignAutoConfiguration.java | 20 ruoyi-gateway/src/main/resources/logback.xml | 74 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java | 68 ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm | 135 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java | 49 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java | 77 ruoyi-modules/ruoyi-system/src/main/resources/banner.txt | 10 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml | 90 ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/CacheRequestFilter.java | 87 ruoyi-modules/pom.xml | 25 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 260 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java | 46 ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm | 602 + ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/AgreementDTO.java | 30 ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm | 169 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java | 34 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java | 29 ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/sub-domain.java.vm | 76 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java | 46 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml | 124 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java | 131 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/IndexDto.java | 11 ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt | 10 ruoyi-common/ruoyi-common-seata/pom.xml | 27 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/query/SysOperLogQuery.java | 16 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java | 148 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java | 98 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleUpdateDto.java | 27 ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm | 61 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/DelayTaskController.java | 50 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java | 44 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/PreAuthorizeAspect.java | 97 ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java | 56 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java | 48 ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SwaggerHandler.java | 56 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java | 155 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java | 86 ruoyi-visual/pom.xml | 22 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java | 40 ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml | 127 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/WebMvcConfig.java | 33 ruoyi-modules/ruoyi-system/src/main/resources/logback.xml | 74 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java | 99 ruoyi-modules/ruoyi-gen/pom.xml | 111 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AgreementServiceImpl.java | 60 ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerWebConfiguration.java | 20 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java | 91 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/AgreementMapper.xml | 5 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CustomConfigVO.java | 28 ruoyi-modules/ruoyi-system/pom.xml | 135 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java | 99 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DelayTaskServiceImpl.java | 67 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SupplierVO.java | 25 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java | 66 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml | 34 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java | 44 ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerProperties.java | 343 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java | 84 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java | 42 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java | 20 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java | 133 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml | 54 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RoleInfoVo.java | 25 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java | 86 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java | 48 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java | 154 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java | 172 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java | 79 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java | 166 ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml | 202 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresLogin.java | 18 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AgreementMapper.java | 16 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierDTO.java | 28 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java | 82 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java | 102 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java | 154 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml | 122 ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm | 474 + ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleAddDto.java | 24 ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm | 505 + ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java | 182 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java | 68 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Agreement.java | 64 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/ApplicationConfig.java | 102 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/WebSocketController.java | 43 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java | 186 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java | 22 ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java | 65 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java | 46 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml | 83 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java | 66 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java | 128 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java | 60 ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm | 91 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java | 586 + ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java | 138 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableRyFeignClients.java | 27 ruoyi-visual/ruoyi-monitor/pom.xml | 75 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java | 645 + ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml | 25 ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt | 1 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java | 25 ruoyi-modules/ruoyi-job/src/main/resources/banner.txt | 10 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java | 60 ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java | 41 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenus.java | 109 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/AgreementController.java | 66 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java | 49 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthLogic.java | 373 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SwaggerProvider.java | 81 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketConfig.java | 20 ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java | 119 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java | 245 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java | 20 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/StateCloudObsUtil.java | 101 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java | 93 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java | 44 ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm | 44 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/interceptor/HeaderInterceptor.java | 54 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DelayTaskMapper.java | 16 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthUtil.java | 167 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java | 572 + ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm | 590 + ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm | 22 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml | 275 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java | 185 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java | 140 ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml | 82 ruoyi-modules/ruoyi-file/src/main/resources/banner.txt | 10 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserRoleServiceImpl.java | 95 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java | 214 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java | 113 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java | 82 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java | 112 ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml | 74 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableCustomConfig.java | 31 ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java | 30 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java | 93 ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/annotation/EnableCustomSwagger2.java | 20 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java | 106 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java | 51 ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobLogMapper.xml | 93 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java | 60 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/IAgreementService.java | 26 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java | 106 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/MemberPointsMapper.xml | 5 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java | 23 ruoyi-modules/ruoyi-file/pom.xml | 96 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketUsers.java | 123 ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java | 129 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java | 46 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java | 34 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java | 48 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java | 171 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java | 135 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PointsConfigDTO.java | 27 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java | 89 ruoyi-common/ruoyi-common-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 3 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java | 139 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java | 461 + ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml | 34 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer_Bak.java | 97 ruoyi-gateway/pom.xml | 159 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java | 138 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java | 117 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserRoleController.java | 106 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TCompanyToUserVo.java | 28 ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java | 41 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/InnerAuth.java | 19 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java | 83 ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 5 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java | 75 ruoyi-modules/ruoyi-job/pom.xml | 100 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java | 38 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java | 31 ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java | 23 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java | 137 ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerAutoConfiguration.java | 129 ruoyi-common/ruoyi-common-security/pom.xml | 39 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java | 102 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java | 49 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/SemaphoreUtils.java | 59 ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java | 29 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java | 53 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml | 34 ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java | 135 ruoyi-modules/ruoyi-system/src/main/resources/mybatis-config.xml | 25 ruoyi-common/ruoyi-common-swagger/pom.xml | 51 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java | 211 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java | 108 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java | 64 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml | 162 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java | 173 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java | 179 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java | 34 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java | 49 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java | 60 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleQuery.java | 23 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java | 67 ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml | 40 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml | 157 ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml | 36 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierQuery.java | 19 ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java | 50 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java | 257 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml | 117 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java | 121 ruoyi-modules/ruoyi-job/src/main/resources/logback.xml | 74 ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java | 79 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/InnerAuthAspect.java | 51 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserRoleVO.java | 22 ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt | 10 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml | 105 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/DelayTaskService.java | 44 ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java | 33 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java | 118 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserDTO.java | 51 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java | 88 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java | 178 ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerBeanPostProcessor.java | 52 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserRoleService.java | 64 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java | 124 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/DelayTaskMapper.xml | 6 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java | 78 ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java | 28 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/Logical.java | 20 ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java | 83 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java | 115 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresRoles.java | 26 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml | 89 ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java | 268 ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml | 25 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java | 95 267 files changed, 27,572 insertions(+), 0 deletions(-) diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml new file mode 100644 index 0000000..529a141 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-common-redis</artifactId> + + <description> + ruoyi-common-redis缓存服务 + </description> + + <dependencies> + + <!-- SpringBoot Boot Redis --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-redis</artifactId> + </dependency> + + <!-- RuoYi Common Core--> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-core</artifactId> + </dependency> + <!-- redis分布式锁框架 --> + <dependency> + <groupId>org.redisson</groupId> + <artifactId>redisson</artifactId> + <version>3.19.3</version> + </dependency> + + </dependencies> +</project> \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..80e1be4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java @@ -0,0 +1,49 @@ +package com.ruoyi.common.redis.configure; + +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<T> implements RedisSerializer<T> +{ + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class<T> clazz; + + + public FastJson2JsonRedisSerializer(Class<T> 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-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java new file mode 100644 index 0000000..60daf6d --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java @@ -0,0 +1,68 @@ +package com.ruoyi.common.redis.configure; + +import java.io.IOException; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +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.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * redis配置 + * + * @author ruoyi + */ +@Configuration +@EnableCaching +@AutoConfigureBefore(RedisAutoConfiguration.class) +public class RedisConfig extends CachingConfigurerSupport +{ + @Bean + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) + { + RedisTemplate<Object, Object> 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; + } + + //Redis监听容器 + @Bean + public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + return container; + } + + @Bean(destroyMethod = "shutdown") // 服务停止后调用 shutdown 方法。 + public RedissonClient redisson() throws IOException { + // 1.创建配置 + Config config = new Config(); + // 集群模式 + // config.useClusterServers().addNodeAddress("192.168.110.188:7004", "192.168.110.188:7001"); + // 2.根据 Config 创建出 RedissonClient 示例。 + config.useSingleServer().setAddress("redis://192.168.110.188:6379").setPassword("123456"); + return Redisson.create(config); + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java new file mode 100644 index 0000000..435cb6e --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java @@ -0,0 +1,268 @@ +package com.ruoyi.common.redis.service; + +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 RedisService +{ + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public <T> void setCacheObject(final String key, final T value) + { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public <T> void setCacheObject(final String key, final T value, final Long 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> T getCacheObject(final String key) + { + ValueOperations<String, T> 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 <T> long setCacheList(final String key, final List<T> dataList) + { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public <T> List<T> getCacheList(final String key) + { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) + { + BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); + Iterator<T> it = dataSet.iterator(); + while (it.hasNext()) + { + setOperation.add(it.next()); + } + return setOperation; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public <T> Set<T> getCacheSet(final String key) + { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public <T> void setCacheMap(final String key, final Map<String, T> dataMap) + { + if (dataMap != null) { + redisTemplate.opsForHash().putAll(key, dataMap); + } + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public <T> Map<String, T> getCacheMap(final String key) + { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public <T> 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> T getCacheMapValue(final String key, final String hKey) + { + HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> 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<String> keys(final String pattern) + { + return redisTemplate.keys(pattern); + } +} 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..9ff60df --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.ruoyi.common.redis.configure.RedisConfig +com.ruoyi.common.redis.service.RedisService diff --git a/ruoyi-common/ruoyi-common-seata/pom.xml b/ruoyi-common/ruoyi-common-seata/pom.xml new file mode 100644 index 0000000..7e8ce07 --- /dev/null +++ b/ruoyi-common/ruoyi-common-seata/pom.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-common-seata</artifactId> + + <description> + ruoyi-common-seata分布式事务 + </description> + + <dependencies> + + <!-- SpringBoot Seata --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-seata</artifactId> + </dependency> + + </dependencies> +</project> \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-security/pom.xml b/ruoyi-common/ruoyi-common-security/pom.xml new file mode 100644 index 0000000..e9ae931 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-common-security</artifactId> + + <description> + ruoyi-common-security安全模块 + </description> + + <dependencies> + + <!-- Spring Web --> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + </dependency> + + <!-- RuoYi Api System --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-api-system</artifactId> + </dependency> + + <!-- RuoYi Common Redis--> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-redis</artifactId> + </dependency> + + </dependencies> + +</project> diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableCustomConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableCustomConfig.java new file mode 100644 index 0000000..c07c3a8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableCustomConfig.java @@ -0,0 +1,31 @@ +package com.ruoyi.common.security.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 org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.context.annotation.Import; +import org.springframework.scheduling.annotation.EnableAsync; +import com.ruoyi.common.security.config.ApplicationConfig; +import com.ruoyi.common.security.feign.FeignAutoConfiguration; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +// 表示通过aop框架暴露该代理对象,AopContext能够访问 +@EnableAspectJAutoProxy(exposeProxy = true) +// 指定要扫描的Mapper类的包的路径 +@MapperScan("com.ruoyi.**.mapper") +// 开启线程异步执行 +@EnableAsync +// 自动加载类 +@Import({ ApplicationConfig.class, FeignAutoConfiguration.class }) +public @interface EnableCustomConfig +{ + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableRyFeignClients.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableRyFeignClients.java new file mode 100644 index 0000000..4eb416e --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/EnableRyFeignClients.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.security.annotation; + +import org.springframework.cloud.openfeign.EnableFeignClients; +import java.lang.annotation.*; + +/** + * 自定义feign注解 + * 添加basePackages路径 + * + * @author ruoyi + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@EnableFeignClients +public @interface EnableRyFeignClients +{ + String[] value() default {}; + + String[] basePackages() default { "com.ruoyi" }; + + Class<?>[] basePackageClasses() default {}; + + Class<?>[] defaultConfiguration() default {}; + + Class<?>[] clients() default {}; +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/InnerAuth.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/InnerAuth.java new file mode 100644 index 0000000..6eada07 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/InnerAuth.java @@ -0,0 +1,19 @@ +package com.ruoyi.common.security.annotation; + +import java.lang.annotation.*; + +/** + * 内部认证注解 + * + * @author ruoyi + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface InnerAuth +{ + /** + * 是否校验用户信息 + */ + boolean isUser() default false; +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/Logical.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/Logical.java new file mode 100644 index 0000000..4b787a0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/Logical.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.security.annotation; + +/** + * 权限注解的验证模式 + * + * @author ruoyi + * + */ +public enum Logical +{ + /** + * 必须具有所有的元素 + */ + AND, + + /** + * 只需具有其中一个元素 + */ + OR +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresLogin.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresLogin.java new file mode 100644 index 0000000..f196ff5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresLogin.java @@ -0,0 +1,18 @@ +package com.ruoyi.common.security.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 登录认证:只有登录之后才能进入该方法 + * + * @author ruoyi + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface RequiresLogin +{ +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresPermissions.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresPermissions.java new file mode 100644 index 0000000..aef624d --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresPermissions.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.security.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 权限认证:必须具有指定权限才能进入该方法 + * + * @author ruoyi + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface RequiresPermissions +{ + /** + * 需要校验的权限码 + */ + String[] value() default {}; + + /** + * 验证模式:AND | OR,默认AND + */ + Logical logical() default Logical.AND; +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresRoles.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresRoles.java new file mode 100644 index 0000000..042e4c2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/annotation/RequiresRoles.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.security.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 角色认证:必须具有指定角色标识才能进入该方法 + * + * @author ruoyi + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) +public @interface RequiresRoles +{ + /** + * 需要校验的角色标识 + */ + String[] value() default {}; + + /** + * 验证逻辑:AND | OR,默认AND + */ + Logical logical() default Logical.AND; +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/InnerAuthAspect.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/InnerAuthAspect.java new file mode 100644 index 0000000..82d8b03 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/InnerAuthAspect.java @@ -0,0 +1,51 @@ +package com.ruoyi.common.security.aspect; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.exception.InnerAuthException; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.annotation.InnerAuth; + +/** + * 内部服务调用验证处理 + * + * @author ruoyi + */ +@Aspect +@Component +public class InnerAuthAspect implements Ordered +{ + @Around("@annotation(innerAuth)") + public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable + { + String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE); + // 内部请求验证 + if (!StringUtils.equals(SecurityConstants.INNER, source)) + { + throw new InnerAuthException("没有内部访问权限,不允许访问"); + } + + String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID); + String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME); + // 用户信息验证 + if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))) + { + throw new InnerAuthException("没有设置用户信息,不允许访问 "); + } + return point.proceed(); + } + + /** + * 确保在权限认证aop执行前执行 + */ + @Override + public int getOrder() + { + return Ordered.HIGHEST_PRECEDENCE + 1; + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/PreAuthorizeAspect.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/PreAuthorizeAspect.java new file mode 100644 index 0000000..bc75873 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/aspect/PreAuthorizeAspect.java @@ -0,0 +1,97 @@ +package com.ruoyi.common.security.aspect; + +import java.lang.reflect.Method; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import com.ruoyi.common.security.annotation.RequiresLogin; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.annotation.RequiresRoles; +import com.ruoyi.common.security.auth.AuthUtil; + +/** + * 基于 Spring Aop 的注解鉴权 + * + * @author kong + */ +@Aspect +@Component +public class PreAuthorizeAspect +{ + /** + * 构建 + */ + public PreAuthorizeAspect() + { + } + + /** + * 定义AOP签名 (切入所有使用鉴权注解的方法) + */ + public static final String POINTCUT_SIGN = " @annotation(com.ruoyi.common.security.annotation.RequiresLogin) || " + + "@annotation(com.ruoyi.common.security.annotation.RequiresPermissions) || " + + "@annotation(com.ruoyi.common.security.annotation.RequiresRoles)"; + + /** + * 声明AOP签名 + */ + @Pointcut(POINTCUT_SIGN) + public void pointcut() + { + } + + /** + * 环绕切入 + * + * @param joinPoint 切面对象 + * @return 底层方法执行后的返回值 + * @throws Throwable 底层方法抛出的异常 + */ + @Around("pointcut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable + { + // 注解鉴权 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + checkMethodAnnotation(signature.getMethod()); + try + { + // 执行原有逻辑 + Object obj = joinPoint.proceed(); + return obj; + } + catch (Throwable e) + { + throw e; + } + } + + /** + * 对一个Method对象进行注解检查 + */ + public void checkMethodAnnotation(Method method) + { + // 校验 @RequiresLogin 注解 + RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class); + if (requiresLogin != null) + { + AuthUtil.checkLogin(); + } + + // 校验 @RequiresRoles 注解 + RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class); + if (requiresRoles != null) + { + AuthUtil.checkRole(requiresRoles); + } + + // 校验 @RequiresPermissions 注解 + RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class); + if (requiresPermissions != null) + { + AuthUtil.checkPermi(requiresPermissions); + } + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthLogic.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthLogic.java new file mode 100644 index 0000000..fa04637 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthLogic.java @@ -0,0 +1,373 @@ +package com.ruoyi.common.security.auth; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import org.springframework.util.PatternMatchUtils; +import com.ruoyi.common.core.context.SecurityContextHolder; +import com.ruoyi.common.core.exception.auth.NotLoginException; +import com.ruoyi.common.core.exception.auth.NotPermissionException; +import com.ruoyi.common.core.exception.auth.NotRoleException; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.annotation.Logical; +import com.ruoyi.common.security.annotation.RequiresLogin; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.annotation.RequiresRoles; +import com.ruoyi.common.security.service.TokenService; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.model.LoginUser; + +/** + * Token 权限验证,逻辑实现类 + * + * @author ruoyi + */ +public class AuthLogic +{ + /** 所有权限标识 */ + private static final String ALL_PERMISSION = "*:*:*"; + + /** 管理员角色权限标识 */ + private static final String SUPER_ADMIN = "admin"; + + public TokenService tokenService = SpringUtils.getBean(TokenService.class); + + /** + * 会话注销 + */ + public void logout() + { + String token = SecurityUtils.getToken(); + if (token == null) + { + return; + } + logoutByToken(token); + } + + /** + * 会话注销,根据指定Token + */ + public void logoutByToken(String token) + { + tokenService.delLoginUser(token); + } + + /** + * 检验用户是否已经登录,如未登录,则抛出异常 + */ + public void checkLogin() + { + getLoginUser(); + } + + /** + * 获取当前用户缓存信息, 如果未登录,则抛出异常 + * + * @return 用户缓存信息 + */ + public LoginUser getLoginUser() + { + String token = SecurityUtils.getToken(); + if (token == null) + { + throw new NotLoginException("未提供token"); + } + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser == null) + { + throw new NotLoginException("无效的token"); + } + return loginUser; + } + + /** + * 获取当前用户缓存信息, 如果未登录,则抛出异常 + * + * @param token 前端传递的认证信息 + * @return 用户缓存信息 + */ + public LoginUser getLoginUser(String token) + { + return tokenService.getLoginUser(token); + } + + /** + * 验证当前用户有效期, 如果相差不足120分钟,自动刷新缓存 + * + * @param loginUser 当前用户信息 + */ + public void verifyLoginUserExpire(LoginUser loginUser) + { + tokenService.verifyToken(loginUser); + } + + /** + * 验证用户是否具备某权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public boolean hasPermi(String permission) + { + return hasPermi(getPermiList(), permission); + } + + /** + * 验证用户是否具备某权限, 如果验证未通过,则抛出异常: NotPermissionException + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public void checkPermi(String permission) + { + if (!hasPermi(getPermiList(), permission)) + { + throw new NotPermissionException(permission); + } + } + + /** + * 根据注解(@RequiresPermissions)鉴权, 如果验证未通过,则抛出异常: NotPermissionException + * + * @param requiresPermissions 注解对象 + */ + public void checkPermi(RequiresPermissions requiresPermissions) + { + SecurityContextHolder.setPermission(StringUtils.join(requiresPermissions.value(), ",")); + if (requiresPermissions.logical() == Logical.AND) + { + checkPermiAnd(requiresPermissions.value()); + } + else + { + checkPermiOr(requiresPermissions.value()); + } + } + + /** + * 验证用户是否含有指定权限,必须全部拥有 + * + * @param permissions 权限列表 + */ + public void checkPermiAnd(String... permissions) + { + Set<String> permissionList = getPermiList(); + for (String permission : permissions) + { + if (!hasPermi(permissionList, permission)) + { + throw new NotPermissionException(permission); + } + } + } + + /** + * 验证用户是否含有指定权限,只需包含其中一个 + * + * @param permissions 权限码数组 + */ + public void checkPermiOr(String... permissions) + { + Set<String> permissionList = getPermiList(); + for (String permission : permissions) + { + if (hasPermi(permissionList, permission)) + { + return; + } + } + if (permissions.length > 0) + { + throw new NotPermissionException(permissions); + } + } + + /** + * 判断用户是否拥有某个角色 + * + * @param role 角色标识 + * @return 用户是否具备某角色 + */ + public boolean hasRole(String role) + { + return hasRole(getRoleList(), role); + } + + /** + * 判断用户是否拥有某个角色, 如果验证未通过,则抛出异常: NotRoleException + * + * @param role 角色标识 + */ + public void checkRole(String role) + { + if (!hasRole(role)) + { + throw new NotRoleException(role); + } + } + + /** + * 根据注解(@RequiresRoles)鉴权 + * + * @param requiresRoles 注解对象 + */ + public void checkRole(RequiresRoles requiresRoles) + { + if (requiresRoles.logical() == Logical.AND) + { + checkRoleAnd(requiresRoles.value()); + } + else + { + checkRoleOr(requiresRoles.value()); + } + } + + /** + * 验证用户是否含有指定角色,必须全部拥有 + * + * @param roles 角色标识数组 + */ + public void checkRoleAnd(String... roles) + { + Set<String> roleList = getRoleList(); + for (String role : roles) + { + if (!hasRole(roleList, role)) + { + throw new NotRoleException(role); + } + } + } + + /** + * 验证用户是否含有指定角色,只需包含其中一个 + * + * @param roles 角色标识数组 + */ + public void checkRoleOr(String... roles) + { + Set<String> roleList = getRoleList(); + for (String role : roles) + { + if (hasRole(roleList, role)) + { + return; + } + } + if (roles.length > 0) + { + throw new NotRoleException(roles); + } + } + + /** + * 根据注解(@RequiresLogin)鉴权 + * + * @param at 注解对象 + */ + public void checkByAnnotation(RequiresLogin at) + { + this.checkLogin(); + } + + /** + * 根据注解(@RequiresRoles)鉴权 + * + * @param at 注解对象 + */ + public void checkByAnnotation(RequiresRoles at) + { + String[] roleArray = at.value(); + if (at.logical() == Logical.AND) + { + this.checkRoleAnd(roleArray); + } + else + { + this.checkRoleOr(roleArray); + } + } + + /** + * 根据注解(@RequiresPermissions)鉴权 + * + * @param at 注解对象 + */ + public void checkByAnnotation(RequiresPermissions at) + { + String[] permissionArray = at.value(); + if (at.logical() == Logical.AND) + { + this.checkPermiAnd(permissionArray); + } + else + { + this.checkPermiOr(permissionArray); + } + } + + /** + * 获取当前账号的角色列表 + * + * @return 角色列表 + */ + public Set<String> getRoleList() + { + try + { + LoginUser loginUser = getLoginUser(); + return loginUser.getRoles(); + } + catch (Exception e) + { + return new HashSet<>(); + } + } + + /** + * 获取当前账号的权限列表 + * + * @return 权限列表 + */ + public Set<String> getPermiList() + { + try + { + LoginUser loginUser = getLoginUser(); + return loginUser.getPermissions(); + } + catch (Exception e) + { + return new HashSet<>(); + } + } + + /** + * 判断是否包含权限 + * + * @param authorities 权限列表 + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public boolean hasPermi(Collection<String> authorities, String permission) + { + return authorities.stream().filter(StringUtils::hasText) + .anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission)); + } + + /** + * 判断是否包含角色 + * + * @param roles 角色列表 + * @param role 角色 + * @return 用户是否具备某角色权限 + */ + public boolean hasRole(Collection<String> roles, String role) + { + return roles.stream().filter(StringUtils::hasText) + .anyMatch(x -> SUPER_ADMIN.contains(x) || PatternMatchUtils.simpleMatch(x, role)); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthUtil.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthUtil.java new file mode 100644 index 0000000..8b0d86c --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthUtil.java @@ -0,0 +1,167 @@ +package com.ruoyi.common.security.auth; + +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.annotation.RequiresRoles; +import com.ruoyi.system.api.model.LoginUser; + +/** + * Token 权限验证工具类 + * + * @author ruoyi + */ +public class AuthUtil +{ + /** + * 底层的 AuthLogic 对象 + */ + public static AuthLogic authLogic = new AuthLogic(); + + /** + * 会话注销 + */ + public static void logout() + { + authLogic.logout(); + } + + /** + * 会话注销,根据指定Token + * + * @param token 指定token + */ + public static void logoutByToken(String token) + { + authLogic.logoutByToken(token); + } + + /** + * 检验当前会话是否已经登录,如未登录,则抛出异常 + */ + public static void checkLogin() + { + authLogic.checkLogin(); + } + + /** + * 获取当前登录用户信息 + * + * @param token 指定token + * @return 用户信息 + */ + public static LoginUser getLoginUser(String token) + { + return authLogic.getLoginUser(token); + } + + /** + * 验证当前用户有效期 + * + * @param loginUser 用户信息 + */ + public static void verifyLoginUserExpire(LoginUser loginUser) + { + authLogic.verifyLoginUserExpire(loginUser); + } + + /** + * 当前账号是否含有指定角色标识, 返回true或false + * + * @param role 角色标识 + * @return 是否含有指定角色标识 + */ + public static boolean hasRole(String role) + { + return authLogic.hasRole(role); + } + + /** + * 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException + * + * @param role 角色标识 + */ + public static void checkRole(String role) + { + authLogic.checkRole(role); + } + + /** + * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotRoleException + * + * @param requiresRoles 角色权限注解 + */ + public static void checkRole(RequiresRoles requiresRoles) + { + authLogic.checkRole(requiresRoles); + } + + /** + * 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] + * + * @param roles 角色标识数组 + */ + public static void checkRoleAnd(String... roles) + { + authLogic.checkRoleAnd(roles); + } + + /** + * 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] + * + * @param roles 角色标识数组 + */ + public static void checkRoleOr(String... roles) + { + authLogic.checkRoleOr(roles); + } + + /** + * 当前账号是否含有指定权限, 返回true或false + * + * @param permission 权限码 + * @return 是否含有指定权限 + */ + public static boolean hasPermi(String permission) + { + return authLogic.hasPermi(permission); + } + + /** + * 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException + * + * @param permission 权限码 + */ + public static void checkPermi(String permission) + { + authLogic.checkPermi(permission); + } + + /** + * 根据注解传入参数鉴权, 如果验证未通过,则抛出异常: NotPermissionException + * + * @param requiresPermissions 权限注解 + */ + public static void checkPermi(RequiresPermissions requiresPermissions) + { + authLogic.checkPermi(requiresPermissions); + } + + /** + * 当前账号是否含有指定权限 [指定多个,必须全部验证通过] + * + * @param permissions 权限码数组 + */ + public static void checkPermiAnd(String... permissions) + { + authLogic.checkPermiAnd(permissions); + } + + /** + * 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] + * + * @param permissions 权限码数组 + */ + public static void checkPermiOr(String... permissions) + { + authLogic.checkPermiOr(permissions); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/ApplicationConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/ApplicationConfig.java new file mode 100644 index 0000000..dfb1063 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/ApplicationConfig.java @@ -0,0 +1,102 @@ +package com.ruoyi.common.security.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.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.core.convert.converter.Converter; + +/** + * 系统配置 + * + * @author ruoyi + */ +public class ApplicationConfig +{ + + private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + private static final String DATE_PATTERN = "yyyy-MM-dd"; + /** + * 时区配置 + */ + @Bean + public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() + { + return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault()); + } + + @Bean + public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { + return builder -> { + // Long 会自动转换成 String + builder.serializerByType(Long.class, ToStringSerializer.instance); + }; + } + + /** + * string转localdate + */ + @Bean + public Converter<String, LocalDate> localDateConverter() { + return new Converter<String, LocalDate>() { + @Override + public LocalDate convert(String source) { + if (source.trim().length() == 0) { + return null; + } + try { + return LocalDate.parse(source); + } catch (Exception e) { + return LocalDate.parse(source, DateTimeFormatter.ofPattern(DATE_PATTERN)); + } + } + }; + } + + /** + * string转localdatetime + */ + @Bean + public Converter<String, LocalDateTime> localDateTimeConverter() { + return new Converter<String, LocalDateTime>() { + @Override + public LocalDateTime convert(String source) { + if (source.trim().length() == 0) { + return null; + } + // 先尝试ISO格式: 2019-07-15T16:00:00 + try { + return LocalDateTime.parse(source); + } catch (Exception e) { + return LocalDateTime.parse(source, + DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)); + } + } + }; + } + + /** + * 统一配置 + */ + @Bean + public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { + JavaTimeModule module = new JavaTimeModule(); + LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer( + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer); + return builder -> { + builder.simpleDateFormat(DATE_TIME_PATTERN); + builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_PATTERN))); + builder.serializers( + new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN))); + builder.modules(module); + }; + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/WebMvcConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/WebMvcConfig.java new file mode 100644 index 0000000..46adfd9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/WebMvcConfig.java @@ -0,0 +1,33 @@ +package com.ruoyi.common.security.config; + +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import com.ruoyi.common.security.interceptor.HeaderInterceptor; + +/** + * 拦截器配置 + * + * @author ruoyi + */ +public class WebMvcConfig implements WebMvcConfigurer +{ + /** 不需要拦截地址 */ + public static final String[] excludeUrls = { "/login", "/logout", "/refresh" }; + + @Override + public void addInterceptors(InterceptorRegistry registry) + { + registry.addInterceptor(getHeaderInterceptor()) + .addPathPatterns("/**") + .excludePathPatterns(excludeUrls) + .order(-10); + } + + /** + * 自定义请求头拦截器 + */ + public HeaderInterceptor getHeaderInterceptor() + { + return new HeaderInterceptor(); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignAutoConfiguration.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignAutoConfiguration.java new file mode 100644 index 0000000..304798d --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignAutoConfiguration.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.security.feign; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import feign.RequestInterceptor; + +/** + * Feign 配置注册 + * + * @author ruoyi + **/ +@Configuration +public class FeignAutoConfiguration +{ + @Bean + public RequestInterceptor requestInterceptor() + { + return new FeignRequestInterceptor(); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignRequestInterceptor.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignRequestInterceptor.java new file mode 100644 index 0000000..33e12c6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/feign/FeignRequestInterceptor.java @@ -0,0 +1,54 @@ +package com.ruoyi.common.security.feign; + +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Component; +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.ip.IpUtils; +import feign.RequestInterceptor; +import feign.RequestTemplate; + +/** + * feign 请求拦截器 + * + * @author ruoyi + */ +@Component +public class FeignRequestInterceptor implements RequestInterceptor +{ + @Override + public void apply(RequestTemplate requestTemplate) + { + HttpServletRequest httpServletRequest = ServletUtils.getRequest(); + if (StringUtils.isNotNull(httpServletRequest)) + { + Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest); + // 传递用户信息请求头,防止丢失 + String userId = headers.get(SecurityConstants.DETAILS_USER_ID); + if (StringUtils.isNotEmpty(userId)) + { + requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId); + } + String userKey = headers.get(SecurityConstants.USER_KEY); + if (StringUtils.isNotEmpty(userKey)) + { + requestTemplate.header(SecurityConstants.USER_KEY, userKey); + } + String userName = headers.get(SecurityConstants.DETAILS_USERNAME); + if (StringUtils.isNotEmpty(userName)) + { + requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName); + } + String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER); + if (StringUtils.isNotEmpty(authentication)) + { + requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication); + } + + // 配置客户端IP + requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr()); + } + } +} \ No newline at end of file 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..a9cb1b7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/handler/GlobalExceptionHandler.java @@ -0,0 +1,154 @@ +package com.ruoyi.common.security.handler; + +import javax.naming.SizeLimitExceededException; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.fileupload.FileUploadBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import com.ruoyi.common.core.constant.HttpStatus; +import com.ruoyi.common.core.exception.DemoModeException; +import com.ruoyi.common.core.exception.InnerAuthException; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.exception.auth.NotPermissionException; +import com.ruoyi.common.core.exception.auth.NotRoleException; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.web.domain.AjaxResult; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartException; + +/** + * 全局异常处理器 + * + * @author ruoyi + */ +@RestControllerAdvice +public class GlobalExceptionHandler +{ + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + @Value("${spring.servlet.multipart.max-file-size:4MB}") + private String maxFileSize; + @Value("${spring.servlet.multipart.max-request-size:100MB}") + private String maxRequestSize; + + + /** + * 权限码异常 + */ + @ExceptionHandler(NotPermissionException.class) + public AjaxResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); + return AjaxResult.error(HttpStatus.FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + + /** + * 角色权限异常 + */ + @ExceptionHandler(NotRoleException.class) + public AjaxResult handleNotRoleException(NotRoleException 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(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(InnerAuthException.class) + public AjaxResult handleInnerAuthException(InnerAuthException e) + { + return AjaxResult.error(e.getMessage()); + } + + /** + * 演示模式异常 + */ + @ExceptionHandler(DemoModeException.class) + public AjaxResult handleDemoModeException(DemoModeException e) + { + return AjaxResult.error("演示模式,不允许操作"); + } + + @ExceptionHandler(MaxUploadSizeExceededException.class) + public AjaxResult fileUpLoad(MaxUploadSizeExceededException e) { + log.error("上传文件异常 => : {}", e.getMessage()); + return AjaxResult.error("文件识别大小超出限制,允许的大小在" + maxFileSize); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/interceptor/HeaderInterceptor.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/interceptor/HeaderInterceptor.java new file mode 100644 index 0000000..18c8d2b --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/interceptor/HeaderInterceptor.java @@ -0,0 +1,54 @@ +package com.ruoyi.common.security.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.AsyncHandlerInterceptor; +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.context.SecurityContextHolder; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.auth.AuthUtil; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.model.LoginUser; + +/** + * 自定义请求头拦截器,将Header数据封装到线程变量中方便获取 + * 注意:此拦截器会同时验证当前用户有效期自动刷新有效期 + * + * @author ruoyi + */ +public class HeaderInterceptor implements AsyncHandlerInterceptor +{ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception + { + if (!(handler instanceof HandlerMethod)) + { + return true; + } + + SecurityContextHolder.setUserId(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USER_ID)); + SecurityContextHolder.setUserName(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USERNAME)); + SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY)); + + String token = SecurityUtils.getToken(); + if (StringUtils.isNotEmpty(token)) + { + LoginUser loginUser = AuthUtil.getLoginUser(token); + if (StringUtils.isNotNull(loginUser)) + { + AuthUtil.verifyLoginUserExpire(loginUser); + SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser); + } + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception + { + SecurityContextHolder.remove(); + } +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java new file mode 100644 index 0000000..b7fa65b --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java @@ -0,0 +1,172 @@ +package com.ruoyi.common.security.service; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; + +import com.ruoyi.common.core.constant.Constants; +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.SecurityConstants; +import com.ruoyi.common.core.utils.JwtUtils; +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.common.core.utils.uuid.IdUtils; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.model.LoginUser; + +/** + * token验证处理 + * + * @author ruoyi + */ +@Component +public class TokenService +{ + @Autowired + private RedisService redisService; + + protected static final long MILLIS_SECOND = 1000; + + protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; + + + private final static long EXPIRE_TIME = CacheConstants.EXPIRATION; + + private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY; + + private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE; + + /** + * 创建令牌 + */ + public Map<String, Object> createToken(LoginUser loginUser) + { + String token = IdUtils.fastUUID(); + Long userId = loginUser.getSysUser().getUserId(); + String userName = loginUser.getSysUser().getUserName(); + loginUser.setToken(token); + loginUser.setUserid(userId); + loginUser.setUsername(userName); + loginUser.setIpaddr(IpUtils.getIpAddr()); + refreshToken(loginUser); + + // Jwt存储信息 + Map<String, Object> claimsMap = new HashMap<String, Object>(); + claimsMap.put(SecurityConstants.USER_KEY, token); + claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); + claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName); + + // 接口返回信息 + Map<String, Object> rspMap = new HashMap<String, Object>(); + rspMap.put("access_token", JwtUtils.createToken(claimsMap)); + rspMap.put("expires_in", EXPIRE_TIME); + return rspMap; + } + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser() + { + return getLoginUser(ServletUtils.getRequest()); + } + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(HttpServletRequest request) + { + // 获取请求携带的令牌 + String token = SecurityUtils.getToken(request); + return getLoginUser(token); + } + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(String token) + { + LoginUser user = null; + try + { + if (StringUtils.isNotEmpty(token)) + { + String userkey = JwtUtils.getUserKey(token); + user = redisService.getCacheObject(getTokenKey(userkey)); + return user; + } + } + catch (Exception e) + { + } + return user; + } + + /** + * 设置用户身份信息 + */ + 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 = JwtUtils.getUserKey(token); + redisService.deleteObject(getTokenKey(userkey)); + } + } + + /** + * 验证令牌有效期,相差不足120分钟,自动刷新缓存 + * + * @param loginUser + */ + 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() + EXPIRE_TIME * MILLIS_MINUTE); + // 根据uuid将loginUser缓存 + String userKey = getTokenKey(loginUser.getToken()); + redisService.setCacheObject(userKey, loginUser, EXPIRE_TIME, TimeUnit.MINUTES); + } + + private String getTokenKey(String token) + { + return ACCESS_TOKEN + token; + } +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/DictUtils.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/DictUtils.java new file mode 100644 index 0000000..8282fdc --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/DictUtils.java @@ -0,0 +1,75 @@ +package com.ruoyi.common.security.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.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.system.api.domain.SysDictData; + +/** + * 字典工具类 + * + * @author ruoyi + */ +public class DictUtils +{ + /** + * 设置字典缓存 + * + * @param key 参数键 + * @param dictDatas 字典数据列表 + */ + public static void setDictCache(String key, List<SysDictData> dictDatas) + { + SpringUtils.getBean(RedisService.class).setCacheObject(getCacheKey(key), dictDatas); + } + + /** + * 获取字典缓存 + * + * @param key 参数键 + * @return dictDatas 字典数据列表 + */ + public static List<SysDictData> getDictCache(String key) + { + JSONArray arrayCache = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key)); + if (StringUtils.isNotNull(arrayCache)) + { + return arrayCache.toList(SysDictData.class); + } + return null; + } + + /** + * 删除指定字典缓存 + * + * @param key 字典键 + */ + public static void removeDictCache(String key) + { + SpringUtils.getBean(RedisService.class).deleteObject(getCacheKey(key)); + } + + /** + * 清空字典缓存 + */ + public static void clearDictCache() + { + Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(CacheConstants.SYS_DICT_KEY + "*"); + SpringUtils.getBean(RedisService.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-security/src/main/java/com/ruoyi/common/security/utils/SecurityUtils.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/SecurityUtils.java new file mode 100644 index 0000000..07129e0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/SecurityUtils.java @@ -0,0 +1,121 @@ +package com.ruoyi.common.security.utils; + +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.constant.TokenConstants; +import com.ruoyi.common.core.context.SecurityContextHolder; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.api.model.LoginUser; +import javax.servlet.http.HttpServletRequest; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * 权限获取工具类 + * + * @author ruoyi + */ +public class SecurityUtils +{ + /** + * 获取用户ID + */ + public static Long getUserId() + { + return SecurityContextHolder.getUserId(); + } + + /** + * 获取用户名称 + */ + public static String getUsername() + { + return SecurityContextHolder.getUserName(); + } + + /** + * 获取用户key + */ + public static String getUserKey() + { + return SecurityContextHolder.getUserKey(); + } + + /** + * 获取登录用户信息 + */ + public static LoginUser getLoginUser() + { + return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class); + } + + /** + * 获取请求token + */ + public static String getToken() + { + return getToken(ServletUtils.getRequest()); + } + + /** + * 根据request获取请求token + */ + public static String getToken(HttpServletRequest request) + { + // 从header获取token标识 + String token = request.getHeader(TokenConstants.AUTHENTICATION); + if (StringUtils.isBlank(token)) { + // 如果Authorization为空,那么尝试读取Sec-Websocket-Protocol的内容 + token = request.getHeader("Sec-Websocket-Protocol"); + } + return replaceTokenPrefix(token); + } + + /** + * 裁剪token前缀 + */ + public static String replaceTokenPrefix(String token) + { + // 如果前端设置了令牌前缀,则裁剪掉前缀 + if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) + { + token = token.replaceFirst(TokenConstants.PREFIX, ""); + } + return token; + } + + /** + * 是否为管理员 + * + * @param userId 用户ID + * @return 结果 + */ + public static boolean isAdmin(Long userId) + { + return userId != null && 1L == userId; + } + + /** + * 生成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); + } +} 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..7418bbc --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,5 @@ +com.ruoyi.common.security.config.WebMvcConfig +com.ruoyi.common.security.service.TokenService +com.ruoyi.common.security.aspect.PreAuthorizeAspect +com.ruoyi.common.security.aspect.InnerAuthAspect +com.ruoyi.common.security.handler.GlobalExceptionHandler diff --git a/ruoyi-common/ruoyi-common-swagger/pom.xml b/ruoyi-common/ruoyi-common-swagger/pom.xml new file mode 100644 index 0000000..942b986 --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/pom.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-common-swagger</artifactId> + + <description> + ruoyi-common-swagger系统接口 + </description> + + <dependencies> + + <!-- SpringBoot Web --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + <!-- Swagger --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>${swagger.fox.version}</version> + </dependency> + + <dependency> + <groupId>com.github.xiaoymin</groupId> + <artifactId>swagger-bootstrap-ui</artifactId> + <version>1.9.6</version> + </dependency> + +<!-- <dependency>--> +<!-- <groupId>com.github.xiaoymin</groupId>--> +<!-- <artifactId>knife4j-spring-boot-starter</artifactId>--> +<!-- <version>2.0.8</version>--> +<!-- </dependency>--> + + <dependency> + <groupId>com.github.xiaoymin</groupId> + <artifactId>knife4j-spring-boot-starter</artifactId> + <version>3.0.3</version> + </dependency> + </dependencies> +</project> diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/annotation/EnableCustomSwagger2.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/annotation/EnableCustomSwagger2.java new file mode 100644 index 0000000..83bb3d7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/annotation/EnableCustomSwagger2.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.swagger.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 org.springframework.context.annotation.Import; +import com.ruoyi.common.swagger.config.SwaggerAutoConfiguration; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Import({ SwaggerAutoConfiguration.class }) +public @interface EnableCustomSwagger2 +{ + +} diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerAutoConfiguration.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerAutoConfiguration.java new file mode 100644 index 0000000..d49100a --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerAutoConfiguration.java @@ -0,0 +1,129 @@ +package com.ruoyi.common.swagger.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; +import io.swagger.annotations.ApiOperation; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.service.AuthorizationScope; +import springfox.documentation.service.Contact; +import springfox.documentation.service.SecurityReference; +import springfox.documentation.service.SecurityScheme; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.ApiSelectorBuilder; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +@EnableKnife4j +@EnableConfigurationProperties(SwaggerProperties.class) +@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true) +@Import({SwaggerBeanPostProcessor.class, SwaggerWebConfiguration.class}) +public class SwaggerAutoConfiguration +{ + /** + * 默认的排除路径,排除Spring Boot默认的错误处理路径和端点 + */ + private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**"); + + private static final String BASE_PATH = "/**"; + + @Bean + public Docket api(SwaggerProperties swaggerProperties) + { + // base-path处理 + if (swaggerProperties.getBasePath().isEmpty()) + { + swaggerProperties.getBasePath().add(BASE_PATH); + } + // noinspection unchecked + List<Predicate<String>> basePath = new ArrayList<Predicate<String>>(); + swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path))); + + // exclude-path处理 + if (swaggerProperties.getExcludePath().isEmpty()) + { + swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH); + } + + List<Predicate<String>> excludePath = new ArrayList<>(); + swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path))); + + ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost()) + .apiInfo(apiInfo(swaggerProperties)).select() +// .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()) + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)); + + swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p))); + swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate())); + +// return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/"); + return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/"); + } + + /** + * 安全模式,这里指定token通过Authorization头请求头传递 + */ + private List<SecurityScheme> securitySchemes() + { + List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>(); + apiKeyList.add(new ApiKey("Authorization", "Authorization", "header")); + return apiKeyList; + } + + /** + * 安全上下文 + */ + private List<SecurityContext> securityContexts() + { + List<SecurityContext> securityContexts = new ArrayList<>(); + securityContexts.add( + SecurityContext.builder() + .securityReferences(defaultAuth()) + .operationSelector(o -> o.requestMappingPattern().matches("/.*")) + .build()); + return securityContexts; + } + + /** + * 默认的全局鉴权策略 + * + * @return + */ + private List<SecurityReference> defaultAuth() + { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List<SecurityReference> securityReferences = new ArrayList<>(); + securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); + return securityReferences; + } + + private ApiInfo apiInfo(SwaggerProperties swaggerProperties) + { + return new ApiInfoBuilder() + .title(swaggerProperties.getTitle()) + .description(swaggerProperties.getDescription()) + .license(swaggerProperties.getLicense()) + .licenseUrl(swaggerProperties.getLicenseUrl()) + .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()) + .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())) + .version(swaggerProperties.getVersion()) + .build(); + } +} diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerBeanPostProcessor.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerBeanPostProcessor.java new file mode 100644 index 0000000..aa223b2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerBeanPostProcessor.java @@ -0,0 +1,52 @@ +package com.ruoyi.common.swagger.config; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; +import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider; +import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; + +/** + * swagger 在 springboot 2.6.x 不兼容问题的处理 + * + * @author ruoyi + */ +public class SwaggerBeanPostProcessor implements BeanPostProcessor +{ + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException + { + if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) + { + customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); + } + return bean; + } + + private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) + { + List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null) + .collect(Collectors.toList()); + mappings.clear(); + mappings.addAll(copy); + } + + @SuppressWarnings("unchecked") + private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) + { + try + { + Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings"); + field.setAccessible(true); + return (List<RequestMappingInfoHandlerMapping>) field.get(bean); + } + catch (IllegalArgumentException | IllegalAccessException e) + { + throw new IllegalStateException(e); + } + } +} diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerProperties.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerProperties.java new file mode 100644 index 0000000..7934ee3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerProperties.java @@ -0,0 +1,343 @@ +package com.ruoyi.common.swagger.config; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("swagger") +public class SwaggerProperties +{ + /** + * 是否开启swagger + */ + private Boolean enabled; + + /** + * swagger会解析的包路径 + **/ + private String basePackage = ""; + + /** + * swagger会解析的url规则 + **/ + private List<String> basePath = new ArrayList<>(); + + /** + * 在basePath基础上需要排除的url规则 + **/ + private List<String> excludePath = new ArrayList<>(); + + /** + * 标题 + **/ + private String title = ""; + + /** + * 描述 + **/ + private String description = ""; + + /** + * 版本 + **/ + private String version = ""; + + /** + * 许可证 + **/ + private String license = ""; + + /** + * 许可证URL + **/ + private String licenseUrl = ""; + + /** + * 服务条款URL + **/ + private String termsOfServiceUrl = ""; + + /** + * host信息 + **/ + private String host = ""; + + /** + * 联系人信息 + */ + private Contact contact = new Contact(); + + /** + * 全局统一鉴权配置 + **/ + private Authorization authorization = new Authorization(); + + public Boolean getEnabled() + { + return enabled; + } + + public void setEnabled(Boolean enabled) + { + this.enabled = enabled; + } + + public String getBasePackage() + { + return basePackage; + } + + public void setBasePackage(String basePackage) + { + this.basePackage = basePackage; + } + + public List<String> getBasePath() + { + return basePath; + } + + public void setBasePath(List<String> basePath) + { + this.basePath = basePath; + } + + public List<String> getExcludePath() + { + return excludePath; + } + + public void setExcludePath(List<String> excludePath) + { + this.excludePath = excludePath; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public String getVersion() + { + return version; + } + + public void setVersion(String version) + { + this.version = version; + } + + public String getLicense() + { + return license; + } + + public void setLicense(String license) + { + this.license = license; + } + + public String getLicenseUrl() + { + return licenseUrl; + } + + public void setLicenseUrl(String licenseUrl) + { + this.licenseUrl = licenseUrl; + } + + public String getTermsOfServiceUrl() + { + return termsOfServiceUrl; + } + + public void setTermsOfServiceUrl(String termsOfServiceUrl) + { + this.termsOfServiceUrl = termsOfServiceUrl; + } + + public String getHost() + { + return host; + } + + public void setHost(String host) + { + this.host = host; + } + + public Contact getContact() + { + return contact; + } + + public void setContact(Contact contact) + { + this.contact = contact; + } + + public Authorization getAuthorization() + { + return authorization; + } + + public void setAuthorization(Authorization authorization) + { + this.authorization = authorization; + } + + public static class Contact + { + /** + * 联系人 + **/ + private String name = ""; + /** + * 联系人url + **/ + private String url = ""; + /** + * 联系人email + **/ + private String email = ""; + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getUrl() + { + return url; + } + + public void setUrl(String url) + { + this.url = url; + } + + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } + } + + public static class Authorization + { + /** + * 鉴权策略ID,需要和SecurityReferences ID保持一致 + */ + private String name = ""; + + /** + * 需要开启鉴权URL的正则 + */ + private String authRegex = "^.*$"; + + /** + * 鉴权作用域列表 + */ + private List<AuthorizationScope> authorizationScopeList = new ArrayList<>(); + + private List<String> tokenUrlList = new ArrayList<>(); + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getAuthRegex() + { + return authRegex; + } + + public void setAuthRegex(String authRegex) + { + this.authRegex = authRegex; + } + + public List<AuthorizationScope> getAuthorizationScopeList() + { + return authorizationScopeList; + } + + public void setAuthorizationScopeList(List<AuthorizationScope> authorizationScopeList) + { + this.authorizationScopeList = authorizationScopeList; + } + + public List<String> getTokenUrlList() + { + return tokenUrlList; + } + + public void setTokenUrlList(List<String> tokenUrlList) + { + this.tokenUrlList = tokenUrlList; + } + } + + public static class AuthorizationScope + { + /** + * 作用域名称 + */ + private String scope = ""; + + /** + * 作用域描述 + */ + private String description = ""; + + public String getScope() + { + return scope; + } + + public void setScope(String scope) + { + this.scope = scope; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + } +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerWebConfiguration.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerWebConfiguration.java new file mode 100644 index 0000000..280aaeb --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SwaggerWebConfiguration.java @@ -0,0 +1,20 @@ +package com.ruoyi.common.swagger.config; + +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * swagger 资源映射路径 + * + * @author ruoyi + */ +public class SwaggerWebConfiguration implements WebMvcConfigurer +{ + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) + { + /** swagger-ui 地址 */ + registry.addResourceHandler("/swagger-ui/**","*/doc.html") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); + } +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..4c2e499 --- /dev/null +++ b/ruoyi-common/ruoyi-common-swagger/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +# com.ruoyi.common.swagger.config.SwaggerAutoConfiguration +# com.ruoyi.common.swagger.config.SwaggerWebConfiguration +# com.ruoyi.common.swagger.config.SwaggerBeanPostProcessor diff --git a/ruoyi-gateway/pom.xml b/ruoyi-gateway/pom.xml new file mode 100644 index 0000000..749a366 --- /dev/null +++ b/ruoyi-gateway/pom.xml @@ -0,0 +1,159 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-gateway</artifactId> + + <description> + ruoyi-gateway网关模块 + </description> + + <properties> + <druid.version>1.1.13</druid.version> + </properties> + + <dependencies> + + <!-- SpringCloud Gateway --> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-gateway</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos Config --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel Gateway --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> + </dependency> + + <!-- Sentinel Datasource Nacos --> + <dependency> + <groupId>com.alibaba.csp</groupId> + <artifactId>sentinel-datasource-nacos</artifactId> + </dependency> + + <!-- SpringBoot Actuator --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + + <!-- SpringCloud Loadbalancer --> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-loadbalancer</artifactId> + </dependency> + + <!--验证码 --> + <dependency> + <groupId>pro.fessional</groupId> + <artifactId>kaptcha</artifactId> + </dependency> + + <!-- RuoYi Common Redis--> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-redis</artifactId> + </dependency> + + <!-- Swagger --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${swagger.fox.version}</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>${swagger.fox.version}</version> + </dependency> + <!-- <dependency>--> + <!-- <groupId>com.github.xiaoymin</groupId>--> + <!-- <artifactId>knife4j-micro-spring-boot-starter</artifactId>--> + <!-- <version>2.0.8</version>--> + <!-- </dependency>--> + <!-- knife4j --> + <dependency> + <groupId>com.github.xiaoymin</groupId> + <artifactId>knife4j-spring-ui</artifactId> + <version>3.0.3</version> + </dependency> + <dependency> + <groupId>com.github.xiaoymin</groupId> + <artifactId>knife4j-spring-boot-starter</artifactId> + <version>3.0.3</version> + </dependency> + + <!-- 引入Druid依赖,阿里巴巴所提供的数据源 --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>druid-spring-boot-starter</artifactId> + <version>${druid.version}</version> + </dependency> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>fastjson</artifactId> + <version>1.2.47</version> + </dependency> + <!--mysql--> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + <!-- <dependency>--> + <!-- <groupId>org.springframework.boot</groupId>--> + <!-- <artifactId>spring-boot-starter-websocket</artifactId>--> + <!-- <optional>true</optional>--> + <!-- </dependency>--> + <!--hutool-all--> + <!-- <dependency>--> + <!-- <groupId>cn.hutool</groupId>--> + <!-- <artifactId>hutool-all</artifactId>--> + <!-- <version>5.0.3</version>--> + <!-- </dependency>--> + + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java new file mode 100644 index 0000000..3c54b77 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java @@ -0,0 +1,29 @@ +package com.ruoyi.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +/** + * 网关启动程序 + * + * @author ruoyi + */ +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) +public class RuoYiGatewayApplication +{ + public static void main(String[] args) + { + SpringApplication.run(RuoYiGatewayApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 若依网关启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java new file mode 100644 index 0000000..e6c6d9d --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java @@ -0,0 +1,83 @@ +package com.ruoyi.gateway.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.gateway.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; + } +} \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java new file mode 100644 index 0000000..3bb6d8e --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java @@ -0,0 +1,23 @@ +package com.ruoyi.gateway.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import com.ruoyi.gateway.handler.SentinelFallbackHandler; + +/** + * 网关限流配置 + * + * @author ruoyi + */ +@Configuration +public class GatewayConfig +{ + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public SentinelFallbackHandler sentinelGatewayExceptionHandler() + { + return new SentinelFallbackHandler(); + } +} \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java new file mode 100644 index 0000000..f68e0fa --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java @@ -0,0 +1,75 @@ +package com.ruoyi.gateway.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 (randomoperands == 2) + { + 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]); + } + } + else + { + result = x + y; + suChinese.append(CNUMBERS[x]); + suChinese.append("+"); + suChinese.append(CNUMBERS[y]); + } + suChinese.append("=?@" + result); + return suChinese.toString(); + } +} \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java new file mode 100644 index 0000000..ccc99f7 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java @@ -0,0 +1,79 @@ +package com.ruoyi.gateway.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.cors.reactive.CorsUtils; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import com.ruoyi.gateway.handler.ValidateCodeHandler; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +/** + * 路由配置信息 + * + * @author ruoyi + */ +@Configuration +public class RouterFunctionConfiguration +{ + + /** + * 这里为支持的请求头,如果有自定义的header字段请自己添加 + */ + private static final String ALLOWED_HEADERS = "X-Requested-With, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, request-origion"; + private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD"; + private static final String ALLOWED_ORIGIN = "*"; + private static final String ALLOWED_EXPOSE = "*"; + private static final String MAX_AGE = "18000L"; + + @Autowired + private ValidateCodeHandler validateCodeHandler; + + @SuppressWarnings("rawtypes") + @Bean + public RouterFunction routerFunction() + { + return RouterFunctions.route( + RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), + validateCodeHandler); + } + + /** + * 跨域配置 + */ + @Bean + public WebFilter corsFilter() + { + return (ServerWebExchange ctx, WebFilterChain chain) -> { + ServerHttpRequest request = ctx.getRequest(); + if (CorsUtils.isCorsRequest(request)) + { + ServerHttpResponse response = ctx.getResponse(); + HttpHeaders headers = response.getHeaders(); + headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS); + headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS); + headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN); + headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE); + headers.add("Access-Control-Max-Age", MAX_AGE); + headers.add("Access-Control-Allow-Credentials", "true"); + if (request.getMethod() == HttpMethod.OPTIONS) + { + response.setStatusCode(HttpStatus.OK); + return Mono.empty(); + } + } + return chain.filter(ctx); + }; + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SwaggerProvider.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SwaggerProvider.java new file mode 100644 index 0000000..b27b0cd --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SwaggerProvider.java @@ -0,0 +1,81 @@ +package com.ruoyi.gateway.config; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.config.GatewayProperties; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.support.NameUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.config.ResourceHandlerRegistry; +import org.springframework.web.reactive.config.WebFluxConfigurer; +import springfox.documentation.swagger.web.SwaggerResource; +import springfox.documentation.swagger.web.SwaggerResourcesProvider; + +/** + * 聚合系统接口 + * + * @author ruoyi + */ +@Primary +@Component +public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer +{ + /** + * Swagger2默认的url后缀 + */ + public static final String SWAGGER2URL = "/v2/api-docs"; + + /** + * 网关路由 + */ + @Lazy + @Autowired + private RouteLocator routeLocator; + + @Autowired + private GatewayProperties gatewayProperties; + + /** + * 聚合其他服务接口 + * + * @return + */ + @Override + public List<SwaggerResource> get() + { + List<SwaggerResource> resourceList = new ArrayList<>(); + List<String> routes = new ArrayList<>(); + // 获取网关中配置的route + routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); + gatewayProperties.getRoutes().stream() + .filter(routeDefinition -> routes + .contains(routeDefinition.getId())) + .forEach(routeDefinition -> routeDefinition.getPredicates().stream() + .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName())) +// .filter(predicateDefinition -> !"ruoyi-auth".equalsIgnoreCase(routeDefinition.getId())) + .forEach(predicateDefinition -> resourceList + .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs() + .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL))))); + return resourceList; + } + + private SwaggerResource swaggerResource(String name, String location) + { + SwaggerResource swaggerResource = new SwaggerResource(); + swaggerResource.setName(name); + swaggerResource.setLocation(location); + swaggerResource.setSwaggerVersion("2.0"); + return swaggerResource; + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) + { + /** swagger-ui 地址 */ + registry.addResourceHandler("/swagger-ui/**","*/doc.html") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java new file mode 100644 index 0000000..f6bb000 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java @@ -0,0 +1,46 @@ +package com.ruoyi.gateway.config.properties; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +/** + * 验证码配置 + * + * @author ruoyi + */ +@Configuration +@RefreshScope +@ConfigurationProperties(prefix = "security.captcha") +public class CaptchaProperties +{ + /** + * 验证码开关 + */ + private Boolean enabled; + + /** + * 验证码类型(math 数组计算 char 字符) + */ + private String type; + + public Boolean getEnabled() + { + return enabled; + } + + public void setEnabled(Boolean enabled) + { + this.enabled = enabled; + } + + public String getType() + { + return type; + } + + public void setType(String type) + { + this.type = type; + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java new file mode 100644 index 0000000..1d2c56a --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java @@ -0,0 +1,33 @@ +package com.ruoyi.gateway.config.properties; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +/** + * 放行白名单配置 + * + * @author ruoyi + */ +@Configuration +@RefreshScope +@ConfigurationProperties(prefix = "security.ignore") +public class IgnoreWhiteProperties +{ + /** + * 放行白名单配置,网关不校验此处的白名单 + */ + private List<String> whites = new ArrayList<>(); + + public List<String> getWhites() + { + return whites; + } + + public void setWhites(List<String> whites) + { + this.whites = whites; + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java new file mode 100644 index 0000000..891679e --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java @@ -0,0 +1,48 @@ +package com.ruoyi.gateway.config.properties; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +/** + * XSS跨站脚本配置 + * + * @author ruoyi + */ +@Configuration +@RefreshScope +@ConfigurationProperties(prefix = "security.xss") +public class XssProperties +{ + /** + * Xss开关 + */ + private Boolean enabled; + + /** + * 排除路径 + */ + private List<String> excludeUrls = new ArrayList<>(); + + public Boolean getEnabled() + { + return enabled; + } + + public void setEnabled(Boolean enabled) + { + this.enabled = enabled; + } + + public List<String> getExcludeUrls() + { + return excludeUrls; + } + + public void setExcludeUrls(List<String> excludeUrls) + { + this.excludeUrls = excludeUrls; + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java new file mode 100644 index 0000000..101de63 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java @@ -0,0 +1,135 @@ +package com.ruoyi.gateway.filter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.constant.HttpStatus; +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.constant.TokenConstants; +import com.ruoyi.common.core.utils.JwtUtils; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties; +import io.jsonwebtoken.Claims; +import reactor.core.publisher.Mono; + +/** + * 网关鉴权 + * + * @author ruoyi + */ +@Component +public class AuthFilter implements GlobalFilter, Ordered +{ + private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); + + // 排除过滤的 uri 地址,nacos自行添加 + @Autowired + private IgnoreWhiteProperties ignoreWhite; + + @Autowired + private RedisService redisService; + + + @Override + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) + { + ServerHttpRequest request = exchange.getRequest(); + ServerHttpRequest.Builder mutate = request.mutate(); + + String url = request.getURI().getPath(); + // 跳过不需要验证的路径 + if (StringUtils.matches(url, ignoreWhite.getWhites())) + { + return chain.filter(exchange); + } + String token = getToken(request); + if (StringUtils.isEmpty(token)) + { + return unauthorizedResponse(exchange, "令牌不能为空"); + } + Claims claims = JwtUtils.parseToken(token); + if (claims == null) + { + return unauthorizedResponse(exchange, "令牌已过期或验证不正确!"); + } + String userkey = JwtUtils.getUserKey(claims); + boolean islogin = redisService.hasKey(getTokenKey(userkey)); + if (!islogin) + { + return unauthorizedResponse(exchange, "登录状态已过期"); + } + String userid = JwtUtils.getUserId(claims); + String username = JwtUtils.getUserName(claims); + if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) + { + return unauthorizedResponse(exchange, "令牌验证失败"); + } + + // 设置用户信息到请求 + addHeader(mutate, SecurityConstants.USER_KEY, userkey); + addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid); + addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username); + // 内部请求来源参数清除 + removeHeader(mutate, SecurityConstants.FROM_SOURCE); + return chain.filter(exchange.mutate().request(mutate.build()).build()); + } + + private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) + { + if (value == null) + { + return; + } + String valueStr = value.toString(); + String valueEncode = ServletUtils.urlEncode(valueStr); + mutate.header(name, valueEncode); + } + + private void removeHeader(ServerHttpRequest.Builder mutate, String name) + { + mutate.headers(httpHeaders -> httpHeaders.remove(name)).build(); + } + + private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) + { + log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath()); + return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED); + } + + /** + * 获取缓存key + */ + private String getTokenKey(String token) + { + return CacheConstants.LOGIN_TOKEN_KEY + token; + } + + /** + * 获取请求token + */ + private String getToken(ServerHttpRequest request) + { + String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION); + // 如果前端设置了令牌前缀,则裁剪掉前缀 + if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) + { + token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY); + } + return token; + } + + @Override + public int getOrder() + { + return -200; + } +} \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java new file mode 100644 index 0000000..343bd01 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java @@ -0,0 +1,65 @@ +package com.ruoyi.gateway.filter; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.stereotype.Component; +import com.ruoyi.common.core.utils.ServletUtils; + +/** + * 黑名单过滤器 + * + * @author ruoyi + */ +@Component +public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config> +{ + @Override + public GatewayFilter apply(Config config) + { + return (exchange, chain) -> { + + String url = exchange.getRequest().getURI().getPath(); + if (config.matchBlacklist(url)) + { + return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问"); + } + + return chain.filter(exchange); + }; + } + + public BlackListUrlFilter() + { + super(Config.class); + } + + public static class Config + { + private List<String> blacklistUrl; + + private List<Pattern> blacklistUrlPattern = new ArrayList<>(); + + public boolean matchBlacklist(String url) + { + return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find()); + } + + public List<String> getBlacklistUrl() + { + return blacklistUrl; + } + + public void setBlacklistUrl(List<String> blacklistUrl) + { + this.blacklistUrl = blacklistUrl; + this.blacklistUrlPattern.clear(); + this.blacklistUrl.forEach(url -> { + this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE)); + }); + } + } + +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/CacheRequestFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/CacheRequestFilter.java new file mode 100644 index 0000000..94c6cb5 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/CacheRequestFilter.java @@ -0,0 +1,87 @@ +package com.ruoyi.gateway.filter; + +import java.util.Collections; +import java.util.List; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * 获取body请求数据(解决流不能重复读取问题) + * + * @author ruoyi + */ +@Component +public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config> +{ + public CacheRequestFilter() + { + super(Config.class); + } + + @Override + public String name() + { + return "CacheRequestFilter"; + } + + @Override + public GatewayFilter apply(Config config) + { + CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter(); + Integer order = config.getOrder(); + if (order == null) + { + return cacheRequestGatewayFilter; + } + return new OrderedGatewayFilter(cacheRequestGatewayFilter, order); + } + + public static class CacheRequestGatewayFilter implements GatewayFilter + { + @Override + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) + { + // GET DELETE 不过滤 + HttpMethod method = exchange.getRequest().getMethod(); + if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) + { + return chain.filter(exchange); + } + return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> { + if (serverHttpRequest == exchange.getRequest()) + { + return chain.filter(exchange); + } + return chain.filter(exchange.mutate().request(serverHttpRequest).build()); + }); + } + } + + @Override + public List<String> shortcutFieldOrder() + { + return Collections.singletonList("order"); + } + + static class Config + { + private Integer order; + + public Integer getOrder() + { + return order; + } + + public void setOrder(Integer order) + { + this.order = order; + } + } +} \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java new file mode 100644 index 0000000..d5b75fd --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java @@ -0,0 +1,79 @@ +package com.ruoyi.gateway.filter; + +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicReference; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.core.utils.ServletUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.gateway.config.properties.CaptchaProperties; +import com.ruoyi.gateway.service.ValidateCodeService; +import reactor.core.publisher.Flux; + +/** + * 验证码过滤器 + * + * @author ruoyi + */ +@Component +public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> +{ + private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" }; + + @Autowired + private ValidateCodeService validateCodeService; + + @Autowired + private CaptchaProperties captchaProperties; + + private static final String CODE = "code"; + + private static final String UUID = "uuid"; + + @Override + public GatewayFilter apply(Object config) + { + return (exchange, chain) -> { + ServerHttpRequest request = exchange.getRequest(); + + // 非登录/注册请求或验证码关闭,不处理 + if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) + { + return chain.filter(exchange); + } + + try + { + String rspStr = resolveBodyFromRequest(request); + JSONObject obj = JSON.parseObject(rspStr); + validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID)); + } + catch (Exception e) + { + return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage()); + } + return chain.filter(exchange); + }; + } + + private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) + { + // 获取请求体 + Flux<DataBuffer> body = serverHttpRequest.getBody(); + AtomicReference<String> bodyRef = new AtomicReference<>(); + body.subscribe(buffer -> { + CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer()); + DataBufferUtils.release(buffer); + bodyRef.set(charBuffer.toString()); + }); + return bodyRef.get(); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java new file mode 100644 index 0000000..6fe6285 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java @@ -0,0 +1,129 @@ +package com.ruoyi.gateway.filter; + +import java.nio.charset.StandardCharsets; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.core.io.buffer.NettyDataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.html.EscapeUtil; +import com.ruoyi.gateway.config.properties.XssProperties; +import io.netty.buffer.ByteBufAllocator; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * 跨站脚本过滤器 + * + * @author ruoyi + */ +@Component +@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true") +public class XssFilter implements GlobalFilter, Ordered +{ + // 跨站脚本的 xss 配置,nacos自行添加 + @Autowired + private XssProperties xss; + + @Override + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) + { + ServerHttpRequest request = exchange.getRequest(); + // xss开关未开启 或 通过nacos关闭,不过滤 + if (!xss.getEnabled()) + { + return chain.filter(exchange); + } + // GET DELETE 不过滤 + HttpMethod method = request.getMethod(); + if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) + { + return chain.filter(exchange); + } + // 非json类型,不过滤 + if (!isJsonRequest(exchange)) + { + return chain.filter(exchange); + } + // excludeUrls 不过滤 + String url = request.getURI().getPath(); + if (StringUtils.matches(url, xss.getExcludeUrls())) + { + return chain.filter(exchange); + } + ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange); + return chain.filter(exchange.mutate().request(httpRequestDecorator).build()); + + } + + private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) + { + ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) + { + @Override + public Flux<DataBuffer> getBody() + { + Flux<DataBuffer> body = super.getBody(); + return body.buffer().map(dataBuffers -> { + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer join = dataBufferFactory.join(dataBuffers); + byte[] content = new byte[join.readableByteCount()]; + join.read(content); + DataBufferUtils.release(join); + String bodyStr = new String(content, StandardCharsets.UTF_8); + // 防xss攻击过滤 + bodyStr = EscapeUtil.clean(bodyStr); + // 转成字节 + byte[] bytes = bodyStr.getBytes(); + NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); + DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); + buffer.write(bytes); + return buffer; + }); + } + + @Override + public HttpHeaders getHeaders() + { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.putAll(super.getHeaders()); + // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length + httpHeaders.remove(HttpHeaders.CONTENT_LENGTH); + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + return httpHeaders; + } + + }; + return serverHttpRequestDecorator; + } + + /** + * 是否是Json请求 + * + * @param exchange HTTP请求 + */ + public boolean isJsonRequest(ServerWebExchange exchange) + { + String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + } + + @Override + public int getOrder() + { + return -100; + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java new file mode 100644 index 0000000..29ea5e3 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java @@ -0,0 +1,56 @@ +package com.ruoyi.gateway.handler; + +import org.springframework.cloud.gateway.support.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.server.ServerWebExchange; +import com.ruoyi.common.core.utils.ServletUtils; +import reactor.core.publisher.Mono; + +/** + * 网关统一异常处理 + * + * @author ruoyi + */ +@Order(-1) +@Configuration +public class GatewayExceptionHandler implements ErrorWebExceptionHandler +{ + private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class); + + @Override + public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) + { + ServerHttpResponse response = exchange.getResponse(); + + if (exchange.getResponse().isCommitted()) + { + return Mono.error(ex); + } + + String msg; + + if (ex instanceof NotFoundException) + { + msg = "服务未找到"; + } + else if (ex instanceof ResponseStatusException) + { + ResponseStatusException responseStatusException = (ResponseStatusException) ex; + msg = responseStatusException.getMessage(); + } + else + { + msg = "内部服务器错误"; + } + + log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage()); + + return ServletUtils.webFluxResponseWriter(response, msg); + } +} \ No newline at end of file diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java new file mode 100644 index 0000000..86abf88 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java @@ -0,0 +1,41 @@ +package com.ruoyi.gateway.handler; + +import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.ruoyi.common.core.utils.ServletUtils; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebExceptionHandler; +import reactor.core.publisher.Mono; + +/** + * 自定义限流异常处理 + * + * @author ruoyi + */ +public class SentinelFallbackHandler implements WebExceptionHandler +{ + private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) + { + return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试"); + } + + @Override + public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) + { + if (exchange.getResponse().isCommitted()) + { + return Mono.error(ex); + } + if (!BlockException.isBlockException(ex)) + { + return Mono.error(ex); + } + return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange)); + } + + private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) + { + return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SwaggerHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SwaggerHandler.java new file mode 100644 index 0000000..daa21af --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SwaggerHandler.java @@ -0,0 +1,56 @@ +package com.ruoyi.gateway.handler; + +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; +import springfox.documentation.swagger.web.SecurityConfiguration; +import springfox.documentation.swagger.web.SecurityConfigurationBuilder; +import springfox.documentation.swagger.web.SwaggerResourcesProvider; +import springfox.documentation.swagger.web.UiConfiguration; +import springfox.documentation.swagger.web.UiConfigurationBuilder; + +@RestController +@RequestMapping("/swagger-resources") +public class SwaggerHandler +{ + @Autowired(required = false) + private SecurityConfiguration securityConfiguration; + + @Autowired(required = false) + private UiConfiguration uiConfiguration; + + private final SwaggerResourcesProvider swaggerResources; + + @Autowired + public SwaggerHandler(SwaggerResourcesProvider swaggerResources) + { + this.swaggerResources = swaggerResources; + } + + @GetMapping("/configuration/security") + public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() + { + return Mono.just(new ResponseEntity<>( + Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), + HttpStatus.OK)); + } + + @GetMapping("/configuration/ui") + public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() + { + return Mono.just(new ResponseEntity<>( + Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); + } + + @SuppressWarnings("rawtypes") + @GetMapping("") + public Mono<ResponseEntity> swaggerResources() + { + return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java new file mode 100644 index 0000000..45e7b15 --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java @@ -0,0 +1,41 @@ +package com.ruoyi.gateway.handler; + +import java.io.IOException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.HandlerFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import com.ruoyi.common.core.exception.CaptchaException; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.gateway.service.ValidateCodeService; +import reactor.core.publisher.Mono; + +/** + * 验证码获取 + * + * @author ruoyi + */ +@Component +public class ValidateCodeHandler implements HandlerFunction<ServerResponse> +{ + @Autowired + private ValidateCodeService validateCodeService; + + @Override + public Mono<ServerResponse> handle(ServerRequest serverRequest) + { + AjaxResult ajax; + try + { + ajax = validateCodeService.createCaptcha(); + } + catch (CaptchaException | IOException e) + { + return Mono.error(e); + } + return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax)); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java new file mode 100644 index 0000000..8a74aeb --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java @@ -0,0 +1,23 @@ +package com.ruoyi.gateway.service; + +import java.io.IOException; +import com.ruoyi.common.core.exception.CaptchaException; +import com.ruoyi.common.core.web.domain.AjaxResult; + +/** + * 验证码处理 + * + * @author ruoyi + */ +public interface ValidateCodeService +{ + /** + * 生成验证码 + */ + public AjaxResult createCaptcha() throws IOException, CaptchaException; + + /** + * 校验验证码 + */ + public void checkCaptcha(String key, String value) throws CaptchaException; +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java new file mode 100644 index 0000000..2ae87bd --- /dev/null +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java @@ -0,0 +1,119 @@ +package com.ruoyi.gateway.service.impl; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.FastByteArrayOutputStream; +import com.google.code.kaptcha.Producer; +import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.exception.CaptchaException; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.sign.Base64; +import com.ruoyi.common.core.utils.uuid.IdUtils; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.gateway.config.properties.CaptchaProperties; +import com.ruoyi.gateway.service.ValidateCodeService; + +/** + * 验证码实现处理 + * + * @author ruoyi + */ +@Service +public class ValidateCodeServiceImpl implements ValidateCodeService +{ + @Resource(name = "captchaProducer") + private Producer captchaProducer; + + @Resource(name = "captchaProducerMath") + private Producer captchaProducerMath; + + @Autowired + private RedisService redisService; + + @Autowired + private CaptchaProperties captchaProperties; + + /** + * 生成验证码 + */ + @Override + public AjaxResult createCaptcha() throws IOException, CaptchaException + { + AjaxResult ajax = AjaxResult.success(); + boolean captchaEnabled = captchaProperties.getEnabled(); + 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 = captchaProperties.getType(); + // 生成验证码 + 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); + } + + redisService.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; + } + + /** + * 校验验证码 + */ + @Override + public void checkCaptcha(String code, String uuid) throws CaptchaException + { + if (StringUtils.isEmpty(code)) + { + throw new CaptchaException("验证码不能为空"); + } + if (StringUtils.isEmpty(uuid)) + { + throw new CaptchaException("验证码已失效"); + } + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + String captcha = redisService.getCacheObject(verifyKey); + redisService.deleteObject(verifyKey); + + if (!code.equalsIgnoreCase(captcha)) + { + throw new CaptchaException("验证码错误"); + } + } +} diff --git a/ruoyi-gateway/src/main/resources/banner.txt b/ruoyi-gateway/src/main/resources/banner.txt new file mode 100644 index 0000000..ceced29 --- /dev/null +++ b/ruoyi-gateway/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ + (_) | | + _ __ _ _ ___ _ _ _ ______ __ _ __ _ | |_ ___ __ __ __ _ _ _ +| '__|| | | | / _ \ | | | || ||______| / _` | / _` || __| / _ \\ \ /\ / / / _` || | | | +| | | |_| || (_) || |_| || | | (_| || (_| || |_ | __/ \ V V / | (_| || |_| | +|_| \__,_| \___/ \__, ||_| \__, | \__,_| \__| \___| \_/\_/ \__,_| \__, | + __/ | __/ | __/ | + |___/ |___/ |___/ \ No newline at end of file diff --git a/ruoyi-gateway/src/main/resources/bootstrap.yml b/ruoyi-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..a30630f --- /dev/null +++ b/ruoyi-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,127 @@ +# Spring +spring: + application: + # 应用名称 + name: ruoyi-gateway + main: + allow-bean-definition-overriding: true + profiles: + # 环境配置 + active: dev +--- +spring: + config: + activate: + on-profile: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.235:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 689e0f09-d102-460c-ac5c-5ea50a3174be + config: + # 配置中心地址 + server-addr: 192.168.110.235:8848 + namespace: 689e0f09-d102-460c-ac5c-5ea50a3174be + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} + sentinel: + # 取消控制台懒加载 + eager: true + transport: + # 控制台地址 + dashboard: 192.168.110.188:8718 + # nacos配置持久化 + datasource: + ds1: + nacos: + server-addr: 192.168.110.235:8848 + dataId: sentinel-ruoyi-gateway + groupId: DEFAULT_GROUP + data-type: json + rule-type: gw-flow +--- +spring: + config: + activate: + on-profile: prod + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.188:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: c2f47d1c-6355-4a68-b357-7523d73b2d13 + config: + # 配置中心地址 + server-addr: 192.168.110.188:8848 + namespace: c2f47d1c-6355-4a68-b357-7523d73b2d13 + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} + sentinel: + # 取消控制台懒加载 + eager: true + transport: + # 控制台地址 + dashboard: 122.9.150.46:8718 + # nacos配置持久化 + datasource: + ds1: + nacos: + server-addr: 192.168.110.188:8848 + dataId: sentinel-ruoyi-gateway + groupId: DEFAULT_GROUP + data-type: json + rule-type: gw-flow +--- +spring: + config: + activate: + on-profile: test + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.188:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce + config: + # 配置中心地址 + server-addr: 192.168.110.188:8848 + namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} + sentinel: + # 取消控制台懒加载 + eager: true + transport: + # 控制台地址 + dashboard: 139.9.236.40:8718 + # nacos配置持久化 + datasource: + ds1: + nacos: + server-addr: 192.168.110.188:8848 + dataId: sentinel-ruoyi-gateway + groupId: DEFAULT_GROUP + data-type: json + rule-type: gw-flow \ No newline at end of file diff --git a/ruoyi-gateway/src/main/resources/logback.xml b/ruoyi-gateway/src/main/resources/logback.xml new file mode 100644 index 0000000..f8e7f8a --- /dev/null +++ b/ruoyi-gateway/src/main/resources/logback.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <!-- 日志存放路径 --> + <property name="log.path" value="logs/ruoyi-gateway" /> + <!-- 日志输出格式 --> + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> + + <!-- 控制台输出 --> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + </appender> + + <!-- 系统日志输出 --> + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/info.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>INFO</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/error.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>ERROR</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 系统模块日志级别控制 --> + <logger name="com.ruoyi" level="info" /> + <!-- Spring日志级别控制 --> + <logger name="org.springframework" level="warn" /> + + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--系统操作日志--> + <root level="info"> + <appender-ref ref="file_info" /> + <appender-ref ref="file_error" /> + </root> +</configuration> \ No newline at end of file diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml new file mode 100644 index 0000000..8643339 --- /dev/null +++ b/ruoyi-modules/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <modules> + <module>ruoyi-system</module> + <module>ruoyi-gen</module> + <module>ruoyi-job</module> + <module>ruoyi-file</module> + <module>ruoyi-management</module> + </modules> + + <artifactId>ruoyi-modules</artifactId> + <packaging>pom</packaging> + + <description> + ruoyi-modules业务模块 + </description> +</project> diff --git a/ruoyi-modules/ruoyi-file/pom.xml b/ruoyi-modules/ruoyi-file/pom.xml new file mode 100644 index 0000000..a67a7bb --- /dev/null +++ b/ruoyi-modules/ruoyi-file/pom.xml @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-modules</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-modules-file</artifactId> + + <description> + ruoyi-modules-file文件服务 + </description> + + <dependencies> + + <!-- SpringCloud Alibaba Nacos --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos Config --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> + </dependency> + + <!-- SpringBoot Actuator --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + + <!-- FastDFS --> + <dependency> + <groupId>com.github.tobato</groupId> + <artifactId>fastdfs-client</artifactId> + </dependency> + + <!-- Minio --> + <dependency> + <groupId>io.minio</groupId> + <artifactId>minio</artifactId> + <version>${minio.version}</version> + </dependency> + + <!-- RuoYi Api System --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-api-system</artifactId> + </dependency> + + <!-- RuoYi Common Swagger --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-swagger</artifactId> + </dependency> + + <dependency> + <groupId>aws-java-sdk-s3</groupId> + <artifactId>aws</artifactId> + <version>1.0.0</version> + <scope>system</scope> + <systemPath>${project.basedir}/lib/aws-java-sdk-s3.jar</systemPath> + </dependency> + + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java new file mode 100644 index 0000000..1f320da --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java @@ -0,0 +1,31 @@ +package com.ruoyi.file; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; + +/** + * 文件服务 + * + * @author ruoyi + */ +@EnableCustomSwagger2 +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) +public class RuoYiFileApplication +{ + public static void main(String[] args) + { + SpringApplication.run(RuoYiFileApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 文件服务模块启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java new file mode 100644 index 0000000..29beea0 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java @@ -0,0 +1,82 @@ +package com.ruoyi.file.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import io.minio.MinioClient; + +/** + * Minio 配置信息 + * + * @author ruoyi + */ +@Configuration +@ConfigurationProperties(prefix = "minio") +public class MinioConfig +{ + /** + * 服务地址 + */ + private String url; + + /** + * 用户名 + */ + private String accessKey; + + /** + * 密码 + */ + private String secretKey; + + /** + * 存储桶名称 + */ + private String bucketName; + + public String getUrl() + { + return url; + } + + public void setUrl(String url) + { + this.url = url; + } + + public String getAccessKey() + { + return accessKey; + } + + public void setAccessKey(String accessKey) + { + this.accessKey = accessKey; + } + + public String getSecretKey() + { + return secretKey; + } + + public void setSecretKey(String secretKey) + { + this.secretKey = secretKey; + } + + public String getBucketName() + { + return bucketName; + } + + public void setBucketName(String bucketName) + { + this.bucketName = bucketName; + } + + @Bean + public MinioClient getMinioClient() + { + return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build(); + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java new file mode 100644 index 0000000..b34ebc2 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java @@ -0,0 +1,53 @@ +package com.ruoyi.file.config; + +import java.io.File; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 通用映射配置 + * + * @author ruoyi + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer +{ + /** + * 上传文件存储在本地的根路径 + */ + @Value("${file.path}") + private String localFilePath; + + /** + * 资源映射路径 前缀 + */ + @Value("${file.prefix}") + public String localFilePrefix; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) + { + /** 本地文件上传路径 */ + registry.addResourceHandler(localFilePrefix + "/**") + .addResourceLocations("file:" + localFilePath + File.separator); + } + + /** + * 开启跨域 + */ + @Override + public void addCorsMappings(CorsRegistry registry) { + // 设置允许跨域的路由 + registry.addMapping(localFilePrefix + "/**") + // 设置允许跨域请求的域名 + .allowedOrigins("*") + // 设置允许的方法 + .allowedMethods("GET") + .allowedMethods("POST") + .allowedMethods("DELETE") + .allowedMethods("PUT"); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java new file mode 100644 index 0000000..56dae85 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java @@ -0,0 +1,102 @@ +package com.ruoyi.file.controller; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.utils.file.FileUtils; +import com.ruoyi.file.service.ISysFileService; +import com.ruoyi.system.api.domain.SysFile; +import io.swagger.annotations.ApiOperation; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +/** + * 文件请求处理 + * + * @author ruoyi + */ +@RestController +public class SysFileController +{ + private static final Logger log = LoggerFactory.getLogger(SysFileController.class); + + @Autowired + private ISysFileService sysFileService; + + /** + * 文件上传请求 + */ + @PostMapping("/upload") + public R<SysFile> upload(MultipartFile file) + { + try + { + // 上传并返回访问地址 + String url = sysFileService.uploadFile(file); + SysFile sysFile = new SysFile(); + sysFile.setName(FileUtils.getName(url)); + sysFile.setUrl(url); + return R.ok(sysFile); + } + catch (Exception e) + { + log.error("上传文件失败", e); + return R.fail(e.getMessage()); + } + } + + /** + * 文件上传请求 + */ + @ApiOperation(value = "obs文件上传", notes = "obs文件上传") + @PostMapping("/obs/upload") + public R<String> obsUpload(@RequestPart("file") MultipartFile file) { + try { + // 上传并返回访问地址 + + return R.ok("1"); + } catch (Exception e) { + log.error("上传文件失败", e); + return R.fail(e.getMessage()); + } + } + + /** + * 文件上传请求 + */ + @ApiOperation(value = "obs文件批量上传", notes = "obs文件批量上传") + @PostMapping("/obs/upload-batch") + public R<List<String>> obsUploadBatch(@RequestPart("file") MultipartFile[] file) { + List<String> urls = new ArrayList<>(); + try { + for (MultipartFile multipartFile : file) { + urls.add("1"); + } + // 上传并返回访问地址 + return R.ok(urls); + } catch (Exception e) { + log.error("上传文件失败", e); + return R.fail(e.getMessage()); + } + } + + @PostMapping("/obs/upload/stream") + public R<String> obsUpload(@RequestParam("code") String code, + @RequestParam("stream") InputStream stream) { + try { + // 上传并返回访问地址 + + return R.ok("1"); + } catch (Exception e) { + log.error("上传文件失败", e); + return R.fail(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java new file mode 100644 index 0000000..0f85449 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/FastDfsSysFileServiceImpl.java @@ -0,0 +1,46 @@ +package com.ruoyi.file.service; + +import java.io.InputStream; +import com.alibaba.nacos.common.utils.IoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import com.github.tobato.fastdfs.domain.fdfs.StorePath; +import com.github.tobato.fastdfs.service.FastFileStorageClient; +import com.ruoyi.common.core.utils.file.FileTypeUtils; + +/** + * FastDFS 文件存储 + * + * @author ruoyi + */ +@Service +public class FastDfsSysFileServiceImpl implements ISysFileService +{ + /** + * 域名或本机访问地址 + */ + @Value("${fdfs.domain}") + public String domain; + + @Autowired + private FastFileStorageClient storageClient; + + /** + * FastDfs文件上传接口 + * + * @param file 上传的文件 + * @return 访问地址 + * @throws Exception + */ + @Override + public String uploadFile(MultipartFile file) throws Exception + { + InputStream inputStream = file.getInputStream(); + StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(), + FileTypeUtils.getExtension(file), null); + IoUtils.closeQuietly(inputStream); + return domain + "/" + storePath.getFullPath(); + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java new file mode 100644 index 0000000..c95e6f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java @@ -0,0 +1,20 @@ +package com.ruoyi.file.service; + +import org.springframework.web.multipart.MultipartFile; + +/** + * 文件上传接口 + * + * @author ruoyi + */ +public interface ISysFileService +{ + /** + * 文件上传接口 + * + * @param file 上传的文件 + * @return 访问地址 + * @throws Exception + */ + public String uploadFile(MultipartFile file) throws Exception; +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java new file mode 100644 index 0000000..3247e9b --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java @@ -0,0 +1,50 @@ +package com.ruoyi.file.service; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import com.ruoyi.file.utils.FileUploadUtils; + +/** + * 本地文件存储 + * + * @author ruoyi + */ +@Primary +@Service +public class LocalSysFileServiceImpl implements ISysFileService +{ + /** + * 资源映射路径 前缀 + */ + @Value("${file.prefix}") + public String localFilePrefix; + + /** + * 域名或本机访问地址 + */ + @Value("${file.domain}") + public String domain; + + /** + * 上传文件存储在本地的根路径 + */ + @Value("${file.path}") + private String localFilePath; + + /** + * 本地文件上传接口 + * + * @param file 上传的文件 + * @return 访问地址 + * @throws Exception + */ + @Override + public String uploadFile(MultipartFile file) throws Exception + { + String name = FileUploadUtils.upload(localFilePath, file); + String url = domain + localFilePrefix + name; + return url; + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java new file mode 100644 index 0000000..f53d86f --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java @@ -0,0 +1,49 @@ +package com.ruoyi.file.service; + +import java.io.InputStream; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import com.alibaba.nacos.common.utils.IoUtils; +import com.ruoyi.file.config.MinioConfig; +import com.ruoyi.file.utils.FileUploadUtils; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; + +/** + * Minio 文件存储 + * + * @author ruoyi + */ +@Service +public class MinioSysFileServiceImpl implements ISysFileService +{ + @Autowired + private MinioConfig minioConfig; + + @Autowired + private MinioClient client; + + /** + * Minio文件上传接口 + * + * @param file 上传的文件 + * @return 访问地址 + * @throws Exception + */ + @Override + public String uploadFile(MultipartFile file) throws Exception + { + String fileName = FileUploadUtils.extractFilename(file); + InputStream inputStream = file.getInputStream(); + PutObjectArgs args = PutObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(fileName) + .stream(inputStream, file.getSize(), -1) + .contentType(file.getContentType()) + .build(); + client.putObject(args); + IoUtils.closeQuietly(inputStream); + return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName; + } +} diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java new file mode 100644 index 0000000..8109d34 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java @@ -0,0 +1,185 @@ +package com.ruoyi.file.utils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Objects; +import org.apache.commons.io.FilenameUtils; +import org.springframework.web.multipart.MultipartFile; +import com.ruoyi.common.core.exception.file.FileException; +import com.ruoyi.common.core.exception.file.FileNameLengthLimitExceededException; +import com.ruoyi.common.core.exception.file.FileSizeLimitExceededException; +import com.ruoyi.common.core.exception.file.InvalidExtensionException; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.file.FileTypeUtils; +import com.ruoyi.common.core.utils.file.MimeTypeUtils; +import com.ruoyi.common.core.utils.uuid.Seq; + +/** + * 文件上传工具类 + * + * @author ruoyi + */ +public class FileUploadUtils +{ + /** + * 默认大小 50M + */ + public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; + + /** + * 默认的文件名最大长度 100 + */ + public static final int DEFAULT_FILE_NAME_LENGTH = 100; + + /** + * 根据文件路径上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 文件名称 + * @throws IOException + */ + public static final String upload(String baseDir, MultipartFile file) throws IOException + { + try + { + return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } + catch (FileException fe) + { + throw new IOException(fe.getDefaultMessage(), fe); + } + catch (Exception e) + { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 文件上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @param allowedExtension 上传文件类型 + * @return 返回上传成功的文件名 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileNameLengthLimitExceededException 文件名太长 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 + */ + public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) + throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, + InvalidExtensionException + { + int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) + { + throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); + } + + assertAllowed(file, allowedExtension); + + String fileName = extractFilename(file); + + String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); + file.transferTo(Paths.get(absPath)); + return getPathFileName(fileName); + } + + /** + * 编码文件名 + */ + public static final String extractFilename(MultipartFile file) + { + return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), + FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), FileTypeUtils.getExtension(file)); + } + + private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException + { + File desc = new File(uploadDir + File.separator + fileName); + + if (!desc.exists()) + { + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + } + return desc.isAbsolute() ? desc : desc.getAbsoluteFile(); + } + + private static final String getPathFileName(String fileName) throws IOException + { + String pathFileName = "/" + fileName; + return pathFileName; + } + + /** + * 文件大小校验 + * + * @param file 上传的文件 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws InvalidExtensionException 文件校验异常 + */ + public static final void assertAllowed(MultipartFile file, String[] allowedExtension) + throws FileSizeLimitExceededException, InvalidExtensionException + { + long size = file.getSize(); + if (size > DEFAULT_MAX_SIZE) + { + throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); + } + + String fileName = file.getOriginalFilename(); + String extension = FileTypeUtils.getExtension(file); + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) + { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) + { + throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, + fileName); + } + else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) + { + throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, + fileName); + } + else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) + { + throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, + fileName); + } + else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) + { + throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, + fileName); + } + else + { + throw new InvalidExtensionException(allowedExtension, extension, fileName); + } + } + } + + /** + * 判断MIME类型是否是允许的MIME类型 + * + * @param extension 上传文件类型 + * @param allowedExtension 允许上传文件类型 + * @return true/false + */ + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) + { + for (String str : allowedExtension) + { + if (str.equalsIgnoreCase(extension)) + { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/StateCloudObsUtil.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/StateCloudObsUtil.java new file mode 100644 index 0000000..5229da9 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/StateCloudObsUtil.java @@ -0,0 +1,101 @@ +/* +package com.ruoyi.file.utils; + + +import java.io.InputStream; +import java.util.UUID; +import org.springframework.web.multipart.MultipartFile; + +*/ +/** + * 天翼云OBS 工具类 + * + * @author mitao + * @date 2024/6/17 + *//* + +public class StateCloudObsUtil { + + public static String ACCESS_KEY = "MZTCFDOW5SGEC88GNMBV"; + public static String SECRET_KEY = "b3HHfKEiEHjyo4ozzN4ZuaveCKvoFUAOPoba44ix"; + public static String END_POINT = "obs.cn-sccd1.ctyun.cn"; + public static String BUCKET = "jyzx-obs"; + public static String DOMAIN = "https://" + BUCKET + "." + END_POINT + "/"; + public static AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, + SECRET_KEY); + + public static String uploadFile(MultipartFile file) { + String originalFilename = file.getOriginalFilename(); + InputStream inputStream = null; + try { + inputStream = file.getInputStream(); + } catch (IOException e) { + throw new RuntimeException(e); + } + String fileName; + AmazonS3 s3client = null; + try { + ClientConfiguration awsClientConfig = new ClientConfiguration(); + awsClientConfig.setSignerOverride("AWSS3V4SignerType"); + awsClientConfig.setProtocol(Protocol.HTTP); + s3client = AmazonS3ClientBuilder.standard() + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withClientConfiguration(awsClientConfig) + .withEndpointConfiguration(new EndpointConfiguration(END_POINT, "")) + .disableChunkedEncoding() + .enablePathStyleAccess() + .build(); + System.out.print("=====connect success=====\n"); + // 上传 object + ObjectMetadata objectMetadata = new ObjectMetadata(); + fileName = + UUID.randomUUID().toString().replaceAll("-", "") + originalFilename.subSequence( + originalFilename.lastIndexOf("."), originalFilename.length()); + PutObjectRequest request = new PutObjectRequest(BUCKET, fileName, inputStream, + objectMetadata); + PutObjectResult result = s3client.putObject(request); + System.out.format("Etag: %s, versionId: %s\n", result.getETag(), + result.getVersionId()); + System.out.print("=====request success=====\n"); + return DOMAIN + fileName; + } catch (Exception e) { + System.out.print("=====request fail=====\n"); + System.out.print(e.getMessage()); + } + return null; + } + + public static String obsUploadStream(String code, InputStream content) throws IOException { + String fileName = ""; + ObjectMetadata objectMetadata = new ObjectMetadata();// 创建上传Object的Metadata + fileName = "qrCode/" + UUID.randomUUID().toString().replaceAll("-", "") + "-id" + code + + ".png"; + AmazonS3 s3client = null; + try { + ClientConfiguration awsClientConfig = new ClientConfiguration(); + awsClientConfig.setSignerOverride("AWSS3V4SignerType"); + awsClientConfig.setProtocol(Protocol.HTTP); + s3client = AmazonS3ClientBuilder.standard() + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withClientConfiguration(awsClientConfig) + .withEndpointConfiguration(new EndpointConfiguration(END_POINT, "")) + .disableChunkedEncoding() + .enablePathStyleAccess() + .build(); + System.out.print("=====connect success=====\n"); + // 上传 object + PutObjectRequest request = new PutObjectRequest(BUCKET, fileName, content, + objectMetadata); + PutObjectResult result = s3client.putObject(request); + System.out.format("Etag: %s, versionId: %s\n", result.getETag(), + result.getVersionId()); + System.out.print("=====request success=====\n"); + return DOMAIN + fileName; + } catch (Exception e) { + System.out.print("=====request fail=====\n"); + System.out.print(e.getMessage()); + } + return fileName; + } +} +*/ diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-file/src/main/resources/banner.txt new file mode 100644 index 0000000..27cacb9 --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ __ _ _ + (_) / _|(_)| | + _ __ _ _ ___ _ _ _ ______ | |_ _ | | ___ +| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \ +| | | |_| || (_) || |_| || | | | | || || __/ +|_| \__,_| \___/ \__, ||_| |_| |_||_| \___| + __/ | + |___/ \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..d50644a --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml @@ -0,0 +1,40 @@ +# Tomcat +server: + port: 9300 +# Spring +spring: + application: + # 应用名称 + name: ruoyi-file + profiles: + # 环境配置 + active: dev + servlet: + multipart: + max-file-size: 100MB + max-request-size: 200MB + location: /data/tmp +--- +spring: + config: + activate: + on-profile: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.235:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 689e0f09-d102-460c-ac5c-5ea50a3174be + config: + # 配置中心地址 + server-addr: 192.168.110.235:8848 + namespace: 689e0f09-d102-460c-ac5c-5ea50a3174be + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-file/src/main/resources/logback.xml new file mode 100644 index 0000000..ed6c17d --- /dev/null +++ b/ruoyi-modules/ruoyi-file/src/main/resources/logback.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <!-- 日志存放路径 --> + <property name="log.path" value="logs/ruoyi-file" /> + <!-- 日志输出格式 --> + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> + + <!-- 控制台输出 --> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + </appender> + + <!-- 系统日志输出 --> + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/info.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>INFO</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/error.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>ERROR</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 系统模块日志级别控制 --> + <logger name="com.ruoyi" level="info" /> + <!-- Spring日志级别控制 --> + <logger name="org.springframework" level="warn" /> + + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--系统操作日志--> + <root level="info"> + <appender-ref ref="file_info" /> + <appender-ref ref="file_error" /> + </root> +</configuration> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/pom.xml b/ruoyi-modules/ruoyi-gen/pom.xml new file mode 100644 index 0000000..17e591e --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/pom.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-modules</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-modules-gen</artifactId> + + <description> + ruoyi-modules-gen代码生成 + </description> + + <dependencies> + + <!-- SpringCloud Alibaba Nacos --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos Config --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> + </dependency> + + <!-- SpringBoot Actuator --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + + <!-- Swagger UI --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${swagger.fox.version}</version> + </dependency> + + <!-- Apache Velocity --> + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity-engine-core</artifactId> + </dependency> + + <!-- Mysql Connector --> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + <!-- RuoYi Common Log --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-log</artifactId> + </dependency> + + <!-- RuoYi Common Swagger --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-swagger</artifactId> + </dependency> + + <!-- 引入Druid依赖,阿里巴巴所提供的数据源 --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>druid-spring-boot-starter</artifactId> + <version>${druid.version}</version> + </dependency> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>fastjson</artifactId> + <version>1.2.47</version> + </dependency> + <!--mysql--> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java new file mode 100644 index 0000000..ba6bdf1 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java @@ -0,0 +1,34 @@ +package com.ruoyi.gen; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import com.ruoyi.common.security.annotation.EnableCustomConfig; +import com.ruoyi.common.security.annotation.EnableRyFeignClients; +import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; + +/** + * 代码生成 + * + * @author ruoyi + */ +@EnableCustomConfig +@EnableCustomSwagger2 +@EnableRyFeignClients +@SpringBootApplication +public class RuoYiGenApplication +{ + public static void main(String[] args) + { + SpringApplication.run(RuoYiGenApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 代码生成模块启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java new file mode 100644 index 0000000..ee7161b --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java @@ -0,0 +1,66 @@ +package com.ruoyi.gen.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 代码生成相关配置 + * + * @author ruoyi + */ +@Component +@ConfigurationProperties(prefix = "gen") +public class GenConfig +{ + /** 作者 */ + public static String author; + + /** 生成包路径 */ + public static String packageName; + + /** 自动去除表前缀,默认是false */ + public static boolean autoRemovePre; + + /** 表前缀(类名不会包含表前缀) */ + public static String tablePrefix; + + public static String getAuthor() + { + return author; + } + + public void setAuthor(String author) + { + GenConfig.author = author; + } + + public static String getPackageName() + { + return packageName; + } + + public void setPackageName(String packageName) + { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() + { + return autoRemovePre; + } + + public void setAutoRemovePre(boolean autoRemovePre) + { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() + { + return tablePrefix; + } + + public void setTablePrefix(String tablePrefix) + { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java new file mode 100644 index 0000000..72f8489 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java @@ -0,0 +1,211 @@ +package com.ruoyi.gen.controller; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.gen.domain.GenTable; +import com.ruoyi.gen.domain.GenTableColumn; +import com.ruoyi.gen.service.IGenTableColumnService; +import com.ruoyi.gen.service.IGenTableService; + +/** + * 代码生成 操作处理 + * + * @author ruoyi + */ +@RequestMapping("/gen") +@RestController +public class GenController extends BaseController +{ + @Autowired + private IGenTableService genTableService; + + @Autowired + private IGenTableColumnService genTableColumnService; + + /** + * 查询代码生成列表 + */ + @RequiresPermissions("tool:gen:list") + @GetMapping("/list") + public TableDataInfo genList(GenTable genTable) + { + startPage(); + List<GenTable> list = genTableService.selectGenTableList(genTable); + return getDataTable(list); + } + + /** + * 修改代码生成业务 + */ + @RequiresPermissions("tool:gen:query") + @GetMapping(value = "/{tableId}") + public AjaxResult getInfo(@PathVariable Long tableId) + { + GenTable table = genTableService.selectGenTableById(tableId); + List<GenTable> tables = genTableService.selectGenTableAll(); + List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId); + Map<String, Object> map = new HashMap<String, Object>(); + map.put("info", table); + map.put("rows", list); + map.put("tables", tables); + return success(map); + } + + /** + * 查询数据库列表 + */ + @RequiresPermissions("tool:gen:list") + @GetMapping("/db/list") + public TableDataInfo dataList(GenTable genTable) + { + startPage(); + List<GenTable> list = genTableService.selectDbTableList(genTable); + return getDataTable(list); + } + + /** + * 查询数据表字段列表 + */ + @GetMapping(value = "/column/{tableId}") + public TableDataInfo columnList(Long tableId) + { + TableDataInfo dataInfo = new TableDataInfo(); + List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId); + dataInfo.setRows(list); + dataInfo.setTotal(list.size()); + return dataInfo; + } + + /** + * 导入表结构(保存) + */ + @RequiresPermissions("tool:gen:import") + @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + public AjaxResult importTableSave(String tables) + { + String[] tableNames = Convert.toStrArray(tables); + // 查询表信息 + List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames); + genTableService.importGenTable(tableList); + return success(); + } + + /** + * 修改保存代码生成业务 + */ + @RequiresPermissions("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult editSave(@Validated @RequestBody GenTable genTable) + { + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + return success(); + } + + /** + * 删除代码生成 + */ + @RequiresPermissions("tool:gen:remove") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @DeleteMapping("/{tableIds}") + public AjaxResult remove(@PathVariable Long[] tableIds) + { + genTableService.deleteGenTableByIds(tableIds); + return success(); + } + + /** + * 预览代码 + */ + @RequiresPermissions("tool:gen:preview") + @GetMapping("/preview/{tableId}") + public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException + { + Map<String, String> dataMap = genTableService.previewCode(tableId); + return success(dataMap); + } + + /** + * 生成代码(下载方式) + */ + @RequiresPermissions("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/download/{tableName}") + public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException + { + byte[] data = genTableService.downloadCode(tableName); + genCode(response, data); + } + + /** + * 生成代码(自定义路径) + */ + @RequiresPermissions("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/genCode/{tableName}") + public AjaxResult genCode(@PathVariable("tableName") String tableName) + { + genTableService.generatorCode(tableName); + return success(); + } + + /** + * 同步数据库 + */ + @RequiresPermissions("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @GetMapping("/synchDb/{tableName}") + public AjaxResult synchDb(@PathVariable("tableName") String tableName) + { + genTableService.synchDb(tableName); + return success(); + } + + /** + * 批量生成代码 + */ + @RequiresPermissions("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/batchGenCode") + public void batchGenCode(HttpServletResponse response, String tables) throws IOException + { + String[] tableNames = Convert.toStrArray(tables); + byte[] data = genTableService.downloadCode(tableNames); + genCode(response, data); + } + + /** + * 生成zip文件 + */ + private void genCode(HttpServletResponse response, byte[] data) throws IOException + { + response.reset(); + response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\""); + response.addHeader("Content-Length", "" + data.length); + response.setContentType("application/octet-stream; charset=UTF-8"); + IOUtils.write(data, response.getOutputStream()); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java new file mode 100644 index 0000000..dac28dc --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java @@ -0,0 +1,370 @@ +package com.ruoyi.gen.domain; + +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import org.apache.commons.lang3.ArrayUtils; +import com.ruoyi.common.core.constant.GenConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.web.domain.BaseEntity; + +/** + * 业务表 gen_table + * + * @author ruoyi + */ +public class GenTable extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 编号 */ + private Long tableId; + + /** 表名称 */ + @NotBlank(message = "表名称不能为空") + private String tableName; + + /** 表描述 */ + @NotBlank(message = "表描述不能为空") + private String tableComment; + + /** 关联父表的表名 */ + private String subTableName; + + /** 本表关联父表的外键名 */ + private String subTableFkName; + + /** 实体类名称(首字母大写) */ + @NotBlank(message = "实体类名称不能为空") + private String className; + + /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */ + private String tplCategory; + + /** 生成包路径 */ + @NotBlank(message = "生成包路径不能为空") + private String packageName; + + /** 生成模块名 */ + @NotBlank(message = "生成模块名不能为空") + private String moduleName; + + /** 生成业务名 */ + @NotBlank(message = "生成业务名不能为空") + private String businessName; + + /** 生成功能名 */ + @NotBlank(message = "生成功能名不能为空") + private String functionName; + + /** 生成作者 */ + @NotBlank(message = "作者不能为空") + private String functionAuthor; + + /** 生成代码方式(0zip压缩包 1自定义路径) */ + private String genType; + + /** 生成路径(不填默认项目路径) */ + private String genPath; + + /** 主键信息 */ + private GenTableColumn pkColumn; + + /** 子表信息 */ + private GenTable subTable; + + /** 表列信息 */ + @Valid + private List<GenTableColumn> columns; + + /** 其它生成选项 */ + private String options; + + /** 树编码字段 */ + private String treeCode; + + /** 树父编码字段 */ + private String treeParentCode; + + /** 树名称字段 */ + private String treeName; + + /** 上级菜单ID字段 */ + private String parentMenuId; + + /** 上级菜单名称字段 */ + private String parentMenuName; + + public Long getTableId() + { + return tableId; + } + + public void setTableId(Long tableId) + { + this.tableId = tableId; + } + + public String getTableName() + { + return tableName; + } + + public void setTableName(String tableName) + { + this.tableName = tableName; + } + + public String getTableComment() + { + return tableComment; + } + + public void setTableComment(String tableComment) + { + this.tableComment = tableComment; + } + + public String getSubTableName() + { + return subTableName; + } + + public void setSubTableName(String subTableName) + { + this.subTableName = subTableName; + } + + public String getSubTableFkName() + { + return subTableFkName; + } + + public void setSubTableFkName(String subTableFkName) + { + this.subTableFkName = subTableFkName; + } + + public String getClassName() + { + return className; + } + + public void setClassName(String className) + { + this.className = className; + } + + public String getTplCategory() + { + return tplCategory; + } + + public void setTplCategory(String tplCategory) + { + this.tplCategory = tplCategory; + } + + public String getPackageName() + { + return packageName; + } + + public void setPackageName(String packageName) + { + this.packageName = packageName; + } + + public String getModuleName() + { + return moduleName; + } + + public void setModuleName(String moduleName) + { + this.moduleName = moduleName; + } + + public String getBusinessName() + { + return businessName; + } + + public void setBusinessName(String businessName) + { + this.businessName = businessName; + } + + public String getFunctionName() + { + return functionName; + } + + public void setFunctionName(String functionName) + { + this.functionName = functionName; + } + + public String getFunctionAuthor() + { + return functionAuthor; + } + + public void setFunctionAuthor(String functionAuthor) + { + this.functionAuthor = functionAuthor; + } + + public String getGenType() + { + return genType; + } + + public void setGenType(String genType) + { + this.genType = genType; + } + + public String getGenPath() + { + return genPath; + } + + public void setGenPath(String genPath) + { + this.genPath = genPath; + } + + public GenTableColumn getPkColumn() + { + return pkColumn; + } + + public void setPkColumn(GenTableColumn pkColumn) + { + this.pkColumn = pkColumn; + } + + public GenTable getSubTable() + { + return subTable; + } + + public void setSubTable(GenTable subTable) + { + this.subTable = subTable; + } + public List<GenTableColumn> getColumns() + { + return columns; + } + + public void setColumns(List<GenTableColumn> columns) + { + this.columns = columns; + } + + public String getOptions() + { + return options; + } + + public void setOptions(String options) + { + this.options = options; + } + + public String getTreeCode() + { + return treeCode; + } + + public void setTreeCode(String treeCode) + { + this.treeCode = treeCode; + } + + public String getTreeParentCode() + { + return treeParentCode; + } + + public void setTreeParentCode(String treeParentCode) + { + this.treeParentCode = treeParentCode; + } + + public String getTreeName() + { + return treeName; + } + + public void setTreeName(String treeName) + { + this.treeName = treeName; + } + + public String getParentMenuId() + { + return parentMenuId; + } + + public void setParentMenuId(String parentMenuId) + { + this.parentMenuId = parentMenuId; + } + + public String getParentMenuName() + { + return parentMenuName; + } + + public void setParentMenuName(String parentMenuName) + { + this.parentMenuName = parentMenuName; + } + + public boolean isSub() + { + return isSub(this.tplCategory); + } + + public static boolean isSub(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory); + } + public boolean isTree() + { + return isTree(this.tplCategory); + } + + public static boolean isTree(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); + } + + public boolean isCrud() + { + return isCrud(this.tplCategory); + } + + public static boolean isCrud(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); + } + + public boolean isSuperColumn(String javaField) + { + return isSuperColumn(this.tplCategory, javaField); + } + + public static boolean isSuperColumn(String tplCategory, String javaField) + { + if (isTree(tplCategory)) + { + return StringUtils.equalsAnyIgnoreCase(javaField, + ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY)); + } + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java new file mode 100644 index 0000000..e53eff5 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java @@ -0,0 +1,374 @@ +package com.ruoyi.gen.domain; + +import javax.validation.constraints.NotBlank; + +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.web.domain.BaseEntity; + +/** + * 代码生成业务字段表 gen_table_column + * + * @author ruoyi + */ +public class GenTableColumn extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 编号 */ + private Long columnId; + + /** 归属表编号 */ + private Long tableId; + + /** 列名称 */ + private String columnName; + + /** 列描述 */ + private String columnComment; + + /** 列类型 */ + private String columnType; + + /** JAVA类型 */ + private String javaType; + + /** JAVA字段名 */ + @NotBlank(message = "Java属性不能为空") + private String javaField; + + /** 是否主键(1是) */ + private String isPk; + + /** 是否自增(1是) */ + private String isIncrement; + + /** 是否必填(1是) */ + private String isRequired; + + /** 是否为插入字段(1是) */ + private String isInsert; + + /** 是否编辑字段(1是) */ + private String isEdit; + + /** 是否列表字段(1是) */ + private String isList; + + /** 是否查询字段(1是) */ + private String isQuery; + + /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */ + private String queryType; + + /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) */ + private String htmlType; + + /** 字典类型 */ + private String dictType; + + /** 排序 */ + private Integer sort; + + public void setColumnId(Long columnId) + { + this.columnId = columnId; + } + + public Long getColumnId() + { + return columnId; + } + + public void setTableId(Long tableId) + { + this.tableId = tableId; + } + + public Long getTableId() + { + return tableId; + } + + public void setColumnName(String columnName) + { + this.columnName = columnName; + } + + public String getColumnName() + { + return columnName; + } + + public void setColumnComment(String columnComment) + { + this.columnComment = columnComment; + } + + public String getColumnComment() + { + return columnComment; + } + + public void setColumnType(String columnType) + { + this.columnType = columnType; + } + + public String getColumnType() + { + return columnType; + } + + public void setJavaType(String javaType) + { + this.javaType = javaType; + } + + public String getJavaType() + { + return javaType; + } + + public void setJavaField(String javaField) + { + this.javaField = javaField; + } + + public String getJavaField() + { + return javaField; + } + + public String getCapJavaField() + { + return StringUtils.capitalize(javaField); + } + + public void setIsPk(String isPk) + { + this.isPk = isPk; + } + + public String getIsPk() + { + return isPk; + } + + public boolean isPk() + { + return isPk(this.isPk); + } + + public boolean isPk(String isPk) + { + return isPk != null && StringUtils.equals("1", isPk); + } + + public String getIsIncrement() + { + return isIncrement; + } + + public void setIsIncrement(String isIncrement) + { + this.isIncrement = isIncrement; + } + + public boolean isIncrement() + { + return isIncrement(this.isIncrement); + } + + public boolean isIncrement(String isIncrement) + { + return isIncrement != null && StringUtils.equals("1", isIncrement); + } + + public void setIsRequired(String isRequired) + { + this.isRequired = isRequired; + } + + public String getIsRequired() + { + return isRequired; + } + + public boolean isRequired() + { + return isRequired(this.isRequired); + } + + public boolean isRequired(String isRequired) + { + return isRequired != null && StringUtils.equals("1", isRequired); + } + + public void setIsInsert(String isInsert) + { + this.isInsert = isInsert; + } + + public String getIsInsert() + { + return isInsert; + } + + public boolean isInsert() + { + return isInsert(this.isInsert); + } + + public boolean isInsert(String isInsert) + { + return isInsert != null && StringUtils.equals("1", isInsert); + } + + public void setIsEdit(String isEdit) + { + this.isEdit = isEdit; + } + + public String getIsEdit() + { + return isEdit; + } + + public boolean isEdit() + { + return isInsert(this.isEdit); + } + + public boolean isEdit(String isEdit) + { + return isEdit != null && StringUtils.equals("1", isEdit); + } + + public void setIsList(String isList) + { + this.isList = isList; + } + + public String getIsList() + { + return isList; + } + + public boolean isList() + { + return isList(this.isList); + } + + public boolean isList(String isList) + { + return isList != null && StringUtils.equals("1", isList); + } + + public void setIsQuery(String isQuery) + { + this.isQuery = isQuery; + } + + public String getIsQuery() + { + return isQuery; + } + + public boolean isQuery() + { + return isQuery(this.isQuery); + } + + public boolean isQuery(String isQuery) + { + return isQuery != null && StringUtils.equals("1", isQuery); + } + + public void setQueryType(String queryType) + { + this.queryType = queryType; + } + + public String getQueryType() + { + return queryType; + } + + public String getHtmlType() + { + return htmlType; + } + + public void setHtmlType(String htmlType) + { + this.htmlType = htmlType; + } + + public void setDictType(String dictType) + { + this.dictType = dictType; + } + + public String getDictType() + { + return dictType; + } + + public void setSort(Integer sort) + { + this.sort = sort; + } + + public Integer getSort() + { + return sort; + } + + public boolean isSuperColumn() + { + return isSuperColumn(this.javaField); + } + + public static boolean isSuperColumn(String javaField) + { + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", "remark", + // TreeEntity + "parentName", "parentId", "orderNum", "ancestors"); + } + + public boolean isUsableColumn() + { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) + { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); + } + + public String readConverterExp() + { + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotEmpty(remarks)) + { + for (String value : remarks.split(" ")) + { + if (StringUtils.isNotEmpty(value)) + { + Object startStr = value.subSequence(0, 1); + String endStr = value.substring(1); + sb.append("").append(startStr).append("=").append(endStr).append(","); + } + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } + else + { + return this.columnComment; + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java new file mode 100644 index 0000000..0be7cc0 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java @@ -0,0 +1,60 @@ +package com.ruoyi.gen.mapper; + +import java.util.List; +import com.ruoyi.gen.domain.GenTableColumn; + +/** + * 业务字段 数据层 + * + * @author ruoyi + */ +public interface GenTableColumnMapper +{ + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + public List<GenTableColumn> selectDbTableColumnsByName(String tableName); + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段 + * + * @param genTableColumns 列数据 + * @return 结果 + */ + public int deleteGenTableColumns(List<GenTableColumn> genTableColumns); + + /** + * 批量删除业务字段 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(Long[] ids); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java new file mode 100644 index 0000000..3487d6a --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java @@ -0,0 +1,83 @@ +package com.ruoyi.gen.mapper; + +import java.util.List; +import com.ruoyi.gen.domain.GenTable; + +/** + * 业务 数据层 + * + * @author ruoyi + */ +public interface GenTableMapper +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List<GenTable> selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List<GenTable> selectGenTableAll(); + + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + public GenTable selectGenTableByName(String tableName); + + /** + * 新增业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int insertGenTable(GenTable genTable); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int updateGenTable(GenTable genTable); + + /** + * 批量删除业务 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableByIds(Long[] ids); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java new file mode 100644 index 0000000..f009c4b --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java @@ -0,0 +1,68 @@ +package com.ruoyi.gen.service; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.gen.domain.GenTableColumn; +import com.ruoyi.gen.mapper.GenTableColumnMapper; + +/** + * 业务字段 服务层实现 + * + * @author ruoyi + */ +@Service +public class GenTableColumnServiceImpl implements IGenTableColumnService +{ + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + @Override + public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) + { + return genTableColumnMapper.selectGenTableColumnListByTableId(tableId); + } + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + @Override + public int insertGenTableColumn(GenTableColumn genTableColumn) + { + return genTableColumnMapper.insertGenTableColumn(genTableColumn); + } + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + @Override + public int updateGenTableColumn(GenTableColumn genTableColumn) + { + return genTableColumnMapper.updateGenTableColumn(genTableColumn); + } + + /** + * 删除业务字段对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteGenTableColumnByIds(String ids) + { + return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java new file mode 100644 index 0000000..11e2a23 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java @@ -0,0 +1,521 @@ +package com.ruoyi.gen.service; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.velocity.Template; +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; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GenConstants; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.text.CharsetKit; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.gen.domain.GenTable; +import com.ruoyi.gen.domain.GenTableColumn; +import com.ruoyi.gen.mapper.GenTableColumnMapper; +import com.ruoyi.gen.mapper.GenTableMapper; +import com.ruoyi.gen.util.GenUtils; +import com.ruoyi.gen.util.VelocityInitializer; +import com.ruoyi.gen.util.VelocityUtils; + +/** + * 业务 服务层实现 + * + * @author ruoyi + */ +@Service +public class GenTableServiceImpl implements IGenTableService +{ + private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class); + + @Autowired + private GenTableMapper genTableMapper; + + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + @Override + public GenTable selectGenTableById(Long id) + { + GenTable genTable = genTableMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + @Override + public List<GenTable> selectGenTableList(GenTable genTable) + { + return genTableMapper.selectGenTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + @Override + public List<GenTable> selectDbTableList(GenTable genTable) + { + return genTableMapper.selectDbTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + @Override + public List<GenTable> selectDbTableListByNames(String[] tableNames) + { + return genTableMapper.selectDbTableListByNames(tableNames); + } + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List<GenTable> selectGenTableAll() + { + return genTableMapper.selectGenTableAll(); + } + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void updateGenTable(GenTable genTable) + { + String options = JSON.toJSONString(genTable.getParams()); + genTable.setOptions(options); + int row = genTableMapper.updateGenTable(genTable); + if (row > 0) + { + for (GenTableColumn cenTableColumn : genTable.getColumns()) + { + genTableColumnMapper.updateGenTableColumn(cenTableColumn); + } + } + } + + /** + * 删除业务对象 + * + * @param tableIds 需要删除的数据ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteGenTableByIds(Long[] tableIds) + { + genTableMapper.deleteGenTableByIds(tableIds); + genTableColumnMapper.deleteGenTableColumnByIds(tableIds); + } + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void importGenTable(List<GenTable> tableList) + { + String operName = SecurityUtils.getUsername(); + try + { + for (GenTable table : tableList) + { + String tableName = table.getTableName(); + GenUtils.initTable(table, operName); + int row = genTableMapper.insertGenTable(table); + if (row > 0) + { + // 保存列信息 + List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + for (GenTableColumn column : genTableColumns) + { + GenUtils.initColumnField(column, table); + genTableColumnMapper.insertGenTableColumn(column); + } + } + } + } + catch (Exception e) + { + throw new ServiceException("导入失败:" + e.getMessage()); + } + } + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + @Override + public Map<String, String> previewCode(Long tableId) + { + Map<String, String> dataMap = new LinkedHashMap<>(); + // 查询表信息 + GenTable table = genTableMapper.selectGenTableById(tableId); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) + { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + dataMap.put(template, sw.toString()); + } + return dataMap; + } + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + @Override + public byte[] downloadCode(String tableName) + { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + generatorCode(tableName, zip); + IOUtils.closeQuietly(zip); + return outputStream.toByteArray(); + } + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + @Override + public void generatorCode(String tableName) + { + // 查询表信息 + GenTable table = genTableMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) + { + if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) + { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try + { + String path = getGenPath(table, template); + FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8); + } + catch (IOException e) + { + throw new ServiceException("渲染模板失败,表名:" + table.getTableName()); + } + } + } + } + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void synchDb(String tableName) + { + GenTable table = genTableMapper.selectGenTableByName(tableName); + List<GenTableColumn> tableColumns = table.getColumns(); + Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity())); + + List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + if (StringUtils.isEmpty(dbTableColumns)) + { + throw new ServiceException("同步数据失败,原表结构不存在"); + } + List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); + + dbTableColumns.forEach(column -> { + GenUtils.initColumnField(column, table); + if (tableColumnMap.containsKey(column.getColumnName())) + { + GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName()); + column.setColumnId(prevColumn.getColumnId()); + if (column.isList()) + { + // 如果是列表,继续保留查询方式/字典类型选项 + column.setDictType(prevColumn.getDictType()); + column.setQueryType(prevColumn.getQueryType()); + } + if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() + && (column.isInsert() || column.isEdit()) + && ((column.isUsableColumn()) || (!column.isSuperColumn()))) + { + // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项 + column.setIsRequired(prevColumn.getIsRequired()); + column.setHtmlType(prevColumn.getHtmlType()); + } + genTableColumnMapper.updateGenTableColumn(column); + } + else + { + genTableColumnMapper.insertGenTableColumn(column); + } + }); + + List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList()); + if (StringUtils.isNotEmpty(delColumns)) + { + genTableColumnMapper.deleteGenTableColumns(delColumns); + } + } + + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + @Override + public byte[] downloadCode(String[] tableNames) + { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + for (String tableName : tableNames) + { + generatorCode(tableName, zip); + } + IOUtils.closeQuietly(zip); + return outputStream.toByteArray(); + } + + /** + * 查询表信息并生成代码 + */ + private void generatorCode(String tableName, ZipOutputStream zip) + { + // 查询表信息 + GenTable table = genTableMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) + { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try + { + // 添加到zip + zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table))); + IOUtils.write(sw.toString(), zip, Constants.UTF8); + IOUtils.closeQuietly(sw); + zip.flush(); + zip.closeEntry(); + } + catch (IOException e) + { + log.error("渲染模板失败,表名:" + table.getTableName(), e); + } + } + } + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + @Override + public void validateEdit(GenTable genTable) + { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) + { + String options = JSON.toJSONString(genTable.getParams()); + JSONObject paramsObj = JSON.parseObject(options); + if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) + { + throw new ServiceException("树编码字段不能为空"); + } + else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) + { + throw new ServiceException("树父编码字段不能为空"); + } + else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) + { + throw new ServiceException("树名称字段不能为空"); + } + else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) + { + if (StringUtils.isEmpty(genTable.getSubTableName())) + { + throw new ServiceException("关联子表的表名不能为空"); + } + else if (StringUtils.isEmpty(genTable.getSubTableFkName())) + { + throw new ServiceException("子表关联的外键名不能为空"); + } + } + } + } + + /** + * 设置主键列信息 + * + * @param table 业务表信息 + */ + public void setPkColumn(GenTable table) + { + for (GenTableColumn column : table.getColumns()) + { + if (column.isPk()) + { + table.setPkColumn(column); + break; + } + } + if (StringUtils.isNull(table.getPkColumn())) + { + table.setPkColumn(table.getColumns().get(0)); + } + if (GenConstants.TPL_SUB.equals(table.getTplCategory())) + { + for (GenTableColumn column : table.getSubTable().getColumns()) + { + if (column.isPk()) + { + table.getSubTable().setPkColumn(column); + break; + } + } + if (StringUtils.isNull(table.getSubTable().getPkColumn())) + { + table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0)); + } + } + } + + /** + * 设置主子表信息 + * + * @param table 业务表信息 + */ + public void setSubTable(GenTable table) + { + String subTableName = table.getSubTableName(); + if (StringUtils.isNotEmpty(subTableName)) + { + table.setSubTable(genTableMapper.selectGenTableByName(subTableName)); + } + } + + /** + * 设置代码生成其他选项值 + * + * @param genTable 设置后的生成对象 + */ + public void setTableFromOptions(GenTable genTable) + { + JSONObject paramsObj = JSON.parseObject(genTable.getOptions()); + if (StringUtils.isNotNull(paramsObj)) + { + String treeCode = paramsObj.getString(GenConstants.TREE_CODE); + String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); + String treeName = paramsObj.getString(GenConstants.TREE_NAME); + String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME); + + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); + } + } + + /** + * 获取代码生成地址 + * + * @param table 业务表信息 + * @param template 模板文件路径 + * @return 生成地址 + */ + public static String getGenPath(GenTable table, String template) + { + String genPath = table.getGenPath(); + if (StringUtils.equals(genPath, "/")) + { + return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table); + } + return genPath + File.separator + VelocityUtils.getFileName(template, table); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java new file mode 100644 index 0000000..1f23685 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java @@ -0,0 +1,44 @@ +package com.ruoyi.gen.service; + +import java.util.List; +import com.ruoyi.gen.domain.GenTableColumn; + +/** + * 业务字段 服务层 + * + * @author ruoyi + */ +public interface IGenTableColumnService +{ + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(String ids); +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java new file mode 100644 index 0000000..0da8af7 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java @@ -0,0 +1,121 @@ +package com.ruoyi.gen.service; + +import java.util.List; +import java.util.Map; +import com.ruoyi.gen.domain.GenTable; + +/** + * 业务 服务层 + * + * @author ruoyi + */ +public interface IGenTableService +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List<GenTable> selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List<GenTable> selectGenTableAll(); + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public void updateGenTable(GenTable genTable); + + /** + * 删除业务信息 + * + * @param tableIds 需要删除的表数据ID + * @return 结果 + */ + public void deleteGenTableByIds(Long[] tableIds); + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + public void importGenTable(List<GenTable> tableList); + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + public Map<String, String> previewCode(Long tableId); + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + public byte[] downloadCode(String tableName); + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + * @return 数据 + */ + public void generatorCode(String tableName); + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + public void synchDb(String tableName); + + /** + * 批量生成代码(下载方式) + * + * @param tableNames 表数组 + * @return 数据 + */ + public byte[] downloadCode(String[] tableNames); + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + public void validateEdit(GenTable genTable); +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java new file mode 100644 index 0000000..3dae786 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java @@ -0,0 +1,257 @@ +package com.ruoyi.gen.util; + +import java.util.Arrays; +import org.apache.commons.lang3.RegExUtils; +import com.ruoyi.common.core.constant.GenConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.gen.config.GenConfig; +import com.ruoyi.gen.domain.GenTable; +import com.ruoyi.gen.domain.GenTableColumn; + +/** + * 代码生成器 工具类 + * + * @author ruoyi + */ +public class GenUtils +{ + /** + * 初始化表信息 + */ + public static void initTable(GenTable genTable, String operName) + { + genTable.setClassName(convertClassName(genTable.getTableName())); + genTable.setPackageName(GenConfig.getPackageName()); + genTable.setModuleName(getModuleName(GenConfig.getPackageName())); + genTable.setBusinessName(getBusinessName(genTable.getTableName())); + genTable.setFunctionName(replaceText(genTable.getTableComment())); + genTable.setFunctionAuthor(GenConfig.getAuthor()); + genTable.setCreateBy(operName); + } + + /** + * 初始化列属性字段 + */ + public static void initColumnField(GenTableColumn column, GenTable table) + { + String dataType = getDbType(column.getColumnType()); + String columnName = column.getColumnName(); + column.setTableId(table.getTableId()); + column.setCreateBy(table.getCreateBy()); + // 设置java字段名 + column.setJavaField(StringUtils.toCamelCase(columnName)); + // 设置默认类型 + column.setJavaType(GenConstants.TYPE_STRING); + column.setQueryType(GenConstants.QUERY_EQ); + + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) + { + // 字符串长度超过500设置为文本域 + Integer columnLength = getColumnLength(column.getColumnType()); + String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + column.setHtmlType(htmlType); + } + else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) + { + column.setJavaType(GenConstants.TYPE_DATE); + column.setHtmlType(GenConstants.HTML_DATETIME); + } + else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) + { + column.setHtmlType(GenConstants.HTML_INPUT); + + // 如果是浮点型 统一用BigDecimal + String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ","); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) + { + column.setJavaType(GenConstants.TYPE_BIGDECIMAL); + } + // 如果是整形 + else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) + { + column.setJavaType(GenConstants.TYPE_INTEGER); + } + // 长整形 + else + { + column.setJavaType(GenConstants.TYPE_LONG); + } + } + + // 插入字段(默认所有字段都需要插入) + column.setIsInsert(GenConstants.REQUIRE); + + // 编辑字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) + { + column.setIsEdit(GenConstants.REQUIRE); + } + // 列表字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) + { + column.setIsList(GenConstants.REQUIRE); + } + // 查询字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) + { + column.setIsQuery(GenConstants.REQUIRE); + } + + // 查询字段类型 + if (StringUtils.endsWithIgnoreCase(columnName, "name")) + { + column.setQueryType(GenConstants.QUERY_LIKE); + } + // 状态字段设置单选框 + if (StringUtils.endsWithIgnoreCase(columnName, "status")) + { + column.setHtmlType(GenConstants.HTML_RADIO); + } + // 类型&性别字段设置下拉框 + else if (StringUtils.endsWithIgnoreCase(columnName, "type") + || StringUtils.endsWithIgnoreCase(columnName, "sex")) + { + column.setHtmlType(GenConstants.HTML_SELECT); + } + // 图片字段设置图片上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) + { + column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); + } + // 文件字段设置文件上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) + { + column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) + { + column.setHtmlType(GenConstants.HTML_EDITOR); + } + } + + /** + * 校验数组是否包含指定值 + * + * @param arr 数组 + * @param targetValue 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) + { + return Arrays.asList(arr).contains(targetValue); + } + + /** + * 获取模块名 + * + * @param packageName 包名 + * @return 模块名 + */ + public static String getModuleName(String packageName) + { + int lastIndex = packageName.lastIndexOf("."); + int nameLength = packageName.length(); + return StringUtils.substring(packageName, lastIndex + 1, nameLength); + } + + /** + * 获取业务名 + * + * @param tableName 表名 + * @return 业务名 + */ + public static String getBusinessName(String tableName) + { + int lastIndex = tableName.lastIndexOf("_"); + int nameLength = tableName.length(); + return StringUtils.substring(tableName, lastIndex + 1, nameLength); + } + + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) + { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) + { + String[] searchList = StringUtils.split(tablePrefix, ","); + tableName = replaceFirst(tableName, searchList); + } + return StringUtils.convertToCamelCase(tableName); + } + + /** + * 批量替换前缀 + * + * @param replacementm 替换值 + * @param searchList 替换列表 + * @return + */ + public static String replaceFirst(String replacementm, String[] searchList) + { + String text = replacementm; + for (String searchString : searchList) + { + if (replacementm.startsWith(searchString)) + { + text = replacementm.replaceFirst(searchString, ""); + break; + } + } + return text; + } + + /** + * 关键字替换 + * + * @param text 需要被替换的名字 + * @return 替换后的名字 + */ + public static String replaceText(String text) + { + return RegExUtils.replaceAll(text, "(?:表|若依)", ""); + } + + /** + * 获取数据库类型字段 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { + return StringUtils.substringBefore(columnType, "("); + } + else + { + return columnType; + } + } + + /** + * 获取字段长度 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { + String length = StringUtils.substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } + else + { + return 0; + } + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java new file mode 100644 index 0000000..d6f0160 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java @@ -0,0 +1,34 @@ +package com.ruoyi.gen.util; + +import java.util.Properties; +import org.apache.velocity.app.Velocity; +import com.ruoyi.common.core.constant.Constants; + +/** + * VelocityEngine工厂 + * + * @author ruoyi + */ +public class VelocityInitializer +{ + /** + * 初始化vm方法 + */ + public static void initVelocity() + { + Properties p = new Properties(); + try + { + // 加载classpath目录下的vm文件 + p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + // 定义字符集 + p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8); + // 初始化Velocity引擎,指定配置Properties + Velocity.init(p); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java new file mode 100644 index 0000000..0db5f9c --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java @@ -0,0 +1,402 @@ +package com.ruoyi.gen.util; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.velocity.VelocityContext; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.core.constant.GenConstants; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.gen.domain.GenTable; +import com.ruoyi.gen.domain.GenTableColumn; + +/** + * 模板工具类 + * + * @author ruoyi + */ +public class VelocityUtils +{ + /** 项目空间路径 */ + private static final String PROJECT_PATH = "main/java"; + + /** mybatis空间路径 */ + private static final String MYBATIS_PATH = "main/resources/mapper"; + + /** 默认上级菜单,系统工具 */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; + + /** + * 设置模板变量信息 + * + * @return 模板列表 + */ + public static VelocityContext prepareContext(GenTable genTable) + { + String moduleName = genTable.getModuleName(); + String businessName = genTable.getBusinessName(); + String packageName = genTable.getPackageName(); + String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("tplCategory", genTable.getTplCategory()); + velocityContext.put("tableName", genTable.getTableName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("ClassName", genTable.getClassName()); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); + velocityContext.put("moduleName", genTable.getModuleName()); + velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); + velocityContext.put("businessName", genTable.getBusinessName()); + velocityContext.put("basePackage", getPackagePrefix(packageName)); + velocityContext.put("packageName", packageName); + velocityContext.put("author", genTable.getFunctionAuthor()); + velocityContext.put("datetime", DateUtils.getDate()); + velocityContext.put("pkColumn", genTable.getPkColumn()); + velocityContext.put("importList", getImportList(genTable)); + velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); + velocityContext.put("columns", genTable.getColumns()); + velocityContext.put("table", genTable); + velocityContext.put("dicts", getDicts(genTable)); + setMenuVelocityContext(velocityContext, genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) + { + setTreeVelocityContext(velocityContext, genTable); + } + if (GenConstants.TPL_SUB.equals(tplCategory)) + { + setSubVelocityContext(velocityContext, genTable); + } + return velocityContext; + } + + public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSON.parseObject(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSON.parseObject(options); + String treeCode = getTreecode(paramsObj); + String treeParentCode = getTreeParentCode(paramsObj); + String treeName = getTreeName(paramsObj); + + context.put("treeCode", treeCode); + context.put("treeParentCode", treeParentCode); + context.put("treeName", treeName); + context.put("expandColumn", getExpandColumn(genTable)); + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { + context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE)); + } + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { + context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME)); + } + } + + public static void setSubVelocityContext(VelocityContext context, GenTable genTable) + { + GenTable subTable = genTable.getSubTable(); + String subTableName = genTable.getSubTableName(); + String subTableFkName = genTable.getSubTableFkName(); + String subClassName = genTable.getSubTable().getClassName(); + String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName); + + context.put("subTable", subTable); + context.put("subTableName", subTableName); + context.put("subTableFkName", subTableFkName); + context.put("subTableFkClassName", subTableFkClassName); + context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName)); + context.put("subClassName", subClassName); + context.put("subclassName", StringUtils.uncapitalize(subClassName)); + context.put("subImportList", getImportList(genTable.getSubTable())); + } + + /** + * 获取模板信息 + * + * @return 模板列表 + */ + public static List<String> getTemplateList(String tplCategory) + { + List<String> templates = new ArrayList<String>(); + templates.add("vm/java/domain.java.vm"); + templates.add("vm/java/mapper.java.vm"); + templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); + templates.add("vm/java/controller.java.vm"); + templates.add("vm/xml/mapper.xml.vm"); + templates.add("vm/sql/sql.vm"); + templates.add("vm/js/api.js.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) + { + templates.add("vm/vue/index.vue.vm"); + } + else if (GenConstants.TPL_TREE.equals(tplCategory)) + { + templates.add("vm/vue/index-tree.vue.vm"); + } + else if (GenConstants.TPL_SUB.equals(tplCategory)) + { + templates.add("vm/vue/index.vue.vm"); + templates.add("vm/java/sub-domain.java.vm"); + } + return templates; + } + + /** + * 获取文件名 + */ + public static String getFileName(String template, GenTable genTable) + { + // 文件名称 + String fileName = ""; + // 包路径 + String packageName = genTable.getPackageName(); + // 模块名 + String moduleName = genTable.getModuleName(); + // 大写类名 + String className = genTable.getClassName(); + // 业务名称 + String businessName = genTable.getBusinessName(); + + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); + String mybatisPath = MYBATIS_PATH + "/" + moduleName; + String vuePath = "vue"; + + if (template.contains("domain.java.vm")) + { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); + } + if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) + { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName()); + } + else if (template.contains("mapper.java.vm")) + { + fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); + } + else if (template.contains("service.java.vm")) + { + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); + } + else if (template.contains("serviceImpl.java.vm")) + { + fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); + } + else if (template.contains("controller.java.vm")) + { + fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); + } + else if (template.contains("mapper.xml.vm")) + { + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + } + else if (template.contains("sql.vm")) + { + fileName = businessName + "Menu.sql"; + } + else if (template.contains("api.js.vm")) + { + fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName); + } + else if (template.contains("index.vue.vm")) + { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + else if (template.contains("index-tree.vue.vm")) + { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + return fileName; + } + + /** + * 获取包前缀 + * + * @param packageName 包名称 + * @return 包前缀名称 + */ + public static String getPackagePrefix(String packageName) + { + int lastIndex = packageName.lastIndexOf("."); + return StringUtils.substring(packageName, 0, lastIndex); + } + + /** + * 根据列类型获取导入包 + * + * @param genTable 业务表对象 + * @return 返回需要导入的包列表 + */ + public static HashSet<String> getImportList(GenTable genTable) + { + List<GenTableColumn> columns = genTable.getColumns(); + GenTable subGenTable = genTable.getSubTable(); + HashSet<String> importList = new HashSet<String>(); + if (StringUtils.isNotNull(subGenTable)) + { + importList.add("java.util.List"); + } + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) + { + importList.add("java.util.Date"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } + else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) + { + importList.add("java.math.BigDecimal"); + } + } + return importList; + } + + /** + * 根据列类型获取字典组 + * + * @param genTable 业务表对象 + * @return 返回字典组 + */ + public static String getDicts(GenTable genTable) + { + List<GenTableColumn> columns = genTable.getColumns(); + Set<String> dicts = new HashSet<String>(); + addDicts(dicts, columns); + if (StringUtils.isNotNull(genTable.getSubTable())) + { + List<GenTableColumn> subColumns = genTable.getSubTable().getColumns(); + addDicts(dicts, subColumns); + } + return StringUtils.join(dicts, ", "); + } + + /** + * 添加字典列表 + * + * @param dicts 字典列表 + * @param columns 列集合 + */ + public static void addDicts(Set<String> dicts, List<GenTableColumn> columns) + { + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( + column.getHtmlType(), + new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) + { + dicts.add("'" + column.getDictType() + "'"); + } + } + } + + /** + * 获取权限前缀 + * + * @param moduleName 模块名称 + * @param businessName 业务名称 + * @return 返回权限前缀 + */ + public static String getPermissionPrefix(String moduleName, String businessName) + { + return StringUtils.format("{}:{}", moduleName, businessName); + } + + /** + * 获取上级菜单ID字段 + * + * @param paramsObj 生成其他选项 + * @return 上级菜单ID字段 + */ + public static String getParentMenuId(JSONObject paramsObj) + { + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID) + && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID))) + { + return paramsObj.getString(GenConstants.PARENT_MENU_ID); + } + return DEFAULT_PARENT_MENU_ID; + } + + /** + * 获取树编码 + * + * @param paramsObj 生成其他选项 + * @return 树编码 + */ + public static String getTreecode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_CODE)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE)); + } + return StringUtils.EMPTY; + } + + /** + * 获取树父编码 + * + * @param paramsObj 生成其他选项 + * @return 树父编码 + */ + public static String getTreeParentCode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE)); + } + return StringUtils.EMPTY; + } + + /** + * 获取树名称 + * + * @param paramsObj 生成其他选项 + * @return 树名称 + */ + public static String getTreeName(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME)); + } + return StringUtils.EMPTY; + } + + /** + * 获取需要在哪一列上面显示展开按钮 + * + * @param genTable 业务表对象 + * @return 展开按钮列序号 + */ + public static int getExpandColumn(GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSON.parseObject(options); + String treeName = paramsObj.getString(GenConstants.TREE_NAME); + int num = 0; + for (GenTableColumn column : genTable.getColumns()) + { + if (column.isList()) + { + num++; + String columnName = column.getColumnName(); + if (columnName.equals(treeName)) + { + break; + } + } + } + return num; + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt new file mode 100644 index 0000000..05f528c --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ + (_) + _ __ _ _ ___ _ _ _ ______ __ _ ___ _ __ +| '__|| | | | / _ \ | | | || ||______| / _` | / _ \| '_ \ +| | | |_| || (_) || |_| || | | (_| || __/| | | | +|_| \__,_| \___/ \__, ||_| \__, | \___||_| |_| + __/ | __/ | + |___/ |___/ \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..3d943b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml @@ -0,0 +1,36 @@ +# Tomcat +server: + port: 9202 + +# Spring +spring: + application: + # 应用名称 + name: ruoyi-gen + profiles: + # 环境配置 + active: dev +--- +spring: + config: + activate: + on-profile: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.64:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 8ebd2324-30b4-477b-af79-b46e717c4fbe + config: + # 配置中心地址 + server-addr: 192.168.110.64:8848 + namespace: 8ebd2324-30b4-477b-af79-b46e717c4fbe + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml new file mode 100644 index 0000000..c301bb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <!-- 日志存放路径 --> + <property name="log.path" value="logs/ruoyi-gen" /> + <!-- 日志输出格式 --> + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> + + <!-- 控制台输出 --> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + </appender> + + <!-- 系统日志输出 --> + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/info.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>INFO</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/error.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>ERROR</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 系统模块日志级别控制 --> + <logger name="com.ruoyi" level="info" /> + <!-- Spring日志级别控制 --> + <logger name="org.springframework" level="warn" /> + + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--系统操作日志--> + <root level="info"> + <appender-ref ref="file_info" /> + <appender-ref ref="file_error" /> + </root> +</configuration> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml new file mode 100644 index 0000000..6d31cda --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.gen.mapper.GenTableColumnMapper"> + + <resultMap type="com.ruoyi.gen.domain.GenTableColumn" id="GenTableColumnResult"> + <id property="columnId" column="column_id" /> + <result property="tableId" column="table_id" /> + <result property="columnName" column="column_name" /> + <result property="columnComment" column="column_comment" /> + <result property="columnType" column="column_type" /> + <result property="javaType" column="java_type" /> + <result property="javaField" column="java_field" /> + <result property="isPk" column="is_pk" /> + <result property="isIncrement" column="is_increment" /> + <result property="isRequired" column="is_required" /> + <result property="isInsert" column="is_insert" /> + <result property="isEdit" column="is_edit" /> + <result property="isList" column="is_list" /> + <result property="isQuery" column="is_query" /> + <result property="queryType" column="query_type" /> + <result property="htmlType" column="html_type" /> + <result property="dictType" column="dict_type" /> + <result property="sort" column="sort" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectGenTableColumnVo"> + select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column + </sql> + + <select id="selectGenTableColumnListByTableId" parameterType="com.ruoyi.gen.domain.GenTableColumn" resultMap="GenTableColumnResult"> + <include refid="selectGenTableColumnVo"/> + where table_id = #{tableId} + order by sort + </select> + + <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult"> + select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type + from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName}) + order by ordinal_position + </select> + + <insert id="insertGenTableColumn" parameterType="com.ruoyi.gen.domain.GenTableColumn" useGeneratedKeys="true" keyProperty="columnId"> + insert into gen_table_column ( + <if test="tableId != null and tableId != ''">table_id,</if> + <if test="columnName != null and columnName != ''">column_name,</if> + <if test="columnComment != null and columnComment != ''">column_comment,</if> + <if test="columnType != null and columnType != ''">column_type,</if> + <if test="javaType != null and javaType != ''">java_type,</if> + <if test="javaField != null and javaField != ''">java_field,</if> + <if test="isPk != null and isPk != ''">is_pk,</if> + <if test="isIncrement != null and isIncrement != ''">is_increment,</if> + <if test="isRequired != null and isRequired != ''">is_required,</if> + <if test="isInsert != null and isInsert != ''">is_insert,</if> + <if test="isEdit != null and isEdit != ''">is_edit,</if> + <if test="isList != null and isList != ''">is_list,</if> + <if test="isQuery != null and isQuery != ''">is_query,</if> + <if test="queryType != null and queryType != ''">query_type,</if> + <if test="htmlType != null and htmlType != ''">html_type,</if> + <if test="dictType != null and dictType != ''">dict_type,</if> + <if test="sort != null">sort,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="tableId != null and tableId != ''">#{tableId},</if> + <if test="columnName != null and columnName != ''">#{columnName},</if> + <if test="columnComment != null and columnComment != ''">#{columnComment},</if> + <if test="columnType != null and columnType != ''">#{columnType},</if> + <if test="javaType != null and javaType != ''">#{javaType},</if> + <if test="javaField != null and javaField != ''">#{javaField},</if> + <if test="isPk != null and isPk != ''">#{isPk},</if> + <if test="isIncrement != null and isIncrement != ''">#{isIncrement},</if> + <if test="isRequired != null and isRequired != ''">#{isRequired},</if> + <if test="isInsert != null and isInsert != ''">#{isInsert},</if> + <if test="isEdit != null and isEdit != ''">#{isEdit},</if> + <if test="isList != null and isList != ''">#{isList},</if> + <if test="isQuery != null and isQuery != ''">#{isQuery},</if> + <if test="queryType != null and queryType != ''">#{queryType},</if> + <if test="htmlType != null and htmlType != ''">#{htmlType},</if> + <if test="dictType != null and dictType != ''">#{dictType},</if> + <if test="sort != null">#{sort},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateGenTableColumn" parameterType="com.ruoyi.gen.domain.GenTableColumn"> + update gen_table_column + <set> + <if test="columnComment != null">column_comment = #{columnComment},</if> + <if test="javaType != null">java_type = #{javaType},</if> + <if test="javaField != null">java_field = #{javaField},</if> + <if test="isInsert != null">is_insert = #{isInsert},</if> + <if test="isEdit != null">is_edit = #{isEdit},</if> + <if test="isList != null">is_list = #{isList},</if> + <if test="isQuery != null">is_query = #{isQuery},</if> + <if test="isRequired != null">is_required = #{isRequired},</if> + <if test="queryType != null">query_type = #{queryType},</if> + <if test="htmlType != null">html_type = #{htmlType},</if> + <if test="dictType != null">dict_type = #{dictType},</if> + <if test="sort != null">sort = #{sort},</if> + <if test="updateBy != null">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where column_id = #{columnId} + </update> + + <delete id="deleteGenTableColumnByIds" parameterType="Long"> + delete from gen_table_column where table_id in + <foreach collection="array" item="tableId" open="(" separator="," close=")"> + #{tableId} + </foreach> + </delete> + + <delete id="deleteGenTableColumns"> + delete from gen_table_column where column_id in + <foreach collection="list" item="item" open="(" separator="," close=")"> + #{item.columnId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml new file mode 100644 index 0000000..9b7c87a --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml @@ -0,0 +1,202 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.gen.mapper.GenTableMapper"> + + <resultMap type="com.ruoyi.gen.domain.GenTable" id="GenTableResult"> + <id property="tableId" column="table_id" /> + <result property="tableName" column="table_name" /> + <result property="tableComment" column="table_comment" /> + <result property="subTableName" column="sub_table_name" /> + <result property="subTableFkName" column="sub_table_fk_name" /> + <result property="className" column="class_name" /> + <result property="tplCategory" column="tpl_category" /> + <result property="packageName" column="package_name" /> + <result property="moduleName" column="module_name" /> + <result property="businessName" column="business_name" /> + <result property="functionName" column="function_name" /> + <result property="functionAuthor" column="function_author" /> + <result property="genType" column="gen_type" /> + <result property="genPath" column="gen_path" /> + <result property="options" column="options" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + <collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" /> + </resultMap> + + <resultMap type="com.ruoyi.gen.domain.GenTableColumn" id="GenTableColumnResult"> + <id property="columnId" column="column_id" /> + <result property="tableId" column="table_id" /> + <result property="columnName" column="column_name" /> + <result property="columnComment" column="column_comment" /> + <result property="columnType" column="column_type" /> + <result property="javaType" column="java_type" /> + <result property="javaField" column="java_field" /> + <result property="isPk" column="is_pk" /> + <result property="isIncrement" column="is_increment" /> + <result property="isRequired" column="is_required" /> + <result property="isInsert" column="is_insert" /> + <result property="isEdit" column="is_edit" /> + <result property="isList" column="is_list" /> + <result property="isQuery" column="is_query" /> + <result property="queryType" column="query_type" /> + <result property="htmlType" column="html_type" /> + <result property="dictType" column="dict_type" /> + <result property="sort" column="sort" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectGenTableVo"> + select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table + </sql> + + <select id="selectGenTableList" parameterType="com.ruoyi.gen.domain.GenTable" resultMap="GenTableResult"> + <include refid="selectGenTableVo"/> + <where> + <if test="tableName != null and tableName != ''"> + AND lower(table_name) like lower(concat('%', #{tableName}, '%')) + </if> + <if test="tableComment != null and tableComment != ''"> + AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + AND date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + AND date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + </where> + </select> + + <select id="selectDbTableList" parameterType="com.ruoyi.gen.domain.GenTable" resultMap="GenTableResult"> + select table_name, table_comment, create_time, update_time from information_schema.tables + where table_schema = (select database()) + AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%' + AND table_name NOT IN (select table_name from gen_table) + <if test="tableName != null and tableName != ''"> + AND lower(table_name) like lower(concat('%', #{tableName}, '%')) + </if> + <if test="tableComment != null and tableComment != ''"> + AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + AND date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + AND date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + order by create_time desc + </select> + + <select id="selectDbTableListByNames" resultMap="GenTableResult"> + select table_name, table_comment, create_time, update_time from information_schema.tables + where table_name NOT LIKE 'qrtz_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database()) + and table_name in + <foreach collection="array" item="name" open="(" separator="," close=")"> + #{name} + </foreach> + </select> + + <select id="selectTableByName" parameterType="String" resultMap="GenTableResult"> + select table_name, table_comment, create_time, update_time from information_schema.tables + where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database()) + and table_name = #{tableName} + </select> + + <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult"> + SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark, + c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort + FROM gen_table t + LEFT JOIN gen_table_column c ON t.table_id = c.table_id + where t.table_id = #{tableId} order by c.sort + </select> + + <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult"> + SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark, + c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort + FROM gen_table t + LEFT JOIN gen_table_column c ON t.table_id = c.table_id + where t.table_name = #{tableName} order by c.sort + </select> + + <select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult"> + SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark, + c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort + FROM gen_table t + LEFT JOIN gen_table_column c ON t.table_id = c.table_id + order by c.sort + </select> + + <insert id="insertGenTable" parameterType="com.ruoyi.gen.domain.GenTable" useGeneratedKeys="true" keyProperty="tableId"> + insert into gen_table ( + <if test="tableName != null">table_name,</if> + <if test="tableComment != null and tableComment != ''">table_comment,</if> + <if test="className != null and className != ''">class_name,</if> + <if test="tplCategory != null and tplCategory != ''">tpl_category,</if> + <if test="packageName != null and packageName != ''">package_name,</if> + <if test="moduleName != null and moduleName != ''">module_name,</if> + <if test="businessName != null and businessName != ''">business_name,</if> + <if test="functionName != null and functionName != ''">function_name,</if> + <if test="functionAuthor != null and functionAuthor != ''">function_author,</if> + <if test="genType != null and genType != ''">gen_type,</if> + <if test="genPath != null and genPath != ''">gen_path,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="tableName != null">#{tableName},</if> + <if test="tableComment != null and tableComment != ''">#{tableComment},</if> + <if test="className != null and className != ''">#{className},</if> + <if test="tplCategory != null and tplCategory != ''">#{tplCategory},</if> + <if test="packageName != null and packageName != ''">#{packageName},</if> + <if test="moduleName != null and moduleName != ''">#{moduleName},</if> + <if test="businessName != null and businessName != ''">#{businessName},</if> + <if test="functionName != null and functionName != ''">#{functionName},</if> + <if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if> + <if test="genType != null and genType != ''">#{genType},</if> + <if test="genPath != null and genPath != ''">#{genPath},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateGenTable" parameterType="com.ruoyi.gen.domain.GenTable"> + update gen_table + <set> + <if test="tableName != null">table_name = #{tableName},</if> + <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if> + <if test="subTableName != null">sub_table_name = #{subTableName},</if> + <if test="subTableFkName != null">sub_table_fk_name = #{subTableFkName},</if> + <if test="className != null and className != ''">class_name = #{className},</if> + <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if> + <if test="genType != null and genType != ''">gen_type = #{genType},</if> + <if test="genPath != null and genPath != ''">gen_path = #{genPath},</if> + <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if> + <if test="packageName != null and packageName != ''">package_name = #{packageName},</if> + <if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if> + <if test="businessName != null and businessName != ''">business_name = #{businessName},</if> + <if test="functionName != null and functionName != ''">function_name = #{functionName},</if> + <if test="options != null and options != ''">options = #{options},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + <if test="remark != null">remark = #{remark},</if> + update_time = sysdate() + </set> + where table_id = #{tableId} + </update> + + <delete id="deleteGenTableByIds" parameterType="Long"> + delete from gen_table where table_id in + <foreach collection="array" item="tableId" open="(" separator="," close=")"> + #{tableId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 0000000..6ef3a78 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,116 @@ +package ${packageName}.controller; + +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +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.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +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.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import ${packageName}.domain.${ClassName}; +import ${packageName}.service.I${ClassName}Service; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +#if($table.crud || $table.sub) +import com.ruoyi.common.core.web.page.TableDataInfo; +#elseif($table.tree) +#end + +/** + * ${functionName}Controller + * + * @author ${author} + * @date ${datetime} + */ +@RestController +@RequestMapping("/{businessName}") +public class ${ClassName}Controller extends BaseController +{ + @Autowired + private I${ClassName}Service ${className}Service; + + /** + * 查询${functionName}列表 + */ + @RequiresPermissions("${permissionPrefix}:list") + @GetMapping("/list") +#if($table.crud || $table.sub) + public TableDataInfo list(${ClassName} ${className}) + { + startPage(); + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return getDataTable(list); + } +#elseif($table.tree) + public AjaxResult list(${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return success(list); + } +#end + + /** + * 导出${functionName}列表 + */ + @RequiresPermissions("${permissionPrefix}:export") + @Log(title = "${functionName}", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); + util.exportExcel(response, list, "${functionName}数据"); + } + + /** + * 获取${functionName}详细信息 + */ + @RequiresPermissions("${permissionPrefix}:query") + @GetMapping(value = "/{${pkColumn.javaField}}") + public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) + { + return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField})); + } + + /** + * 新增${functionName} + */ + @RequiresPermissions("${permissionPrefix}:add") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ${ClassName} ${className}) + { + return toAjax(${className}Service.insert${ClassName}(${className})); + } + + /** + * 修改${functionName} + */ + @RequiresPermissions("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ${ClassName} ${className}) + { + return toAjax(${className}Service.update${ClassName}(${className})); + } + + /** + * 删除${functionName} + */ + @RequiresPermissions("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @DeleteMapping("/{${pkColumn.javaField}s}") + public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) + { + return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s)); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm new file mode 100644 index 0000000..ee3b7b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm @@ -0,0 +1,105 @@ +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; +#if($table.crud || $table.sub) +import com.ruoyi.common.core.web.domain.BaseEntity; +#elseif($table.tree) +import com.ruoyi.common.core.web.domain.TreeEntity; +#end + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($table.crud || $table.sub) +#set($Entity="BaseEntity") +#elseif($table.tree) +#set($Entity="TreeEntity") +#end +public class ${ClassName} extends ${Entity} +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ +#if($column.list) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($parentheseIndex != -1) + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") +#elseif($column.javaType == 'Date') + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; + +#end +#end +#if($table.sub) + /** $table.subTable.functionName信息 */ + private List<${subClassName}> ${subclassName}List; + +#end +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end + +#if($table.sub) + public List<${subClassName}> get${subClassName}List() + { + return ${subclassName}List; + } + + public void set${subClassName}List(List<${subClassName}> ${subclassName}List) + { + this.${subclassName}List = ${subclassName}List; + } + +#end + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $columns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#end +#if($table.sub) + .append("${subclassName}List", get${subClassName}List()) +#end + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 0000000..7e7d7c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,91 @@ +package ${packageName}.mapper; + +import java.util.List; +import ${packageName}.domain.${ClassName}; +#if($table.sub) +import ${packageName}.domain.${subClassName}; +#end + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper +{ + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return ${functionName} + */ + public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName}集合 + */ + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int insert${ClassName}(${ClassName} ${className}); + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int update${ClassName}(${ClassName} ${className}); + + /** + * 删除${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的数据主键集合 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); +#if($table.sub) + + /** + * 批量删除${subTable.functionName} + * + * @param ${pkColumn.javaField}s 需要删除的数据主键集合 + * @return 结果 + */ + public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); + + /** + * 批量新增${subTable.functionName} + * + * @param ${subclassName}List ${subTable.functionName}列表 + * @return 结果 + */ + public int batch${subClassName}(List<${subClassName}> ${subclassName}List); + + + /** + * 通过${functionName}主键删除${subTable.functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return 结果 + */ + public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField}); +#end +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm new file mode 100644 index 0000000..264882b --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,61 @@ +package ${packageName}.service; + +import java.util.List; +import ${packageName}.domain.${ClassName}; + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service +{ + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return ${functionName} + */ + public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName}集合 + */ + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int insert${ClassName}(${ClassName} ${className}); + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int update${ClassName}(${ClassName} ${className}); + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s); + + /** + * 删除${functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return 结果 + */ + public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 0000000..d590b92 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,169 @@ +package ${packageName}.service.impl; + +import java.util.List; +#foreach ($column in $columns) +#if($column.javaField == 'createTime' || $column.javaField == 'updateTime') +import com.ruoyi.common.core.utils.DateUtils; +#break +#end +#end +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +#if($table.sub) +import java.util.ArrayList; +import com.ruoyi.common.core.utils.StringUtils; +import org.springframework.transaction.annotation.Transactional; +import ${packageName}.domain.${subClassName}; +#end +import ${packageName}.mapper.${ClassName}Mapper; +import ${packageName}.domain.${ClassName}; +import ${packageName}.service.I${ClassName}Service; + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service +{ + @Autowired + private ${ClassName}Mapper ${className}Mapper; + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return ${functionName} + */ + @Override + public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}) + { + return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}); + } + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName} + */ + @Override + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}) + { + return ${className}Mapper.select${ClassName}List(${className}); + } + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int insert${ClassName}(${ClassName} ${className}) + { +#foreach ($column in $columns) +#if($column.javaField == 'createTime') + ${className}.setCreateTime(DateUtils.getNowDate()); +#end +#end +#if($table.sub) + int rows = ${className}Mapper.insert${ClassName}(${className}); + insert${subClassName}(${className}); + return rows; +#else + return ${className}Mapper.insert${ClassName}(${className}); +#end + } + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int update${ClassName}(${ClassName} ${className}) + { +#foreach ($column in $columns) +#if($column.javaField == 'updateTime') + ${className}.setUpdateTime(DateUtils.getNowDate()); +#end +#end +#if($table.sub) + ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}()); + insert${subClassName}(${className}); +#end + return ${className}Mapper.update${ClassName}(${className}); + } + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的${functionName}主键 + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s) + { +#if($table.sub) + ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s); +#end + return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s); + } + + /** + * 删除${functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}主键 + * @return 结果 + */ +#if($table.sub) + @Transactional +#end + @Override + public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}) + { +#if($table.sub) + ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField}); +#end + return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}); + } +#if($table.sub) + + /** + * 新增${subTable.functionName}信息 + * + * @param ${className} ${functionName}对象 + */ + public void insert${subClassName}(${ClassName} ${className}) + { + List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List(); + ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}(); + if (StringUtils.isNotNull(${subclassName}List)) + { + List<${subClassName}> list = new ArrayList<${subClassName}>(); + for (${subClassName} ${subclassName} : ${subclassName}List) + { + ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField}); + list.add(${subclassName}); + } + if (list.size() > 0) + { + ${className}Mapper.batch${subClassName}(list); + } + } + } +#end +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/sub-domain.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/sub-domain.java.vm new file mode 100644 index 0000000..2e039ff --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/sub-domain.java.vm @@ -0,0 +1,76 @@ +package ${packageName}.domain; + +#foreach ($import in $subImportList) +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 com.ruoyi.common.core.web.domain.BaseEntity; + +/** + * ${subTable.functionName}对象 ${subTableName} + * + * @author ${author} + * @date ${datetime} + */ +public class ${subClassName} extends BaseEntity +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ +#if($column.list) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($parentheseIndex != -1) + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") +#elseif($column.javaType == 'Date') + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; + +#end +#end +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $subTable.columns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#end + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm new file mode 100644 index 0000000..9295524 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询${functionName}列表 +export function list${BusinessName}(query) { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'get', + params: query + }) +} + +// 查询${functionName}详细 +export function get${BusinessName}(${pkColumn.javaField}) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'get' + }) +} + +// 新增${functionName} +export function add${BusinessName}(data) { + return request({ + url: '/${moduleName}/${businessName}', + method: 'post', + data: data + }) +} + +// 修改${functionName} +export function update${BusinessName}(data) { + return request({ + url: '/${moduleName}/${businessName}', + method: 'put', + data: data + }) +} + +// 删除${functionName} +export function del${BusinessName}(${pkColumn.javaField}) { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'delete' + }) +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm new file mode 100644 index 0000000..0575583 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,22 @@ +-- 菜单 SQL +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单'); + +-- 按钮父菜单ID +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, ''); + +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, ''); \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm new file mode 100644 index 0000000..a4c64a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm @@ -0,0 +1,505 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> +#foreach($column in $columns) +#if($column.query) +#set($dictType=$column.dictType) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.htmlType == "input") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-input + v-model="queryParams.${column.javaField}" + placeholder="请输入${comment}" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option + v-for="dict in dict.type.${dictType}" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-date-picker clearable + v-model="queryParams.${column.javaField}" + type="date" + value-format="yyyy-MM-dd" + placeholder="选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + <el-form-item label="${comment}"> + <el-date-picker + v-model="daterange${AttrName}" + style="width: 240px" + value-format="yyyy-MM-dd" + type="daterange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + ></el-date-picker> + </el-form-item> +#end +#end +#end + <el-form-item> + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="el-icon-plus" + size="mini" + @click="handleAdd" + v-hasPermi="['${moduleName}:${businessName}:add']" + >新增</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="info" + plain + icon="el-icon-sort" + size="mini" + @click="toggleExpandAll" + >展开/折叠</el-button> + </el-col> + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> + </el-row> + + <el-table + v-if="refreshTable" + v-loading="loading" + :data="${businessName}List" + row-key="${treeCode}" + :default-expand-all="isExpandAll" + :tree-props="{children: 'children', hasChildren: 'hasChildren'}" + > +#foreach($column in $columns) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk) +#elseif($column.list && $column.htmlType == "datetime") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="180"> + <template slot-scope="scope"> + <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> + </template> + </el-table-column> +#elseif($column.list && $column.htmlType == "imageUpload") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="100"> + <template slot-scope="scope"> + <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/> + </template> + </el-table-column> +#elseif($column.list && "" != $column.dictType) + <el-table-column label="${comment}" align="center" prop="${javaField}"> + <template slot-scope="scope"> +#if($column.htmlType == "checkbox") + <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/> +#else + <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/> +#end + </template> + </el-table-column> +#elseif($column.list && "" != $javaField) +#if(${foreach.index} == 1) + <el-table-column label="${comment}" prop="${javaField}" /> +#else + <el-table-column label="${comment}" align="center" prop="${javaField}" /> +#end +#end +#end + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template slot-scope="scope"> + <el-button + size="mini" + type="text" + icon="el-icon-edit" + @click="handleUpdate(scope.row)" + v-hasPermi="['${moduleName}:${businessName}:edit']" + >修改</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-plus" + @click="handleAdd(scope.row)" + v-hasPermi="['${moduleName}:${businessName}:add']" + >新增</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-delete" + @click="handleDelete(scope.row)" + v-hasPermi="['${moduleName}:${businessName}:remove']" + >删除</el-button> + </template> + </el-table-column> + </el-table> + + <!-- 添加或修改${functionName}对话框 --> + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> + <el-form ref="form" :model="form" :rules="rules" label-width="80px"> +#foreach($column in $columns) +#set($field=$column.javaField) +#if($column.insert && !$column.pk) +#if(($column.usableColumn) || (!$column.superColumn)) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#set($dictType=$column.dictType) +#if("" != $treeParentCode && $column.javaField == $treeParentCode) + <el-form-item label="${comment}" prop="${treeParentCode}"> + <treeselect v-model="form.${treeParentCode}" :options="${businessName}Options" :normalizer="normalizer" placeholder="请选择${comment}" /> + </el-form-item> +#elseif($column.htmlType == "input") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" placeholder="请输入${comment}" /> + </el-form-item> +#elseif($column.htmlType == "imageUpload") + <el-form-item label="${comment}" prop="${field}"> + <image-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "fileUpload") + <el-form-item label="${comment}" prop="${field}"> + <file-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "editor") + <el-form-item label="${comment}"> + <editor v-model="form.${field}" :min-height="192"/> + </el-form-item> +#elseif($column.htmlType == "select" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option + v-for="dict in dict.type.${dictType}" + :key="dict.value" + :label="dict.label" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :value="parseInt(dict.value)" +#else + :value="dict.value" +#end + ></el-option> + </el-select> + </el-form-item> +#elseif($column.htmlType == "select" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "checkbox" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox + v-for="dict in dict.type.${dictType}" + :key="dict.value" + :label="dict.value"> + {{dict.label}} + </el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "checkbox" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox>请选择字典生成</el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "radio" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio + v-for="dict in dict.type.${dictType}" + :key="dict.value" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :label="parseInt(dict.value)" +#else + :label="dict.value" +#end + >{{dict.label}}</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "radio" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio label="1">请选择字典生成</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "datetime") + <el-form-item label="${comment}" prop="${field}"> + <el-date-picker clearable + v-model="form.${field}" + type="date" + value-format="yyyy-MM-dd" + placeholder="选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "textarea") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" /> + </el-form-item> +#end +#end +#end +#end + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </el-dialog> + </div> +</template> + +<script> +import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; +import Treeselect from "@riophae/vue-treeselect"; +import "@riophae/vue-treeselect/dist/vue-treeselect.css"; + +export default { + name: "${BusinessName}", +#if(${dicts} != '') + dicts: [${dicts}], +#end + components: { + Treeselect + }, + data() { + return { + // 遮罩层 + loading: true, + // 显示搜索条件 + showSearch: true, + // ${functionName}表格数据 + ${businessName}List: [], + // ${functionName}树选项 + ${businessName}Options: [], + // 弹出层标题 + title: "", + // 是否显示弹出层 + open: false, + // 是否展开,默认全部展开 + isExpandAll: true, + // 重新渲染表格状态 + refreshTable: true, +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + // $comment时间范围 + daterange${AttrName}: [], +#end +#end + // 查询参数 + queryParams: { +#foreach ($column in $columns) +#if($column.query) + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }, + // 表单参数 + form: {}, + // 表单校验 + rules: { +#foreach ($column in $columns) +#if($column.required) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end + $column.javaField: [ + { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end } + ]#if($foreach.count != $columns.size()),#end +#end +#end + } + }; + }, + created() { + this.getList(); + }, + methods: { + /** 查询${functionName}列表 */ + getList() { + this.loading = true; +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + this.queryParams.params = {}; +#break +#end +#end +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) { + this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]; + this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]; + } +#end +#end + list${BusinessName}(this.queryParams).then(response => { + this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}"); + this.loading = false; + }); + }, + /** 转换${functionName}数据结构 */ + normalizer(node) { + if (node.children && !node.children.length) { + delete node.children; + } + return { + id: node.${treeCode}, + label: node.${treeName}, + children: node.children + }; + }, + /** 查询${functionName}下拉树结构 */ + getTreeselect() { + list${BusinessName}().then(response => { + this.${businessName}Options = []; + const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }; + data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}"); + this.${businessName}Options.push(data); + }); + }, + // 取消按钮 + cancel() { + this.open = false; + this.reset(); + }, + // 表单重置 + reset() { + this.form = { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + $column.javaField: []#if($foreach.count != $columns.size()),#end +#else + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }; + this.resetForm("form"); + }, + /** 搜索按钮操作 */ + handleQuery() { + this.getList(); + }, + /** 重置按钮操作 */ + resetQuery() { +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + this.daterange${AttrName} = []; +#end +#end + this.resetForm("queryForm"); + this.handleQuery(); + }, + /** 新增按钮操作 */ + handleAdd(row) { + this.reset(); + this.getTreeselect(); + if (row != null && row.${treeCode}) { + this.form.${treeParentCode} = row.${treeCode}; + } else { + this.form.${treeParentCode} = 0; + } + this.open = true; + this.title = "添加${functionName}"; + }, + /** 展开/折叠操作 */ + toggleExpandAll() { + this.refreshTable = false; + this.isExpandAll = !this.isExpandAll; + this.$nextTick(() => { + this.refreshTable = true; + }); + }, + /** 修改按钮操作 */ + handleUpdate(row) { + this.reset(); + this.getTreeselect(); + if (row != null) { + this.form.${treeParentCode} = row.${treeCode}; + } + get${BusinessName}(row.${pkColumn.javaField}).then(response => { + this.form = response.data; +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + this.form.$column.javaField = this.form.${column.javaField}.split(","); +#end +#end + this.open = true; + this.title = "修改${functionName}"; + }); + }, + /** 提交按钮 */ + submitForm() { + this.#[[$]]#refs["form"].validate(valid => { + if (valid) { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + this.form.$column.javaField = this.form.${column.javaField}.join(","); +#end +#end + if (this.form.${pkColumn.javaField} != null) { + update${BusinessName}(this.form).then(response => { + this.#[[$modal]]#.msgSuccess("修改成功"); + this.open = false; + this.getList(); + }); + } else { + add${BusinessName}(this.form).then(response => { + this.#[[$modal]]#.msgSuccess("新增成功"); + this.open = false; + this.getList(); + }); + } + } + }); + }, + /** 删除按钮操作 */ + handleDelete(row) { + this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() { + return del${BusinessName}(row.${pkColumn.javaField}); + }).then(() => { + this.getList(); + this.#[[$modal]]#.msgSuccess("删除成功"); + }).catch(() => {}); + } + } +}; +</script> diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm new file mode 100644 index 0000000..6296014 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm @@ -0,0 +1,602 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> +#foreach($column in $columns) +#if($column.query) +#set($dictType=$column.dictType) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.htmlType == "input") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-input + v-model="queryParams.${column.javaField}" + placeholder="请输入${comment}" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option + v-for="dict in dict.type.${dictType}" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-date-picker clearable + v-model="queryParams.${column.javaField}" + type="date" + value-format="yyyy-MM-dd" + placeholder="请选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + <el-form-item label="${comment}"> + <el-date-picker + v-model="daterange${AttrName}" + style="width: 240px" + value-format="yyyy-MM-dd" + type="daterange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + ></el-date-picker> + </el-form-item> +#end +#end +#end + <el-form-item> + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="el-icon-plus" + size="mini" + @click="handleAdd" + v-hasPermi="['${moduleName}:${businessName}:add']" + >新增</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="success" + plain + icon="el-icon-edit" + size="mini" + :disabled="single" + @click="handleUpdate" + v-hasPermi="['${moduleName}:${businessName}:edit']" + >修改</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="danger" + plain + icon="el-icon-delete" + size="mini" + :disabled="multiple" + @click="handleDelete" + v-hasPermi="['${moduleName}:${businessName}:remove']" + >删除</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="warning" + plain + icon="el-icon-download" + size="mini" + @click="handleExport" + v-hasPermi="['${moduleName}:${businessName}:export']" + >导出</el-button> + </el-col> + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> + </el-row> + + <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange"> + <el-table-column type="selection" width="55" align="center" /> +#foreach($column in $columns) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk) + <el-table-column label="${comment}" align="center" prop="${javaField}" /> +#elseif($column.list && $column.htmlType == "datetime") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="180"> + <template slot-scope="scope"> + <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> + </template> + </el-table-column> +#elseif($column.list && $column.htmlType == "imageUpload") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="100"> + <template slot-scope="scope"> + <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/> + </template> + </el-table-column> +#elseif($column.list && "" != $column.dictType) + <el-table-column label="${comment}" align="center" prop="${javaField}"> + <template slot-scope="scope"> +#if($column.htmlType == "checkbox") + <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/> +#else + <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/> +#end + </template> + </el-table-column> +#elseif($column.list && "" != $javaField) + <el-table-column label="${comment}" align="center" prop="${javaField}" /> +#end +#end + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template slot-scope="scope"> + <el-button + size="mini" + type="text" + icon="el-icon-edit" + @click="handleUpdate(scope.row)" + v-hasPermi="['${moduleName}:${businessName}:edit']" + >修改</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-delete" + @click="handleDelete(scope.row)" + v-hasPermi="['${moduleName}:${businessName}:remove']" + >删除</el-button> + </template> + </el-table-column> + </el-table> + + <pagination + v-show="total>0" + :total="total" + :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" + @pagination="getList" + /> + + <!-- 添加或修改${functionName}对话框 --> + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> + <el-form ref="form" :model="form" :rules="rules" label-width="80px"> +#foreach($column in $columns) +#set($field=$column.javaField) +#if($column.insert && !$column.pk) +#if(($column.usableColumn) || (!$column.superColumn)) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#set($dictType=$column.dictType) +#if($column.htmlType == "input") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" placeholder="请输入${comment}" /> + </el-form-item> +#elseif($column.htmlType == "imageUpload") + <el-form-item label="${comment}" prop="${field}"> + <image-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "fileUpload") + <el-form-item label="${comment}" prop="${field}"> + <file-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "editor") + <el-form-item label="${comment}"> + <editor v-model="form.${field}" :min-height="192"/> + </el-form-item> +#elseif($column.htmlType == "select" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option + v-for="dict in dict.type.${dictType}" + :key="dict.value" + :label="dict.label" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :value="parseInt(dict.value)" +#else + :value="dict.value" +#end + ></el-option> + </el-select> + </el-form-item> +#elseif($column.htmlType == "select" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "checkbox" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox + v-for="dict in dict.type.${dictType}" + :key="dict.value" + :label="dict.value"> + {{dict.label}} + </el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "checkbox" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox>请选择字典生成</el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "radio" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio + v-for="dict in dict.type.${dictType}" + :key="dict.value" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :label="parseInt(dict.value)" +#else + :label="dict.value" +#end + >{{dict.label}}</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "radio" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio label="1">请选择字典生成</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "datetime") + <el-form-item label="${comment}" prop="${field}"> + <el-date-picker clearable + v-model="form.${field}" + type="date" + value-format="yyyy-MM-dd" + placeholder="请选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "textarea") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" /> + </el-form-item> +#end +#end +#end +#end +#if($table.sub) + <el-divider content-position="center">${subTable.functionName}信息</el-divider> + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">添加</el-button> + </el-col> + <el-col :span="1.5"> + <el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">删除</el-button> + </el-col> + </el-row> + <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}"> + <el-table-column type="selection" width="50" align="center" /> + <el-table-column label="序号" align="center" prop="index" width="50"/> +#foreach($column in $subTable.columns) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk || $javaField == ${subTableFkclassName}) +#elseif($column.list && $column.htmlType == "input") + <el-table-column label="$comment" prop="${javaField}" width="150"> + <template slot-scope="scope"> + <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" /> + </template> + </el-table-column> +#elseif($column.list && $column.htmlType == "datetime") + <el-table-column label="$comment" prop="${javaField}" width="240"> + <template slot-scope="scope"> + <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" /> + </template> + </el-table-column> +#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType) + <el-table-column label="$comment" prop="${javaField}" width="150"> + <template slot-scope="scope"> + <el-select v-model="scope.row.$javaField" placeholder="请选择$comment"> + <el-option + v-for="dict in dict.type.$column.dictType" + :key="dict.value" + :label="dict.label" + :value="dict.value" + ></el-option> + </el-select> + </template> + </el-table-column> +#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType) + <el-table-column label="$comment" prop="${javaField}" width="150"> + <template slot-scope="scope"> + <el-select v-model="scope.row.$javaField" placeholder="请选择$comment"> + <el-option label="请选择字典生成" value="" /> + </el-select> + </template> + </el-table-column> +#end +#end + </el-table> +#end + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </el-dialog> + </div> +</template> + +<script> +import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; + +export default { + name: "${BusinessName}", +#if(${dicts} != '') + dicts: [${dicts}], +#end + data() { + return { + // 遮罩层 + loading: true, + // 选中数组 + ids: [], +#if($table.sub) + // 子表选中数据 + checked${subClassName}: [], +#end + // 非单个禁用 + single: true, + // 非多个禁用 + multiple: true, + // 显示搜索条件 + showSearch: true, + // 总条数 + total: 0, + // ${functionName}表格数据 + ${businessName}List: [], +#if($table.sub) + // ${subTable.functionName}表格数据 + ${subclassName}List: [], +#end + // 弹出层标题 + title: "", + // 是否显示弹出层 + open: false, +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + // $comment时间范围 + daterange${AttrName}: [], +#end +#end + // 查询参数 + queryParams: { + pageNum: 1, + pageSize: 10, +#foreach ($column in $columns) +#if($column.query) + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }, + // 表单参数 + form: {}, + // 表单校验 + rules: { +#foreach ($column in $columns) +#if($column.required) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end + $column.javaField: [ + { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end } + ]#if($foreach.count != $columns.size()),#end +#end +#end + } + }; + }, + created() { + this.getList(); + }, + methods: { + /** 查询${functionName}列表 */ + getList() { + this.loading = true; +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + this.queryParams.params = {}; +#break +#end +#end +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) { + this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]; + this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]; + } +#end +#end + list${BusinessName}(this.queryParams).then(response => { + this.${businessName}List = response.rows; + this.total = response.total; + this.loading = false; + }); + }, + // 取消按钮 + cancel() { + this.open = false; + this.reset(); + }, + // 表单重置 + reset() { + this.form = { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + $column.javaField: []#if($foreach.count != $columns.size()),#end +#else + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }; +#if($table.sub) + this.${subclassName}List = []; +#end + this.resetForm("form"); + }, + /** 搜索按钮操作 */ + handleQuery() { + this.queryParams.pageNum = 1; + this.getList(); + }, + /** 重置按钮操作 */ + resetQuery() { +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + this.daterange${AttrName} = []; +#end +#end + this.resetForm("queryForm"); + this.handleQuery(); + }, + // 多选框选中数据 + handleSelectionChange(selection) { + this.ids = selection.map(item => item.${pkColumn.javaField}) + this.single = selection.length!==1 + this.multiple = !selection.length + }, + /** 新增按钮操作 */ + handleAdd() { + this.reset(); + this.open = true; + this.title = "添加${functionName}"; + }, + /** 修改按钮操作 */ + handleUpdate(row) { + this.reset(); + const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids + get${BusinessName}(${pkColumn.javaField}).then(response => { + this.form = response.data; +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + this.form.$column.javaField = this.form.${column.javaField}.split(","); +#end +#end +#if($table.sub) + this.${subclassName}List = response.data.${subclassName}List; +#end + this.open = true; + this.title = "修改${functionName}"; + }); + }, + /** 提交按钮 */ + submitForm() { + this.#[[$]]#refs["form"].validate(valid => { + if (valid) { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + this.form.$column.javaField = this.form.${column.javaField}.join(","); +#end +#end +#if($table.sub) + this.form.${subclassName}List = this.${subclassName}List; +#end + if (this.form.${pkColumn.javaField} != null) { + update${BusinessName}(this.form).then(response => { + this.#[[$modal]]#.msgSuccess("修改成功"); + this.open = false; + this.getList(); + }); + } else { + add${BusinessName}(this.form).then(response => { + this.#[[$modal]]#.msgSuccess("新增成功"); + this.open = false; + this.getList(); + }); + } + } + }); + }, + /** 删除按钮操作 */ + handleDelete(row) { + const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids; + this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() { + return del${BusinessName}(${pkColumn.javaField}s); + }).then(() => { + this.getList(); + this.#[[$modal]]#.msgSuccess("删除成功"); + }).catch(() => {}); + }, +#if($table.sub) + /** ${subTable.functionName}序号 */ + row${subClassName}Index({ row, rowIndex }) { + row.index = rowIndex + 1; + }, + /** ${subTable.functionName}添加按钮操作 */ + handleAdd${subClassName}() { + let obj = {}; +#foreach($column in $subTable.columns) +#if($column.pk || $column.javaField == ${subTableFkclassName}) +#elseif($column.list && "" != $javaField) + obj.$column.javaField = ""; +#end +#end + this.${subclassName}List.push(obj); + }, + /** ${subTable.functionName}删除按钮操作 */ + handleDelete${subClassName}() { + if (this.checked${subClassName}.length == 0) { + this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据"); + } else { + const ${subclassName}List = this.${subclassName}List; + const checked${subClassName} = this.checked${subClassName}; + this.${subclassName}List = ${subclassName}List.filter(function(item) { + return checked${subClassName}.indexOf(item.index) == -1 + }); + } + }, + /** 复选框选中数据 */ + handle${subClassName}SelectionChange(selection) { + this.checked${subClassName} = selection.map(item => item.index) + }, +#end + /** 导出按钮操作 */ + handleExport() { + this.download('${moduleName}/${businessName}/export', { + ...this.queryParams + }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`) + } + } +}; +</script> diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm new file mode 100644 index 0000000..7bbd2fc --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm @@ -0,0 +1,474 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> +#foreach($column in $columns) +#if($column.query) +#set($dictType=$column.dictType) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.htmlType == "input") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-input + v-model="queryParams.${column.javaField}" + placeholder="请输入${comment}" + clearable + @keyup.enter="handleQuery" + /> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option + v-for="dict in ${dictType}" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-date-picker clearable + v-model="queryParams.${column.javaField}" + type="date" + value-format="YYYY-MM-DD" + placeholder="选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + <el-form-item label="${comment}" style="width: 308px"> + <el-date-picker + v-model="daterange${AttrName}" + value-format="YYYY-MM-DD" + type="daterange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + ></el-date-picker> + </el-form-item> +#end +#end +#end + <el-form-item> + <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> + <el-button icon="Refresh" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="Plus" + @click="handleAdd" + v-hasPermi="['${moduleName}:${businessName}:add']" + >新增</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="info" + plain + icon="Sort" + @click="toggleExpandAll" + >展开/折叠</el-button> + </el-col> + <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> + </el-row> + + <el-table + v-if="refreshTable" + v-loading="loading" + :data="${businessName}List" + row-key="${treeCode}" + :default-expand-all="isExpandAll" + :tree-props="{children: 'children', hasChildren: 'hasChildren'}" + > +#foreach($column in $columns) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk) +#elseif($column.list && $column.htmlType == "datetime") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="180"> + <template #default="scope"> + <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> + </template> + </el-table-column> +#elseif($column.list && $column.htmlType == "imageUpload") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="100"> + <template #default="scope"> + <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/> + </template> + </el-table-column> +#elseif($column.list && "" != $column.dictType) + <el-table-column label="${comment}" align="center" prop="${javaField}"> + <template #default="scope"> +#if($column.htmlType == "checkbox") + <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/> +#else + <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/> +#end + </template> + </el-table-column> +#elseif($column.list && "" != $javaField) +#if(${foreach.index} == 1) + <el-table-column label="${comment}" prop="${javaField}" /> +#else + <el-table-column label="${comment}" align="center" prop="${javaField}" /> +#end +#end +#end + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template #default="scope"> + <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button> + <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button> + <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button> + </template> + </el-table-column> + </el-table> + + <!-- 添加或修改${functionName}对话框 --> + <el-dialog :title="title" v-model="open" width="500px" append-to-body> + <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px"> +#foreach($column in $columns) +#set($field=$column.javaField) +#if($column.insert && !$column.pk) +#if(($column.usableColumn) || (!$column.superColumn)) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#set($dictType=$column.dictType) +#if("" != $treeParentCode && $column.javaField == $treeParentCode) + <el-form-item label="${comment}" prop="${treeParentCode}"> + <el-tree-select + v-model="form.${treeParentCode}" + :data="${businessName}Options" + :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }" + value-key="${treeCode}" + placeholder="请选择${comment}" + check-strictly + /> + </el-form-item> +#elseif($column.htmlType == "input") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" placeholder="请输入${comment}" /> + </el-form-item> +#elseif($column.htmlType == "imageUpload") + <el-form-item label="${comment}" prop="${field}"> + <image-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "fileUpload") + <el-form-item label="${comment}" prop="${field}"> + <file-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "editor") + <el-form-item label="${comment}"> + <editor v-model="form.${field}" :min-height="192"/> + </el-form-item> +#elseif($column.htmlType == "select" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option + v-for="dict in ${dictType}" + :key="dict.value" + :label="dict.label" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :value="parseInt(dict.value)" +#else + :value="dict.value" +#end + ></el-option> + </el-select> + </el-form-item> +#elseif($column.htmlType == "select" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "checkbox" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox + v-for="dict in ${dictType}" + :key="dict.value" + :label="dict.value"> + {{dict.label}} + </el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "checkbox" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox>请选择字典生成</el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "radio" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio + v-for="dict in ${dictType}" + :key="dict.value" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :label="parseInt(dict.value)" +#else + :label="dict.value" +#end + >{{dict.label}}</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "radio" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio label="1">请选择字典生成</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "datetime") + <el-form-item label="${comment}" prop="${field}"> + <el-date-picker clearable + v-model="form.${field}" + type="date" + value-format="YYYY-MM-DD" + placeholder="选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "textarea") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" /> + </el-form-item> +#end +#end +#end +#end + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup name="${BusinessName}"> +import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; + +const { proxy } = getCurrentInstance(); +#if(${dicts} != '') +#set($dictsNoSymbol=$dicts.replace("'", "")) +const { ${dictsNoSymbol} } = proxy.useDict(${dicts}); +#end + +const ${businessName}List = ref([]); +const ${businessName}Options = ref([]); +const open = ref(false); +const loading = ref(true); +const showSearch = ref(true); +const title = ref(""); +const isExpandAll = ref(true); +const refreshTable = ref(true); +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +const daterange${AttrName} = ref([]); +#end +#end + +const data = reactive({ + form: {}, + queryParams: { + #foreach ($column in $columns) +#if($column.query) + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }, + rules: { + #foreach ($column in $columns) +#if($column.required) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end + $column.javaField: [ + { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end } + ]#if($foreach.count != $columns.size()),#end +#end +#end + } +}); + +const { queryParams, form, rules } = toRefs(data); + +/** 查询${functionName}列表 */ +function getList() { + loading.value = true; +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + queryParams.value.params = {}; +#break +#end +#end +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + if (null != daterange${AttrName} && '' != daterange${AttrName}) { + queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]; + queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]; + } +#end +#end + list${BusinessName}(queryParams.value).then(response => { + ${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}"); + loading.value = false; + }); +} + +/** 查询${functionName}下拉树结构 */ +function getTreeselect() { + list${BusinessName}().then(response => { + ${businessName}Options.value = []; + const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }; + data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}"); + ${businessName}Options.value.push(data); + }); +} + +// 取消按钮 +function cancel() { + open.value = false; + reset(); +} + +// 表单重置 +function reset() { + form.value = { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + $column.javaField: []#if($foreach.count != $columns.size()),#end +#else + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }; + proxy.resetForm("${businessName}Ref"); +} + +/** 搜索按钮操作 */ +function handleQuery() { + getList(); +} + +/** 重置按钮操作 */ +function resetQuery() { +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + daterange${AttrName}.value = []; +#end +#end + proxy.resetForm("queryRef"); + handleQuery(); +} + +/** 新增按钮操作 */ +function handleAdd(row) { + reset(); + getTreeselect(); + if (row != null && row.${treeCode}) { + form.value.${treeParentCode} = row.${treeCode}; + } else { + form.value.${treeParentCode} = 0; + } + open.value = true; + title.value = "添加${functionName}"; +} + +/** 展开/折叠操作 */ +function toggleExpandAll() { + refreshTable.value = false; + isExpandAll.value = !isExpandAll.value; + nextTick(() => { + refreshTable.value = true; + }); +} + +/** 修改按钮操作 */ +async function handleUpdate(row) { + reset(); + await getTreeselect(); + if (row != null) { + form.value.${treeParentCode} = row.${treeCode}; + } + get${BusinessName}(row.${pkColumn.javaField}).then(response => { + form.value = response.data; +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + form.value.$column.javaField = form.value.${column.javaField}.split(","); +#end +#end + open.value = true; + title.value = "修改${functionName}"; + }); +} + +/** 提交按钮 */ +function submitForm() { + proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => { + if (valid) { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + form.value.$column.javaField = form.value.${column.javaField}.join(","); +#end +#end + if (form.value.${pkColumn.javaField} != null) { + update${BusinessName}(form.value).then(response => { + proxy.#[[$modal]]#.msgSuccess("修改成功"); + open.value = false; + getList(); + }); + } else { + add${BusinessName}(form.value).then(response => { + proxy.#[[$modal]]#.msgSuccess("新增成功"); + open.value = false; + getList(); + }); + } + } + }); +} + +/** 删除按钮操作 */ +function handleDelete(row) { + proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() { + return del${BusinessName}(row.${pkColumn.javaField}); + }).then(() => { + getList(); + proxy.#[[$modal]]#.msgSuccess("删除成功"); + }).catch(() => {}); +} + +getList(); +</script> diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm new file mode 100644 index 0000000..8b25665 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm @@ -0,0 +1,590 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> +#foreach($column in $columns) +#if($column.query) +#set($dictType=$column.dictType) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.htmlType == "input") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-input + v-model="queryParams.${column.javaField}" + placeholder="请输入${comment}" + clearable + @keyup.enter="handleQuery" + /> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option + v-for="dict in ${dictType}" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> +#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") + <el-form-item label="${comment}" prop="${column.javaField}"> + <el-date-picker clearable + v-model="queryParams.${column.javaField}" + type="date" + value-format="YYYY-MM-DD" + placeholder="请选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + <el-form-item label="${comment}" style="width: 308px"> + <el-date-picker + v-model="daterange${AttrName}" + value-format="YYYY-MM-DD" + type="daterange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + ></el-date-picker> + </el-form-item> +#end +#end +#end + <el-form-item> + <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> + <el-button icon="Refresh" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="Plus" + @click="handleAdd" + v-hasPermi="['${moduleName}:${businessName}:add']" + >新增</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="success" + plain + icon="Edit" + :disabled="single" + @click="handleUpdate" + v-hasPermi="['${moduleName}:${businessName}:edit']" + >修改</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="danger" + plain + icon="Delete" + :disabled="multiple" + @click="handleDelete" + v-hasPermi="['${moduleName}:${businessName}:remove']" + >删除</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="warning" + plain + icon="Download" + @click="handleExport" + v-hasPermi="['${moduleName}:${businessName}:export']" + >导出</el-button> + </el-col> + <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> + </el-row> + + <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange"> + <el-table-column type="selection" width="55" align="center" /> +#foreach($column in $columns) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk) + <el-table-column label="${comment}" align="center" prop="${javaField}" /> +#elseif($column.list && $column.htmlType == "datetime") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="180"> + <template #default="scope"> + <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> + </template> + </el-table-column> +#elseif($column.list && $column.htmlType == "imageUpload") + <el-table-column label="${comment}" align="center" prop="${javaField}" width="100"> + <template #default="scope"> + <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/> + </template> + </el-table-column> +#elseif($column.list && "" != $column.dictType) + <el-table-column label="${comment}" align="center" prop="${javaField}"> + <template #default="scope"> +#if($column.htmlType == "checkbox") + <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/> +#else + <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/> +#end + </template> + </el-table-column> +#elseif($column.list && "" != $javaField) + <el-table-column label="${comment}" align="center" prop="${javaField}" /> +#end +#end + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template #default="scope"> + <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button> + <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button> + </template> + </el-table-column> + </el-table> + + <pagination + v-show="total>0" + :total="total" + v-model:page="queryParams.pageNum" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + + <!-- 添加或修改${functionName}对话框 --> + <el-dialog :title="title" v-model="open" width="500px" append-to-body> + <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px"> +#foreach($column in $columns) +#set($field=$column.javaField) +#if($column.insert && !$column.pk) +#if(($column.usableColumn) || (!$column.superColumn)) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#set($dictType=$column.dictType) +#if($column.htmlType == "input") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" placeholder="请输入${comment}" /> + </el-form-item> +#elseif($column.htmlType == "imageUpload") + <el-form-item label="${comment}" prop="${field}"> + <image-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "fileUpload") + <el-form-item label="${comment}" prop="${field}"> + <file-upload v-model="form.${field}"/> + </el-form-item> +#elseif($column.htmlType == "editor") + <el-form-item label="${comment}"> + <editor v-model="form.${field}" :min-height="192"/> + </el-form-item> +#elseif($column.htmlType == "select" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option + v-for="dict in ${dictType}" + :key="dict.value" + :label="dict.label" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :value="parseInt(dict.value)" +#else + :value="dict.value" +#end + ></el-option> + </el-select> + </el-form-item> +#elseif($column.htmlType == "select" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-select v-model="form.${field}" placeholder="请选择${comment}"> + <el-option label="请选择字典生成" value="" /> + </el-select> + </el-form-item> +#elseif($column.htmlType == "checkbox" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox + v-for="dict in ${dictType}" + :key="dict.value" + :label="dict.value"> + {{dict.label}} + </el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "checkbox" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-checkbox-group v-model="form.${field}"> + <el-checkbox>请选择字典生成</el-checkbox> + </el-checkbox-group> + </el-form-item> +#elseif($column.htmlType == "radio" && "" != $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio + v-for="dict in ${dictType}" + :key="dict.value" +#if($column.javaType == "Integer" || $column.javaType == "Long") + :label="parseInt(dict.value)" +#else + :label="dict.value" +#end + >{{dict.label}}</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "radio" && $dictType) + <el-form-item label="${comment}" prop="${field}"> + <el-radio-group v-model="form.${field}"> + <el-radio label="1">请选择字典生成</el-radio> + </el-radio-group> + </el-form-item> +#elseif($column.htmlType == "datetime") + <el-form-item label="${comment}" prop="${field}"> + <el-date-picker clearable + v-model="form.${field}" + type="date" + value-format="YYYY-MM-DD" + placeholder="请选择${comment}"> + </el-date-picker> + </el-form-item> +#elseif($column.htmlType == "textarea") + <el-form-item label="${comment}" prop="${field}"> + <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" /> + </el-form-item> +#end +#end +#end +#end +#if($table.sub) + <el-divider content-position="center">${subTable.functionName}信息</el-divider> + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button type="primary" icon="Plus" @click="handleAdd${subClassName}">添加</el-button> + </el-col> + <el-col :span="1.5"> + <el-button type="danger" icon="Delete" @click="handleDelete${subClassName}">删除</el-button> + </el-col> + </el-row> + <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}"> + <el-table-column type="selection" width="50" align="center" /> + <el-table-column label="序号" align="center" prop="index" width="50"/> +#foreach($column in $subTable.columns) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk || $javaField == ${subTableFkclassName}) +#elseif($column.list && $column.htmlType == "input") + <el-table-column label="$comment" prop="${javaField}" width="150"> + <template #default="scope"> + <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" /> + </template> + </el-table-column> +#elseif($column.list && $column.htmlType == "datetime") + <el-table-column label="$comment" prop="${javaField}" width="240"> + <template #default="scope"> + <el-date-picker clearable + v-model="scope.row.$javaField" + type="date" + value-format="YYYY-MM-DD" + placeholder="请选择$comment"> + </el-date-picker> + </template> + </el-table-column> +#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType) + <el-table-column label="$comment" prop="${javaField}" width="150"> + <template #default="scope"> + <el-select v-model="scope.row.$javaField" placeholder="请选择$comment"> + <el-option + v-for="dict in $column.dictType" + :key="dict.value" + :label="dict.label" + :value="dict.value" + ></el-option> + </el-select> + </template> + </el-table-column> +#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType) + <el-table-column label="$comment" prop="${javaField}" width="150"> + <template #default="scope"> + <el-select v-model="scope.row.$javaField" placeholder="请选择$comment"> + <el-option label="请选择字典生成" value="" /> + </el-select> + </template> + </el-table-column> +#end +#end + </el-table> +#end + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup name="${BusinessName}"> +import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; + +const { proxy } = getCurrentInstance(); +#if(${dicts} != '') +#set($dictsNoSymbol=$dicts.replace("'", "")) +const { ${dictsNoSymbol} } = proxy.useDict(${dicts}); +#end + +const ${businessName}List = ref([]); +#if($table.sub) +const ${subclassName}List = ref([]); +#end +const open = ref(false); +const loading = ref(true); +const showSearch = ref(true); +const ids = ref([]); +#if($table.sub) +const checked${subClassName} = ref([]); +#end +const single = ref(true); +const multiple = ref(true); +const total = ref(0); +const title = ref(""); +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +const daterange${AttrName} = ref([]); +#end +#end + +const data = reactive({ + form: {}, + queryParams: { + pageNum: 1, + pageSize: 10, + #foreach ($column in $columns) +#if($column.query) + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }, + rules: { + #foreach ($column in $columns) +#if($column.required) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end + $column.javaField: [ + { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end } + ]#if($foreach.count != $columns.size()),#end +#end +#end + } +}); + +const { queryParams, form, rules } = toRefs(data); + +/** 查询${functionName}列表 */ +function getList() { + loading.value = true; +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + queryParams.value.params = {}; +#break +#end +#end +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + if (null != daterange${AttrName} && '' != daterange${AttrName}) { + queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]; + queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]; + } +#end +#end + list${BusinessName}(queryParams.value).then(response => { + ${businessName}List.value = response.rows; + total.value = response.total; + loading.value = false; + }); +} + +// 取消按钮 +function cancel() { + open.value = false; + reset(); +} + +// 表单重置 +function reset() { + form.value = { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + $column.javaField: []#if($foreach.count != $columns.size()),#end +#else + $column.javaField: null#if($foreach.count != $columns.size()),#end +#end +#end + }; +#if($table.sub) + ${subclassName}List.value = []; +#end + proxy.resetForm("${businessName}Ref"); +} + +/** 搜索按钮操作 */ +function handleQuery() { + queryParams.value.pageNum = 1; + getList(); +} + +/** 重置按钮操作 */ +function resetQuery() { +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + daterange${AttrName}.value = []; +#end +#end + proxy.resetForm("queryRef"); + handleQuery(); +} + +// 多选框选中数据 +function handleSelectionChange(selection) { + ids.value = selection.map(item => item.${pkColumn.javaField}); + single.value = selection.length != 1; + multiple.value = !selection.length; +} + +/** 新增按钮操作 */ +function handleAdd() { + reset(); + open.value = true; + title.value = "添加${functionName}"; +} + +/** 修改按钮操作 */ +function handleUpdate(row) { + reset(); + const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value + get${BusinessName}(_${pkColumn.javaField}).then(response => { + form.value = response.data; +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + form.value.$column.javaField = form.value.${column.javaField}.split(","); +#end +#end +#if($table.sub) + ${subclassName}List.value = response.data.${subclassName}List; +#end + open.value = true; + title.value = "修改${functionName}"; + }); +} + +/** 提交按钮 */ +function submitForm() { + proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => { + if (valid) { +#foreach ($column in $columns) +#if($column.htmlType == "checkbox") + form.value.$column.javaField = form.value.${column.javaField}.join(","); +#end +#end +#if($table.sub) + form.value.${subclassName}List = ${subclassName}List.value; +#end + if (form.value.${pkColumn.javaField} != null) { + update${BusinessName}(form.value).then(response => { + proxy.#[[$modal]]#.msgSuccess("修改成功"); + open.value = false; + getList(); + }); + } else { + add${BusinessName}(form.value).then(response => { + proxy.#[[$modal]]#.msgSuccess("新增成功"); + open.value = false; + getList(); + }); + } + } + }); +} + +/** 删除按钮操作 */ +function handleDelete(row) { + const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value; + proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').then(function() { + return del${BusinessName}(_${pkColumn.javaField}s); + }).then(() => { + getList(); + proxy.#[[$modal]]#.msgSuccess("删除成功"); + }).catch(() => {}); +} + +#if($table.sub) +/** ${subTable.functionName}序号 */ +function row${subClassName}Index({ row, rowIndex }) { + row.index = rowIndex + 1; +} + +/** ${subTable.functionName}添加按钮操作 */ +function handleAdd${subClassName}() { + let obj = {}; +#foreach($column in $subTable.columns) +#if($column.pk || $column.javaField == ${subTableFkclassName}) +#elseif($column.list && "" != $javaField) + obj.$column.javaField = ""; +#end +#end + ${subclassName}List.value.push(obj); +} + +/** ${subTable.functionName}删除按钮操作 */ +function handleDelete${subClassName}() { + if (checked${subClassName}.value.length == 0) { + proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据"); + } else { + const ${subclassName}s = ${subclassName}List.value; + const checked${subClassName}s = checked${subClassName}.value; + ${subclassName}List.value = ${subclassName}s.filter(function(item) { + return checked${subClassName}s.indexOf(item.index) == -1 + }); + } +} + +/** 复选框选中数据 */ +function handle${subClassName}SelectionChange(selection) { + checked${subClassName}.value = selection.map(item => item.index) +} + +#end +/** 导出按钮操作 */ +function handleExport() { + proxy.download('${moduleName}/${businessName}/export', { + ...queryParams.value + }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`) +} + +getList(); +</script> diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt new file mode 100644 index 0000000..10362d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt @@ -0,0 +1 @@ +���ʹ�õ���RuoYi-Cloud-Vue3ǰ�ˣ���ô��Ҫ����һ�´�Ŀ¼��ģ��index.vue.vm��index-tree.vue.vm�ļ����ϼ�vueĿ¼�� \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 0000000..0ceb3d8 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="${packageName}.mapper.${ClassName}Mapper"> + + <resultMap type="${ClassName}" id="${ClassName}Result"> +#foreach ($column in $columns) + <result property="${column.javaField}" column="${column.columnName}" /> +#end + </resultMap> +#if($table.sub) + + <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result"> + <collection property="${subclassName}List" notNullColumn="sub_${subTable.pkColumn.columnName}" javaType="java.util.List" resultMap="${subClassName}Result" /> + </resultMap> + + <resultMap type="${subClassName}" id="${subClassName}Result"> +#foreach ($column in $subTable.columns) + <result property="${column.javaField}" column="sub_${column.columnName}" /> +#end + </resultMap> +#end + + <sql id="select${ClassName}Vo"> + select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName} + </sql> + + <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result"> + <include refid="select${ClassName}Vo"/> + <where> +#foreach($column in $columns) +#set($queryType=$column.queryType) +#set($javaField=$column.javaField) +#set($javaType=$column.javaType) +#set($columnName=$column.columnName) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#if($column.query) +#if($column.queryType == "EQ") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if> +#elseif($queryType == "NE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if> +#elseif($queryType == "GT") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName > #{$javaField}</if> +#elseif($queryType == "GTE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName >= #{$javaField}</if> +#elseif($queryType == "LT") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName < #{$javaField}</if> +#elseif($queryType == "LTE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName <= #{$javaField}</if> +#elseif($queryType == "LIKE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if> +#elseif($queryType == "BETWEEN") + <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if> +#end +#end +#end + </where> + </select> + + <select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end"> +#if($table.crud || $table.tree) + <include refid="select${ClassName}Vo"/> + where ${pkColumn.columnName} = #{${pkColumn.javaField}} +#elseif($table.sub) + select#foreach($column in $columns) a.$column.columnName#if($foreach.count != $columns.size()),#end#end, + #foreach($column in $subTable.columns) b.$column.columnName as sub_$column.columnName#if($foreach.count != $subTable.columns.size()),#end#end + + from ${tableName} a + left join ${subTableName} b on b.${subTableFkName} = a.${pkColumn.columnName} + where a.${pkColumn.columnName} = #{${pkColumn.javaField}} +#end + </select> + + <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end> + insert into ${tableName} + <trim prefix="(" suffix=")" suffixOverrides=","> +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment) + <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName,</if> +#end +#end + </trim> + <trim prefix="values (" suffix=")" suffixOverrides=","> +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment) + <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">#{$column.javaField},</if> +#end +#end + </trim> + </insert> + + <update id="update${ClassName}" parameterType="${ClassName}"> + update ${tableName} + <trim prefix="SET" suffixOverrides=","> +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName) + <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if> +#end +#end + </trim> + where ${pkColumn.columnName} = #{${pkColumn.javaField}} + </update> + + <delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}"> + delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}} + </delete> + + <delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String"> + delete from ${tableName} where ${pkColumn.columnName} in + <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")"> + #{${pkColumn.javaField}} + </foreach> + </delete> +#if($table.sub) + + <delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String"> + delete from ${subTableName} where ${subTableFkName} in + <foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")"> + #{${subTableFkclassName}} + </foreach> + </delete> + + <delete id="delete${subClassName}By${subTableFkClassName}" parameterType="${pkColumn.javaType}"> + delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}} + </delete> + + <insert id="batch${subClassName}"> + insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values + <foreach item="item" index="index" collection="list" separator=","> + (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end) + </foreach> + </insert> +#end +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/pom.xml b/ruoyi-modules/ruoyi-job/pom.xml new file mode 100644 index 0000000..14334bf --- /dev/null +++ b/ruoyi-modules/ruoyi-job/pom.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-modules</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-modules-job</artifactId> + + <description> + ruoyi-modules-job定时任务 + </description> + + <dependencies> + + <!-- SpringCloud Alibaba Nacos --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos Config --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> + </dependency> + + <!-- SpringBoot Actuator --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + + <!-- Swagger UI --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${swagger.fox.version}</version> + </dependency> + + <!-- Quartz --> + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz</artifactId> + <exclusions> + <exclusion> + <groupId>com.mchange</groupId> + <artifactId>c3p0</artifactId> + </exclusion> + </exclusions> + </dependency> + + <!-- Mysql Connector --> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + <!-- RuoYi Common Log --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-log</artifactId> + </dependency> + + <!-- RuoYi Common Swagger --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-swagger</artifactId> + </dependency> + + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java new file mode 100644 index 0000000..fcd1963 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java @@ -0,0 +1,34 @@ +package com.ruoyi.job; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import com.ruoyi.common.security.annotation.EnableCustomConfig; +import com.ruoyi.common.security.annotation.EnableRyFeignClients; +import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; + +/** + * 定时任务 + * + * @author ruoyi + */ +@EnableCustomConfig +@EnableCustomSwagger2 +@EnableRyFeignClients +@SpringBootApplication +public class RuoYiJobApplication +{ + public static void main(String[] args) + { + SpringApplication.run(RuoYiJobApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 定时任务模块启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java new file mode 100644 index 0000000..1c02b0c --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java @@ -0,0 +1,57 @@ +//package com.ruoyi.job.config; +// +//import java.util.Properties; +//import javax.sql.DataSource; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.scheduling.quartz.SchedulerFactoryBean; +// +///** +// * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效) +// * +// * @author ruoyi +// */ +//@Configuration +//public class ScheduleConfig +//{ +// @Bean +// public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) +// { +// SchedulerFactoryBean factory = new SchedulerFactoryBean(); +// factory.setDataSource(dataSource); +// +// // quartz参数 +// Properties prop = new Properties(); +// prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler"); +// prop.put("org.quartz.scheduler.instanceId", "AUTO"); +// // 线程池配置 +// prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); +// prop.put("org.quartz.threadPool.threadCount", "20"); +// prop.put("org.quartz.threadPool.threadPriority", "5"); +// // JobStore配置 +// prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); +// // 集群配置 +// prop.put("org.quartz.jobStore.isClustered", "true"); +// prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); +// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); +// prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); +// +// // sqlserver 启用 +// // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); +// prop.put("org.quartz.jobStore.misfireThreshold", "12000"); +// prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); +// factory.setQuartzProperties(prop); +// +// factory.setSchedulerName("RuoyiScheduler"); +// // 延时启动 +// factory.setStartupDelay(1); +// factory.setApplicationContextSchedulerContextKey("applicationContextKey"); +// // 可选,QuartzScheduler +// // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 +// factory.setOverwriteExistingJobs(true); +// // 设置自动启动,默认为true +// factory.setAutoStartup(true); +// +// return factory; +// } +//} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java new file mode 100644 index 0000000..7625e88 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java @@ -0,0 +1,186 @@ +package com.ruoyi.job.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.exception.job.TaskException; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.job.domain.SysJob; +import com.ruoyi.job.service.ISysJobService; +import com.ruoyi.job.util.CronUtils; +import com.ruoyi.job.util.ScheduleUtils; + +/** + * 调度任务信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/job") +public class SysJobController extends BaseController +{ + @Autowired + private ISysJobService jobService; + + /** + * 查询定时任务列表 + */ + @RequiresPermissions("monitor:job:list") + @GetMapping("/list") + public TableDataInfo list(SysJob sysJob) + { + startPage(); + List<SysJob> list = jobService.selectJobList(sysJob); + return getDataTable(list); + } + + /** + * 导出定时任务列表 + */ + @RequiresPermissions("monitor:job:export") + @Log(title = "定时任务", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysJob sysJob) + { + List<SysJob> list = jobService.selectJobList(sysJob); + ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class); + util.exportExcel(response, list, "定时任务"); + } + + /** + * 获取定时任务详细信息 + */ + @RequiresPermissions("monitor:job:query") + @GetMapping(value = "/{jobId}") + public AjaxResult getInfo(@PathVariable("jobId") Long jobId) + { + return success(jobService.selectJobById(jobId)); + } + + /** + * 新增定时任务 + */ + @RequiresPermissions("monitor:job:add") + @Log(title = "定时任务", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException + { + if (!CronUtils.isValid(job.getCronExpression())) + { + return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确"); + } + else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS })) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规"); + } + else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) + { + return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); + } + job.setCreateBy(SecurityUtils.getUsername()); + return toAjax(jobService.insertJob(job)); + } + + /** + * 修改定时任务 + */ + @RequiresPermissions("monitor:job:edit") + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException + { + if (!CronUtils.isValid(job.getCronExpression())) + { + return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确"); + } + else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS })) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规"); + } + else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) + { + return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); + } + job.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(jobService.updateJob(job)); + } + + /** + * 定时任务状态修改 + */ + @RequiresPermissions("monitor:job:changeStatus") + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException + { + SysJob newJob = jobService.selectJobById(job.getJobId()); + newJob.setStatus(job.getStatus()); + return toAjax(jobService.changeStatus(newJob)); + } + + /** + * 定时任务立即执行一次 + */ + @RequiresPermissions("monitor:job:changeStatus") + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @PutMapping("/run") + public AjaxResult run(@RequestBody SysJob job) throws SchedulerException + { + boolean result = jobService.run(job); + return result ? success() : error("任务不存在或已过期!"); + } + + /** + * 删除定时任务 + */ + @RequiresPermissions("monitor:job:remove") + @Log(title = "定时任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{jobIds}") + public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException + { + jobService.deleteJobByIds(jobIds); + return success(); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java new file mode 100644 index 0000000..caf7451 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java @@ -0,0 +1,91 @@ +package com.ruoyi.job.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +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.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.job.domain.SysJobLog; +import com.ruoyi.job.service.ISysJobLogService; + +/** + * 调度日志操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/job/log") +public class SysJobLogController extends BaseController +{ + @Autowired + private ISysJobLogService jobLogService; + + /** + * 查询定时任务调度日志列表 + */ + @RequiresPermissions("monitor:job:list") + @GetMapping("/list") + public TableDataInfo list(SysJobLog sysJobLog) + { + startPage(); + List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog); + return getDataTable(list); + } + + /** + * 导出定时任务调度日志列表 + */ + @RequiresPermissions("monitor:job:export") + @Log(title = "任务调度日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysJobLog sysJobLog) + { + List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog); + ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class); + util.exportExcel(response, list, "调度日志"); + } + + /** + * 根据调度编号获取详细信息 + */ + @RequiresPermissions("monitor:job:query") + @GetMapping(value = "/{jobLogId}") + public AjaxResult getInfo(@PathVariable Long jobLogId) + { + return success(jobLogService.selectJobLogById(jobLogId)); + } + + /** + * 删除定时任务调度日志 + */ + @RequiresPermissions("monitor:job:remove") + @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{jobLogIds}") + public AjaxResult remove(@PathVariable Long[] jobLogIds) + { + return toAjax(jobLogService.deleteJobLogByIds(jobLogIds)); + } + + /** + * 清空定时任务调度日志 + */ + @RequiresPermissions("monitor:job:remove") + @Log(title = "调度日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public AjaxResult clean() + { + jobLogService.cleanJobLog(); + return success(); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java new file mode 100644 index 0000000..dd630ba --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java @@ -0,0 +1,171 @@ +package com.ruoyi.job.domain; + +import java.util.Date; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +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.utils.StringUtils; +import com.ruoyi.common.core.web.domain.BaseEntity; +import com.ruoyi.job.util.CronUtils; + +/** + * 定时任务调度表 sys_job + * + * @author ruoyi + */ +public class SysJob extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 任务ID */ + @Excel(name = "任务序号", cellType = ColumnType.NUMERIC) + private Long jobId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String jobName; + + /** 任务组名 */ + @Excel(name = "任务组名") + private String jobGroup; + + /** 调用目标字符串 */ + @Excel(name = "调用目标字符串") + private String invokeTarget; + + /** cron执行表达式 */ + @Excel(name = "执行表达式 ") + private String cronExpression; + + /** cron计划策略 */ + @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行") + private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT; + + /** 是否并发执行(0允许 1禁止) */ + @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止") + private String concurrent; + + /** 任务状态(0正常 1暂停) */ + @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停") + private String status; + + public Long getJobId() + { + return jobId; + } + + public void setJobId(Long jobId) + { + this.jobId = jobId; + } + + @NotBlank(message = "任务名称不能为空") + @Size(min = 0, max = 64, message = "任务名称不能超过64个字符") + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + @NotBlank(message = "调用目标字符串不能为空") + @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符") + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + @NotBlank(message = "Cron执行表达式不能为空") + @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符") + public String getCronExpression() + { + return cronExpression; + } + + public void setCronExpression(String cronExpression) + { + this.cronExpression = cronExpression; + } + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + public Date getNextValidTime() + { + if (StringUtils.isNotEmpty(cronExpression)) + { + return CronUtils.getNextExecution(cronExpression); + } + return null; + } + + public String getMisfirePolicy() + { + return misfirePolicy; + } + + public void setMisfirePolicy(String misfirePolicy) + { + this.misfirePolicy = misfirePolicy; + } + + public String getConcurrent() + { + return concurrent; + } + + public void setConcurrent(String concurrent) + { + this.concurrent = concurrent; + } + + 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("jobId", getJobId()) + .append("jobName", getJobName()) + .append("jobGroup", getJobGroup()) + .append("cronExpression", getCronExpression()) + .append("nextValidTime", getNextValidTime()) + .append("misfirePolicy", getMisfirePolicy()) + .append("concurrent", getConcurrent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java new file mode 100644 index 0000000..6c2c7ed --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java @@ -0,0 +1,155 @@ +package com.ruoyi.job.domain; + +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.web.domain.BaseEntity; + +/** + * 定时任务调度日志表 sys_job_log + * + * @author ruoyi + */ +public class SysJobLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + @Excel(name = "日志序号") + private Long jobLogId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String jobName; + + /** 任务组名 */ + @Excel(name = "任务组名") + private String jobGroup; + + /** 调用目标字符串 */ + @Excel(name = "调用目标字符串") + private String invokeTarget; + + /** 日志信息 */ + @Excel(name = "日志信息") + private String jobMessage; + + /** 执行状态(0正常 1失败) */ + @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败") + private String status; + + /** 异常信息 */ + @Excel(name = "异常信息") + private String exceptionInfo; + + /** 开始时间 */ + private Date startTime; + + /** 停止时间 */ + private Date stopTime; + + public Long getJobLogId() + { + return jobLogId; + } + + public void setJobLogId(Long jobLogId) + { + this.jobLogId = jobLogId; + } + + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + public String getJobMessage() + { + return jobMessage; + } + + public void setJobMessage(String jobMessage) + { + this.jobMessage = jobMessage; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getExceptionInfo() + { + return exceptionInfo; + } + + public void setExceptionInfo(String exceptionInfo) + { + this.exceptionInfo = exceptionInfo; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getStopTime() + { + return stopTime; + } + + public void setStopTime(Date stopTime) + { + this.stopTime = stopTime; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("jobLogId", getJobLogId()) + .append("jobName", getJobName()) + .append("jobGroup", getJobGroup()) + .append("jobMessage", getJobMessage()) + .append("status", getStatus()) + .append("exceptionInfo", getExceptionInfo()) + .append("startTime", getStartTime()) + .append("stopTime", getStopTime()) + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java new file mode 100644 index 0000000..80f0716 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java @@ -0,0 +1,64 @@ +package com.ruoyi.job.mapper; + +import java.util.List; +import com.ruoyi.job.domain.SysJobLog; + +/** + * 调度任务日志信息 数据层 + * + * @author ruoyi + */ +public interface SysJobLogMapper +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public List<SysJobLog> selectJobLogList(SysJobLog jobLog); + + /** + * 查询所有调度任务日志 + * + * @return 调度任务日志列表 + */ + public List<SysJobLog> selectJobLogAll(); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + * @return 结果 + */ + public int insertJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + public int deleteJobLogByIds(Long[] logIds); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java new file mode 100644 index 0000000..d7e499e --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java @@ -0,0 +1,67 @@ +package com.ruoyi.job.mapper; + +import java.util.List; +import com.ruoyi.job.domain.SysJob; + +/** + * 调度任务信息 数据层 + * + * @author ruoyi + */ +public interface SysJobMapper +{ + /** + * 查询调度任务日志集合 + * + * @param job 调度信息 + * @return 操作日志集合 + */ + public List<SysJob> selectJobList(SysJob job); + + /** + * 查询所有调度任务 + * + * @return 调度任务列表 + */ + public List<SysJob> selectJobAll(); + + /** + * 通过调度ID查询调度任务信息 + * + * @param jobId 调度ID + * @return 角色对象信息 + */ + public SysJob selectJobById(Long jobId); + + /** + * 通过调度ID删除调度任务信息 + * + * @param jobId 调度ID + * @return 结果 + */ + public int deleteJobById(Long jobId); + + /** + * 批量删除调度任务信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteJobByIds(Long[] ids); + + /** + * 修改调度任务信息 + * + * @param job 调度任务信息 + * @return 结果 + */ + public int updateJob(SysJob job); + + /** + * 新增调度任务信息 + * + * @param job 调度任务信息 + * @return 结果 + */ + public int insertJob(SysJob job); +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java new file mode 100644 index 0000000..75b3dc5 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java @@ -0,0 +1,56 @@ +package com.ruoyi.job.service; + +import java.util.List; +import com.ruoyi.job.domain.SysJobLog; + +/** + * 定时任务调度日志信息信息 服务层 + * + * @author ruoyi + */ +public interface ISysJobLogService +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public List<SysJobLog> selectJobLogList(SysJobLog jobLog); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + public void addJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的日志ID + * @return 结果 + */ + public int deleteJobLogByIds(Long[] logIds); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java new file mode 100644 index 0000000..5270b34 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java @@ -0,0 +1,102 @@ +package com.ruoyi.job.service; + +import java.util.List; +import org.quartz.SchedulerException; +import com.ruoyi.common.core.exception.job.TaskException; +import com.ruoyi.job.domain.SysJob; + +/** + * 定时任务调度信息信息 服务层 + * + * @author ruoyi + */ +public interface ISysJobService +{ + /** + * 获取quartz调度器的计划任务 + * + * @param job 调度信息 + * @return 调度任务集合 + */ + public List<SysJob> selectJobList(SysJob job); + + /** + * 通过调度任务ID查询调度信息 + * + * @param jobId 调度任务ID + * @return 调度任务对象信息 + */ + public SysJob selectJobById(Long jobId); + + /** + * 暂停任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int pauseJob(SysJob job) throws SchedulerException; + + /** + * 恢复任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int resumeJob(SysJob job) throws SchedulerException; + + /** + * 删除任务后,所对应的trigger也将被删除 + * + * @param job 调度信息 + * @return 结果 + */ + public int deleteJob(SysJob job) throws SchedulerException; + + /** + * 批量删除调度信息 + * + * @param jobIds 需要删除的任务ID + * @return 结果 + */ + public void deleteJobByIds(Long[] jobIds) throws SchedulerException; + + /** + * 任务调度状态修改 + * + * @param job 调度信息 + * @return 结果 + */ + public int changeStatus(SysJob job) throws SchedulerException; + + /** + * 立即运行任务 + * + * @param job 调度信息 + * @return 结果 + */ + public boolean run(SysJob job) throws SchedulerException; + + /** + * 新增任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int insertJob(SysJob job) throws SchedulerException, TaskException; + + /** + * 更新任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int updateJob(SysJob job) throws SchedulerException, TaskException; + + /** + * 校验cron表达式是否有效 + * + * @param cronExpression 表达式 + * @return 结果 + */ + public boolean checkCronExpressionIsValid(String cronExpression); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java new file mode 100644 index 0000000..41bdcca --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java @@ -0,0 +1,86 @@ +package com.ruoyi.job.service; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.job.domain.SysJobLog; +import com.ruoyi.job.mapper.SysJobLogMapper; + +/** + * 定时任务调度日志信息 服务层 + * + * @author ruoyi + */ +@Service +public class SysJobLogServiceImpl implements ISysJobLogService +{ + @Autowired + private SysJobLogMapper jobLogMapper; + + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + @Override + public List<SysJobLog> selectJobLogList(SysJobLog jobLog) + { + return jobLogMapper.selectJobLogList(jobLog); + } + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + @Override + public SysJobLog selectJobLogById(Long jobLogId) + { + return jobLogMapper.selectJobLogById(jobLogId); + } + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + @Override + public void addJobLog(SysJobLog jobLog) + { + jobLogMapper.insertJobLog(jobLog); + } + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteJobLogByIds(Long[] logIds) + { + return jobLogMapper.deleteJobLogByIds(logIds); + } + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + */ + @Override + public int deleteJobLogById(Long jobId) + { + return jobLogMapper.deleteJobLogById(jobId); + } + + /** + * 清空任务日志 + */ + @Override + public void cleanJobLog() + { + jobLogMapper.cleanJobLog(); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java new file mode 100644 index 0000000..8936b9c --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java @@ -0,0 +1,260 @@ +package com.ruoyi.job.service; + +import java.util.List; +import javax.annotation.PostConstruct; +import org.quartz.JobDataMap; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.ruoyi.common.core.constant.ScheduleConstants; +import com.ruoyi.common.core.exception.job.TaskException; +import com.ruoyi.job.domain.SysJob; +import com.ruoyi.job.mapper.SysJobMapper; +import com.ruoyi.job.util.CronUtils; +import com.ruoyi.job.util.ScheduleUtils; + +/** + * 定时任务调度信息 服务层 + * + * @author ruoyi + */ +@Service +public class SysJobServiceImpl implements ISysJobService +{ + @Autowired + private Scheduler scheduler; + + @Autowired + private SysJobMapper jobMapper; + + /** + * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据) + */ + @PostConstruct + public void init() throws SchedulerException, TaskException + { + scheduler.clear(); + List<SysJob> jobList = jobMapper.selectJobAll(); + for (SysJob job : jobList) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + } + + /** + * 获取quartz调度器的计划任务列表 + * + * @param job 调度信息 + * @return + */ + @Override + public List<SysJob> selectJobList(SysJob job) + { + return jobMapper.selectJobList(job); + } + + /** + * 通过调度任务ID查询调度信息 + * + * @param jobId 调度任务ID + * @return 调度任务对象信息 + */ + @Override + public SysJob selectJobById(Long jobId) + { + return jobMapper.selectJobById(jobId); + } + + /** + * 暂停任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int pauseJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 恢复任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int resumeJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + job.setStatus(ScheduleConstants.Status.NORMAL.getValue()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 删除任务后,所对应的trigger也将被删除 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + int rows = jobMapper.deleteJobById(jobId); + if (rows > 0) + { + scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 批量删除调度信息 + * + * @param jobIds 需要删除的任务ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteJobByIds(Long[] jobIds) throws SchedulerException + { + for (Long jobId : jobIds) + { + SysJob job = jobMapper.selectJobById(jobId); + deleteJob(job); + } + } + + /** + * 任务调度状态修改 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int changeStatus(SysJob job) throws SchedulerException + { + int rows = 0; + String status = job.getStatus(); + if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) + { + rows = resumeJob(job); + } + else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) + { + rows = pauseJob(job); + } + return rows; + } + + /** + * 立即运行任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean run(SysJob job) throws SchedulerException + { + boolean result = false; + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + SysJob properties = selectJobById(job.getJobId()); + // 参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties); + JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); + if (scheduler.checkExists(jobKey)) + { + result = true; + scheduler.triggerJob(jobKey, dataMap); + } + return result; + } + + /** + * 新增任务 + * + * @param job 调度信息 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertJob(SysJob job) throws SchedulerException, TaskException + { + job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); + int rows = jobMapper.insertJob(job); + if (rows > 0) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + return rows; + } + + /** + * 更新任务的时间表达式 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateJob(SysJob job) throws SchedulerException, TaskException + { + SysJob properties = selectJobById(job.getJobId()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + updateSchedulerJob(job, properties.getJobGroup()); + } + return rows; + } + + /** + * 更新任务 + * + * @param job 任务对象 + * @param jobGroup 任务组名 + */ + public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException + { + Long jobId = job.getJobId(); + // 判断是否存在 + JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); + if (scheduler.checkExists(jobKey)) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(jobKey); + } + ScheduleUtils.createScheduleJob(scheduler, job); + } + + /** + * 校验cron表达式是否有效 + * + * @param cronExpression 表达式 + * @return 结果 + */ + @Override + public boolean checkCronExpressionIsValid(String cronExpression) + { + return CronUtils.isValid(cronExpression); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java new file mode 100644 index 0000000..3a127ef --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java @@ -0,0 +1,28 @@ +package com.ruoyi.job.task; + +import org.springframework.stereotype.Component; +import com.ruoyi.common.core.utils.StringUtils; + +/** + * 定时任务调度测试 + * + * @author ruoyi + */ +@Component("ryTask") +public class RyTask +{ + public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) + { + System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i)); + } + + public void ryParams(String params) + { + System.out.println("执行有参方法:" + params); + } + + public void ryNoParams() + { + System.out.println("执行无参方法"); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java new file mode 100644 index 0000000..55ff671 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java @@ -0,0 +1,106 @@ +package com.ruoyi.job.util; + +import java.util.Date; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.ruoyi.common.core.constant.ScheduleConstants; +import com.ruoyi.common.core.utils.ExceptionUtil; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.bean.BeanUtils; +import com.ruoyi.job.domain.SysJob; +import com.ruoyi.job.domain.SysJobLog; +import com.ruoyi.job.service.ISysJobLogService; + +/** + * 抽象quartz调用 + * + * @author ruoyi + */ +public abstract class AbstractQuartzJob implements Job +{ + private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); + + /** + * 线程本地变量 + */ + private static ThreadLocal<Date> threadLocal = new ThreadLocal<>(); + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException + { + SysJob sysJob = new SysJob(); + BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES)); + try + { + before(context, sysJob); + if (sysJob != null) + { + doExecute(context, sysJob); + } + after(context, sysJob, null); + } + catch (Exception e) + { + log.error("任务执行异常 - :", e); + after(context, sysJob, e); + } + } + + /** + * 执行前 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void before(JobExecutionContext context, SysJob sysJob) + { + threadLocal.set(new Date()); + } + + /** + * 执行后 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void after(JobExecutionContext context, SysJob sysJob, Exception e) + { + Date startTime = threadLocal.get(); + threadLocal.remove(); + + final SysJobLog sysJobLog = new SysJobLog(); + sysJobLog.setJobName(sysJob.getJobName()); + sysJobLog.setJobGroup(sysJob.getJobGroup()); + sysJobLog.setInvokeTarget(sysJob.getInvokeTarget()); + sysJobLog.setStartTime(startTime); + sysJobLog.setStopTime(new Date()); + long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime(); + sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); + if (e != null) + { + sysJobLog.setStatus("1"); + String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000); + sysJobLog.setExceptionInfo(errorMsg); + } + else + { + sysJobLog.setStatus("0"); + } + + // 写入数据库当中 + SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog); + } + + /** + * 执行方法,由子类重载 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + * @throws Exception 执行过程中的异常 + */ + protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception; +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java new file mode 100644 index 0000000..9fc6c9f --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java @@ -0,0 +1,63 @@ +package com.ruoyi.job.util; + +import java.text.ParseException; +import java.util.Date; +import org.quartz.CronExpression; + +/** + * cron表达式工具类 + * + * @author ruoyi + * + */ +public class CronUtils +{ + /** + * 返回一个布尔值代表一个给定的Cron表达式的有效性 + * + * @param cronExpression Cron表达式 + * @return boolean 表达式是否有效 + */ + public static boolean isValid(String cronExpression) + { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 返回一个字符串值,表示该消息无效Cron表达式给出有效性 + * + * @param cronExpression Cron表达式 + * @return String 无效时返回表达式错误描述,如果有效返回null + */ + public static String getInvalidMessage(String cronExpression) + { + try + { + new CronExpression(cronExpression); + return null; + } + catch (ParseException pe) + { + return pe.getMessage(); + } + } + + /** + * 返回下一个执行时间根据给定的Cron表达式 + * + * @param cronExpression Cron表达式 + * @return Date 下次Cron表达式执行时间 + */ + public static Date getNextExecution(String cronExpression) + { + try + { + CronExpression cron = new CronExpression(cronExpression); + return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); + } + catch (ParseException e) + { + throw new IllegalArgumentException(e.getMessage()); + } + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java new file mode 100644 index 0000000..1f2c8d3 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java @@ -0,0 +1,182 @@ +package com.ruoyi.job.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.job.domain.SysJob; + +/** + * 任务执行工具 + * + * @author ruoyi + */ +public class JobInvokeUtil +{ + /** + * 执行方法 + * + * @param sysJob 系统任务 + */ + public static void invokeMethod(SysJob sysJob) throws Exception + { + String invokeTarget = sysJob.getInvokeTarget(); + String beanName = getBeanName(invokeTarget); + String methodName = getMethodName(invokeTarget); + List<Object[]> methodParams = getMethodParams(invokeTarget); + + if (!isValidClassName(beanName)) + { + Object bean = SpringUtils.getBean(beanName); + invokeMethod(bean, methodName, methodParams); + } + else + { + Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance(); + invokeMethod(bean, methodName, methodParams); + } + } + + /** + * 调用任务方法 + * + * @param bean 目标对象 + * @param methodName 方法名称 + * @param methodParams 方法参数 + */ + private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException + { + if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) + { + Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams)); + method.invoke(bean, getMethodParamsValue(methodParams)); + } + else + { + Method method = bean.getClass().getMethod(methodName); + method.invoke(bean); + } + } + + /** + * 校验是否为为class包名 + * + * @param invokeTarget 名称 + * @return true是 false否 + */ + public static boolean isValidClassName(String invokeTarget) + { + return StringUtils.countMatches(invokeTarget, ".") > 1; + } + + /** + * 获取bean名称 + * + * @param invokeTarget 目标字符串 + * @return bean名称 + */ + public static String getBeanName(String invokeTarget) + { + String beanName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringBeforeLast(beanName, "."); + } + + /** + * 获取bean方法 + * + * @param invokeTarget 目标字符串 + * @return method方法 + */ + public static String getMethodName(String invokeTarget) + { + String methodName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringAfterLast(methodName, "."); + } + + /** + * 获取method方法参数相关列表 + * + * @param invokeTarget 目标字符串 + * @return method方法相关参数列表 + */ + public static List<Object[]> getMethodParams(String invokeTarget) + { + String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); + if (StringUtils.isEmpty(methodStr)) + { + return null; + } + String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); + List<Object[]> classs = new LinkedList<>(); + for (int i = 0; i < methodParams.length; i++) + { + String str = StringUtils.trimToEmpty(methodParams[i]); + // String字符串类型,以'或"开头 + if (StringUtils.startsWithAny(str, "'", "\"")) + { + classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class }); + } + // boolean布尔类型,等于true或者false + else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) + { + classs.add(new Object[] { Boolean.valueOf(str), Boolean.class }); + } + // long长整形,以L结尾 + else if (StringUtils.endsWith(str, "L")) + { + classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class }); + } + // double浮点类型,以D结尾 + else if (StringUtils.endsWith(str, "D")) + { + classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class }); + } + // 其他类型归类为整形 + else + { + classs.add(new Object[] { Integer.valueOf(str), Integer.class }); + } + } + return classs; + } + + /** + * 获取参数类型 + * + * @param methodParams 参数相关列表 + * @return 参数类型列表 + */ + public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) + { + Class<?>[] classs = new Class<?>[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Class<?>) os[1]; + index++; + } + return classs; + } + + /** + * 获取参数值 + * + * @param methodParams 参数相关列表 + * @return 参数值列表 + */ + public static Object[] getMethodParamsValue(List<Object[]> methodParams) + { + Object[] classs = new Object[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Object) os[0]; + index++; + } + return classs; + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java new file mode 100644 index 0000000..325bd93 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java @@ -0,0 +1,22 @@ +package com.ruoyi.job.util; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; + +import com.ruoyi.job.domain.SysJob; + +/** + * 定时任务处理(禁止并发执行) + * + * @author ruoyi + * + */ +@DisallowConcurrentExecution +public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java new file mode 100644 index 0000000..bab4ee9 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java @@ -0,0 +1,20 @@ +package com.ruoyi.job.util; + +import org.quartz.JobExecutionContext; + +import com.ruoyi.job.domain.SysJob; + +/** + * 定时任务处理(允许并发执行) + * + * @author ruoyi + * + */ +public class QuartzJobExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java new file mode 100644 index 0000000..4140140 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java @@ -0,0 +1,139 @@ +package com.ruoyi.job.util; + +import org.quartz.CronScheduleBuilder; +import org.quartz.CronTrigger; +import org.quartz.Job; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; +import com.ruoyi.common.core.constant.Constants; +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.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.job.domain.SysJob; + +/** + * 定时任务工具类 + * + * @author ruoyi + * + */ +public class ScheduleUtils +{ + /** + * 得到quartz任务类 + * + * @param sysJob 执行计划 + * @return 具体执行任务类 + */ + private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) + { + boolean isConcurrent = "0".equals(sysJob.getConcurrent()); + return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; + } + + /** + * 构建任务触发对象 + */ + public static TriggerKey getTriggerKey(Long jobId, String jobGroup) + { + return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 构建任务键对象 + */ + public static JobKey getJobKey(Long jobId, String jobGroup) + { + return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 创建定时任务 + */ + public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException + { + Class<? extends Job> jobClass = getQuartzJobClass(job); + // 构建job信息 + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build(); + + // 表达式调度构建器 + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()); + cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)) + .withSchedule(cronScheduleBuilder).build(); + + // 放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); + + // 判断是否存在 + if (scheduler.checkExists(getJobKey(jobId, jobGroup))) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(getJobKey(jobId, jobGroup)); + } + + // 判断任务是否过期 + if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))) + { + // 执行调度任务 + scheduler.scheduleJob(jobDetail, trigger); + } + + // 暂停任务 + if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) + { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + } + + /** + * 设置定时任务策略 + */ + public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) + throws TaskException + { + switch (job.getMisfirePolicy()) + { + case ScheduleConstants.MISFIRE_DEFAULT: + return cb; + case ScheduleConstants.MISFIRE_IGNORE_MISFIRES: + return cb.withMisfireHandlingInstructionIgnoreMisfires(); + case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED: + return cb.withMisfireHandlingInstructionFireAndProceed(); + case ScheduleConstants.MISFIRE_DO_NOTHING: + return cb.withMisfireHandlingInstructionDoNothing(); + default: + throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); + } + } + + /** + * 检查包名是否为白名单配置 + * + * @param invokeTarget 目标字符串 + * @return 结果 + */ + public static boolean whiteList(String invokeTarget) + { + String packageName = StringUtils.substringBefore(invokeTarget, "("); + int count = StringUtils.countMatches(packageName, "."); + if (count > 1) + { + return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR); + } + Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]); + return StringUtils.containsAnyIgnoreCase(obj.getClass().getPackage().getName(), Constants.JOB_WHITELIST_STR); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt new file mode 100644 index 0000000..0b9cd42 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ _ + (_) (_) | | + _ __ _ _ ___ _ _ _ ______ _ ___ | |__ +| '__|| | | | / _ \ | | | || ||______| | | / _ \ | '_ \ +| | | |_| || (_) || |_| || | | || (_) || |_) | +|_| \__,_| \___/ \__, ||_| | | \___/ |_.__/ + __/ | _/ | + |___/ |__/ \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..9aefcf1 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml @@ -0,0 +1,25 @@ +# Tomcat +server: + port: 9203 + +# Spring +spring: + application: + # 应用名称 + name: ruoyi-job + profiles: + # 环境配置 + active: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.188:8848 + config: + # 配置中心地址 + server-addr: 192.168.110.188:8848 + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-job/src/main/resources/logback.xml new file mode 100644 index 0000000..44e4ff2 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/resources/logback.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <!-- 日志存放路径 --> + <property name="log.path" value="logs/ruoyi-job" /> + <!-- 日志输出格式 --> + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> + + <!-- 控制台输出 --> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + </appender> + + <!-- 系统日志输出 --> + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/info.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>INFO</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/error.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>ERROR</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 系统模块日志级别控制 --> + <logger name="com.ruoyi" level="info" /> + <!-- Spring日志级别控制 --> + <logger name="org.springframework" level="warn" /> + + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--系统操作日志--> + <root level="info"> + <appender-ref ref="file_info" /> + <appender-ref ref="file_error" /> + </root> +</configuration> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobLogMapper.xml b/ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobLogMapper.xml new file mode 100644 index 0000000..2e1cad1 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobLogMapper.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.job.mapper.SysJobLogMapper"> + + <resultMap type="SysJobLog" id="SysJobLogResult"> + <id property="jobLogId" column="job_log_id" /> + <result property="jobName" column="job_name" /> + <result property="jobGroup" column="job_group" /> + <result property="invokeTarget" column="invoke_target" /> + <result property="jobMessage" column="job_message" /> + <result property="status" column="status" /> + <result property="exceptionInfo" column="exception_info" /> + <result property="createTime" column="create_time" /> + </resultMap> + + <sql id="selectJobLogVo"> + select job_log_id, job_name, job_group, invoke_target, job_message, status, exception_info, create_time + from sys_job_log + </sql> + + <select id="selectJobLogList" parameterType="SysJobLog" resultMap="SysJobLogResult"> + <include refid="selectJobLogVo"/> + <where> + <if test="jobName != null and jobName != ''"> + AND job_name like concat('%', #{jobName}, '%') + </if> + <if test="jobGroup != null and jobGroup != ''"> + AND job_group = #{jobGroup} + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + <if test="invokeTarget != null and invokeTarget != ''"> + AND invoke_target like concat('%', #{invokeTarget}, '%') + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + and date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + and date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + </where> + </select> + + <select id="selectJobLogAll" resultMap="SysJobLogResult"> + <include refid="selectJobLogVo"/> + </select> + + <select id="selectJobLogById" parameterType="Long" resultMap="SysJobLogResult"> + <include refid="selectJobLogVo"/> + where job_log_id = #{jobLogId} + </select> + + <delete id="deleteJobLogById" parameterType="Long"> + delete from sys_job_log where job_log_id = #{jobLogId} + </delete> + + <delete id="deleteJobLogByIds" parameterType="Long"> + delete from sys_job_log where job_log_id in + <foreach collection="array" item="jobLogId" open="(" separator="," close=")"> + #{jobLogId} + </foreach> + </delete> + + <update id="cleanJobLog"> + truncate table sys_job_log + </update> + + <insert id="insertJobLog" parameterType="SysJobLog"> + insert into sys_job_log( + <if test="jobLogId != null and jobLogId != 0">job_log_id,</if> + <if test="jobName != null and jobName != ''">job_name,</if> + <if test="jobGroup != null and jobGroup != ''">job_group,</if> + <if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if> + <if test="jobMessage != null and jobMessage != ''">job_message,</if> + <if test="status != null and status != ''">status,</if> + <if test="exceptionInfo != null and exceptionInfo != ''">exception_info,</if> + create_time + )values( + <if test="jobLogId != null and jobLogId != 0">#{jobLogId},</if> + <if test="jobName != null and jobName != ''">#{jobName},</if> + <if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if> + <if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if> + <if test="jobMessage != null and jobMessage != ''">#{jobMessage},</if> + <if test="status != null and status != ''">#{status},</if> + <if test="exceptionInfo != null and exceptionInfo != ''">#{exceptionInfo},</if> + sysdate() + ) + </insert> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobMapper.xml b/ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobMapper.xml new file mode 100644 index 0000000..a0b0ce8 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/resources/mapper/job/SysJobMapper.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.job.mapper.SysJobMapper"> + + <resultMap type="SysJob" id="SysJobResult"> + <id property="jobId" column="job_id" /> + <result property="jobName" column="job_name" /> + <result property="jobGroup" column="job_group" /> + <result property="invokeTarget" column="invoke_target" /> + <result property="cronExpression" column="cron_expression" /> + <result property="misfirePolicy" column="misfire_policy" /> + <result property="concurrent" column="concurrent" /> + <result property="status" column="status" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + </resultMap> + + <sql id="selectJobVo"> + select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark + from sys_job + </sql> + + <select id="selectJobList" parameterType="SysJob" resultMap="SysJobResult"> + <include refid="selectJobVo"/> + <where> + <if test="jobName != null and jobName != ''"> + AND job_name like concat('%', #{jobName}, '%') + </if> + <if test="jobGroup != null and jobGroup != ''"> + AND job_group = #{jobGroup} + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + <if test="invokeTarget != null and invokeTarget != ''"> + AND invoke_target like concat('%', #{invokeTarget}, '%') + </if> + </where> + </select> + + <select id="selectJobAll" resultMap="SysJobResult"> + <include refid="selectJobVo"/> + </select> + + <select id="selectJobById" parameterType="Long" resultMap="SysJobResult"> + <include refid="selectJobVo"/> + where job_id = #{jobId} + </select> + + <delete id="deleteJobById" parameterType="Long"> + delete from sys_job where job_id = #{jobId} + </delete> + + <delete id="deleteJobByIds" parameterType="Long"> + delete from sys_job where job_id in + <foreach collection="array" item="jobId" open="(" separator="," close=")"> + #{jobId} + </foreach> + </delete> + + <update id="updateJob" parameterType="SysJob"> + update sys_job + <set> + <if test="jobName != null and jobName != ''">job_name = #{jobName},</if> + <if test="jobGroup != null and jobGroup != ''">job_group = #{jobGroup},</if> + <if test="invokeTarget != null and invokeTarget != ''">invoke_target = #{invokeTarget},</if> + <if test="cronExpression != null and cronExpression != ''">cron_expression = #{cronExpression},</if> + <if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy = #{misfirePolicy},</if> + <if test="concurrent != null and concurrent != ''">concurrent = #{concurrent},</if> + <if test="status !=null">status = #{status},</if> + <if test="remark != null and remark != ''">remark = #{remark},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where job_id = #{jobId} + </update> + + <insert id="insertJob" parameterType="SysJob" useGeneratedKeys="true" keyProperty="jobId"> + insert into sys_job( + <if test="jobId != null and jobId != 0">job_id,</if> + <if test="jobName != null and jobName != ''">job_name,</if> + <if test="jobGroup != null and jobGroup != ''">job_group,</if> + <if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if> + <if test="cronExpression != null and cronExpression != ''">cron_expression,</if> + <if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy,</if> + <if test="concurrent != null and concurrent != ''">concurrent,</if> + <if test="status != null and status != ''">status,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="jobId != null and jobId != 0">#{jobId},</if> + <if test="jobName != null and jobName != ''">#{jobName},</if> + <if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if> + <if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if> + <if test="cronExpression != null and cronExpression != ''">#{cronExpression},</if> + <if test="misfirePolicy != null and misfirePolicy != ''">#{misfirePolicy},</if> + <if test="concurrent != null and concurrent != ''">#{concurrent},</if> + <if test="status != null and status != ''">#{status},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml new file mode 100644 index 0000000..579270f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-modules</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-modules-system</artifactId> + + <description> + ruoyi-modules-system系统模块 + </description> + + <dependencies> + + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-api-system</artifactId> + <scope>compile</scope> + </dependency> + + <!-- SpringCloud Alibaba Nacos --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos Config --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> + </dependency> + + <!-- SpringBoot Actuator --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + + <!-- Swagger UI --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${swagger.fox.version}</version> + </dependency> + + <!-- Mysql Connector --> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + + <!-- RuoYi Common DataSource --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-datasource</artifactId> + </dependency> + + <!-- RuoYi Common DataScope --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-datascope</artifactId> + </dependency> + + <!-- RuoYi Common Log --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-log</artifactId> + </dependency> + + <!-- RuoYi Common Swagger --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-swagger</artifactId> + </dependency> + + <!-- 引入Druid依赖,阿里巴巴所提供的数据源 --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>druid-spring-boot-starter</artifactId> + <version>${druid.version}</version> + </dependency> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>fastjson</artifactId> + <version>1.2.47</version> + </dependency> + + <!-- 分布式事务 --> + <dependency> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-common-seata</artifactId> + </dependency> + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + <resources> + <resource> + <directory>src/main/resources</directory> + </resource> + <resource> + <directory>src/main/java</directory> + <includes> + <include>**/*.xml</include> + </includes> + <filtering>false</filtering> + </resource> + </resources> + </build> + +</project> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java new file mode 100644 index 0000000..fc5d736 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java @@ -0,0 +1,38 @@ +package com.ruoyi.system; + +import com.ruoyi.common.security.annotation.EnableCustomConfig; +import com.ruoyi.common.security.annotation.EnableRyFeignClients; +import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +/** + * 系统模块 + * + * @author ruoyi + */ +@EnableAsync +@EnableCustomConfig +@MapperScan({"com.ruoyi.system.mapper"}) +@EnableCustomSwagger2 +@EnableRyFeignClients +@SpringBootApplication +public class RuoYiSystemApplication +{ + public static void main(String[] args) + { + SpringApplication.run(RuoYiSystemApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 系统模块启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/AgreementController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/AgreementController.java new file mode 100644 index 0000000..c5d1970 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/AgreementController.java @@ -0,0 +1,66 @@ +package com.ruoyi.system.controller; + + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.utils.page.BeanUtils; +import com.ruoyi.system.domain.Agreement; +import com.ruoyi.system.domain.dto.AgreementDTO; +import com.ruoyi.system.service.IAgreementService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import java.util.List; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * <p> + * 前端控制器 + * </p> + * + * @author mitao + * @since 2024-05-21 + */ +@RestController +@RequestMapping("/agreement") +@Api(tags = "系统管理相关接口") +public class AgreementController { + @Resource + private IAgreementService iAgreementService; + + @RequestMapping(value = "/getAgreement/{agreementType}", method = RequestMethod.GET) + @ApiOperation(value = "获取用户协议/隐私协议") + public R<Agreement> getAgreement(@PathVariable("agreementType") Integer agreementType) { + return R.ok(iAgreementService.getAgreement(agreementType)); + } + + /** + * 管理后台-获取协议列表 + * + * @return List<AgreementDTO> + */ + @ApiOperation("管理后台-获取协议列表") + @GetMapping("/list") + public R<List<AgreementDTO>> getAgreementList() { + List<Agreement> list = iAgreementService.lambdaQuery().last("limit 2").list(); + return R.ok(BeanUtils.copyList(list, AgreementDTO.class)); + } + + /** + * 保存协议 + * + * @param dto 协议对象 + */ + @ApiOperation(value = "管理后台-保存用户协议", notes = "接收一个包含多个AgreementDTO的列表") + @PostMapping("/save") + public R<?> saveAgreement(@Validated @RequestBody AgreementDTO dto) { + iAgreementService.saveAgreement(dto); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/DelayTaskController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/DelayTaskController.java new file mode 100644 index 0000000..403c9da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/DelayTaskController.java @@ -0,0 +1,50 @@ +package com.ruoyi.system.controller; + + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.security.annotation.InnerAuth; +import com.ruoyi.system.api.domain.DelayTask; +import com.ruoyi.system.service.DelayTaskService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * <p> + * 前端控制器 + * </p> + * + * @author mitao + * @since 2024-05-21 + */ +@RestController +@RequestMapping("/delay-task") +@RequiredArgsConstructor +public class DelayTaskController { + + private final DelayTaskService delayTaskService; + + @InnerAuth + @PostMapping("/getDelayTask") + public R<DelayTask> getDelayTask(@RequestBody String key) { + DelayTask delayTask = delayTaskService.getDelayTask(key); + return R.ok(delayTask); + } + + @InnerAuth + @PostMapping("/addDelayTask") + public R<?> + addDelayTask(@RequestBody DelayTask delayTask) { + delayTaskService.addDelayTask(delayTask); + return R.ok(); + } + + @InnerAuth + @PostMapping("/deleteDelayTask") + public R<?> deleteDelayTask(@RequestBody String key) { + delayTaskService.deleteDelayTask(key); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java new file mode 100644 index 0000000..64e30ae --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java @@ -0,0 +1,138 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.system.api.domain.SysConfig; +import com.ruoyi.system.service.ISysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; + +/** + * 参数配置 信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/config") +public class SysConfigController extends BaseController +{ + @Autowired + private ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @RequiresPermissions("system:config:list") + @GetMapping("/list") + public TableDataInfo list(SysConfig config) + { + startPage(); + List<SysConfig> list = configService.selectConfigList(config); + return getDataTable(list); + } + + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:config:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysConfig config) + { + List<SysConfig> list = configService.selectConfigList(config); + ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class); + util.exportExcel(response, list, "参数数据"); + } + + /** + * 根据参数编号获取详细信息 + */ + @GetMapping(value = "/{configId}") + public AjaxResult getInfo(@PathVariable Long configId) + { + return success(configService.selectConfigById(configId)); + } + + + + + /** + * 根据参数键名查询参数值 + */ + @GetMapping(value = "/configKey/{configKey}") + public AjaxResult getConfigKey(@PathVariable String configKey) + { + return success(configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @RequiresPermissions("system:config:add") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysConfig config) + { + if (!configService.checkConfigKeyUnique(config)) + { + return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setCreateBy(SecurityUtils.getUsername()); + return toAjax(configService.insertConfig(config)); + } + + /** + * 修改参数配置 + */ + @RequiresPermissions("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysConfig config) + { + if (!configService.checkConfigKeyUnique(config)) + { + return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(configService.updateConfig(config)); + } + + /** + * 删除参数配置 + */ + @RequiresPermissions("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public AjaxResult remove(@PathVariable Long[] configIds) + { + configService.deleteConfigByIds(configIds); + return success(); + } + + /** + * 刷新参数缓存 + */ + @RequiresPermissions("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() + { + configService.resetConfigCache(); + return success(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java new file mode 100644 index 0000000..7fe9d0e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java @@ -0,0 +1,135 @@ +package com.ruoyi.system.controller; + +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import java.util.List; + +import com.ruoyi.system.service.ISysDeptService; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysDept; + +/** + * 部门信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/dept") +public class SysDeptController extends BaseController +{ + @Autowired + private ISysDeptService deptService; + + /** + * 获取部门列表 + */ + @RequiresPermissions("system:dept:list") + @GetMapping("/list") + public AjaxResult list(SysDept dept) + { + List<SysDept> depts = deptService.selectDeptList(dept); + return success(depts); + } + + /** + * 查询部门列表(排除节点) + */ + @RequiresPermissions("system:dept:list") + @GetMapping("/list/exclude/{deptId}") + public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) + { + List<SysDept> depts = deptService.selectDeptList(new SysDept()); + depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); + return success(depts); + } + + /** + * 根据部门编号获取详细信息 + */ + @RequiresPermissions("system:dept:query") + @GetMapping(value = "/{deptId}") + public AjaxResult getInfo(@PathVariable Long deptId) + { + deptService.checkDeptDataScope(deptId); + return success(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门 + */ + @RequiresPermissions("system:dept:add") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDept dept) + { + if (!deptService.checkDeptNameUnique(dept)) + { + return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + dept.setCreateBy(SecurityUtils.getUsername()); + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @RequiresPermissions("system:dept:edit") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDept dept) + { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) + { + return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + else if (dept.getParentId().equals(deptId)) + { + return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } + else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) + { + return error("该部门包含未停用的子部门!"); + } + dept.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + */ + @RequiresPermissions("system:dept:remove") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public AjaxResult remove(@PathVariable Long deptId) + { + if (deptService.hasChildByDeptId(deptId)) + { + return warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) + { + return warn("部门存在用户,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java new file mode 100644 index 0000000..a4c12c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java @@ -0,0 +1,123 @@ +package com.ruoyi.system.controller; + +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.system.service.ISysDictDataService; +import com.ruoyi.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysDictData; + +/** + * 数据字典信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/dict/data") +public class SysDictDataController extends BaseController +{ + @Autowired + private ISysDictDataService dictDataService; + + @Autowired + private ISysDictTypeService dictTypeService; + + @RequiresPermissions("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictData dictData) + { + startPage(); + List<SysDictData> list = dictDataService.selectDictDataList(dictData); + return getDataTable(list); + } + + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:dict:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictData dictData) + { + List<SysDictData> list = dictDataService.selectDictDataList(dictData); + ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class); + util.exportExcel(response, list, "字典数据"); + } + + /** + * 查询字典数据详细 + */ + @RequiresPermissions("system:dict:query") + @GetMapping(value = "/{dictCode}") + public AjaxResult getInfo(@PathVariable Long dictCode) + { + return success(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + */ + @GetMapping(value = "/type/{dictType}") + public AjaxResult dictType(@PathVariable String dictType) + { + List<SysDictData> data = dictTypeService.selectDictDataByType(dictType); + if (StringUtils.isNull(data)) + { + data = new ArrayList<SysDictData>(); + } + return success(data); + } + + /** + * 新增字典类型 + */ + @RequiresPermissions("system:dict:add") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictData dict) + { + dict.setCreateBy(SecurityUtils.getUsername()); + return toAjax(dictDataService.insertDictData(dict)); + } + + /** + * 修改保存字典类型 + */ + @RequiresPermissions("system:dict:edit") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictData dict) + { + dict.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(dictDataService.updateDictData(dict)); + } + + /** + * 删除字典类型 + */ + @RequiresPermissions("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public AjaxResult remove(@PathVariable Long[] dictCodes) + { + dictDataService.deleteDictDataByIds(dictCodes); + return success(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java new file mode 100644 index 0000000..5df1183 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java @@ -0,0 +1,133 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysDictType; + +/** + * 数据字典信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/dict/type") +public class SysDictTypeController extends BaseController +{ + @Autowired + private ISysDictTypeService dictTypeService; + + @RequiresPermissions("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictType dictType) + { + startPage(); + List<SysDictType> list = dictTypeService.selectDictTypeList(dictType); + return getDataTable(list); + } + + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:dict:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictType dictType) + { + List<SysDictType> list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class); + util.exportExcel(response, list, "字典类型"); + } + + /** + * 查询字典类型详细 + */ + @RequiresPermissions("system:dict:query") + @GetMapping(value = "/{dictId}") + public AjaxResult getInfo(@PathVariable Long dictId) + { + return success(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @RequiresPermissions("system:dict:add") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictType dict) + { + if (!dictTypeService.checkDictTypeUnique(dict)) + { + return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setCreateBy(SecurityUtils.getUsername()); + return toAjax(dictTypeService.insertDictType(dict)); + } + + /** + * 修改字典类型 + */ + @RequiresPermissions("system:dict:edit") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictType dict) + { + if (!dictTypeService.checkDictTypeUnique(dict)) + { + return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(dictTypeService.updateDictType(dict)); + } + + /** + * 删除字典类型 + */ + @RequiresPermissions("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public AjaxResult remove(@PathVariable Long[] dictIds) + { + dictTypeService.deleteDictTypeByIds(dictIds); + return success(); + } + + /** + * 刷新字典缓存 + */ + @RequiresPermissions("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() + { + dictTypeService.resetDictCache(); + return success(); + } + + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll(); + return success(dictTypes); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java new file mode 100644 index 0000000..aa116a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java @@ -0,0 +1,93 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.system.service.ISysLogininforService; +import org.springframework.beans.factory.annotation.Autowired; +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.RequestBody; +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.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.common.security.annotation.InnerAuth; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.system.api.domain.SysLogininfor; + +/** + * 系统访问记录 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/logininfor") +public class SysLogininforController extends BaseController +{ + @Autowired + private ISysLogininforService logininforService; + + @Autowired + private RedisService redisService; + + @RequiresPermissions("system:logininfor:list") + @GetMapping("/list") + public TableDataInfo list(SysLogininfor logininfor) + { + startPage(); + List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); + return getDataTable(list); + } + + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:logininfor:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysLogininfor logininfor) + { + List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); + ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class); + util.exportExcel(response, list, "登录日志"); + } + + @RequiresPermissions("system:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public AjaxResult remove(@PathVariable Long[] infoIds) + { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + @RequiresPermissions("system:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/clean") + public AjaxResult clean() + { + logininforService.cleanLogininfor(); + return success(); + } + + @RequiresPermissions("system:logininfor:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public AjaxResult unlock(@PathVariable("userName") String userName) + { + redisService.deleteObject(CacheConstants.PWD_ERR_CNT_KEY + userName); + return success(); + } + + @InnerAuth + @PostMapping + public AjaxResult add(@RequestBody SysLogininfor logininfor) + { + return toAjax(logininforService.insertLogininfor(logininfor)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java new file mode 100644 index 0000000..9bd61b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java @@ -0,0 +1,173 @@ +package com.ruoyi.system.controller; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.SysMenus; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.service.ISysMenuService; + +/** + * 菜单信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/menu") +@Api(tags = "菜单模块") +public class SysMenuController extends BaseController +{ + @Autowired + private ISysMenuService menuService; + + /** + * 获取菜单列表 + */ + @GetMapping("/list") + @ApiOperation("所有菜单列表") + public AjaxResult list() + { + List<SysMenus> list= menuService.getAllMenu(); + return success(list); + } + + /** + * 根据菜单编号获取详细信息 + */ + @RequiresPermissions("system:menu:query") + @GetMapping(value = "/{menuId}") + public AjaxResult getInfo(@PathVariable Long menuId) + { + return success(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @GetMapping("/treeselect") + public AjaxResult treeselect(SysMenu menu) + { + Long userId = SecurityUtils.getUserId(); + List<SysMenu> menus = menuService.selectMenuList(menu, userId); + ArrayList<SysMenus> sysMenus = new ArrayList<>(); + for (SysMenu sysMenu : menus) { + SysMenus sysMenus1 = new SysMenus(); + BeanUtils.copyProperties(sysMenu,sysMenus1); + sysMenus.add(sysMenus1); + } + + return success(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + */ + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) + { + Long userId = SecurityUtils.getUserId(); + List<SysMenu> menus = menuService.selectMenuList(userId); + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); + ajax.put("menus", menuService.buildMenuTreeSelect(menus)); + return ajax; + } + + /** + * 新增菜单 + */ + @RequiresPermissions("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysMenu menu) + { + if (!menuService.checkMenuNameUnique(menu)) + { + return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) + { + return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + menu.setCreateBy(SecurityUtils.getUsername()); + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @RequiresPermissions("system:menu:edit") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysMenu menu) + { + if (!menuService.checkMenuNameUnique(menu)) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + else if (menu.getMenuId().equals(menu.getParentId())) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + menu.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + */ + @RequiresPermissions("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public AjaxResult remove(@PathVariable("menuId") Long menuId) + { + if (menuService.hasChildByMenuId(menuId)) + { + return warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) + { + return warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("getRouters") + public AjaxResult getRouters() + { + Long userId = SecurityUtils.getUserId(); + List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId); + return success(menuService.buildMenus(menus)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java new file mode 100644 index 0000000..831f707 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java @@ -0,0 +1,93 @@ +package com.ruoyi.system.controller; + +import java.util.List; + +import com.ruoyi.system.domain.SysNotice; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.service.ISysNoticeService; + +/** + * 公告 信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/notice") +public class SysNoticeController extends BaseController +{ + @Autowired + private ISysNoticeService noticeService; + + /** + * 获取通知公告列表 + */ + @RequiresPermissions("system:notice:list") + @GetMapping("/list") + public TableDataInfo list(SysNotice notice) + { + startPage(); + List<SysNotice> list = noticeService.selectNoticeList(notice); + return getDataTable(list); + } + + /** + * 根据通知公告编号获取详细信息 + */ + @RequiresPermissions("system:notice:query") + @GetMapping(value = "/{noticeId}") + public AjaxResult getInfo(@PathVariable Long noticeId) + { + return success(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @RequiresPermissions("system:notice:add") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysNotice notice) + { + notice.setCreateBy(SecurityUtils.getUsername()); + return toAjax(noticeService.insertNotice(notice)); + } + + /** + * 修改通知公告 + */ + @RequiresPermissions("system:notice:edit") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysNotice notice) + { + notice.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + */ + @RequiresPermissions("system:notice:remove") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public AjaxResult remove(@PathVariable Long[] noticeIds) + { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java new file mode 100644 index 0000000..4a6ec7c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java @@ -0,0 +1,108 @@ +package com.ruoyi.system.controller; + +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.query.SysOperLogQuery; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.InnerAuth; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.system.api.domain.SysOperLog; +import com.ruoyi.system.service.ISysOperLogService; + +/** + * 操作日志记录 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/operlog") +public class SysOperlogController extends BaseController +{ + @Autowired + private ISysOperLogService operLogService; + +// @RequiresPermissions("system:operlog:list") +// @GetMapping("/list") +// public TableDataInfo list(SysOperLog operLog) +// { +// startPage(); +// List<SysOperLog> list = operLogService.selectOperLogList(operLog); +// return getDataTable(list); +// } + + @ApiOperation(value = "当前车辆操作日志查询") + @PostMapping("/list") + public AjaxResult list(@RequestBody SysOperLogQuery query) + { + LambdaQueryWrapper<SysOperLog> wrapper = new LambdaQueryWrapper<>(); + wrapper.like(SysOperLog::getTitle,"车辆管理"); + wrapper.ne(SysOperLog::getBusinessType,1); + List<SysOperLog> list = operLogService.list(wrapper); + Iterator<SysOperLog> iterator = list.iterator(); + while (iterator.hasNext()){ + SysOperLog sysOperLog = iterator.next(); + String operParam = sysOperLog.getOperParam(); + JSONObject jsonObject = JSONObject.parseObject(operParam); + String carId = jsonObject.getString("carId"); + if(StringUtils.isNotEmpty(carId) && Objects.nonNull(query.getCarId()) && !carId.equals(String.valueOf(query.getCarId()))){ + iterator.remove(); + } + } + return AjaxResult.success(list); + } + + + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:operlog:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysOperLog operLog) + { + List<SysOperLog> list = operLogService.selectOperLogList(operLog); + ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class); + util.exportExcel(response, list, "操作日志"); + } + + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @RequiresPermissions("system:operlog:remove") + @DeleteMapping("/{operIds}") + public AjaxResult remove(@PathVariable Long[] operIds) + { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + @RequiresPermissions("system:operlog:remove") + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public AjaxResult clean() + { + operLogService.cleanOperLog(); + return success(); + } + + @InnerAuth + @PostMapping + public AjaxResult add(@RequestBody SysOperLog operLog) + { + return toAjax(operLogService.insertOperlog(operLog)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java new file mode 100644 index 0000000..ef8449b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java @@ -0,0 +1,131 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.system.domain.SysPost; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.service.ISysPostService; + +/** + * 岗位信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/post") +public class SysPostController extends BaseController +{ + @Autowired + private ISysPostService postService; + + /** + * 获取岗位列表 + */ + @RequiresPermissions("system:post:list") + @GetMapping("/list") + public TableDataInfo list(SysPost post) + { + startPage(); + List<SysPost> list = postService.selectPostList(post); + return getDataTable(list); + } + + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:post:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysPost post) + { + List<SysPost> list = postService.selectPostList(post); + ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class); + util.exportExcel(response, list, "岗位数据"); + } + + /** + * 根据岗位编号获取详细信息 + */ + @RequiresPermissions("system:post:query") + @GetMapping(value = "/{postId}") + public AjaxResult getInfo(@PathVariable Long postId) + { + return success(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @RequiresPermissions("system:post:add") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysPost post) + { + if (!postService.checkPostNameUnique(post)) + { + return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } + else if (!postService.checkPostCodeUnique(post)) + { + return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setCreateBy(SecurityUtils.getUsername()); + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @RequiresPermissions("system:post:edit") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysPost post) + { + if (!postService.checkPostNameUnique(post)) + { + return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } + else if (!postService.checkPostCodeUnique(post)) + { + return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + */ + @RequiresPermissions("system:post:remove") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public AjaxResult remove(@PathVariable Long[] postIds) + { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + List<SysPost> posts = postService.selectPostAll(); + return success(posts); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java new file mode 100644 index 0000000..e6eb5af --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java @@ -0,0 +1,166 @@ +package com.ruoyi.system.controller; + +import java.util.Arrays; + +import com.ruoyi.system.service.ISysUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +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.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +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.domain.R; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.file.FileTypeUtils; +import com.ruoyi.common.core.utils.file.MimeTypeUtils; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.service.TokenService; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.RemoteFileService; +import com.ruoyi.system.api.domain.SysFile; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.api.model.LoginUser; + +/** + * 个人信息 业务处理 + * + * @author ruoyi + */ +@Api(tags = "个人信息") +@RestController +@RequestMapping("/user/profile") +public class SysProfileController extends BaseController +{ + @Autowired + private ISysUserService userService; + + @Autowired + private TokenService tokenService; + + @Autowired + private RemoteFileService remoteFileService; + + /** + * 个人信息 + */ + @GetMapping + public AjaxResult profile() + { + String username = SecurityUtils.getUsername(); + SysUser user = userService.selectUserByUserName(username); + AjaxResult ajax = AjaxResult.success(user); + ajax.put("roleGroup", userService.selectUserRoleGroup(username)); + ajax.put("postGroup", userService.selectUserPostGroup(username)); + return ajax; + } + + /** + * 修改用户 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult updateProfile(@RequestBody SysUser user) + { + LoginUser loginUser = SecurityUtils.getLoginUser(); + SysUser sysUser = loginUser.getSysUser(); + user.setUserName(sysUser.getUserName()); + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUserId(sysUser.getUserId()); + user.setPassword(null); + user.setAvatar(null); + user.setDeptId(null); + if (userService.updateUserProfile(user) > 0) + { + // 更新缓存用户信息 + loginUser.getSysUser().setNickName(user.getNickName()); + loginUser.getSysUser().setPhonenumber(user.getPhonenumber()); + loginUser.getSysUser().setEmail(user.getEmail()); + loginUser.getSysUser().setSex(user.getSex()); + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + */ + @ApiOperation(value = "个人信息-修改密码") + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PostMapping("/updatePwd") + public AjaxResult updatePwd(String oldPassword, String newPassword) + { + System.err.println(oldPassword); + System.err.println(newPassword); + String username = SecurityUtils.getUsername(); + SysUser user = userService.selectUserByUserName(username); + String password = user.getPassword(); + if (!SecurityUtils.matchesPassword(oldPassword, password)) + { + return error("修改密码失败,旧密码错误"); + } + if (SecurityUtils.matchesPassword(newPassword, password)) + { + return error("新密码不能与旧密码相同"); + } + if (userService.resetUserPwd(username, SecurityUtils.encryptPassword(newPassword)) > 0) + { + // 更新缓存用户密码 +// LoginUser loginUser = SecurityUtils.getLoginUser(); +// SysUser sysUser = loginUser.getSysUser(); +// loginUser.getSysUser().setPassword(SecurityUtils.encryptPassword(newPassword)); +// tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + */ + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping("/avatar") + public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) + { + if (!file.isEmpty()) + { + LoginUser loginUser = SecurityUtils.getLoginUser(); + String extension = FileTypeUtils.getExtension(file); + if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) + { + return error("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式"); + } + R<SysFile> fileResult = remoteFileService.upload(file); + if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) + { + return error("文件服务异常,请联系管理员"); + } + String url = fileResult.getData().getUrl(); + if (userService.updateUserAvatar(loginUser.getUsername(), url)) + { + AjaxResult ajax = AjaxResult.success(); + ajax.put("imgUrl", url); + // 更新缓存用户头像 + loginUser.getSysUser().setAvatar(url); + tokenService.setLoginUser(loginUser); + return ajax; + } + } + return error("上传图片异常,请联系管理员"); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java new file mode 100644 index 0000000..fcd0fdc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java @@ -0,0 +1,494 @@ +package com.ruoyi.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.PageInfo; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysDept; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.domain.SysMenus; +import com.ruoyi.system.domain.SysRoleMenu; +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.domain.dto.RoleAddDto; +import com.ruoyi.system.domain.dto.RoleQuery; +import com.ruoyi.system.domain.dto.RoleUpdateDto; +import com.ruoyi.system.domain.vo.RoleInfoVo; +import com.ruoyi.system.mapper.SysMenuMapper; +import com.ruoyi.system.mapper.SysRoleMenuMapper; +import com.ruoyi.system.service.ISysDeptService; +import com.ruoyi.system.service.ISysRoleService; +import com.ruoyi.system.service.ISysUserRoleService; +import com.ruoyi.system.service.ISysUserService; +import io.seata.common.util.StringUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 角色信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/role") +@Api(tags = "角色模块") +public class SysRoleController extends BaseController +{ + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysDeptService deptService; + + @Resource + private SysRoleMenuMapper sysRoleMenuMapper; + + @Autowired + private ISysUserRoleService sysUserRoleService; + + + @Resource + private SysMenuMapper menuMapper; + + // @ApiOperation("获取所有角色信息根据公司id") + @GetMapping("/list") + public AjaxResult list(Integer companyId) + { + SysRole role = new SysRole(); + List<SysRole> list = roleService.selectRoleList(role); + return AjaxResult.success(list); + } + + + @ApiOperation("获取角色列表") + @PostMapping("/listPage") + public AjaxResult listPage(@Validated @RequestBody RoleQuery query) + { + PageInfo<SysRole> pageInfo = new PageInfo<>(query.getPageCurr(), query.getPageSize()); + + PageInfo<SysRole> page = roleService.page(pageInfo, + new LambdaQueryWrapper<SysRole>().ne(SysRole::getRoleId, 20) + .like(StringUtils.isNotBlank(query.getRoleName()), SysRole::getRoleName, + query.getRoleName()).eq(SysRole::getDelFlag, "0")); + return AjaxResult.success(page); + } + + + // @ApiOperation("角色启用停用") + @GetMapping("/roleStart") + public AjaxResult roleStart(Long roleId) + { + SysRole role = roleService.selectRoleById(roleId); + if(role.getStatus().equals("1")){ + role.setStatus("0"); + }else { + role.setStatus("1"); + } + return AjaxResult.success(roleService.updateRole(role)); + } + + + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @ApiOperation("添加角色") + @PostMapping("/roleAdd") + public AjaxResult roleAdd(@Validated @RequestBody RoleAddDto dto) + { + SysRole role = new SysRole(); + role.setRoleName(dto.getRoleName()); + long count = roleService.count(Wrappers.lambdaQuery(SysRole.class) + .eq(SysRole::getRoleName, dto.getRoleName())); + if(count>0){ + return AjaxResult.error("角色已存在,请重新输入"); + } + List<Long> menuIds1 = dto.getMenuIds(); + if(CollectionUtils.isEmpty(menuIds1)){ + return AjaxResult.error("菜单id不能为空"); + } + role.setMenuIds(dto.getMenuIds().toArray(new Long[0])); + // 添加角色 + role.setCreateBy(SecurityUtils.getUsername()); + role.setCreateTime(new Date()); + roleService.insertRole(role); +// ArrayList<SysRoleMenu> sysRoleMenus = new ArrayList<>(); +// List<Long> menuIds = dto.getMenuIds(); +// for (Long menuId : menuIds) { +// SysRoleMenu sysRoleMenu = new SysRoleMenu(); +// sysRoleMenu.setMenuId(menuId); +// sysRoleMenu.setRoleId(role.getRoleId()); +// sysRoleMenus.add(sysRoleMenu); +// } +// sysRoleMenuMapper.batchRoleMenu(sysRoleMenus); + return AjaxResult.success(); + } + + + @ApiOperation("角色详情") + @GetMapping("/roleInfo/{id}") + public AjaxResult roleInfo( + @ApiParam(value = "角色id", name = "id", required = true) @PathVariable("id") Long id) + { + SysRole role = roleService.selectRoleById(id); + RoleInfoVo roleInfoVo = new RoleInfoVo(); + roleInfoVo.setRoleId(role.getRoleId()); + roleInfoVo.setRoleName(role.getRoleName()); + // 获取当前角色的菜单id + List<Long> menusId = sysRoleMenuMapper.selectList(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, id)).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); + if(menusId.size()==0){ + return AjaxResult.success(new ArrayList<>()); + } + //获取当前的权限菜单 + List<SysMenus> all = menuMapper.getAllInIds(menusId); + // 第三级 + List<SysMenus> s3 = all.stream().filter(e -> e.getMenuType().equals("F")).collect(Collectors.toList()); + // 第二级 + List<SysMenus> s2 = all.stream().filter(e -> e.getMenuType().equals("C")).collect(Collectors.toList()); + // 第一级 + List<SysMenus> s1 = all.stream().filter(e -> e.getMenuType().equals("M")).collect(Collectors.toList()); + + for (SysMenus menus : s2) { + List<SysMenus> collect = s3.stream().filter(e -> e.getParentId().equals(menus.getMenuId())).collect(Collectors.toList()); + menus.setChildren(collect); + } + + for (SysMenus menus : s1) { + List<SysMenus> collect = s2.stream().filter(e -> e.getParentId().equals(menus.getMenuId())).collect(Collectors.toList()); + menus.setChildren(collect); + } + + roleInfoVo.setMenus(menusId); + return AjaxResult.success(roleInfoVo); + } + + + @ApiOperation("用户获取权限菜单") + @GetMapping("/roleInfoFromUserId") + public AjaxResult roleInfoFromUserId( @RequestParam Long userId) + { + SysUserRole one = sysUserRoleService.getOne(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId)); + if (Objects.isNull(one)) { + return AjaxResult.success(); + } + Long id =one.getRoleId(); + // 获取当前角色的菜单id + List<Long> menusId = sysRoleMenuMapper.selectList(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, id)).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); + if(menusId.size()==0){ + return AjaxResult.success(new ArrayList<>()); + } + //获取当前的权限菜单 + List<SysMenus> allUser = menuMapper.getAllInIds(menusId); + // 查询所有权限菜单 + List<SysMenus> all = menuMapper.getAll(); + // 创建一个Map来存储all集合中的menuId + Map<Long, Boolean> menuIdExistMap = allUser.stream() + .collect(Collectors.toMap(SysMenus::getMenuId, aMenu -> true, + (oldValue, newValue) -> oldValue)); + + // 遍历allUser集合,根据menuIdExistMap来设置isHave值 + for (SysMenus allMenu : all) { + allMenu.setIsHave(menuIdExistMap.containsKey(allMenu.getMenuId()) ? 1 : 2); + } + + // 第三级 + List<SysMenus> s3 = all.stream().filter(e -> e.getMenuType().equals("F")).collect(Collectors.toList()); + // 第二级 + List<SysMenus> s2 = all.stream().filter(e -> e.getMenuType().equals("C")).collect(Collectors.toList()); + // 第一级 + List<SysMenus> s1 = all.stream().filter(e -> e.getMenuType().equals("M")).collect(Collectors.toList()); + + for (SysMenus menus : s2) { + List<SysMenus> collect = s3.stream().filter(e -> e.getParentId().equals(menus.getMenuId())).collect(Collectors.toList()); + menus.setChildren(collect); + } + + for (SysMenus menus : s1) { + List<SysMenus> collect = s2.stream().filter(e -> e.getParentId().equals(menus.getMenuId())).collect(Collectors.toList()); + menus.setChildren(collect); + } + + return AjaxResult.success(s1); + } + + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @ApiOperation("编辑角色") + @PostMapping("/roleUpdate") + public AjaxResult roleUpdate(@Validated @RequestBody RoleUpdateDto dto) + { + SysRole role = new SysRole(); + role.setRoleName(dto.getRoleName()); + SysRole one = roleService.getOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleId, dto.getRoleId())); + List<SysRole> sysRoles = roleService.isExitUpdate(dto.getRoleName(), dto.getRoleId()); + if(sysRoles.size()>0){ + return AjaxResult.error("角色已存在,请重新输入"); + } + // 编辑角色 + role.setUpdateBy(SecurityUtils.getUsername()); + role.setUpdateTime(new Date()); + role.setRoleId(dto.getRoleId()); + roleService.updateRole(role); + ArrayList<SysRoleMenu> sysRoleMenus = new ArrayList<>(); + List<Long> menuIds = dto.getMenuIds(); + // 移除原来的权限菜单 + if(menuIds.contains(1061L)){ + sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>() + .eq(SysRoleMenu::getRoleId,dto.getRoleId())); + }else { + sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>() + .eq(SysRoleMenu::getRoleId,dto.getRoleId()) + .ne(SysRoleMenu::getMenuId,1061L) + .ne(SysRoleMenu::getMenuId,1062L) + .ne(SysRoleMenu::getMenuId,1065L) + .ne(SysRoleMenu::getMenuId,1073L) + .ne(SysRoleMenu::getMenuId,1161L) + .ne(SysRoleMenu::getMenuId,1203L) + ); + } + for (Long menuId : menuIds) { + SysRoleMenu sysRoleMenu = new SysRoleMenu(); + sysRoleMenu.setMenuId(menuId); + sysRoleMenu.setRoleId(role.getRoleId()); + sysRoleMenus.add(sysRoleMenu); + } + sysRoleMenuMapper.batchRoleMenu(sysRoleMenus); + return AjaxResult.success(); + } + + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @ApiOperation("删除角色") + @DeleteMapping("/del/{id}") + public AjaxResult removeRole( + @ApiParam(name = "id", value = "角色ID", required = true) @PathVariable Long id) { + roleService.removeRole(id); + return AjaxResult.success(); + } + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:role:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysRole role) + { + List<SysRole> list = roleService.selectRoleList(role); + ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class); + util.exportExcel(response, list, "角色数据"); + } + + /** + * 根据角色编号获取详细信息 + */ + @RequiresPermissions("system:role:query") + @GetMapping(value = "/{roleId}") + public AjaxResult getInfo(@PathVariable Long roleId) + { + roleService.checkRoleDataScope(roleId); + return success(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @RequiresPermissions("system:role:add") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysRole role) + { + if (!roleService.checkRoleNameUnique(role)) + { + return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } + else if (!roleService.checkRoleKeyUnique(role)) + { + return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setCreateBy(SecurityUtils.getUsername()); + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改保存角色 + */ + @RequiresPermissions("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) + { + return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } + else if (!roleService.checkRoleKeyUnique(role)) + { + return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(roleService.updateRole(role)); + } + + /** + * 修改保存数据权限 + */ + @RequiresPermissions("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public AjaxResult dataScope(@RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @RequiresPermissions("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(SecurityUtils.getUsername()); + return toAjax(roleService.updateRoleStatus(role)); + } + + /** + * 删除角色 + */ + @RequiresPermissions("system:role:remove") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public AjaxResult remove(@PathVariable Long[] roleIds) + { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + + + /** + * 停用角色 + */ + @RequiresPermissions("system:role:stop") + @Log(title = "角色管理", businessType = BusinessType.STOP) + @PutMapping("/stop") + public AjaxResult stop(@RequestBody Long roleId) + { + SysRole sysRole = roleService.selectRoleById(roleId); + if(sysRole.getStatus().equals("0")){ + sysRole.setStatus("1"); + }else { + sysRole.setStatus("0"); + } + return toAjax(roleService.updateRole(sysRole)); + } + + /** + * 获取角色选择框列表 + */ + @RequiresPermissions("system:role:query") + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + return success(roleService.selectRoleAll()); + } + /** + * 查询已分配用户角色列表 + */ + @RequiresPermissions("system:role:list") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user) + { + startPage(); + List<SysUser> list = userService.selectAllocatedList(user); + return getDataTable(list); + } + + /** + * 查询未分配用户角色列表 + */ + @RequiresPermissions("system:role:list") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user) + { + startPage(); + List<SysUser> list = userService.selectUnallocatedList(user); + return getDataTable(list); + } + + /** + * 取消授权用户 + */ + @RequiresPermissions("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) + { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + */ + @RequiresPermissions("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) + { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + */ + @RequiresPermissions("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) + { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + */ + @RequiresPermissions("system:role:query") + @GetMapping(value = "/deptTree/{roleId}") + public AjaxResult deptTree(@PathVariable("roleId") Long roleId) + { + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); + ajax.put("depts", deptService.selectDeptTreeList(new SysDept())); + return ajax; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java new file mode 100644 index 0000000..b9e6e5d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java @@ -0,0 +1,586 @@ +package com.ruoyi.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.page.BeanUtils; +import com.ruoyi.common.core.utils.page.PageDTO; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.PageInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.InnerAuth; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysDept; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.api.model.LoginUser; +import com.ruoyi.system.api.validate.InsertGroup; +import com.ruoyi.system.api.validate.UpdateGroup; +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.domain.dto.ResetPwdDTO; +import com.ruoyi.system.domain.dto.SupplierDTO; +import com.ruoyi.system.domain.dto.SupplierQuery; +import com.ruoyi.system.domain.dto.SysUserDTO; +import com.ruoyi.system.domain.dto.SysUserQuery; +import com.ruoyi.system.domain.vo.SupplierVO; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysDeptService; +import com.ruoyi.system.service.ISysPermissionService; +import com.ruoyi.system.service.ISysPostService; +import com.ruoyi.system.service.ISysRoleService; +import com.ruoyi.system.service.ISysUserRoleService; +import com.ruoyi.system.service.ISysUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import java.io.IOException; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +/** + * 用户信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/user") +@Api(tags = "用户信息") +public class SysUserController extends BaseController { + @Autowired + private ISysUserService userService; + + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysDeptService deptService; + + @Autowired + private ISysPostService postService; + + @Autowired + private ISysPermissionService permissionService; + + @Autowired + private ISysConfigService configService; + + + @Autowired + private ISysUserRoleService userRoleService; + + @Autowired + private ISysUserRoleService sysUserRoleService; + /** + * 获取用户列表 + */ + @PostMapping("/list") + @ApiOperation("账号管理列表") + public AjaxResult list(@Validated @RequestBody SysUserQuery query) { + PageInfo<SysUser> pageInfo = new PageInfo<>(query.getPageCurr(), query.getPageSize()); + PageInfo<SysUser> page = userService.getList(pageInfo, query.getNickName(), + query.getPhonenumber(), query.getStatus()); + return AjaxResult.success(page); + } + + /** + * 新增用户 + */ + @Log(title = "账号管理", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ApiOperation("添加账号") + @Transactional(rollbackFor = Exception.class) + public AjaxResult add(@Validated(InsertGroup.class) @RequestBody SysUserDTO dto) { + SysUser user = BeanUtils.copyBean(dto, SysUser.class); + user.setUserId(null); + user.setUserType(dto.getIsAuctioneer() == 1 ? "04" : "00"); + user.setUserName(user.getPhonenumber()); + if(!org.springframework.util.StringUtils.hasLength(user.getNickName())){ + user.setNickName(user.getPhonenumber()); + } + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return error("手机号已开通账号"); + } + user.setCreateBy(SecurityUtils.getUsername()); + user.setPassword(SecurityUtils.encryptPassword("123456")); + user.setRoleType(1); + int i = userService.insertUser(user); + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setRoleId(dto.getRoleId()); + sysUserRole.setUserId(user.getUserId()); + int i1 = userRoleService.insertSysUserRole(sysUserRole); + return AjaxResult.success(); + } + + + /** + * 根据用户编号获取详细信息 + */ + @ApiOperation("账号详情") + @GetMapping("/{userId}") + public AjaxResult getInfo( + @ApiParam(value = "用户ID", required = true) @PathVariable(value = "userId", required = true) Long userId) { + userService.checkUserDataScope(userId); + AjaxResult ajax = AjaxResult.success(); + List<SysRole> roles = roleService.selectRoleAll(); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + ajax.put("posts", postService.selectPostAll()); + if (StringUtils.isNotNull(userId)) { + SysUser sysUser = userService.selectUserById(userId); + ajax.put(AjaxResult.DATA_TAG, sysUser); + ajax.put("postIds", postService.selectPostListByUserId(userId)); + ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); + } + return AjaxResult.success(ajax); + } + + + /** + * 修改用户 + */ + @Log(title = "账号管理", businessType = BusinessType.UPDATE) + @PutMapping("/update") + @ApiOperation("编辑账号") + public AjaxResult edit(@Validated(UpdateGroup.class) @RequestBody SysUserDTO dto) { + SysUser user = BeanUtils.copyBean(dto, SysUser.class); + user.setUserName(user.getPhonenumber()); + if(!org.springframework.util.StringUtils.hasLength(user.getNickName())){ + user.setNickName(user.getPhonenumber()); + } + R<Integer> admin = this.isAdmin(user.getUserId()); + Integer data = admin.getData(); + if(data == null || data != 1){ + SysUserRole one = sysUserRoleService.getOne(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, user.getUserId())); + one.setRoleId(dto.getRoleId()); + sysUserRoleService.updateSysUserRole(one); + } + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + SysUser sysUser = userService.getOne(Wrappers.lambdaQuery(SysUser.class) + .eq(SysUser::getPhonenumber, user.getPhonenumber()) + .eq(SysUser::getDelFlag,0) + .last("LIMIT 1")); + + if (StringUtils.isNotEmpty(user.getPhonenumber()) && (Objects.nonNull(sysUser) && !user.getUserId().equals(sysUser.getUserId()) )) { + return error("手机号已开通账号"); + } + user.setUpdateBy(SecurityUtils.getUsername()); + if (user.getPassword() != null && !"".equals(user.getPassword())) { + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + user.setPassWordUpdate(new Date()); + } + if (user.getPhonenumber() != null) { + user.setUserName(user.getPhonenumber()); + } + user.setPassword(null); + user.setUpdateBy(SecurityUtils.getUsername()); + user.setUpdateTime(new Date()); + return toAjax(userService.updateUser(user)); + } + + + /** + * 删除用户 + */ + @Log(title = "账号管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + @ApiOperation("删除账号") + public AjaxResult remove(@PathVariable Long[] userIds) { + if (ArrayUtils.contains(userIds, SecurityUtils.getUserId())) { + return error("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + @PostMapping("/updStatus/{userId}") + @ApiOperation("账号管理--冻结/解冻") + public AjaxResult updStatus( + @ApiParam(value = "账号ID", required = true) @PathVariable("userId") Long userId) { + if (userId == null) { + return AjaxResult.error("userId不能为空"); + } + SysUser sysUser = userService.selectUserById(userId); + if (sysUser.getStatus().equals("0")) { + sysUser.setStatus("1"); + } else { + sysUser.setStatus("0"); + } + return toAjax(userService.updateUser(sysUser)); + } + + + @Autowired + private ISysUserRoleService iSysUserRoleService; + + @PostMapping("/getUserList") + public R<List<SysUser>> getUserList(@RequestBody List<Integer> userIds) { + List<SysUser> list = userService.list(new LambdaQueryWrapper<SysUser>().in(SysUser::getUserId, userIds)); + return R.ok(list); + } + + + @PostMapping("/isAdmin") + public R<Integer> isAdmin(@RequestBody Long userId){ + SysUserRole one = sysUserRoleService.getOne(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId)); + Long id =one.getRoleId(); + return R.ok(id.intValue()); + } + + @PostMapping("/getSysUser") + public R<SysUser> getSysUser(@RequestBody Long userId) { + try { + SysUser sysUser = userService.selectUserById(userId); + return R.ok(sysUser); + } catch (Exception e) { + e.printStackTrace(); + return R.ok(); + } + } + + @PostMapping("/updateSysUser") + public R<Boolean> updateSysUser(@RequestBody SysUser sysUser) { + try { + sysUser.setUpdateBy(SecurityUtils.getUsername()); + sysUser.setUpdateTime(new Date()); + userService.updateUser(sysUser); + return R.ok(true); + } catch (Exception e) { + e.printStackTrace(); + return R.ok(); + } + } + + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @RequiresPermissions("system:user:export") + @PostMapping("/export") + public void export(HttpServletResponse response, SysUser user) { + List<SysUser> list = userService.selectUserList(user); + ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); + util.exportExcel(response, list, "用户数据"); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) throws IOException { + ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); + util.importTemplateExcel(response, "用户数据"); + } + + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @RequiresPermissions("system:user:import") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); + List<SysUser> userList = util.importExcel(file.getInputStream()); + String operName = SecurityUtils.getUsername(); + String message = userService.importUser(userList, updateSupport, operName); + return success(message); + } + + /** + * 获取当前用户信息 + */ + @InnerAuth + @GetMapping("/info/{username}") + public R<LoginUser> info(@PathVariable("username") String username) { + SysUser sysUser = userService.selectUserByUserName(username); + if (StringUtils.isNull(sysUser)) { + return R.fail("用户名或密码错误"); + } + LoginUser sysUserVo = new LoginUser(); + sysUserVo.setSysUser(sysUser); + if (sysUser.getUserType().equals("00")) { + // 角色集合 + Set<String> roles = permissionService.getRolePermission(sysUser); + // 权限集合 + Set<String> permissions = permissionService.getMenuPermission(sysUser); + sysUserVo.setRoles(roles); + sysUserVo.setPermissions(permissions); + } + return R.ok(sysUserVo); + } + + /** + * 注册用户信息 + */ + @InnerAuth + @PostMapping("/register") + public R<SysUser> register(@RequestBody SysUser sysUser) { + String username = sysUser.getUserName(); + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { + return R.fail("当前系统没有开启注册功能!"); + } + if (!userService.checkUserNameUnique(sysUser)) { + return R.fail("保存用户'" + username + "'失败,注册账号已存在"); + } + return R.ok(userService.registerUser(sysUser)); + } + + @PostMapping("/registerUser") + public R<SysUser> registerUser(@RequestBody SysUser sysUser){ + sysUser = userService.registerUser(sysUser); + return R.ok(sysUser); + } + + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("/getInfo") + public AjaxResult getInfo() { + SysUser user = userService.selectUserById(SecurityUtils.getUserId()); + // 角色集合 + Set<String> roles = permissionService.getRolePermission(user); + // 权限集合 + Set<String> permissions = permissionService.getMenuPermission(user); + AjaxResult ajax = AjaxResult.success(); + ajax.put("user", user); + ajax.put("roles", roles); + ajax.put("permissions", permissions); + return ajax; + } + + + /** + * 重置密码 + */ + @RequiresPermissions("system:user:edit") + @ApiOperation("重置密码") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PostMapping("/resetPwd") + public AjaxResult resetPwd(@RequestBody ResetPwdDTO dto) { + SysUser user = userService.lambdaQuery().eq(SysUser::getUserId, dto.getUserId()) + .in(SysUser::getUserType, "00", "01").one(); + if (StringUtils.isNull(user)) { + throw new ServiceException("账号不存在"); + } + + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(SecurityUtils.encryptPassword(dto.getPassword())); + user.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(userService.resetPwd(user)); + } + + /** + * 获取当前用户信息 + */ + @InnerAuth + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/change-password") + public R<LoginUser> info(@RequestParam("username") String username, + @RequestParam("password") String password) { + SysUser user = userService.selectUserByUserName(username); + user.setPassword(password); + user.setUpdateBy(SecurityUtils.getUsername()); + int i = userService.updateUser(user); + if (i == 1) { + return R.ok(); + } else { + return R.fail(); + } + } + /** + * 状态修改 + */ + @RequiresPermissions("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(SecurityUtils.getUsername()); + return toAjax(userService.updateUserStatus(user)); + } + + /** + * 根据用户编号获取授权角色 + */ + @RequiresPermissions("system:user:query") + @GetMapping("/authRole/{userId}") + public AjaxResult authRole(@PathVariable("userId") Long userId) { + AjaxResult ajax = AjaxResult.success(); + SysUser user = userService.selectUserById(userId); + List<SysRole> roles = roleService.selectRolesByUserId(userId); + ajax.put("user", user); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + return ajax; + } + + /** + * 用户授权角色 + */ + @RequiresPermissions("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return success(); + } + + /** + * 获取部门树列表 + */ + @RequiresPermissions("system:user:list") + @GetMapping("/deptTree") + public AjaxResult deptTree(SysDept dept) { + return success(deptService.selectDeptTreeList(dept)); + } + + @PostMapping("/updateUser") + public R<Boolean> updateUser(@RequestBody SysUser sysUser){ + return R.ok(userService.updateById(sysUser)); + } + + /** + * 通过用户id查询角色对象 + * @param userId + * @return + */ + @GetMapping("/queryRoleByUserId/{userId}") + public R<SysRole> queryRoleByUserId(@PathVariable("userId") Long userId){ + SysUserRole one = sysUserRoleService.getOne(Wrappers.lambdaQuery(SysUserRole.class) + .eq(SysUserRole::getUserId, userId) + .last("LIMIT 1")); + System.out.println("通过用户id查询角色对象"+one); + if(Objects.nonNull(one)){ + SysRole byId = roleService.getOne(Wrappers.lambdaQuery(SysRole.class) + .eq(SysRole::getRoleId,one.getRoleId()) + .last("LIMIT 1")); + return R.ok(byId); + } + return R.ok(); + } + + + @GetMapping("/queryRoleByRoleId/{roleId}") + public R<SysRole> queryRoleByRoleId(@PathVariable("roleId") Long roleId){ + return R.ok( roleService.getOne(Wrappers.lambdaQuery(SysRole.class) + .eq(SysRole::getRoleId, roleId) + .last("LIMIT 1"))); + } + + /** + * 通过手机号集合查询用户 + * @param phoneList + * @return + */ + @PostMapping("/queryUserByPhoneList") + public R<List<SysUser>> queryUserByPhoneList(@RequestBody List<String> phoneList){ + List<SysUser> list = userService.list(Wrappers.lambdaQuery(SysUser.class) + .in(SysUser::getPhonenumber, phoneList) + .ne(SysUser::getDelFlag,2)); + return R.ok(list); + } + + /** + * 通过手机号查询用户 + * @param phone + * @return + */ + @PostMapping("/queryUserByPhone") + public R<SysUser> queryUserByPhone(@RequestBody String phone){ + SysUser user = userService.getOne(Wrappers.lambdaQuery(SysUser.class) + .eq(SysUser::getPhonenumber, phone) + .last("LIMIT 1")); + return R.ok(user); + } + +// @PostMapping("/queryUserByPhone1") +// public R<SysUser> queryUserByPhone1(@RequestBody String phone){ +// SysUser user = userService.getOne(Wrappers.lambdaQuery(SysUser.class) +// .eq(SysUser::getPhonenumber, phone) +// .eq(SysUser::get, phone) +// .last("LIMIT 1")); +// return R.ok(user); +// } + + + /** + * 通过账号查询用户 + * @param userName + * @return + */ + @PostMapping("/queryUserByUserName") + public R<SysUser> queryUserByUserName(@RequestBody String userName){ + SysUser user = userService.getOne(Wrappers.lambdaQuery(SysUser.class) + .eq(SysUser::getUserName, userName) + .last("LIMIT 1")); + return R.ok(user); + } + + /** + * 获取供应商分页列表 + * + * @param query 供应商列表查询数据传输对象 + * @return PageDTO<SupplyUserVO> + */ + @ApiOperation(value = "获取供应商分页列表", notes = "获取供应商分页列表") + @PostMapping("/supplier-page") + public R<PageDTO<SupplierVO>> getSupplierPage(@Validated @RequestBody SupplierQuery query) { + return R.ok(userService.getSupplierPage(query)); + } + + /** + * 添加/编辑供应商 + * + * @param dto 供应商数据传输对象 + */ + @Log(title = "供应商管理", businessType = BusinessType.UPDATE) + @ApiOperation(value = "添加/编辑供应商", notes = "添加/编辑供应商") + @PostMapping("/save-supplier") + public R<?> saveSupplier(@Validated @RequestBody SupplierDTO dto) { + userService.saveSupplier(dto); + return R.ok(); + } + + /** + * 删除供应商 + * + * @param id 供应商id + */ + @ApiOperation(value = "删除供应商", notes = "删除供应商") + @DeleteMapping("/delete-supplier/{id}") + public R<?> deleteSupplier(@PathVariable("id") Long id) { + userService.deleteSupplier(id); + return R.ok(); + } + + @InnerAuth + @GetMapping("/list-by-name") + R<List<SysUser>> getUserListByName(@RequestBody SysUser sysUser) { + List<SysUser> list = userService.lambdaQuery() + .like(StringUtils.isNotBlank(sysUser.getNickName()), SysUser::getNickName, + sysUser.getNickName()) + .like(StringUtils.isNotBlank(sysUser.getPhonenumber()), SysUser::getPhonenumber, + sysUser.getPhonenumber()) + .eq(SysUser::getUserType, "00") + .eq(SysUser::getDelFlag, 0).list(); + return R.ok(list); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java new file mode 100644 index 0000000..cae521a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java @@ -0,0 +1,84 @@ +package com.ruoyi.system.controller; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import com.ruoyi.system.domain.SysUserOnline; +import org.springframework.beans.factory.annotation.Autowired; +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.utils.StringUtils; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.web.page.TableDataInfo; +import com.ruoyi.common.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.system.api.model.LoginUser; +import com.ruoyi.system.service.ISysUserOnlineService; + +/** + * 在线用户监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/online") +public class SysUserOnlineController extends BaseController +{ + @Autowired + private ISysUserOnlineService userOnlineService; + + @Autowired + private RedisService redisService; + + @RequiresPermissions("monitor:online:list") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) + { + Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*"); + List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>(); + for (String key : keys) + { + LoginUser user = redisService.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)) + { + userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); + } + else + { + userOnlineList.add(userOnlineService.loginUserToUserOnline(user)); + } + } + Collections.reverse(userOnlineList); + userOnlineList.removeAll(Collections.singleton(null)); + return getDataTable(userOnlineList); + } + + /** + * 强退用户 + */ + @RequiresPermissions("monitor:online:forceLogout") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public AjaxResult forceLogout(@PathVariable String tokenId) + { + redisService.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId); + return success(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserRoleController.java new file mode 100644 index 0000000..25ac609 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserRoleController.java @@ -0,0 +1,106 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.service.ISysUserRoleService; +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.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +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.log.annotation.Log; +import com.ruoyi.common.log.enums.BusinessType; +import com.ruoyi.common.security.annotation.RequiresPermissions; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.AjaxResult; +import com.ruoyi.common.core.utils.poi.ExcelUtil; +import com.ruoyi.common.core.web.page.TableDataInfo; + +/** + * 用户和角色关联Controller + * + * @author xiaochen + * @date 2023-06-12 + */ +@RestController +@RequestMapping("/userRole") +public class SysUserRoleController extends BaseController +{ + @Autowired + private ISysUserRoleService sysUserRoleService; + + /** + * 查询用户和角色关联列表 + */ + @RequiresPermissions("car:role:list") + @GetMapping("/list") + public TableDataInfo list(SysUserRole sysUserRole) + { + startPage(); + List<SysUserRole> list = sysUserRoleService.selectSysUserRoleList(sysUserRole); + return getDataTable(list); + } + + /** + * 导出用户和角色关联列表 + */ + @RequiresPermissions("car:role:export") + @Log(title = "用户和角色关联", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysUserRole sysUserRole) + { + List<SysUserRole> list = sysUserRoleService.selectSysUserRoleList(sysUserRole); + ExcelUtil<SysUserRole> util = new ExcelUtil<SysUserRole>(SysUserRole.class); + util.exportExcel(response, list, "用户和角色关联数据"); + } + + /** + * 获取用户和角色关联详细信息 + */ + @RequiresPermissions("car:role:query") + @GetMapping(value = "/{userId}") + public AjaxResult getInfo(@PathVariable("userId") Long userId) + { + return success(sysUserRoleService.selectSysUserRoleByUserId(userId)); + } + + /** + * 新增用户和角色关联 + */ + @RequiresPermissions("car:role:add") + @Log(title = "用户和角色关联", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysUserRole sysUserRole) + { + return toAjax(sysUserRoleService.insertSysUserRole(sysUserRole)); + } + + /** + * 修改用户和角色关联 + */ + @RequiresPermissions("car:role:edit") + @Log(title = "用户和角色关联", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysUserRole sysUserRole) + { + return toAjax(sysUserRoleService.updateSysUserRole(sysUserRole)); + } + + /** + * 删除用户和角色关联 + */ + @RequiresPermissions("car:role:remove") + @Log(title = "用户和角色关联", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public AjaxResult remove(@PathVariable Long[] userIds) + { + return toAjax(sysUserRoleService.deleteSysUserRoleByUserIds(userIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/WebSocketController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/WebSocketController.java new file mode 100644 index 0000000..8a721a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/WebSocketController.java @@ -0,0 +1,43 @@ +package com.ruoyi.system.controller; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.security.annotation.InnerAuth; +import com.ruoyi.system.api.domain.WebsocketMessageDTO; +import com.ruoyi.system.websocket.WebSocketUsers; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/websocket") +public class WebSocketController { + + @GetMapping("/push") + public R<?> push() { + WebSocketUsers.sendMessageToUsersByText("长江长江,我是黄河!"); + return R.ok(); + } + + @GetMapping("/push/{type}/{msg}") + public R<?> push(@PathVariable("type") Integer type, @PathVariable("msg") String msg) { + WebSocketUsers.sendMessageToUsersByType(type, msg); + return R.ok(); + } + + @InnerAuth + @PostMapping("/push-by-client-type") + public R<?> pushByClientType(@RequestBody WebsocketMessageDTO dto) { + WebSocketUsers.sendMessageToUsersByType(dto.getClientType().getCode(), dto.getMessage()); + return R.ok(); + } + + @InnerAuth + @GetMapping("/push-all/{message}") + public R<?> pushAll(@PathVariable("message") String message) { + WebSocketUsers.sendMessageToUsersByText(message); + return R.ok(); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Agreement.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Agreement.java new file mode 100644 index 0000000..6829b9c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/Agreement.java @@ -0,0 +1,64 @@ +package com.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import java.time.LocalDateTime; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * <p> + * + * </p> + * + * @author mitao + * @since 2024-05-21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_agreement") +@ApiModel(value = "Agreement对象", description = "") +public class Agreement implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty(value = "协议类型 1=用户协议 2=隐私协议") + @TableField(value = "agreement_type") + private Integer agreementType; + + @ApiModelProperty(value = "协议内容") + @TableField(value = "agreement_content") + private String agreementContent; + + @ApiModelProperty(value = "创建者") + @TableField(value = "create_by") + private String createBy; + + @ApiModelProperty(value = "创建时间") + @TableField(value = "create_time") + private LocalDateTime createTime; + + @ApiModelProperty(value = "更新者") + @TableField(value = "update_by") + private String updateBy; + + @ApiModelProperty(value = "更新时间") + @TableField(value = "update_time") + private LocalDateTime updateTime; + + @ApiModelProperty(value = "删除标志(0代表存在 1代表删除)") + @TableField(value = "del_flag") + private Integer delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java new file mode 100644 index 0000000..5fe3f11 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java @@ -0,0 +1,270 @@ +package com.ruoyi.system.domain; + +import java.util.ArrayList; +import java.util.List; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.baomidou.mybatisplus.annotation.TableField; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.core.web.domain.BaseEntity; + +/** + * 菜单权限表 sys_menu + * + * @author ruoyi + */ +public class SysMenu extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 菜单ID */ + @TableField("menu_id") + private Long menuId; + + /** 菜单名称 */ + @TableField("menu_name") + private String menuName; + + /** 父菜单名称 */ + @TableField(exist = false) + private String parentName; + + /** 父菜单ID */ + @TableField("parent_id") + private Long parentId; + + /** 显示顺序 */ + @TableField("order_num") + private Integer orderNum; + + /** 路由地址 */ + private String path; + + /** 组件路径 */ + private String component; + + /** 路由参数 */ + private String query; + + /** 是否为外链(0是 1否) */ + @TableField("is_frame") + private String isFrame; + + /** 是否缓存(0缓存 1不缓存) */ + @TableField("is_cache") + private String isCache; + + /** 类型(M目录 C菜单 F按钮) */ + @TableField("menu_type") + private String menuType; + + /** 显示状态(0显示 1隐藏) */ + private String visible; + + /** 菜单状态(0正常 1停用) */ + private String status; + + /** 权限字符串 */ + private String perms; + + /** 菜单图标 */ + private String icon; + + /** 子菜单 */ + @TableField(exist = false) + private List<SysMenu> children = new ArrayList<SysMenu>(); + + public Long getMenuId() + { + return menuId; + } + + public void setMenuId(Long menuId) + { + this.menuId = menuId; + } + + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符") + public String getMenuName() + { + return menuName; + } + + public void setMenuName(String menuName) + { + this.menuName = menuName; + } + + public String getParentName() + { + return parentName; + } + + public void setParentName(String parentName) + { + this.parentName = parentName; + } + + public Long getParentId() + { + return parentId; + } + + public void setParentId(Long parentId) + { + this.parentId = parentId; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getOrderNum() + { + return orderNum; + } + + public void setOrderNum(Integer orderNum) + { + this.orderNum = orderNum; + } + + @Size(min = 0, max = 200, message = "路由地址不能超过200个字符") + public String getPath() + { + return path; + } + + public void setPath(String path) + { + this.path = path; + } + + @Size(min = 0, max = 200, message = "组件路径不能超过255个字符") + public String getComponent() + { + return component; + } + + public void setComponent(String component) + { + this.component = component; + } + + public String getQuery() + { + return query; + } + + public void setQuery(String query) + { + this.query = query; + } + + public String getIsFrame() + { + return isFrame; + } + + public void setIsFrame(String isFrame) + { + this.isFrame = isFrame; + } + + public String getIsCache() + { + return isCache; + } + + public void setIsCache(String isCache) + { + this.isCache = isCache; + } + + @NotBlank(message = "菜单类型不能为空") + public String getMenuType() + { + return menuType; + } + + public void setMenuType(String menuType) + { + this.menuType = menuType; + } + + public String getVisible() + { + return visible; + } + + public void setVisible(String visible) + { + this.visible = visible; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") + public String getPerms() + { + return perms; + } + + public void setPerms(String perms) + { + this.perms = perms; + } + + public String getIcon() + { + return icon; + } + + public void setIcon(String icon) + { + this.icon = icon; + } + + public List<SysMenu> getChildren() + { + return children; + } + + public void setChildren(List<SysMenu> children) + { + this.children = children; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("menuId", getMenuId()) + .append("menuName", getMenuName()) + .append("parentId", getParentId()) + .append("orderNum", getOrderNum()) + .append("path", getPath()) + .append("component", getComponent()) + .append("isFrame", getIsFrame()) + .append("IsCache", getIsCache()) + .append("menuType", getMenuType()) + .append("visible", getVisible()) + .append("status ", getStatus()) + .append("perms", getPerms()) + .append("icon", getIcon()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenus.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenus.java new file mode 100644 index 0000000..cc611d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenus.java @@ -0,0 +1,109 @@ +package com.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 菜单权限表 sys_menu + * + * @author ruoyi + */ +@Data +public class SysMenus extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 菜单ID */ + @TableField("menu_id") + private Long menuId; + + /** 菜单名称 */ + @TableField("menu_name") + private String menuName; + + /** 父菜单名称 */ + @TableField(exist = false) + private String parentName; + + /** 父菜单ID */ + @TableField("parent_id") + private Long parentId; + + /** 显示顺序 */ + @TableField("order_num") + private Integer orderNum; + + /** 路由地址 */ + private String path; + + /** 组件路径 */ + private String component; + + /** 路由参数 */ + private String query; + + /** 是否为外链(0是 1否) */ + @TableField("is_frame") + private String isFrame; + + /** 是否缓存(0缓存 1不缓存) */ + @TableField("is_cache") + private String isCache; + + /** 类型(M目录 C菜单 F按钮) */ + @TableField("menu_type") + private String menuType; + + /** 显示状态(0显示 1隐藏) */ + private String visible; + + /** 菜单状态(0正常 1停用) */ + private Boolean status=false; + + /** 权限字符串 */ + private String perms; + + /** 菜单图标 */ + private String icon; + @TableField("create_by") + private String createBy; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @TableField("create_time") + private Date createTime; + + /** 更新者 */ + @ApiModelProperty(value = "记录修改人,前端忽略") + //@JsonIgnore + @TableField("update_by") + private String updateBy; + + /** 更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @TableField("update_time") + private Date updateTime; + + /** 备注 */ + private String remark; + + /** 子菜单 */ + @TableField(exist = false) + private List<SysMenus> children = new ArrayList<SysMenus>(); + + @ApiModelProperty("1 拥有 2未拥有") + private Integer isHave; + +} 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 new file mode 100644 index 0000000..e3ce821 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java @@ -0,0 +1,117 @@ +package com.ruoyi.system.domain; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +import com.ruoyi.common.core.annotation.Excel; +import com.ruoyi.common.core.web.domain.BaseModel; +import io.swagger.annotations.ApiModelProperty; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.core.web.domain.BaseEntity; +import com.ruoyi.common.core.xss.Xss; + +/** + * 通知公告表 sys_notice + * + * @author ruoyi + */ +public class SysNotice extends BaseModel +{ + 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; + + public Long getNoticeId() + { + return noticeId; + } + + public void setNoticeId(Long noticeId) + { + this.noticeId = noticeId; + } + + public void setNoticeTitle(String noticeTitle) + { + this.noticeTitle = noticeTitle; + } + + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过50个字符") + public String getNoticeTitle() + { + return noticeTitle; + } + + public void setNoticeType(String noticeType) + { + this.noticeType = noticeType; + } + + public String getNoticeType() + { + return noticeType; + } + + public void setNoticeContent(String noticeContent) + { + this.noticeContent = noticeContent; + } + + public String getNoticeContent() + { + return noticeContent; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getStatus() + { + return status; + } + @ApiModelProperty(value = "备注说明") + @Excel(name = "备注说明") + private String remark; + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("noticeId", getNoticeId()) + .append("noticeTitle", getNoticeTitle()) + .append("noticeType", getNoticeType()) + .append("noticeContent", getNoticeContent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} 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 new file mode 100644 index 0000000..f93ca99 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java @@ -0,0 +1,138 @@ +package com.ruoyi.system.domain; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.ruoyi.common.core.web.domain.BaseModel; +import io.swagger.annotations.ApiModelProperty; +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.web.domain.BaseEntity; + +/** + * 岗位表 sys_post + * + * @author ruoyi + */ +public class SysPost extends BaseModel +{ + private static final long serialVersionUID = 1L; + + /** 岗位序号 */ + @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC) + private Long postId; + + /** 岗位编码 */ + @Excel(name = "岗位编码") + private String postCode; + + /** 岗位名称 */ + @Excel(name = "岗位名称") + private String postName; + + /** 岗位排序 */ + @Excel(name = "岗位排序") + private Integer postSort; + + /** 状态(0正常 1停用) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=停用") + private String status; + + /** 用户是否存在此岗位标识 默认不存在 */ + private boolean flag = false; + + public Long getPostId() + { + return postId; + } + + public void setPostId(Long postId) + { + this.postId = postId; + } + + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符") + public String getPostCode() + { + return postCode; + } + + public void setPostCode(String postCode) + { + this.postCode = postCode; + } + + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符") + public String getPostName() + { + return postName; + } + + public void setPostName(String postName) + { + this.postName = postName; + } + + @NotNull(message = "显示顺序不能为空") + public Integer getPostSort() + { + return postSort; + } + + public void setPostSort(Integer postSort) + { + this.postSort = postSort; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public boolean isFlag() + { + return flag; + } + + public void setFlag(boolean flag) + { + this.flag = flag; + } + @ApiModelProperty(value = "备注说明") + @Excel(name = "备注说明") + private String remark; + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("postId", getPostId()) + .append("postCode", getPostCode()) + .append("postName", getPostName()) + .append("postSort", getPostSort()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java new file mode 100644 index 0000000..47b21bf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java @@ -0,0 +1,46 @@ +package com.ruoyi.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 角色和部门关联 sys_role_dept + * + * @author ruoyi + */ +public class SysRoleDept +{ + /** 角色ID */ + private Long roleId; + + /** 部门ID */ + private Long deptId; + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("deptId", getDeptId()) + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java new file mode 100644 index 0000000..c7af96f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java @@ -0,0 +1,49 @@ +package com.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author ruoyi + */ +public class SysRoleMenu +{ + /** 角色ID */ + @TableField("role_id") + private Long roleId; + + /** 菜单ID */ + @TableField("menu_id") + private Long menuId; + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + public Long getMenuId() + { + return menuId; + } + + public void setMenuId(Long menuId) + { + this.menuId = menuId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("roleId", getRoleId()) + .append("menuId", getMenuId()) + .toString(); + } +} 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 new file mode 100644 index 0000000..69bac9a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java @@ -0,0 +1,100 @@ +package com.ruoyi.system.domain; + +/** + * 当前在线会话 + * + * @author ruoyi + */ +public class SysUserOnline +{ + /** 会话编号 */ + private String tokenId; + + /** 用户名称 */ + private String userName; + + /** 登录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 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-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java new file mode 100644 index 0000000..6e8c416 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java @@ -0,0 +1,46 @@ +package com.ruoyi.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 用户和岗位关联 sys_user_post + * + * @author ruoyi + */ +public class SysUserPost +{ + /** 用户ID */ + private Long userId; + + /** 岗位ID */ + private Long postId; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getPostId() + { + return postId; + } + + public void setPostId(Long postId) + { + this.postId = postId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("postId", getPostId()) + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java new file mode 100644 index 0000000..0e76368 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java @@ -0,0 +1,49 @@ +package com.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 用户和角色关联 sys_user_role + * + * @author ruoyi + */ +public class SysUserRole +{ + /** 用户ID */ + @TableField("user_id") + private Long userId; + + /** 角色ID */ + @TableField("role_id") + private Long roleId; + + public Long getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public Long getRoleId() + { + return roleId; + } + + public void setRoleId(Long roleId) + { + this.roleId = roleId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("roleId", getRoleId()) + .toString(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/AgreementDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/AgreementDTO.java new file mode 100644 index 0000000..6a739c6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/AgreementDTO.java @@ -0,0 +1,30 @@ +package com.ruoyi.system.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import lombok.Data; + +/** + * @author mitao + * @date 2024/6/18 + */ +@Data +@ApiModel(value = "协议对象") +public class AgreementDTO implements Serializable { + + private static final long serialVersionUID = 7144114465287126540L; + + @ApiModelProperty(value = "协议id") + private Long id; + + @ApiModelProperty(value = "协议类型 1=用户协议 2=隐私协议") + @NotNull(message = "协议类型不能为空") + private Integer agreementType; + + @ApiModelProperty(value = "协议内容") + @NotBlank(message = "协议内容不能为空") + private String agreementContent; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/IndexDto.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/IndexDto.java new file mode 100644 index 0000000..6636482 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/IndexDto.java @@ -0,0 +1,11 @@ +package com.ruoyi.system.domain.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class IndexDto { + private Integer companyId; + private List<Integer> shopIds; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PointsConfigDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PointsConfigDTO.java new file mode 100644 index 0000000..0b693a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PointsConfigDTO.java @@ -0,0 +1,27 @@ +package com.ruoyi.system.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import java.math.BigDecimal; +import javax.validation.constraints.NotNull; +import lombok.Data; + +/** + * @author mitao + * @date 2024/6/11 + */ +@Data +@ApiModel(value = "积分配置数据传输对象", description = "积分配置数据传输对象") +public class PointsConfigDTO implements Serializable { + + private static final long serialVersionUID = 8009805126467325247L; + + @ApiModelProperty(value = "消费金额") + @NotNull(message = "消费金额不能为空") + private BigDecimal consumeAmount; + + @ApiModelProperty(value = "积分") + @NotNull(message = "积分不能为空") + private Integer points; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ResetPwdDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ResetPwdDTO.java new file mode 100644 index 0000000..9e50468 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ResetPwdDTO.java @@ -0,0 +1,27 @@ +package com.ruoyi.system.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import lombok.Data; + +/** + * @author mitao + * @date 2024/6/19 + */ +@Data +@ApiModel("重置密码") +public class ResetPwdDTO implements Serializable { + + private static final long serialVersionUID = -4349599620340762098L; + + @ApiModelProperty(value = "账号id") + @NotNull(message = "账号ID不能为空") + private Long userId; + + @ApiModelProperty(value = "新密码") + @NotBlank(message = "新密码不能为空") + private String password; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleAddDto.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleAddDto.java new file mode 100644 index 0000000..f927794 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleAddDto.java @@ -0,0 +1,24 @@ +package com.ruoyi.system.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import java.util.List; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import lombok.Data; + +@Data +@ApiModel("角色添加数据传输对象") +public class RoleAddDto implements Serializable { + + private static final long serialVersionUID = 5748474501961956215L; + + @ApiModelProperty("角色名称") + @NotBlank(message = "角色名称不能为空") + private String roleName; + + @ApiModelProperty("菜单id") + @NotEmpty(message = "菜单id不能为空") + private List<Long> menuIds; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleQuery.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleQuery.java new file mode 100644 index 0000000..3c1dcd3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleQuery.java @@ -0,0 +1,23 @@ +package com.ruoyi.system.domain.dto; + +import com.ruoyi.common.core.web.page.BasePage; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author mitao + * @date 2024/6/19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("角色查询") +public class RoleQuery extends BasePage { + + private static final long serialVersionUID = 6935257450787285105L; + + @ApiModelProperty("角色名称") + private String roleName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleUpdateDto.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleUpdateDto.java new file mode 100644 index 0000000..a5eb0e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/RoleUpdateDto.java @@ -0,0 +1,27 @@ +package com.ruoyi.system.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import java.util.List; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class RoleUpdateDto implements Serializable { + + private static final long serialVersionUID = 8640434597899168206L; + + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空") + private Long roleId; + + @ApiModelProperty("角色名称") + @NotBlank(message = "角色名称不能为空") + private String roleName; + + @ApiModelProperty("菜单id") + @NotEmpty(message = "菜单id不能为空") + private List<Long> menuIds; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierDTO.java new file mode 100644 index 0000000..f942688 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierDTO.java @@ -0,0 +1,28 @@ +package com.ruoyi.system.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import lombok.Data; + +@Data +@ApiModel("供应商数据传输对象") +public class SupplierDTO implements Serializable { + + private static final long serialVersionUID = -5026529248548952066L; + + @ApiModelProperty(value = "供应商id", notes = "更新必传") + private Long userId; + + @ApiModelProperty("供应商名称") + @NotBlank(message = "供应商名称不能为空") + private String nickName; + + @ApiModelProperty("联系电话") + @NotBlank(message = "联系电话不能为空") + private String phonenumber; + + @ApiModelProperty("登录密码") + private String password; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierQuery.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierQuery.java new file mode 100644 index 0000000..39ea365 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SupplierQuery.java @@ -0,0 +1,19 @@ +package com.ruoyi.system.domain.dto; + +import com.ruoyi.common.core.web.page.BasePage; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("供应商列表查询数据传输对象") +public class SupplierQuery extends BasePage { + + private static final long serialVersionUID = -5026529248548952066L; + + @ApiModelProperty("供应商名称") + private String nickName; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserDTO.java new file mode 100644 index 0000000..d9a57e8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserDTO.java @@ -0,0 +1,51 @@ +package com.ruoyi.system.domain.dto; + +import com.ruoyi.system.api.validate.UpdateGroup; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import lombok.Data; + +/** + * 用户对象 sys_user + * + * @author ruoyi + */ +@Data +public class SysUserDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ApiModelProperty(value = "账号id", notes = "添加不传") + @NotNull(message = "账号ID不能为空", groups = {UpdateGroup.class}) + private Long userId; + + /** + * 用户昵称 + */ + @ApiModelProperty(value = "员工姓名") + @NotBlank(message = "员工姓名不能为空") + private String nickName; + + /** + * 手机号码 + */ + @ApiModelProperty(value = "联系电话") + @NotBlank(message = "联系电话不能为空") + private String phonenumber; + + /** + * 角色ID + */ + @ApiModelProperty(value = "所属角色") + @NotNull(message = "角色id不能为空") + private Long roleId; + + @ApiModelProperty(value = "是否为拍卖师 1=否 2=是") + @NotNull(message = "是否为拍卖师不能为空") + private Integer isAuctioneer; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java new file mode 100644 index 0000000..834b131 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java @@ -0,0 +1,25 @@ +package com.ruoyi.system.domain.dto; + +import com.ruoyi.common.core.web.page.BasePage; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author mitao + * @date 2024/6/19 + */ +@Data +@ApiModel("用户查询条件") +public class SysUserQuery extends BasePage { + + private static final long serialVersionUID = -5515862189079789834L; + @ApiModelProperty("员工姓名") + private String nickName; + + @ApiModelProperty("联系电话") + private String phonenumber; + + @ApiModelProperty("状态 0:正常 1:冻结") + private Integer status; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CustomConfigVO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CustomConfigVO.java new file mode 100644 index 0000000..054c463 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/CustomConfigVO.java @@ -0,0 +1,28 @@ +package com.ruoyi.system.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import lombok.Data; + +/** + * @author mitao + * @date 2024/6/12 + */ +@Data +@ApiModel(value = "系统配置视图对象", description = "系统配置视图对象") +public class CustomConfigVO implements Serializable { + + private static final long serialVersionUID = -3924918944203960354L; + @ApiModelProperty(value = "配置id") + private Integer configId; + + @ApiModelProperty(value = "配置键") + private String configKey; + + @ApiModelProperty(value = "配置名") + private String configName; + + @ApiModelProperty(value = "配置值") + private String configValue; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java new file mode 100644 index 0000000..53bb9f6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java @@ -0,0 +1,106 @@ +package com.ruoyi.system.domain.vo; + +import com.ruoyi.common.core.utils.StringUtils; + +/** + * 路由显示信息 + * + * @author ruoyi + */ +public class MetaVo +{ + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + + /** + * 设置为true,则不会被 <keep-alive>缓存 + */ + private boolean noCache; + + /** + * 内链地址(http(s)://开头) + */ + private String link; + + public MetaVo() + { + } + + public MetaVo(String title, String icon) + { + this.title = title; + this.icon = icon; + } + + public MetaVo(String title, String icon, boolean noCache) + { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + public MetaVo(String title, String icon, String link) + { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) + { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) + { + this.link = link; + } + } + + public boolean isNoCache() + { + return noCache; + } + + public void setNoCache(boolean noCache) + { + this.noCache = noCache; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public String getIcon() + { + return icon; + } + + public void setIcon(String icon) + { + this.icon = icon; + } + + public String getLink() + { + return link; + } + + public void setLink(String link) + { + this.link = link; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RoleInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RoleInfoVo.java new file mode 100644 index 0000000..cfd6915 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RoleInfoVo.java @@ -0,0 +1,25 @@ +package com.ruoyi.system.domain.vo; + +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.SysMenus; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class RoleInfoVo { + private Long roleId; + + private String roleName; + + @ApiModelProperty("车辆数据权限:1=所有数据 2=已租 3=未租 4=已租(仅自己负责的合同) 5=无数据权限") + private Integer carDataAuth; + @ApiModelProperty("车务数据权限:1=所有数据 2=已租 3=未租 4=已租(仅自己负责的合同) 5=无数据权限") + private Integer carTrainOperAuth; + @ApiModelProperty("合同数据权限:1=所有数据 2=仅自己负责的合同 3=无数据权限") + private Integer contractDataAuth; + + @ApiModelProperty("菜单id") + private List<Long> menus; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java new file mode 100644 index 0000000..afff8c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java @@ -0,0 +1,148 @@ +package com.ruoyi.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.util.List; + +/** + * 路由配置信息 + * + * @author ruoyi + */ +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo +{ + /** + * 路由名字 + */ + private String name; + + /** + * 路由地址 + */ + private String path; + + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private boolean hidden; + + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + + /** + * 其他元素 + */ + private MetaVo meta; + + /** + * 子路由 + */ + private List<RouterVo> children; + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getPath() + { + return path; + } + + public void setPath(String path) + { + this.path = path; + } + + public boolean getHidden() + { + return hidden; + } + + public void setHidden(boolean hidden) + { + this.hidden = hidden; + } + + public String getRedirect() + { + return redirect; + } + + public void setRedirect(String redirect) + { + this.redirect = redirect; + } + + public String getComponent() + { + return component; + } + + public void setComponent(String component) + { + this.component = component; + } + + public String getQuery() + { + return query; + } + + public void setQuery(String query) + { + this.query = query; + } + + public Boolean getAlwaysShow() + { + return alwaysShow; + } + + public void setAlwaysShow(Boolean alwaysShow) + { + this.alwaysShow = alwaysShow; + } + + public MetaVo getMeta() + { + return meta; + } + + public void setMeta(MetaVo meta) + { + this.meta = meta; + } + + public List<RouterVo> getChildren() + { + return children; + } + + public void setChildren(List<RouterVo> children) + { + this.children = children; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SupplierVO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SupplierVO.java new file mode 100644 index 0000000..70030e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SupplierVO.java @@ -0,0 +1,25 @@ +package com.ruoyi.system.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; +import lombok.Data; + +/** + * @author mitao + * @date 2024/6/5 + */ +@Data +@ApiModel("供应商视图对象") +public class SupplierVO implements Serializable { + + private static final long serialVersionUID = -5026529248548952066L; + @ApiModelProperty("供应商id") + private Long userId; + + @ApiModelProperty("供应商名称") + private String nickName; + + @ApiModelProperty("联系电话") + private String phonenumber; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TCompanyToUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TCompanyToUserVo.java new file mode 100644 index 0000000..c000230 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TCompanyToUserVo.java @@ -0,0 +1,28 @@ +package com.ruoyi.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class TCompanyToUserVo { + @ApiModelProperty("用户id") + private Long id; + + private String phonenumber; + + private String roleName; + + private String status; + + private List<String> shopName; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date loginDate; + + private String userName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java new file mode 100644 index 0000000..cc542ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java @@ -0,0 +1,77 @@ +package com.ruoyi.system.domain.vo; + +import java.io.Serializable; +import java.util.List; +import java.util.stream.Collectors; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.ruoyi.system.api.domain.SysDept; +import com.ruoyi.system.domain.SysMenu; + +/** + * Treeselect树结构实体类 + * + * @author ruoyi + */ +public class TreeSelect implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 节点ID */ + private Long id; + + /** 节点名称 */ + private String label; + + /** 子节点 */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List<TreeSelect> children; + + public TreeSelect() + { + + } + + public TreeSelect(SysDept dept) + { + this.id = dept.getDeptId(); + this.label = dept.getDeptName(); + this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + public TreeSelect(SysMenu menu) + { + this.id = menu.getMenuId(); + this.label = menu.getMenuName(); + this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getLabel() + { + return label; + } + + public void setLabel(String label) + { + this.label = label; + } + + public List<TreeSelect> getChildren() + { + return children; + } + + public void setChildren(List<TreeSelect> children) + { + this.children = children; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserRoleVO.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserRoleVO.java new file mode 100644 index 0000000..095a4a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserRoleVO.java @@ -0,0 +1,22 @@ +package com.ruoyi.system.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel(value = "司管用户VO") +public class UserRoleVO implements Serializable { + + @ApiModelProperty(value = "司管用户id") + private Integer manageId; + + @ApiModelProperty(value = "司管用户名称") + private String manageName; + + @ApiModelProperty(value = "司管账号") + private String userName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java new file mode 100644 index 0000000..2cb1d04 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java @@ -0,0 +1,88 @@ +package com.ruoyi.system.listener; + + +import com.ruoyi.common.core.constant.SecurityConstants; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.api.constants.DelayTaskEnum; + +import java.util.Date; +import javax.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + + +/** + * @author mitao + * @date 2024/5/22 + */ +@Slf4j +@Component +public class RedisListener extends KeyExpirationEventMessageListener { + + private RedisTemplate<String, Object> redisTemplate; + + public RedisListener(RedisMessageListenerContainer listenerContainer, + RedisTemplate redisTemplate) { + super(listenerContainer); + this.redisTemplate=redisTemplate; + } + + @Override + public void onMessage(Message message, byte[] pattern) { + // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key + String expiredKey = message.toString(); + log.info("RedisListener key={}", expiredKey); + String time= DateUtils.dateTime(new Date()); + try { + if(StringUtils.isNotBlank(expiredKey)){ + if(expiredKey.contains("-")){ + String[] split = expiredKey.split("-"); + String operation=split[0]; + Long id = Long.valueOf(split[1]); + if(DelayTaskEnum.SECKILL_START_TASK.getCode().equals(operation)){ + }else if(DelayTaskEnum.SECKILL_END_TASK.getCode().equals(operation)){ + }else if(DelayTaskEnum.GROUP_PURCHASES_START_TASK.getCode().equals(operation)){ + } + else if(DelayTaskEnum.GROUP_PURCHASES_END_TASK.getCode().equals(operation)){ + } else if (DelayTaskEnum.AUCTION_GOODS_START_TASK.getCode().equals(operation)) { + // 自动开始拍卖商品任务 + } else if (DelayTaskEnum.AUCTION_GOODS_END_TASK.getCode().equals(operation)) { + // 自动结束拍卖商品任务 + }else if(DelayTaskEnum.ORDER_AUTOMATIC_CANCEL.getCode().equals(operation)){ + //自动取消订单 + autoCancelOrder(id); + } + //删除失效的key + redisTemplate.delete(expiredKey); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + } + + + public <T> T getAndSet(final String key, T value){ + T oldValue=null; + try { + ValueOperations<String, Object> operations = redisTemplate.opsForValue(); + oldValue =(T) operations.getAndSet(key, value); + } catch (Exception e) { + e.printStackTrace(); + } + return oldValue; + } + + + @Async + public void autoCancelOrder(Long orderId) { + log.info("autoCancelOrder scheduler task is running :{}", orderId); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AgreementMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AgreementMapper.java new file mode 100644 index 0000000..2889cd3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AgreementMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.domain.Agreement; + +/** + * <p> + * Mapper 接口 + * </p> + * + * @author mitao + * @since 2024-05-21 + */ +public interface AgreementMapper extends BaseMapper<Agreement> { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DelayTaskMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DelayTaskMapper.java new file mode 100644 index 0000000..dd142c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DelayTaskMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.api.domain.DelayTask; + +/** + * <p> + * Mapper 接口 + * </p> + * + * @author jqs + * @since 2023-05-29 + */ +public interface DelayTaskMapper extends BaseMapper<DelayTask> { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..99b26aa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java @@ -0,0 +1,78 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.api.domain.SysConfig; +import org.apache.ibatis.annotations.Mapper; + +/** + * 参数配置 数据层 + * + * @author ruoyi + */ +@Mapper +public interface SysConfigMapper +{ + /** + * 查询参数配置信息 + * + * @param config 参数配置信息 + * @return 参数配置信息 + */ + public SysConfig selectConfig(SysConfig config); + + /** + * 通过ID查询配置 + * + * @param configId 参数ID + * @return 参数配置信息 + */ + public SysConfig selectConfigById(Long configId); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + public List<SysConfig> selectConfigList(SysConfig config); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数配置信息 + */ + public SysConfig checkConfigKeyUnique(String configKey); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 删除参数配置 + * + * @param configId 参数ID + * @return 结果 + */ + public int deleteConfigById(Long configId); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + * @return 结果 + */ + public int deleteConfigByIds(Long[] configIds); +} \ No newline at end of file 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 new file mode 100644 index 0000000..77e7e83 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java @@ -0,0 +1,118 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.ruoyi.system.api.domain.SysDept; + +/** + * 部门管理 数据层 + * + * @author ruoyi + */ +public interface SysDeptMapper +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List<SysDept> selectDeptList(SysDept dept); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + public List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门 + * + * @param deptId 部门ID + * @return 部门列表 + */ + public List<SysDept> selectChildrenDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + public int hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 + */ + public int checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param deptName 部门名称 + * @param parentId 父部门ID + * @return 结果 + */ + public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId); + + /** + * 新增部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 修改所在部门正常状态 + * + * @param deptIds 部门ID组 + */ + public void updateDeptStatusNormal(Long[] deptIds); + + /** + * 修改子元素关系 + * + * @param depts 子元素 + * @return 结果 + */ + public int updateDeptChildren(@Param("depts") List<SysDept> depts); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); +} 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 new file mode 100644 index 0000000..b004c59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java @@ -0,0 +1,95 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.ruoyi.system.api.domain.SysDictData; + +/** + * 字典表 数据层 + * + * @author ruoyi + */ +public interface SysDictDataMapper +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List<SysDictData> selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List<SysDictData> selectDictDataByType(String dictType); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + public SysDictData selectDictDataById(Long dictCode); + + /** + * 查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据 + */ + public int countDictDataByType(String dictType); + + /** + * 通过字典ID删除字典数据信息 + * + * @param dictCode 字典数据ID + * @return 结果 + */ + public int deleteDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + * @return 结果 + */ + public int deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); + + /** + * 同步修改字典类型 + * + * @param oldDictType 旧字典类型 + * @param newDictType 新旧字典类型 + * @return 结果 + */ + public int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType); +} 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 new file mode 100644 index 0000000..d217293 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,83 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.api.domain.SysDictType; + +/** + * 字典表 数据层 + * + * @author ruoyi + */ +public interface SysDictTypeMapper +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List<SysDictType> selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List<SysDictType> selectDictTypeAll(); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 通过字典ID删除字典信息 + * + * @param dictId 字典ID + * @return 结果 + */ + public int deleteDictTypeById(Long dictId); + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + * @return 结果 + */ + public int deleteDictTypeByIds(Long[] dictIds); + + /** + * 新增字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int insertDictType(SysDictType dictType); + + /** + * 修改字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int updateDictType(SysDictType dictType); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + public SysDictType checkDictTypeUnique(String dictType); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000..19671f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java @@ -0,0 +1,42 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.api.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 数据层 + * + * @author ruoyi + */ +public interface SysLogininforMapper +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public int insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + public int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + * + * @return 结果 + */ + public int cleanLogininfor(); +} 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 new file mode 100644 index 0000000..928a998 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java @@ -0,0 +1,137 @@ +package com.ruoyi.system.mapper; + +import java.util.List; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.domain.SysMenus; +import org.apache.ibatis.annotations.Param; +import com.ruoyi.system.domain.SysMenu; + +/** + * 菜单表 数据层 + * + * @author ruoyi + */ +public interface SysMenuMapper extends BaseMapper<SysMenu> +{ + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List<SysMenu> selectMenuList(SysMenu menu); + + /** + * 根据用户所有权限 + * + * @return 权限列表 + */ + public List<String> selectMenuPerms(); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List<SysMenu> selectMenuListByUserId(SysMenu menu); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public List<String> selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public List<String> selectMenuPermsByUserId(Long userId); + + /** + * 根据用户ID查询菜单 + * + * @return 菜单列表 + */ + public List<SysMenu> selectMenuTreeAll(); + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List<SysMenu> selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + public List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int hasChildByMenuId(Long menuId); + + /** + * 新增菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menuName 菜单名称 + * @param parentId 父菜单ID + * @return 结果 + */ + public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId); + + List<SysMenus> getAll(); + + List<SysMenus> getAllInIds(@Param("menusId") List<Long> menusId); + + List<SysMenus> getAllOne(); + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000..226fdab --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java @@ -0,0 +1,60 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.SysNotice; + +/** + * 通知公告表 数据层 + * + * @author ruoyi + */ +public interface SysNoticeMapper +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List<SysNotice> selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 批量删除公告 + * + * @param noticeId 公告ID + * @return 结果 + */ + public int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + public int deleteNoticeByIds(Long[] noticeIds); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..f243dcd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java @@ -0,0 +1,48 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.api.domain.SysOperLog; + +/** + * 操作日志 数据层 + * + * @author ruoyi + */ +public interface SysOperLogMapper +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public int insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List<SysOperLog> selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + public int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java new file mode 100644 index 0000000..19be227 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java @@ -0,0 +1,99 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.SysPost; + +/** + * 岗位信息 数据层 + * + * @author ruoyi + */ +public interface SysPostMapper +{ + /** + * 查询岗位数据集合 + * + * @param post 岗位信息 + * @return 岗位数据集合 + */ + public List<SysPost> selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List<SysPost> selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + public List<Long> selectPostListByUserId(Long userId); + + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + public List<SysPost> selectPostsByUserName(String userName); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + public int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + public int deletePostByIds(Long[] postIds); + + /** + * 修改岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); + + /** + * 新增岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 校验岗位名称 + * + * @param postName 岗位名称 + * @return 结果 + */ + public SysPost checkPostNameUnique(String postName); + + /** + * 校验岗位编码 + * + * @param postCode 岗位编码 + * @return 结果 + */ + public SysPost checkPostCodeUnique(String postCode); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000..f9d3a2f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,44 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.SysRoleDept; + +/** + * 角色与部门关联表 数据层 + * + * @author ruoyi + */ +public interface SysRoleDeptMapper +{ + /** + * 通过角色ID删除角色和部门关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleDeptByRoleId(Long roleId); + + /** + * 批量删除角色部门关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleDept(Long[] ids); + + /** + * 查询部门使用数量 + * + * @param deptId 部门ID + * @return 结果 + */ + public int selectCountRoleDeptByDeptId(Long deptId); + + /** + * 批量新增角色部门信息 + * + * @param roleDeptList 角色部门列表 + * @return 结果 + */ + public int batchRoleDept(List<SysRoleDept> roleDeptList); +} 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 new file mode 100644 index 0000000..6b83982 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java @@ -0,0 +1,113 @@ +package com.ruoyi.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.api.domain.SysRole; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +/** + * 角色表 数据层 + * + * @author ruoyi + */ +public interface SysRoleMapper extends BaseMapper<SysRole> +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List<SysRole> selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List<SysRole> selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List<SysRole> selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + public List<Long> selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 根据用户ID查询角色 + * + * @param userName 用户名 + * @return 角色列表 + */ + public List<SysRole> selectRolesByUserName(String userName); + + /** + * 校验角色名称是否唯一 + * + * @param roleName 角色名称 + * @return 角色信息 + */ + public SysRole checkRoleNameUnique(String roleName); + + /** + * 校验角色权限是否唯一 + * + * @param roleKey 角色权限 + * @return 角色信息 + */ + public SysRole checkRoleKeyUnique(String roleKey); + + /** + * 修改角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 新增角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] roleIds); + + List<SysRole> isExitUpdate(@Param("roleName") String roleName, @Param("roleId") Long roleId); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..099789c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,46 @@ +package com.ruoyi.system.mapper; + +import java.util.List; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.domain.SysRoleMenu; + +/** + * 角色与菜单关联表 数据层 + * + * @author ruoyi + */ +public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> +{ + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int checkMenuExistRole(Long menuId); + + /** + * 通过角色ID删除角色和菜单关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleMenuByRoleId(Long roleId); + + /** + * 批量删除角色菜单关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleMenu(Long[] ids); + + /** + * 批量新增角色菜单信息 + * + * @param roleMenuList 角色菜单列表 + * @return 结果 + */ + public int batchRoleMenu(List<SysRoleMenu> roleMenuList); +} 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 new file mode 100644 index 0000000..8c2148c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java @@ -0,0 +1,140 @@ +package com.ruoyi.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.common.core.web.page.PageInfo; +import com.ruoyi.system.api.domain.SysUser; +import java.util.ArrayList; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +/** + * 用户表 数据层 + * + * @author ruoyi + */ +public interface SysUserMapper extends BaseMapper<SysUser> +{ + /** + * 根据条件分页查询用户列表 + * + * @param sysUser 用户信息 + * @return 用户信息集合信息 + */ + public List<SysUser> selectUserList(SysUser sysUser); + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List<SysUser> selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List<SysUser> selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + public int updateUserAvatar(@Param("userName") String userName, @Param("avatar") String avatar); + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + public int resetUserPwd(@Param("userName") String userName, @Param("password") String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + public int deleteUserByIds(Long[] userIds); + + /** + * 校验用户名称是否唯一 + * + * @param userName 用户名称 + * @return 结果 + */ + public SysUser checkUserNameUnique(String userName); + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public SysUser checkPhoneUnique(String phonenumber); + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public SysUser checkEmailUnique(String email); + + PageInfo<SysUser> getList(@Param("pageInfo") PageInfo<SysUser> pageInfo, + @Param("nickName") String nickName, @Param("phonenumber") String phonenumber, + @Param("status") Integer status); + + PageInfo<SysUser> getAllList(@Param("pageInfo") PageInfo<SysUser> pageInfo, @Param("ids") List<Integer> collect); + + List<Long> getSysUserFromPhone(@Param("phoneNumber") String phoneNumber); + + void deleteSysUser(@Param("userIds") ArrayList<Integer> userIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000..e08991d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java @@ -0,0 +1,44 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.SysUserPost; + +/** + * 用户与岗位关联表 数据层 + * + * @author ruoyi + */ +public interface SysUserPostMapper +{ + /** + * 通过用户ID删除用户和岗位关联 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserPostByUserId(Long userId); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 批量删除用户和岗位关联 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserPost(Long[] ids); + + /** + * 批量新增用户岗位信息 + * + * @param userPostList 用户角色列表 + * @return 结果 + */ + public int batchUserPost(List<SysUserPost> userPostList); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..717dee9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,115 @@ +package com.ruoyi.system.mapper; + +import java.util.List; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.api.domain.SysUser; +import org.apache.ibatis.annotations.Param; +import com.ruoyi.system.domain.SysUserRole; + +/** + * 用户与角色关联表 数据层 + * + * @author ruoyi + */ +public interface SysUserRoleMapper extends BaseMapper<SysUserRole> +{ + /** + * 通过用户ID删除用户和角色关联 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserRoleByUserId(Long userId); + + /** + * 批量删除用户和角色关联 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserRole(Long[] ids); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + public int countUserRoleByRoleId(Long roleId); + + /** + * 批量新增用户角色信息 + * + * @param userRoleList 用户角色列表 + * @return 结果 + */ + public int batchUserRole(List<SysUserRole> userRoleList); + + /** + * 删除用户和角色关联信息 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteUserRoleInfo(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds); + + + /** + * 查询用户和角色关联 + * + * @param userId 用户和角色关联主键 + * @return 用户和角色关联 + */ + public SysUserRole selectSysUserRoleByUserId(Long userId); + + /** + * 查询用户和角色关联列表 + * + * @param sysUserRole 用户和角色关联 + * @return 用户和角色关联集合 + */ + public List<SysUserRole> selectSysUserRoleList(SysUserRole sysUserRole); + + /** + * 新增用户和角色关联 + * + * @param sysUserRole 用户和角色关联 + * @return 结果 + */ + public int insertSysUserRole(SysUserRole sysUserRole); + + /** + * 修改用户和角色关联 + * + * @param sysUserRole 用户和角色关联 + * @return 结果 + */ + public int updateSysUserRole(SysUserRole sysUserRole); + + /** + * 删除用户和角色关联 + * + * @param userId 用户和角色关联主键 + * @return 结果 + */ + public int deleteSysUserRoleByUserId(Long userId); + + /** + * 批量删除用户和角色关联 + * + * @param userIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteSysUserRoleByUserIds(Long[] userIds); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/query/SysOperLogQuery.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/query/SysOperLogQuery.java new file mode 100644 index 0000000..84d75e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/query/SysOperLogQuery.java @@ -0,0 +1,16 @@ +package com.ruoyi.system.query; + +import com.ruoyi.common.core.web.page.BasePage; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "当前车辆查询操作日志") +public class SysOperLogQuery extends BasePage { + + + @ApiModelProperty(value = "车辆id") + private Integer carId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/DelayTaskService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/DelayTaskService.java new file mode 100644 index 0000000..d819d27 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/DelayTaskService.java @@ -0,0 +1,44 @@ +package com.ruoyi.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.system.api.domain.DelayTask; + +; + +/** + * <p> + * 服务类 + * </p> + * + * @author jqs + * @since 2023-05-29 + */ +public interface DelayTaskService extends IService<DelayTask> { + + /** + * @param key + * @return DelayTask + * @description + * @author jqs + * @date 2023/7/12 11:39 + */ + DelayTask getDelayTask(String key); + + /** + * @param delayTask + * @return void + * @description + * @author jqs + * @date 2023/7/12 11:37 + */ + void addDelayTask(DelayTask delayTask); + + /** + * @param key + * @return DelayTask + * @description + * @author jqs + * @date 2023/7/12 11:39 + */ + void deleteDelayTask(String key); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/IAgreementService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/IAgreementService.java new file mode 100644 index 0000000..2c31dd6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/IAgreementService.java @@ -0,0 +1,26 @@ +package com.ruoyi.system.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.system.domain.Agreement; +import com.ruoyi.system.domain.dto.AgreementDTO; + +/** + * <p> + * 服务类 + * </p> + * + * @author mitao + * @since 2024-05-21 + */ +public interface IAgreementService extends IService<Agreement> { + + Agreement getAgreement(Integer agreementType); + + /** + * 保存协议 + * + * @param dto 协议对象 + */ + void saveAgreement(AgreementDTO dto); +} 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 new file mode 100644 index 0000000..be0d2d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java @@ -0,0 +1,82 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.api.domain.SysConfig; + +/** + * 参数配置 服务层 + * + * @author ruoyi + */ +public interface ISysConfigService +{ + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + public SysConfig selectConfigById(Long configId); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + public String selectConfigByKey(String configKey); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + public List<SysConfig> selectConfigList(SysConfig config); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + public void deleteConfigByIds(Long[] configIds); + + /** + * 加载参数缓存数据 + */ + public void loadingConfigCache(); + + /** + * 清空参数缓存数据 + */ + public void clearConfigCache(); + + /** + * 重置参数缓存数据 + */ + public void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + public boolean checkConfigKeyUnique(SysConfig config); +} 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 new file mode 100644 index 0000000..313d577 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java @@ -0,0 +1,124 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.api.domain.SysDept; +import com.ruoyi.system.domain.vo.TreeSelect; + +/** + * 部门管理 服务层 + * + * @author ruoyi + */ +public interface ISysDeptService +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List<SysDept> selectDeptList(SysDept dept); + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + public List<TreeSelect> selectDeptTreeList(SysDept dept); + + /** + * 构建前端所需要树结构 + * + * @param depts 部门列表 + * @return 树结构列表 + */ + public List<SysDept> buildDeptTree(List<SysDept> depts); + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + public List<Long> selectDeptListByRoleId(Long roleId); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + public boolean hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + public boolean checkDeptNameUnique(SysDept dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + public void checkDeptDataScope(Long deptId); + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); +} 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 new file mode 100644 index 0000000..ba9d8ea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java @@ -0,0 +1,60 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.api.domain.SysDictData; + +/** + * 字典 业务层 + * + * @author ruoyi + */ +public interface ISysDictDataService +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List<SysDictData> selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String selectDictLabel(String dictType, String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + public SysDictData selectDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + public void deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); +} 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 new file mode 100644 index 0000000..ceb80e7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java @@ -0,0 +1,98 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.api.domain.SysDictData; +import com.ruoyi.system.api.domain.SysDictType; + +/** + * 字典 业务层 + * + * @author ruoyi + */ +public interface ISysDictTypeService +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List<SysDictType> selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List<SysDictType> selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List<SysDictData> selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + public void deleteDictTypeByIds(Long[] dictIds); + + /** + * 加载字典缓存数据 + */ + public void loadingDictCache(); + + /** + * 清空字典缓存数据 + */ + public void clearDictCache(); + + /** + * 重置字典缓存数据 + */ + public void resetDictCache(); + + /** + * 新增保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int insertDictType(SysDictType dictType); + + /** + * 修改保存字典类型信息 + * + * @param dictType 字典类型信息 + * @return 结果 + */ + public int updateDictType(SysDictType dictType); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + public boolean checkDictTypeUnique(SysDictType dictType); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java new file mode 100644 index 0000000..509cc54 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java @@ -0,0 +1,40 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.api.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 服务层 + * + * @author ruoyi + */ +public interface ISysLogininforService +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public int insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + public int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + */ + public void cleanLogininfor(); +} 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 new file mode 100644 index 0000000..31dcdac --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java @@ -0,0 +1,154 @@ +package com.ruoyi.system.service; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.SysMenus; +import com.ruoyi.system.domain.vo.RouterVo; +import com.ruoyi.system.domain.vo.TreeSelect; + +/** + * 菜单 业务层 + * + * @author ruoyi + */ +public interface ISysMenuService extends IService<SysMenu> +{ + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List<SysMenu> selectMenuList(Long userId); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + public List<SysMenu> selectMenuList(SysMenu menu, Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set<String> selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public Set<String> selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List<SysMenu> selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + public List<Long> selectMenuListByRoleId(Long roleId); + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + public List<RouterVo> buildMenus(List<SysMenu> menus); + + /** + * 构建前端所需要树结构 + * + * @param menus 菜单列表 + * @return 树结构列表 + */ + public List<SysMenu> buildMenuTree(List<SysMenu> menus); + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + public boolean hasChildByMenuId(Long menuId); + + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkMenuExistRole(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean checkMenuNameUnique(SysMenu menu); + + List<SysMenus> getAllMenu(); + + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java new file mode 100644 index 0000000..47ce1b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java @@ -0,0 +1,60 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.domain.SysNotice; + +/** + * 公告 服务层 + * + * @author ruoyi + */ +public interface ISysNoticeService +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List<SysNotice> selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + public int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + public int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java new file mode 100644 index 0000000..46a31f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java @@ -0,0 +1,51 @@ +package com.ruoyi.system.service; + +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.system.api.domain.SysOperLog; + +/** + * 操作日志 服务层 + * + * @author ruoyi + */ +public interface ISysOperLogService extends IService<SysOperLog> +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + * @return 结果 + */ + public int insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List<SysOperLog> selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + public int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); +} 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..230f9b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java @@ -0,0 +1,29 @@ +package com.ruoyi.system.service; + +import java.util.Set; + +import com.ruoyi.system.api.domain.SysUser; + +/** + * 权限信息 服务层 + * + * @author ruoyi + */ +public interface ISysPermissionService +{ + /** + * 获取角色数据权限 + * + * @param userId 用户Id + * @return 角色权限信息 + */ + public Set<String> getRolePermission(SysUser user); + + /** + * 获取菜单数据权限 + * + * @param userId 用户Id + * @return 菜单权限信息 + */ + public Set<String> getMenuPermission(SysUser user); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java new file mode 100644 index 0000000..84779bf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java @@ -0,0 +1,99 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.domain.SysPost; + +/** + * 岗位信息 服务层 + * + * @author ruoyi + */ +public interface ISysPostService +{ + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + public List<SysPost> selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List<SysPost> selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + public List<Long> selectPostListByUserId(Long userId); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostNameUnique(SysPost post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostCodeUnique(SysPost post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + public int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + public int deletePostByIds(Long[] postIds); + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); +} 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 new file mode 100644 index 0000000..d7a79b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java @@ -0,0 +1,178 @@ +package com.ruoyi.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.domain.SysUserRole; +import java.util.List; +import java.util.Set; + +/** + * 角色业务层 + * + * @author ruoyi + */ +public interface ISysRoleService extends IService<SysRole> +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List<SysRole> selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List<SysRole> selectRolesByUserId(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set<String> selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List<SysRole> selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + public List<Long> selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + public boolean checkRoleNameUnique(SysRole role); + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + public boolean checkRoleKeyUnique(SysRole role); + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + public void checkRoleAllowed(SysRole role); + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + public void checkRoleDataScope(Long roleId); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + public int countUserRoleByRoleId(Long roleId); + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRoleStatus(SysRole role); + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int authDataScope(SysRole role); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] roleIds); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + public int deleteAuthUsers(Long roleId, Long[] userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int insertAuthUsers(Long roleId, Long[] userIds); + + List<SysRole> isExitUpdate(String roleName, Long roleId); + + void removeRole(Long id); +} 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 new file mode 100644 index 0000000..9ca0ac4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java @@ -0,0 +1,48 @@ +package com.ruoyi.system.service; + +import com.ruoyi.system.api.model.LoginUser; +import com.ruoyi.system.domain.SysUserOnline; + +/** + * 在线用户 服务层 + * + * @author ruoyi + */ +public interface ISysUserOnlineService +{ + /** + * 通过登录地址查询信息 + * + * @param ipaddr 登录地址 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user); + + /** + * 通过用户名称查询信息 + * + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByUserName(String userName, LoginUser user); + + /** + * 通过登录地址/用户名称查询信息 + * + * @param ipaddr 登录地址 + * @param userName 用户名称 + * @param user 用户信息 + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user); + + /** + * 设置在线用户信息 + * + * @param user 用户信息 + * @return 在线用户 + */ + public SysUserOnline loginUserToUserOnline(LoginUser user); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserRoleService.java new file mode 100644 index 0000000..ad53da0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserRoleService.java @@ -0,0 +1,64 @@ +package com.ruoyi.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.system.domain.SysUserRole; + +import java.util.List; + + +/** + * 用户和角色关联Service接口 + * + * @author xiaochen + * @date 2023-06-12 + */ +public interface ISysUserRoleService extends IService<SysUserRole> +{ + /** + * 查询用户和角色关联 + * + * @param userId 用户和角色关联主键 + * @return 用户和角色关联 + */ + public SysUserRole selectSysUserRoleByUserId(Long userId); + + /** + * 查询用户和角色关联列表 + * + * @param sysUserRole 用户和角色关联 + * @return 用户和角色关联集合 + */ + public List<SysUserRole> selectSysUserRoleList(SysUserRole sysUserRole); + + /** + * 新增用户和角色关联 + * + * @param sysUserRole 用户和角色关联 + * @return 结果 + */ + public int insertSysUserRole(SysUserRole sysUserRole); + + /** + * 修改用户和角色关联 + * + * @param sysUserRole 用户和角色关联 + * @return 结果 + */ + public int updateSysUserRole(SysUserRole sysUserRole); + + /** + * 批量删除用户和角色关联 + * + * @param userIds 需要删除的用户和角色关联主键集合 + * @return 结果 + */ + public int deleteSysUserRoleByUserIds(Long[] userIds); + + /** + * 删除用户和角色关联信息 + * + * @param userId 用户和角色关联主键 + * @return 结果 + */ + public int deleteSysUserRoleByUserId(Long userId); +} 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 new file mode 100644 index 0000000..f8154ad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -0,0 +1,245 @@ +package com.ruoyi.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.common.core.utils.page.PageDTO; +import com.ruoyi.common.core.web.page.PageInfo; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.domain.dto.SupplierDTO; +import com.ruoyi.system.domain.dto.SupplierQuery; +import com.ruoyi.system.domain.vo.SupplierVO; +import java.util.ArrayList; +import java.util.List; + +/** + * 用户 业务层 + * + * @author ruoyi + */ +public interface ISysUserService extends IService<SysUser> +{ + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List<SysUser> selectUserList(SysUser user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List<SysUser> selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List<SysUser> selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByUserName(String userName); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + public String selectUserRoleGroup(String userName); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + public String selectUserPostGroup(String userName); + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkUserNameUnique(SysUser user); + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkPhoneUnique(SysUser user); + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkEmailUnique(SysUser user); + + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + public void checkUserAllowed(SysUser user); + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + public void checkUserDataScope(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public SysUser registerUser(SysUser user); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserStatus(SysUser user); + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserProfile(SysUser user); + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + public boolean updateUserAvatar(String userName, String avatar); + + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + public int resetPwd(SysUser user); + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + public int resetUserPwd(String userName, String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + public int deleteUserByIds(Long[] userIds); + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName); + + PageInfo<SysUser> getList(PageInfo<SysUser> pageInfo, String nickname, String phonenumber, + Integer status); + + + PageInfo<SysUser> getAllList(PageInfo<SysUser> pageInfo, List<Integer> collect); + + List<Long> getSysUserFromPhone(String phoneNumber); + + void deleteSysUser(ArrayList<Integer> userIds); + + /** + * 获取供应商分页列表 + * + * @param query 供应商列表查询数据传输对象 + * @return PageDTO<SupplyUserVO> + */ + PageDTO<SupplierVO> getSupplierPage(SupplierQuery query); + + /** + * 添加/编辑供应商 + * + * @param dto 供应商数据传输对象 + */ + void saveSupplier(SupplierDTO dto); + + /** + * 删除供应商 + * + * @param id 供应商id + */ + void deleteSupplier(Long id); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AgreementServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AgreementServiceImpl.java new file mode 100644 index 0000000..86cbd67 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AgreementServiceImpl.java @@ -0,0 +1,60 @@ +package com.ruoyi.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.utils.page.BeanUtils; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.domain.Agreement; +import com.ruoyi.system.domain.dto.AgreementDTO; +import com.ruoyi.system.mapper.AgreementMapper; +import com.ruoyi.system.service.IAgreementService; +import java.time.LocalDateTime; +import java.util.Optional; +import org.springframework.stereotype.Service; + +/** + * <p> + * 服务实现类 + * </p> + * + * @author mitao + * @since 2024-05-21 + */ +@Service +public class AgreementServiceImpl extends ServiceImpl<AgreementMapper, Agreement> implements IAgreementService { + + @Override + public Agreement getAgreement(Integer agreementType) { + LambdaQueryWrapper<Agreement> wrapper= Wrappers.lambdaQuery(); + wrapper.eq(Agreement::getAgreementType,agreementType); + wrapper.eq(Agreement::getDelFlag,0); + return this.getOne(wrapper); + } + + /** + * 保存协议 + * + * @param dto 协议对象 + */ + @Override + public void saveAgreement(AgreementDTO dto) { + Optional<Agreement> agreementOpt = this.lambdaQuery() + .eq(Agreement::getAgreementType, dto.getAgreementType()).oneOpt(); + Agreement agreement; + if (agreementOpt.isPresent()) { + agreement = agreementOpt.get(); + agreement.setAgreementType(dto.getAgreementType()); + agreement.setAgreementContent(dto.getAgreementContent()); + agreement.setUpdateBy(SecurityUtils.getUsername()); + agreement.setUpdateTime(LocalDateTime.now()); + this.updateById(agreement); + } else { + agreement = BeanUtils.copyBean(dto, Agreement.class); + agreement.setCreateBy(SecurityUtils.getUsername()); + agreement.setCreateTime(LocalDateTime.now()); + this.save(agreement); + } + + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DelayTaskServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DelayTaskServiceImpl.java new file mode 100644 index 0000000..dadfc19 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DelayTaskServiceImpl.java @@ -0,0 +1,67 @@ +package com.ruoyi.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.system.api.domain.DelayTask; +import com.ruoyi.system.mapper.DelayTaskMapper; +import com.ruoyi.system.service.DelayTaskService; +import org.springframework.stereotype.Service; + +/** + * <p> + * 服务实现类 + * </p> + * + * @author jqs + * @since 2023-05-29 + */ +@Service +public class DelayTaskServiceImpl extends ServiceImpl<DelayTaskMapper, DelayTask> implements + DelayTaskService { + + + /** + * @param key + * @return DelayTask + * @description + * @author jqs + * @date 2023/7/12 11:38 + */ + @Override + public DelayTask getDelayTask(String key) { + LambdaQueryWrapper<DelayTask> queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(DelayTask::getDelFlag, 0); + queryWrapper.eq(DelayTask::getRedisKey, key); + DelayTask delayTask = this.getOne(queryWrapper, false); + return delayTask; + } + + /** + * @param delayTask + * @return void + * @description + * @author jqs + * @date 2023/7/12 11:37 + */ + @Override + public void addDelayTask(DelayTask delayTask) { + this.saveOrUpdate(delayTask); + } + + /** + * @param key + * @return DelayTask + * @description + * @author jqs + * @date 2023/7/12 11:39 + */ + @Override + public void deleteDelayTask(String key) { + LambdaUpdateWrapper<DelayTask> updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(DelayTask::getDelFlag, 0); + updateWrapper.eq(DelayTask::getRedisKey, key); + updateWrapper.set(DelayTask::getDelFlag, 1); + this.update(updateWrapper); + } +} 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 new file mode 100644 index 0000000..8207bdf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,214 @@ +package com.ruoyi.system.service.impl; + +import java.util.Collection; +import java.util.List; +import javax.annotation.PostConstruct; + +import com.ruoyi.system.api.domain.SysConfig; +import com.ruoyi.system.mapper.SysConfigMapper; +import com.ruoyi.system.service.ISysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.common.core.constant.CacheConstants; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.service.RedisService; + +/** + * 参数配置 服务层实现 + * + * @author ruoyi + */ +@Service +public class SysConfigServiceImpl implements ISysConfigService +{ + @Autowired + private SysConfigMapper configMapper; + + @Autowired + private RedisService redisService; + + /** + * 项目启动时,初始化参数到缓存 + */ + @PostConstruct + public void init() + { + // TODO +// loadingConfigCache(); + } + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + public SysConfig selectConfigById(Long configId) + { + SysConfig config = new SysConfig(); + config.setConfigId(configId); + return configMapper.selectConfig(config); + } + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + @Override + public String selectConfigByKey(String configKey) + { + String configValue = Convert.toStr(redisService.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)) + { + redisService.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue()); + return retConfig.getConfigValue(); + } + return StringUtils.EMPTY; + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List<SysConfig> selectConfigList(SysConfig config) + { + return configMapper.selectConfigList(config); + } + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int insertConfig(SysConfig config) + { + int row = configMapper.insertConfig(config); + if (row > 0) + { + redisService.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + return row; + } + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int updateConfig(SysConfig config) + { + SysConfig temp = configMapper.selectConfigById(config.getConfigId()); + if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) + { + redisService.deleteObject(getCacheKey(temp.getConfigKey())); + } + + int row = configMapper.updateConfig(config); + if (row > 0) + { + redisService.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + return row; + } + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + @Override + public void deleteConfigByIds(Long[] configIds) + { + for (Long configId : configIds) + { + SysConfig config = selectConfigById(configId); + if (StringUtils.equals(UserConstants.YES, config.getConfigType())) + { + throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey())); + } + configMapper.deleteConfigById(configId); + redisService.deleteObject(getCacheKey(config.getConfigKey())); + } + } + + /** + * 加载参数缓存数据 + */ + @Override + public void loadingConfigCache(){ + List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig()); + for (SysConfig config : configsList) + { + redisService.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + } + + /** + * 清空参数缓存数据 + */ + @Override + public void clearConfigCache() + { + Collection<String> keys = redisService.keys(CacheConstants.SYS_CONFIG_KEY + "*"); + redisService.deleteObject(keys); + } + + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() + { + clearConfigCache(); + loadingConfigCache(); + } + + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfig config) + { + Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId(); + SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey()); + if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 设置cache key + * + * @param configKey 参数键 + * @return 缓存键key + */ + private String getCacheKey(String configKey) + { + return CacheConstants.SYS_CONFIG_KEY + 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 new file mode 100644 index 0000000..53c564d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,339 @@ +package com.ruoyi.system.service.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +import com.ruoyi.system.domain.vo.TreeSelect; +import com.ruoyi.system.mapper.SysDeptMapper; +import com.ruoyi.system.mapper.SysRoleMapper; +import com.ruoyi.system.service.ISysDeptService; +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; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.datascope.annotation.DataScope; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysDept; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; + +/** + * 部门管理 服务实现 + * + * @author ruoyi + */ +@Service +public class SysDeptServiceImpl implements ISysDeptService +{ + @Autowired + private SysDeptMapper deptMapper; + + @Autowired + private SysRoleMapper roleMapper; + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + @DataScope(deptAlias = "d") + public List<SysDept> selectDeptList(SysDept dept) + { + return deptMapper.selectDeptList(dept); + } + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + @Override + public List<TreeSelect> selectDeptTreeList(SysDept dept) + { + List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + return buildDeptTreeSelect(depts); + } + + /** + * 构建前端所需要树结构 + * + * @param depts 部门列表 + * @return 树结构列表 + */ + @Override + public List<SysDept> buildDeptTree(List<SysDept> depts) + { + List<SysDept> returnList = new ArrayList<SysDept>(); + List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()); + for (SysDept dept : depts) + { + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.contains(dept.getParentId())) + { + recursionFn(depts, dept); + returnList.add(dept); + } + } + if (returnList.isEmpty()) + { + returnList = depts; + } + return returnList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) + { + List<SysDept> deptTrees = buildDeptTree(depts); + return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List<Long> 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) + { + return deptMapper.selectDeptById(deptId); + } + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public int selectNormalChildrenDeptById(Long deptId) + { + return deptMapper.selectNormalChildrenDeptById(deptId); + } + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + 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) + { + int result = deptMapper.checkDeptExistUser(deptId); + return result > 0; + } + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + 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()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) + { + if (!SysUser.isAdmin(SecurityUtils.getUserId())) + { + SysDept dept = new SysDept(); + dept.setDeptId(deptId); + List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + if (StringUtils.isEmpty(depts)) + { + throw new ServiceException("没有权限访问部门数据!"); + } + } + } + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int insertDept(SysDept dept) + { + SysDept info = deptMapper.selectDeptById(dept.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) + { + throw new ServiceException("部门停用,不允许新增"); + } + dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); + return deptMapper.insertDept(dept); + } + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public int updateDept(SysDept dept) + { + SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId()); + SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId()); + if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept)) + { + String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + int result = deptMapper.updateDept(dept); + if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals("0", dept.getAncestors())) + { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) + { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + deptMapper.updateDeptStatusNormal(deptIds); + } + + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) + { + List<SysDept> children = deptMapper.selectChildrenDeptById(deptId); + for (SysDept child : children) + { + child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + } + if (children.size() > 0) + { + deptMapper.updateDeptChildren(children); + } + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public int deleteDeptById(Long deptId) + { + return deptMapper.deleteDeptById(deptId); + } + + /** + * 递归列表 + */ + private void recursionFn(List<SysDept> list, SysDept t) + { + // 得到子节点列表 + List<SysDept> childList = getChildList(list, t); + t.setChildren(childList); + for (SysDept tChild : childList) + { + if (hasChild(list, tChild)) + { + recursionFn(list, tChild); + } + } + } + + /** + * 得到子节点列表 + */ + private List<SysDept> getChildList(List<SysDept> list, SysDept t) + { + List<SysDept> tlist = new ArrayList<SysDept>(); + Iterator<SysDept> it = list.iterator(); + while (it.hasNext()) + { + SysDept n = (SysDept) it.next(); + if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) + { + tlist.add(n); + } + } + return tlist; + } + + /** + * 判断是否有子节点 + */ + private boolean hasChild(List<SysDept> list, SysDept t) + { + return getChildList(list, t).size() > 0 ? true : false; + } +} 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 new file mode 100644 index 0000000..ffc4a5d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,112 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; + +import com.ruoyi.system.mapper.SysDictDataMapper; +import com.ruoyi.system.service.ISysDictDataService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.common.security.utils.DictUtils; +import com.ruoyi.system.api.domain.SysDictData; + +/** + * 字典 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysDictDataServiceImpl implements ISysDictDataService +{ + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List<SysDictData> selectDictDataList(SysDictData dictData) + { + return dictDataMapper.selectDictDataList(dictData); + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) + { + return dictDataMapper.selectDictLabel(dictType, dictValue); + } + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictData selectDictDataById(Long dictCode) + { + return dictDataMapper.selectDictDataById(dictCode); + } + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Long[] dictCodes) + { + for (Long dictCode : dictCodes) + { + SysDictData data = selectDictDataById(dictCode); + dictDataMapper.deleteDictDataById(dictCode); + List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + } + + /** + * 新增保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @Override + public int insertDictData(SysDictData data) + { + int row = dictDataMapper.insertDictData(data); + if (row > 0) + { + List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + return row; + } + + /** + * 修改保存字典数据信息 + * + * @param data 字典数据信息 + * @return 结果 + */ + @Override + public int updateDictData(SysDictData data) + { + int row = dictDataMapper.updateDictData(data); + if (row > 0) + { + List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + 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 new file mode 100644 index 0000000..5eb494b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,225 @@ +package com.ruoyi.system.service.impl; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; + +import com.ruoyi.system.mapper.SysDictDataMapper; +import com.ruoyi.system.mapper.SysDictTypeMapper; +import com.ruoyi.system.service.ISysDictTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.security.utils.DictUtils; +import com.ruoyi.system.api.domain.SysDictData; +import com.ruoyi.system.api.domain.SysDictType; + +/** + * 字典 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService +{ + @Autowired + private SysDictTypeMapper dictTypeMapper; + + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 项目启动时,初始化字典到缓存 + */ + @PostConstruct + public void init() + { + // TODO +// loadingDictCache(); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List<SysDictType> selectDictTypeList(SysDictType dictType) + { + return dictTypeMapper.selectDictTypeList(dictType); + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List<SysDictType> selectDictTypeAll() + { + return dictTypeMapper.selectDictTypeAll(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Override + public List<SysDictData> selectDictDataByType(String dictType) + { + List<SysDictData> dictDatas = DictUtils.getDictCache(dictType); + if (StringUtils.isNotEmpty(dictDatas)) + { + return dictDatas; + } + dictDatas = dictDataMapper.selectDictDataByType(dictType); + if (StringUtils.isNotEmpty(dictDatas)) + { + DictUtils.setDictCache(dictType, dictDatas); + return dictDatas; + } + return null; + } + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeById(Long dictId) + { + return dictTypeMapper.selectDictTypeById(dictId); + } + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + @Override + public SysDictType selectDictTypeByType(String dictType) + { + return dictTypeMapper.selectDictTypeByType(dictType); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Long[] dictIds) + { + for (Long dictId : dictIds) + { + SysDictType dictType = selectDictTypeById(dictId); + if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0) + { + throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName())); + } + dictTypeMapper.deleteDictTypeById(dictId); + DictUtils.removeDictCache(dictType.getDictType()); + } + } + + /** + * 加载字典缓存数据 + */ + @Override + public void loadingDictCache() + { + SysDictData dictData = new SysDictData(); + dictData.setStatus("0"); + Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType)); + for (Map.Entry<String, List<SysDictData>> 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(); + } + + /** + * 新增保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @Override + public int insertDictType(SysDictType dict) + { + int row = dictTypeMapper.insertDictType(dict); + if (row > 0) + { + DictUtils.setDictCache(dict.getDictType(), null); + } + return row; + } + + /** + * 修改保存字典类型信息 + * + * @param dict 字典类型信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateDictType(SysDictType dict) + { + SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId()); + dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType()); + int row = dictTypeMapper.updateDictType(dict); + if (row > 0) + { + List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType()); + DictUtils.setDictCache(dict.getDictType(), dictDatas); + } + return row; + } + + /** + * 校验字典类型称是否唯一 + * + * @param dict 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictType dict) + { + Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId(); + SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType()); + if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000..525d9d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,66 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; + +import com.ruoyi.system.mapper.SysLogininforMapper; +import com.ruoyi.system.service.ISysLogininforService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.system.api.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysLogininforServiceImpl implements ISysLogininforService +{ + + @Autowired + private SysLogininforMapper logininforMapper; + + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + @Override + public int insertLogininfor(SysLogininfor logininfor) + { + return logininforMapper.insertLogininfor(logininfor); + } + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor) + { + return logininforMapper.selectLogininforList(logininfor); + } + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLogininforByIds(Long[] infoIds) + { + return logininforMapper.deleteLogininforByIds(infoIds); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() + { + logininforMapper.cleanLogininfor(); + } +} 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 new file mode 100644 index 0000000..0ff8d39 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,572 @@ +package com.ruoyi.system.service.impl; + +import java.util.*; +import java.util.stream.Collectors; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.security.service.TokenService; +import com.ruoyi.system.api.model.LoginUser; +import com.ruoyi.system.domain.SysMenu; +import com.ruoyi.system.domain.SysMenus; +import com.ruoyi.system.domain.SysRoleMenu; +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.domain.vo.MetaVo; +import com.ruoyi.system.domain.vo.RouterVo; +import com.ruoyi.system.domain.vo.TreeSelect; +import com.ruoyi.system.mapper.SysMenuMapper; +import com.ruoyi.system.mapper.SysRoleMapper; +import com.ruoyi.system.mapper.SysRoleMenuMapper; +import com.ruoyi.system.mapper.SysUserRoleMapper; +import com.ruoyi.system.service.ISysMenuService; +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.utils.StringUtils; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; + +/** + * 菜单 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService +{ + public static final String PREMISSION_STRING = "perms[\"{0}\"]"; + + @Autowired + private SysMenuMapper menuMapper; + + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysRoleMenuMapper roleMenuMapper; + + @Autowired + private TokenService tokenService; + + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + @Override + public List<SysMenu> selectMenuList(Long userId) + { + return selectMenuList(new SysMenu(), userId); + } + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + @Override + public List<SysMenu> selectMenuList(SysMenu menu, Long userId) + { + List<SysMenu> menuList = null; + // 管理员显示所有菜单信息 + { + menu.getParams().put("userId", userId); + menuList = menuMapper.selectMenuListByUserId(menu); + } + return menuList; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set<String> selectMenuPermsByUserId(Long userId) + { + List<String> perms = menuMapper.selectMenuPermsByUserId(userId); + Set<String> permsSet = new HashSet<>(); + for (String perm : perms) + { + if (StringUtils.isNotEmpty(perm)) + { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set<String> selectMenuPermsByRoleId(Long roleId) + { + List<String> perms = menuMapper.selectMenuPermsByRoleId(roleId); + Set<String> permsSet = new HashSet<>(); + for (String perm : perms) + { + if (StringUtils.isNotEmpty(perm)) + { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户名称 + * @return 菜单列表 + */ + @Override + public List<SysMenu> selectMenuTreeByUserId(Long userId) + { + List<SysMenu> menus = null; + if (SecurityUtils.isAdmin(userId)) + { + menus = menuMapper.selectMenuTreeAll(); + } + else + { + menus = menuMapper.selectMenuTreeByUserId(userId); + } + return getChildPerms(menus, 0); + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List<Long> selectMenuListByRoleId(Long roleId) + { + SysRole role = roleMapper.selectRoleById(roleId); + return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly()); + } + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + @Override + public List<RouterVo> buildMenus(List<SysMenu> menus) + { + List<RouterVo> routers = new LinkedList<RouterVo>(); + for (SysMenu menu : menus) + { + RouterVo router = new RouterVo(); + router.setHidden("1".equals(menu.getVisible())); + router.setName(getRouteName(menu)); + router.setPath(getRouterPath(menu)); + router.setComponent(getComponent(menu)); + router.setQuery(menu.getQuery()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + List<SysMenu> cMenus = menu.getChildren(); + if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())) + { + router.setAlwaysShow(true); + router.setRedirect("noRedirect"); + router.setChildren(buildMenus(cMenus)); + } + else if (isMenuFrame(menu)) + { + router.setMeta(null); + List<RouterVo> childrenList = new ArrayList<RouterVo>(); + RouterVo children = new RouterVo(); + children.setPath(menu.getPath()); + children.setComponent(menu.getComponent()); + children.setName(StringUtils.capitalize(menu.getPath())); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + children.setQuery(menu.getQuery()); + childrenList.add(children); + router.setChildren(childrenList); + } + else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) + { + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); + router.setPath("/"); + List<RouterVo> childrenList = new ArrayList<RouterVo>(); + RouterVo children = new RouterVo(); + String routerPath = innerLinkReplaceEach(menu.getPath()); + children.setPath(routerPath); + children.setComponent(UserConstants.INNER_LINK); + children.setName(StringUtils.capitalize(routerPath)); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); + childrenList.add(children); + router.setChildren(childrenList); + } + routers.add(router); + } + return routers; + } + + /** + * 构建前端所需要树结构 + * + * @param menus 菜单列表 + * @return 树结构列表 + */ + @Override + public List<SysMenu> buildMenuTree(List<SysMenu> menus) + { + List<SysMenu> returnList = new ArrayList<SysMenu>(); + List<Long> tempList = menus.stream().map(SysMenu::getMenuId).collect(Collectors.toList()); + for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();) + { + SysMenu menu = (SysMenu) iterator.next(); + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.contains(menu.getParentId())) + { + recursionFn(menus, menu); + returnList.add(menu); + } + } + if (returnList.isEmpty()) + { + returnList = menus; + } + return returnList; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus) + { + List<SysMenu> menuTrees = buildMenuTree(menus); + return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenu selectMenuById(Long menuId) + { + return menuMapper.selectMenuById(menuId); + } + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) + { + int result = menuMapper.hasChildByMenuId(menuId); + return result > 0; + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) + { + int result = roleMenuMapper.checkMenuExistRole(menuId); + return result > 0; + } + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenu menu) + { + return menuMapper.insertMenu(menu); + } + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenu menu) + { + return menuMapper.updateMenu(menu); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) + { + return menuMapper.deleteMenuById(menuId); + } + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + 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()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + @Override + public List<SysMenus> getAllMenu() { + Long roleId = tokenService.getLoginUser().getSysUser().getRoles().get(0).getRoleId(); + List<SysMenus> list=null; + if(roleId!=1){ + list = menuMapper.getAllOne(); + }else { + list = menuMapper.getAll(); + } + + // 获取所有 + + // 第三级 + List<SysMenus> s3 = list.stream().filter(e -> e.getMenuType().equals("F")).collect(Collectors.toList()); + // 第二级 + List<SysMenus> s2 = list.stream().filter(e -> e.getMenuType().equals("C") + && e.getMenuId() != 1196 + && e.getMenuId() != 1197 + && e.getMenuId() != 1198 + && e.getMenuId() != 1199 + && e.getMenuId() != 1201 + && e.getMenuId() != 1205).collect(Collectors.toList()); + // 第一级 + List<SysMenus> s1 = list.stream().filter(e -> e.getMenuType().equals("M")).collect(Collectors.toList()); + + for (SysMenus menus : s2) { + List<SysMenus> collect = s3.stream().filter(e -> e.getParentId().equals(menus.getMenuId())).collect(Collectors.toList()); + menus.setChildren(collect); + } + + for (SysMenus menus : s1) { + List<SysMenus> collect = s2.stream().filter(e -> e.getParentId().equals(menus.getMenuId())).collect(Collectors.toList()); + menus.setChildren(collect); + } + return s1; + } + + /** + * 获取路由名称 + * + * @param menu 菜单信息 + * @return 路由名称 + */ + public String getRouteName(SysMenu menu) + { + String routerName = StringUtils.capitalize(menu.getPath()); + // 非外链并且是一级目录(类型为目录) + if (isMenuFrame(menu)) + { + routerName = StringUtils.EMPTY; + } + return routerName; + } + + /** + * 获取路由地址 + * + * @param menu 菜单信息 + * @return 路由地址 + */ + public String getRouterPath(SysMenu menu) + { + String routerPath = menu.getPath(); + // 内链打开外网方式 + 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())) + { + routerPath = "/" + menu.getPath(); + } + // 非外链并且是一级目录(类型为菜单) + else if (isMenuFrame(menu)) + { + routerPath = "/"; + } + return routerPath; + } + + /** + * 获取组件信息 + * + * @param menu 菜单信息 + * @return 组件信息 + */ + public String getComponent(SysMenu menu) + { + String component = UserConstants.LAYOUT; + if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) + { + component = menu.getComponent(); + } + else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) + { + component = UserConstants.INNER_LINK; + } + else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) + { + component = UserConstants.PARENT_VIEW; + } + return component; + } + + /** + * 是否为菜单内部跳转 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean isMenuFrame(SysMenu menu) + { + return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType()) + && menu.getIsFrame().equals(UserConstants.NO_FRAME); + } + + /** + * 是否为内链组件 + * + * @param menu 菜单信息 + * @return 结果 + */ + 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) + { + return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()); + } + + /** + * 根据父节点的ID获取所有子节点 + * + * @param list 分类表 + * @param parentId 传入的父节点ID + * @return String + */ + public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) + { + List<SysMenu> returnList = new ArrayList<SysMenu>(); + for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();) + { + SysMenu t = (SysMenu) iterator.next(); + // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 + if (t.getParentId() == parentId) + { + recursionFn(list, t); + returnList.add(t); + } + } + return returnList; + } + + /** + * 递归列表 + * + * @param list + * @param t + */ + private void recursionFn(List<SysMenu> list, SysMenu t) + { + // 得到子节点列表 + List<SysMenu> childList = getChildList(list, t); + t.setChildren(childList); + for (SysMenu tChild : childList) + { + if (hasChild(list, tChild)) + { + recursionFn(list, tChild); + } + } + } + + /** + * 得到子节点列表 + */ + private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t) + { + List<SysMenu> tlist = new ArrayList<SysMenu>(); + Iterator<SysMenu> it = list.iterator(); + while (it.hasNext()) + { + SysMenu n = (SysMenu) it.next(); + if (n.getParentId().longValue() == t.getMenuId().longValue()) + { + tlist.add(n); + } + } + return tlist; + } + + /** + * 判断是否有子节点 + */ + private boolean hasChild(List<SysMenu> list, SysMenu t) + { + return getChildList(list, t).size() > 0; + } + + /** + * 内链域名特殊字符替换 + * + * @return + */ + public String innerLinkReplaceEach(String path) + { + return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, "." }, + new String[] { "", "", "", "/" }); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000..1fc4ed2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,93 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; + +import com.ruoyi.system.domain.SysNotice; +import com.ruoyi.system.mapper.SysNoticeMapper; +import com.ruoyi.system.service.ISysNoticeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 公告 服务层实现 + * + * @author ruoyi + */ +@Service +public class SysNoticeServiceImpl implements ISysNoticeService +{ + @Autowired + private SysNoticeMapper noticeMapper; + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNotice selectNoticeById(Long noticeId) + { + return noticeMapper.selectNoticeById(noticeId); + } + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List<SysNotice> selectNoticeList(SysNotice notice) + { + return noticeMapper.selectNoticeList(notice); + } + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNotice notice) + { + return noticeMapper.insertNotice(notice); + } + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNotice notice) + { + return noticeMapper.updateNotice(notice); + } + + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) + { + return noticeMapper.deleteNoticeById(noticeId); + } + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) + { + return noticeMapper.deleteNoticeByIds(noticeIds); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000..7ca5d1b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,128 @@ +package com.ruoyi.system.service.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.system.mapper.SysOperLogMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.system.api.domain.SysOperLog; +import com.ruoyi.system.service.ISysOperLogService; + +/** + * 操作日志 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysOperLogServiceImpl implements ISysOperLogService +{ + @Autowired + private SysOperLogMapper operLogMapper; + + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + * @return 结果 + */ + @Override + public int insertOperlog(SysOperLog operLog) + { + return operLogMapper.insertOperlog(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List<SysOperLog> selectOperLogList(SysOperLog operLog) + { + return operLogMapper.selectOperLogList(operLog); + } + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) + { + return operLogMapper.deleteOperLogByIds(operIds); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLog selectOperLogById(Long operId) + { + return operLogMapper.selectOperLogById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() + { + operLogMapper.cleanOperLog(); + } + + @Override + public boolean saveBatch(Collection<SysOperLog> entityList, int batchSize) { + return false; + } + + @Override + public boolean saveOrUpdateBatch(Collection<SysOperLog> entityList, int batchSize) { + return false; + } + + @Override + public boolean updateBatchById(Collection<SysOperLog> entityList, int batchSize) { + return false; + } + + @Override + public boolean saveOrUpdate(SysOperLog entity) { + return false; + } + + @Override + public SysOperLog getOne(Wrapper<SysOperLog> queryWrapper, boolean throwEx) { + return null; + } + + @Override + public Map<String, Object> getMap(Wrapper<SysOperLog> queryWrapper) { + return null; + } + + @Override + public <V> V getObj(Wrapper<SysOperLog> queryWrapper, Function<? super Object, V> mapper) { + return null; + } + + @Override + public BaseMapper<SysOperLog> getBaseMapper() { + return null; + } + + @Override + public Class<SysOperLog> getEntityClass() { + return null; + } +} 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..8048c7b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java @@ -0,0 +1,86 @@ +package com.ruoyi.system.service.impl; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.ruoyi.system.service.ISysRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.service.ISysMenuService; +import com.ruoyi.system.service.ISysPermissionService; + +/** + * 用户权限处理 + * + * @author ruoyi + */ +@Service +public class SysPermissionServiceImpl implements ISysPermissionService +{ + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysMenuService menuService; + + /** + * 获取角色数据权限 + * + * @param userId 用户Id + * @return 角色权限信息 + */ + @Override + public Set<String> getRolePermission(SysUser user) + { + Set<String> roles = new HashSet<String>(); + // 管理员拥有所有权限 + if (user.isAdmin()) + { + roles.add("admin"); + } + else + { + roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId())); + } + return roles; + } + + /** + * 获取菜单数据权限 + * + * @param userId 用户Id + * @return 菜单权限信息 + */ + @Override + public Set<String> getMenuPermission(SysUser user) + { + Set<String> perms = new HashSet<String>(); + // 管理员拥有所有权限 + if (user.isAdmin()) + { + perms.add("*:*:*"); + } + else + { + List<SysRole> roles = user.getRoles(); + if (!roles.isEmpty() && roles.size() > 1) + { + // 多角色设置permissions属性,以便数据权限匹配权限 + for (SysRole role : roles) + { + Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); + role.setPermissions(rolePerms); + perms.addAll(rolePerms); + } + } + else + { + perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId())); + } + } + 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 new file mode 100644 index 0000000..b2abdec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,179 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; + +import com.ruoyi.system.domain.SysPost; +import com.ruoyi.system.mapper.SysPostMapper; +import com.ruoyi.system.mapper.SysUserPostMapper; +import com.ruoyi.system.service.ISysPostService; +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; +import com.ruoyi.common.core.utils.StringUtils; + +/** + * 岗位信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysPostServiceImpl implements ISysPostService +{ + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List<SysPost> selectPostList(SysPost post) + { + return postMapper.selectPostList(post); + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List<SysPost> selectPostAll() + { + return postMapper.selectPostAll(); + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPost selectPostById(Long postId) + { + return postMapper.selectPostById(postId); + } + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List<Long> selectPostListByUserId(Long userId) + { + return postMapper.selectPostListByUserId(userId); + } + + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPost post) + { + Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); + SysPost info = postMapper.checkPostNameUnique(post.getPostName()); + if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPost post) + { + Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); + SysPost info = postMapper.checkPostCodeUnique(post.getPostCode()); + if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int countUserPostById(Long postId) + { + return userPostMapper.countUserPostById(postId); + } + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) + { + return postMapper.deletePostById(postId); + } + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + @Override + public int deletePostByIds(Long[] postIds) + { + for (Long postId : postIds) + { + SysPost post = selectPostById(postId); + if (countUserPostById(postId) > 0) + { + throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName())); + } + } + return postMapper.deletePostByIds(postIds); + } + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPost post) + { + return postMapper.insertPost(post); + } + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPost post) + { + return postMapper.updatePost(post); + } +} 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 new file mode 100644 index 0000000..e6fbbde --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,461 @@ +package com.ruoyi.system.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.datascope.annotation.DataScope; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.domain.SysRoleDept; +import com.ruoyi.system.domain.SysRoleMenu; +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.mapper.SysRoleDeptMapper; +import com.ruoyi.system.mapper.SysRoleMapper; +import com.ruoyi.system.mapper.SysRoleMenuMapper; +import com.ruoyi.system.mapper.SysUserRoleMapper; +import com.ruoyi.system.service.ISysRoleService; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 角色 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService +{ + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysRoleMenuMapper roleMenuMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private SysRoleDeptMapper roleDeptMapper; + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + @DataScope(deptAlias = "d") + public List<SysRole> selectRoleList(SysRole role) + { + return roleMapper.selectRoleList(role); + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List<SysRole> selectRolesByUserId(Long userId) + { + List<SysRole> userRoles = roleMapper.selectRolePermissionByUserId(userId); + List<SysRole> roles = selectRoleAll(); + for (SysRole role : roles) + { + for (SysRole userRole : userRoles) + { + if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) + { + role.setFlag(true); + break; + } + } + } + return roles; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set<String> selectRolePermissionByUserId(Long userId) + { + List<SysRole> perms = roleMapper.selectRolePermissionByUserId(userId); + Set<String> permsSet = new HashSet<>(); + for (SysRole perm : perms) + { + if (StringUtils.isNotNull(perm)) + { + permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(","))); + } + } + return permsSet; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List<SysRole> selectRoleAll() + { + return SpringUtils.getAopProxy(this).selectRoleList(new SysRole()); + } + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List<Long> selectRoleListByUserId(Long userId) + { + return roleMapper.selectRoleListByUserId(userId); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRole selectRoleById(Long roleId) + { + return roleMapper.selectRoleById(roleId); + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + 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()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + 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()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + 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<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role); + if (StringUtils.isEmpty(roles)) + { + throw new ServiceException("没有权限访问角色数据!"); + } + } + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public int countUserRoleByRoleId(Long roleId) + { + return userRoleMapper.countUserRoleByRoleId(roleId); + } + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertRole(SysRole role) + { + // 新增角色信息 + roleMapper.insertRole(role); + return insertRoleMenu(role); + } + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateRole(SysRole role) + { + // 修改角色信息 + // roleMapper.updateRole(role); + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId()); + return roleMapper.updateRole(role); + } + + /** + * 修改角色状态 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public int updateRoleStatus(SysRole role) + { + return roleMapper.updateRole(role); + } + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int authDataScope(SysRole role) + { + // 修改角色信息 + roleMapper.updateRole(role); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId()); + // 新增角色和部门信息(数据权限) + return insertRoleDept(role); + } + + /** + * 新增角色菜单信息 + * + * @param role 角色对象 + */ + public int insertRoleMenu(SysRole role) + { + int rows = 1; + // 新增用户与角色管理 + List<SysRoleMenu> list = new ArrayList<SysRoleMenu>(); + Long[] menuIds = role.getMenuIds(); +// List<Long> longs = Arrays.asList(menuIds); + List<Long> longs = new ArrayList<>(); + for (Long menuId : menuIds) { + longs.add(menuId); + } + if(!longs.contains(1061L)){ + longs.add(1061L); + longs.add(1062L); + longs.add(1065L); + longs.add(1073L); + longs.add(1161L); + longs.add(1203L); + } + + for (Long menuId : longs) + { + SysRoleMenu rm = new SysRoleMenu(); + rm.setRoleId(role.getRoleId()); + rm.setMenuId(menuId); + list.add(rm); + } + if (list.size() > 0) + { + rows = roleMenuMapper.batchRoleMenu(list); + } + return rows; + } + + /** + * 新增角色部门信息(数据权限) + * + * @param role 角色对象 + */ + public int insertRoleDept(SysRole role) + { + int rows = 1; + // 新增角色与部门(数据权限)管理 + List<SysRoleDept> list = new ArrayList<SysRoleDept>(); + for (Long deptId : role.getDeptIds()) + { + SysRoleDept rd = new SysRoleDept(); + rd.setRoleId(role.getRoleId()); + rd.setDeptId(deptId); + list.add(rd); + } + if (list.size() > 0) + { + rows = roleDeptMapper.batchRoleDept(list); + } + return rows; + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleById(Long roleId) + { + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(roleId); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(roleId); + return roleMapper.deleteRoleById(roleId); + } + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + 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())); + } + } + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenu(roleIds); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDept(roleIds); + return roleMapper.deleteRoleByIds(roleIds); + } + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) + { + return userRoleMapper.deleteUserRoleInfo(userRole); + } + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) + { + return userRoleMapper.deleteUserRoleInfos(roleId, userIds); + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) + { + // 新增用户与角色管理 + List<SysUserRole> list = new ArrayList<SysUserRole>(); + for (Long userId : userIds) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + return userRoleMapper.batchUserRole(list); + } + + @Override + public List<SysRole> isExitUpdate(String roleName, Long roleId) { + return roleMapper.isExitUpdate(roleName, roleId); + } + + @Override + public void removeRole(Long id) { + SysRole sysRole = baseMapper.selectRoleById(id); + Long count = userRoleMapper.selectCount( + Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getRoleId, id)); + if (count > 0) { + throw new ServiceException("角色已绑定账号,不能删除"); + } + if (StringUtils.isNull(sysRole)) { + throw new ServiceException("角色不存在"); + } + sysRole.setDelFlag("2"); + this.updateRole(sysRole); + } +} 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 new file mode 100644 index 0000000..42c70be --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java @@ -0,0 +1,89 @@ +package com.ruoyi.system.service.impl; + +import com.ruoyi.system.domain.SysUserOnline; +import com.ruoyi.system.service.ISysUserOnlineService; +import org.springframework.stereotype.Service; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.system.api.model.LoginUser; + +/** + * 在线用户 服务层处理 + * + * @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)) + { + return null; + } + SysUserOnline sysUserOnline = new SysUserOnline(); + sysUserOnline.setTokenId(user.getToken()); + sysUserOnline.setUserName(user.getUsername()); + sysUserOnline.setIpaddr(user.getIpaddr()); + sysUserOnline.setLoginTime(user.getLoginTime()); + return sysUserOnline; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 0000000..8a777ec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,95 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.mapper.SysUserRoleMapper; +import com.ruoyi.system.service.ISysUserRoleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 用户和角色关联Service业务层处理 + * + * @author xiaochen + * @date 2023-06-12 + */ +@Service +public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUserRole> implements ISysUserRoleService +{ + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + + /** + * 查询用户和角色关联 + * + * @param userId 用户和角色关联主键 + * @return 用户和角色关联 + */ + @Override + public SysUserRole selectSysUserRoleByUserId(Long userId) + { + return sysUserRoleMapper.selectSysUserRoleByUserId(userId); + } + + /** + * 查询用户和角色关联列表 + * + * @param sysUserRole 用户和角色关联 + * @return 用户和角色关联 + */ + @Override + public List<SysUserRole> selectSysUserRoleList(SysUserRole sysUserRole) + { + return sysUserRoleMapper.selectSysUserRoleList(sysUserRole); + } + + /** + * 新增用户和角色关联 + * + * @param sysUserRole 用户和角色关联 + * @return 结果 + */ + @Override + public int insertSysUserRole(SysUserRole sysUserRole) + { + return sysUserRoleMapper.insertSysUserRole(sysUserRole); + } + + /** + * 修改用户和角色关联 + * + * @param sysUserRole 用户和角色关联 + * @return 结果 + */ + @Override + public int updateSysUserRole(SysUserRole sysUserRole) + { + return sysUserRoleMapper.updateSysUserRole(sysUserRole); + } + + /** + * 批量删除用户和角色关联 + * + * @param userIds 需要删除的用户和角色关联主键 + * @return 结果 + */ + @Override + public int deleteSysUserRoleByUserIds(Long[] userIds) + { + return sysUserRoleMapper.deleteSysUserRoleByUserIds(userIds); + } + + /** + * 删除用户和角色关联信息 + * + * @param userId 用户和角色关联主键 + * @return 结果 + */ + @Override + public int deleteSysUserRoleByUserId(Long userId) + { + return sysUserRoleMapper.deleteSysUserRoleByUserId(userId); + } +} 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 new file mode 100644 index 0000000..22c9d1d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,645 @@ +package com.ruoyi.system.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.constant.UserConstants; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.bean.BeanValidators; +import com.ruoyi.common.core.utils.page.BeanUtils; +import com.ruoyi.common.core.utils.page.PageDTO; +import com.ruoyi.common.core.web.page.PageInfo; +import com.ruoyi.common.datascope.annotation.DataScope; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.system.api.domain.SysRole; +import com.ruoyi.system.api.domain.SysUser; +import com.ruoyi.system.domain.SysPost; +import com.ruoyi.system.domain.SysUserPost; +import com.ruoyi.system.domain.SysUserRole; +import com.ruoyi.system.domain.dto.SupplierDTO; +import com.ruoyi.system.domain.dto.SupplierQuery; +import com.ruoyi.system.domain.vo.SupplierVO; +import com.ruoyi.system.mapper.SysPostMapper; +import com.ruoyi.system.mapper.SysRoleMapper; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.system.mapper.SysUserPostMapper; +import com.ruoyi.system.mapper.SysUserRoleMapper; +import com.ruoyi.system.service.ISysConfigService; +import com.ruoyi.system.service.ISysUserService; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import javax.validation.Validator; +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 org.springframework.util.CollectionUtils; + +/** + * 用户 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService +{ + private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class); + + @Autowired + private SysUserMapper userMapper; + + @Autowired + private SysRoleMapper roleMapper; + + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + @Autowired + private ISysConfigService configService; + + @Autowired + protected Validator validator; + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List<SysUser> selectUserList(SysUser user) + { + return userMapper.selectUserList(user); + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List<SysUser> selectAllocatedList(SysUser user) + { + return userMapper.selectAllocatedList(user); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List<SysUser> selectUnallocatedList(SysUser user) + { + return userMapper.selectUnallocatedList(user); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByUserName(String userName) + { + return userMapper.selectUserByUserName(userName); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUser selectUserById(Long userId) + { + return userMapper.selectUserById(userId); + } + + /** + * 查询用户所属角色组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserRoleGroup(String userName) + { + List<SysRole> list = roleMapper.selectRolesByUserName(userName); + if (CollectionUtils.isEmpty(list)) + { + return StringUtils.EMPTY; + } + return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(",")); + } + + /** + * 查询用户所属岗位组 + * + * @param userName 用户名 + * @return 结果 + */ + @Override + public String selectUserPostGroup(String userName) + { + List<SysPost> list = postMapper.selectPostsByUserName(userName); + if (CollectionUtils.isEmpty(list)) + { + return StringUtils.EMPTY; + } + return list.stream().map(SysPost::getPostName).collect(Collectors.joining(",")); + } + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + 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()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return + */ + @Override + public boolean checkPhoneUnique(SysUser user) + { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); + if (StringUtils.isNotNull(info) ) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return + */ + @Override + 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()) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /** + * 校验用户是否允许操作 + * + * @param user 用户信息 + */ + @Override + 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<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user); + if (StringUtils.isEmpty(users)) + { + throw new ServiceException("没有权限访问用户数据!"); + } + } + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertUser(SysUser user) + { + // 新增用户信息 + int rows = userMapper.insertUser(user); +// // 新增用户岗位关联 +// insertUserPost(user); +// // 新增用户与角色管理 +// insertUserRole(user); + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public SysUser registerUser(SysUser user) + { + int id = userMapper.insertUser(user); + log.info("user------------------"+user.toString()); + return user; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateUser(SysUser user) + { +// Long userId = user.getUserId(); +// // 删除用户与角色关联 +// userRoleMapper.deleteUserRoleByUserId(userId); +// // 新增用户与角色管理 +// insertUserRole(user); +// // 删除用户与岗位关联 +// userPostMapper.deleteUserPostByUserId(userId); +// // 新增用户与岗位管理 +// insertUserPost(user); + return userMapper.updateUser(user); + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertUserAuth(Long userId, Long[] roleIds) + { + userRoleMapper.deleteUserRoleByUserId(userId); + insertUserRole(userId, roleIds); + } + + /** + * 修改用户状态 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserStatus(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserProfile(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 修改用户头像 + * + * @param userName 用户名 + * @param avatar 头像地址 + * @return 结果 + */ + @Override + public boolean updateUserAvatar(String userName, String avatar) + { + return userMapper.updateUserAvatar(userName, avatar) > 0; + } + + /** + * 重置用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int resetPwd(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 重置用户密码 + * + * @param userName 用户名 + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(String userName, String password) + { + return userMapper.resetUserPwd(userName, password); + } + + /** + * 新增用户角色信息 + * + * @param user 用户对象 + */ + public void insertUserRole(SysUser user) + { + this.insertUserRole(user.getUserId(), user.getRoleIds()); + } + + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + */ + public void insertUserPost(SysUser user) + { + Long[] posts = user.getPostIds(); + if (StringUtils.isNotEmpty(posts)) + { + // 新增用户与岗位管理 + List<SysUserPost> list = new ArrayList<SysUserPost>(); + for (Long postId : posts) + { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + list.add(up); + } + userPostMapper.batchUserPost(list); + } + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserRole(Long userId, Long[] roleIds) + { + if (StringUtils.isNotEmpty(roleIds)) + { + // 新增用户与角色管理 + List<SysUserRole> list = new ArrayList<SysUserRole>(); + for (Long roleId : roleIds) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + userRoleMapper.batchUserRole(list); + } + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserById(Long userId) + { + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 删除用户与岗位表 + userPostMapper.deleteUserPostByUserId(userId); + return userMapper.deleteUserById(userId); + } + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserByIds(Long[] userIds) + { + for (Long userId : userIds) + { + checkUserAllowed(new SysUser(userId)); +// checkUserDataScope(userId); + } + // 删除用户与角色关联 +// userRoleMapper.deleteUserRole(userIds); +// // 删除用户与岗位关联 +// userPostMapper.deleteUserPost(userIds); + return userMapper.deleteUserByIds(userIds); + } + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + @Override + public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) + { + if (StringUtils.isNull(userList) || userList.size() == 0) + { + throw new ServiceException("导入用户数据不能为空!"); + } + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + String password = configService.selectConfigByKey("sys.user.initPassword"); + for (SysUser user : userList) + { + try + { + // 验证是否存在这个用户 + SysUser u = userMapper.selectUserByUserName(user.getUserName()); + if (StringUtils.isNull(u)) + { + BeanValidators.validateWithException(validator, user); + user.setPassword(SecurityUtils.encryptPassword(password)); + user.setCreateBy(operName); + userMapper.insertUser(user); + successNum++; + successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功"); + } + else if (isUpdateSupport) + { + BeanValidators.validateWithException(validator, user); + checkUserAllowed(u); + checkUserDataScope(u.getUserId()); + user.setUserId(u.getUserId()); + user.setUpdateBy(operName); + userMapper.updateUser(user); + successNum++; + successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功"); + } + else + { + failureNum++; + failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在"); + } + } + catch (Exception e) + { + failureNum++; + String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + if (failureNum > 0) + { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } + else + { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + @Override + public PageInfo<SysUser> getList(PageInfo<SysUser> pageInfo, String nickName, + String phonenumber, Integer status) { + return this.baseMapper.getList(pageInfo, nickName, phonenumber, status); + } + + @Override + public PageInfo<SysUser> getAllList(PageInfo<SysUser> pageInfo, List<Integer> collect) { + return this.baseMapper.getAllList(pageInfo,collect); + } + + @Override + public List<Long> getSysUserFromPhone(String phoneNumber) { + return this.baseMapper.getSysUserFromPhone(phoneNumber); + } + + @Override + public void deleteSysUser(ArrayList<Integer> userIds) { + this.baseMapper.deleteSysUser(userIds); + } + + /** + * 获取供应商分页列表 + * + * @param query 供应商列表查询数据传输对象 + * @return PageDTO<SupplyUserVO> + */ + @Override + public PageDTO<SupplierVO> getSupplierPage(SupplierQuery query) { + Page<SysUser> page = this.lambdaQuery() + .select(SysUser::getUserId, SysUser::getNickName, SysUser::getPhonenumber) + .like(StringUtils.isNotBlank(query.getNickName() + ), SysUser::getNickName, query.getNickName()).eq(SysUser::getUserType, "04") + .eq(SysUser::getDelFlag, "0").orderByDesc(SysUser::getCreateTime) + .page(new Page<>(query.getPageCurr(), query.getPageSize())); + if (StringUtils.isEmpty(page.getRecords())) { + return PageDTO.empty(page); + } + return PageDTO.of(page, SupplierVO.class); + } + + /** + * 添加/编辑供应商 + * + * @param dto 供应商数据传输对象 + */ + @Override + public void saveSupplier(SupplierDTO dto) { + + SysUser user = BeanUtils.copyBean(dto, SysUser.class); + boolean b = checkPhoneUnique(user); + if (!b) { + throw new ServiceException("该手机号已存在"); + } + // 添加 + if (StringUtils.isNull(dto.getUserId())) { + user.setUserName(dto.getPhonenumber()); + user.setPassword(SecurityUtils.encryptPassword(dto.getPassword())); + user.setUserType("04"); + user.setCreateTime(new Date()); + user.setCreateBy(SecurityUtils.getUsername()); + this.save(user); + } else { + // 编辑 + user = this.getById(dto.getUserId()); + if (StringUtils.isNull(user)) { + throw new ServiceException("供应商不存在"); + } + user.setNickName(dto.getNickName()); + user.setPhonenumber(dto.getPhonenumber()); + user.setUserName(dto.getPhonenumber()); + user.setUpdateTime(new Date()); + user.setUpdateBy(SecurityUtils.getUsername()); + if (StringUtils.isNotBlank(dto.getPassword())) { + user.setPassword(SecurityUtils.encryptPassword(dto.getPassword())); + } + this.updateById(user); + } + } + + /** + * 删除供应商 + * + * @param id 供应商id + */ + @Override + public void deleteSupplier(Long id) { + this.lambdaUpdate().set(SysUser::getDelFlag, "2").eq(SysUser::getUserId, id).update(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/utils/HuaWeiSMSUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/utils/HuaWeiSMSUtil.java new file mode 100644 index 0000000..b534b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/utils/HuaWeiSMSUtil.java @@ -0,0 +1,180 @@ +package com.ruoyi.system.utils; + +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.util.EntityUtils; + +//如果JDK版本是1.8,可使用原生Base64类 + +public class HuaWeiSMSUtil { + + //无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 + private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; + //无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 + private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; + + public static void main(String[] args) throws Exception{ + + sendSms("[\""+12356+"\"]","18283820718","8823121426646","cf1707ec44694627b1b483b0277e12fd"); + +// sendSms("[\"17623778642\",\"蓉A-7823\"]","17623778642","8819122535459","6c848255000c4619833ab690e393f906"); +// sendSms("[\"17623778642\",\"蓉A-7823\",\"2019/12/27\",\"14:00\"]","17623778642","8819122535459","bb13d00d11e043659001a89c72d54cab"); + } + + /** + * 调用短信 + * @param code 入参 + * @param phone 接收短信手机号 + * @param sender 国内短信签名通道号或国际/港澳台短信通道号 + * @param templateId 模板ID + * @throws Exception + */ + public static void sendSms(String code,String phone,String sender,String templateId) throws Exception{ + //必填,请参考"开发准备"获取如下数据,替换为实际值 + String url = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址+接口访问URI + String appKey = "tTMBH29Tm6tKKHf882JXob82P1rb"; //APP_Key + String appSecret = "Ob02q15WAgDZRwW9kDlVPklBSdfR"; //APP_Secret + + //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称 + //国际/港澳台短信不用关注该参数 + String signature = null; //签名名称 + + //必填,全局号码格式(包含国家码),示例:+8615123456789,多个号码之间用英文逗号分隔 + String receiver = "+86"+phone; //短信接收人号码 + + //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 + String statusCallBack = ""; + + /** + * 选填,使用无变量模板时请赋空值 String templateParas = ""; + * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"369751\"]" + * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]" + * ${DATE}${TIME}变量不允许取值为空,${TXT_20}变量可以使用英文空格或点号替代空值,${NUM_6}变量可以使用0替代空值 + * 查看更多模板和变量规范:产品介绍>模板和变量规范 + */ + String templateParas = code; //模板变量 + + //请求Body,不携带签名名称时,signature请填null + String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature); + if (null == body || body.isEmpty()) { + System.out.println("body is null."); + return; + } + + //请求Headers中的X-WSSE参数值 + String wsseHeader = buildWsseHeader(appKey, appSecret); + if (null == wsseHeader || wsseHeader.isEmpty()) { + System.out.println("wsse header is null."); + return; + } + + //如果JDK版本低于1.8,可使用如下代码 + //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 + //CloseableHttpClient client = HttpClients.custom() + // .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + // @Override + // public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + // return true; + // } + // }).build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); + + //如果JDK版本是1.8,可使用如下代码 + //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 + CloseableHttpClient client = HttpClients.custom() + .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, + (x509CertChain, authType) -> true).build()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + + HttpResponse response = client.execute(RequestBuilder.create("POST")//请求方法POST + .setUri(url) + .addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded") + .addHeader(HttpHeaders.AUTHORIZATION, AUTH_HEADER_VALUE) + .addHeader("X-WSSE", wsseHeader) + .setEntity(new StringEntity(body)).build()); + + System.out.println(response.toString()); //打印响应头域信息 + System.out.println(EntityUtils.toString(response.getEntity())); //打印响应消息实体 + } + + /** + * 构造请求Body体 + * @param sender + * @param receiver + * @param templateId + * @param templateParas + * @param statusCallbackUrl + * @param signature | 签名名称,使用国内短信通用模板时填写 + * @return + */ + static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, + String statusCallbackUrl, String signature) { + if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() + || templateId.isEmpty()) { + System.out.println("buildRequestBody(): sender, receiver or templateId is null."); + return null; + } + List<NameValuePair> keyValues = new ArrayList<NameValuePair>(); + + keyValues.add(new BasicNameValuePair("from", sender)); + keyValues.add(new BasicNameValuePair("to", receiver)); + keyValues.add(new BasicNameValuePair("templateId", templateId)); + if (null != templateParas && !templateParas.isEmpty()) { + keyValues.add(new BasicNameValuePair("templateParas", templateParas)); + } + if (null != statusCallbackUrl && !statusCallbackUrl.isEmpty()) { + keyValues.add(new BasicNameValuePair("statusCallback", statusCallbackUrl)); + } + if (null != signature && !signature.isEmpty()) { + keyValues.add(new BasicNameValuePair("signature", signature)); + } + + return URLEncodedUtils.format(keyValues, Charset.forName("UTF-8")); + } + + /** + * 构造X-WSSE参数值 + * @param appKey + * @param appSecret + * @return + */ + static String buildWsseHeader(String appKey, String appSecret) { + if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { + System.out.println("buildWsseHeader(): appKey or appSecret is null."); + return null; + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + String time = sdf.format(new Date()); //Created + String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce + + byte[] passwordDigest = DigestUtils.sha256(nonce + time + appSecret); + String hexDigest = Hex.encodeHexString(passwordDigest); + + //如果JDK版本是1.8,请加载原生Base64类,并使用如下代码 + String passwordDigestBase64Str = Base64.getEncoder().encodeToString(hexDigest.getBytes()); //PasswordDigest + //如果JDK版本低于1.8,请加载三方库提供Base64类,并使用如下代码 + //String passwordDigestBase64Str = Base64.encodeBase64String(hexDigest.getBytes(Charset.forName("utf-8"))); //PasswordDigest + //若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正 + //passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", ""); + + return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/SemaphoreUtils.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/SemaphoreUtils.java new file mode 100644 index 0000000..545621a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/SemaphoreUtils.java @@ -0,0 +1,59 @@ +package com.ruoyi.system.websocket; + +import java.util.concurrent.Semaphore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 信号量相关处理 + * + * @author ruoyi + */ +public class SemaphoreUtils +{ + + /** + * SemaphoreUtils 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(SemaphoreUtils.class); + + /** + * 获取信号量 + * + * @param semaphore + * @return + */ + public static boolean tryAcquire(Semaphore semaphore) + { + boolean flag = false; + + try + { + flag = semaphore.tryAcquire(); + } + catch (Exception e) + { + LOGGER.error("获取信号量异常", e); + } + + return flag; + } + + /** + * 释放信号量 + * + * @param semaphore + */ + public static void release(Semaphore semaphore) + { + + try + { + semaphore.release(); + } + catch (Exception e) + { + LOGGER.error("释放信号量异常", e); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketConfig.java new file mode 100644 index 0000000..e7c191a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketConfig.java @@ -0,0 +1,20 @@ +package com.ruoyi.system.websocket; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * websocket 配置 + * + * @author ruoyi + */ +@Configuration +public class WebSocketConfig +{ + @Bean + public ServerEndpointExporter serverEndpointExporter() + { + return new ServerEndpointExporter(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer.java new file mode 100644 index 0000000..ee679e8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer.java @@ -0,0 +1,77 @@ +package com.ruoyi.system.websocket; + +import java.util.concurrent.Semaphore; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * websocket 消息处理 + * + * @作者 ruoyi + */ +@Component +@ServerEndpoint("/websocket/message/{clientType}") +public class WebSocketServer { + + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class); + public static int socketMaxOnlineCount = 1000; + private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount); + + @OnOpen + public void onOpen(Session session, @PathParam("clientType") Integer clientType) + throws Exception { + boolean semaphoreFlag = false; + semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore); + if (!semaphoreFlag) { + LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount); + WebSocketUsers.sendMessageToUserByText(session, + "当前在线人数超过限制数:" + socketMaxOnlineCount); + session.close(); + } else { + WebSocketUsers.put(session.getId(), session, clientType); + + if (clientType == 1) { + LOGGER.info("\n 用户端建立连接 - {}", session); + WebSocketUsers.sendMessageToUserByText(session, "用户端连接成功"); + } else if (clientType == 2) { + LOGGER.info("\n 拍卖师端建立连接 - {}", session); + WebSocketUsers.sendMessageToUserByText(session, "拍卖师端连接成功"); + } + LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size()); + } + } + + @OnClose + public void onClose(Session session) { + LOGGER.info("\n 关闭连接 - {}", session); + WebSocketUsers.remove(session.getId()); + SemaphoreUtils.release(socketSemaphore); + } + + @OnError + public void onError(Session session, Throwable exception) throws Exception { + if (session.isOpen()) { + session.close(); + } + String sessionId = session.getId(); + LOGGER.info("\n 连接异常 - {}", sessionId); + LOGGER.info("\n 异常信息 - {}", exception); + WebSocketUsers.remove(sessionId); + SemaphoreUtils.release(socketSemaphore); + } + + @OnMessage + public void onMessage(String message, Session session) { + String msg = message.replace("你", "我").replace("吗", "").replace("PING", "PONG") + .replace("ping", "pong"); + WebSocketUsers.sendMessageToUserByText(session, msg); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer_Bak.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer_Bak.java new file mode 100644 index 0000000..8e8fafc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketServer_Bak.java @@ -0,0 +1,97 @@ +package com.ruoyi.system.websocket; + +import com.ruoyi.system.api.util.WebSocketUsers_Bak; +import java.util.concurrent.Semaphore; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * websocket 消息处理 + * + * @author ruoyi + */ +@Component +@ServerEndpoint("/websocket/message") +public class WebSocketServer_Bak { + + /** + * WebSocketServer 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer_Bak.class); + + /** + * 默认最多允许同时在线人数100 + */ + public static int socketMaxOnlineCount = 100; + + private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount); + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session) throws Exception { + boolean semaphoreFlag = false; + // 尝试获取信号量 + semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore); + if (!semaphoreFlag) { + // 未获取到信号量 + LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount); + WebSocketUsers_Bak.sendMessageToUserByText(session, + "当前在线人数超过限制数:" + socketMaxOnlineCount); + session.close(); + } else { + // 添加用户 + WebSocketUsers_Bak.put(session.getId(), session); + LOGGER.info("\n 建立连接 - {}", session); + LOGGER.info("\n 当前人数 - {}", WebSocketUsers_Bak.getUsers().size()); + WebSocketUsers_Bak.sendMessageToUserByText(session, "连接成功"); + } + } + + /** + * 连接关闭时处理 + */ + @OnClose + public void onClose(Session session) { + LOGGER.info("\n 关闭连接 - {}", session); + // 移除用户 + WebSocketUsers_Bak.remove(session.getId()); + // 获取到信号量则需释放 + SemaphoreUtils.release(socketSemaphore); + } + + /** + * 抛出异常时处理 + */ + @OnError + public void onError(Session session, Throwable exception) throws Exception { + if (session.isOpen()) { + // 关闭连接 + session.close(); + } + String sessionId = session.getId(); + LOGGER.info("\n 连接异常 - {}", sessionId); + LOGGER.info("\n 异常信息 - {}", exception); + // 移出用户 + WebSocketUsers_Bak.remove(sessionId); + // 获取到信号量则需释放 + SemaphoreUtils.release(socketSemaphore); + } + + /** + * 服务器接收到客户端消息时调用的方法 + */ + @OnMessage + public void onMessage(String message, Session session) { + String msg = message.replace("你", "我").replace("吗", ""); + WebSocketUsers_Bak.sendMessageToUserByText(session, msg); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketUsers.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketUsers.java new file mode 100644 index 0000000..9b162c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/websocket/WebSocketUsers.java @@ -0,0 +1,123 @@ +package com.ruoyi.system.websocket; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import javax.websocket.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * websocket 客户端用户集 + * + * @author ruoyi + */ +public class WebSocketUsers +{ + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUsers.class); + + private static Map<String, Session> USERS = new ConcurrentHashMap<>(); + private static Map<String, Integer> USER_TYPES = new ConcurrentHashMap<>(); + + public static void put(String key, Session session, Integer clientType) + { + USERS.put(key, session); + USER_TYPES.put(key, clientType); + } + + public static boolean remove(Session session) + { + String key = null; + boolean flag = USERS.containsValue(session); + if (flag) + { + Set<Map.Entry<String, Session>> entries = USERS.entrySet(); + for (Map.Entry<String, Session> entry : entries) + { + Session value = entry.getValue(); + if (value.equals(session)) + { + key = entry.getKey(); + break; + } + } + } + else + { + return true; + } + return remove(key); + } + + public static boolean remove(String key) + { + LOGGER.info("\n 正在移出用户 - {}", key); + Session remove = USERS.remove(key); + USER_TYPES.remove(key); + if (remove != null) + { + boolean containsValue = USERS.containsValue(remove); + LOGGER.info("\n 移出结果 - {}", containsValue ? "失败" : "成功"); + return containsValue; + } + else + { + return true; + } + } + + public static Map<String, Session> getUsers() + { + return USERS; + } + + public static Integer getUserType(String key) { + return USER_TYPES.get(key); + } + + public static void sendMessageToUsersByText(String message) + { + Collection<Session> values = USERS.values(); + for (Session value : values) + { + sendMessageToUserByText(value, message); + } + } + + public static void sendMessageToUserByText(Session session, String message) + { + if (session != null) + { + try + { + session.getBasicRemote().sendText(message); + } + catch (IOException e) + { + LOGGER.error("\n[发送消息异常]", e); + } + } + else + { + LOGGER.info("\n[你已离线]"); + } + } + + /** + * 根据客户端类型发送消息 + * + * @param clientType 1=会员小程序 2=拍卖师小程序 + * @param message 发送的消息 + */ + public static void sendMessageToUsersByType(Integer clientType, String message) { + for (Map.Entry<String, Session> entry : USERS.entrySet()) { + String key = entry.getKey(); + Session session = entry.getValue(); + if (clientType.equals(USER_TYPES.get(key))) { + sendMessageToUserByText(session, message); + } + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt new file mode 100644 index 0000000..dcc7b80 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ + (_) | | + _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___ +| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ +| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | | +|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_| + __/ | __/ | + |___/ |___/ \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..d1aede2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml @@ -0,0 +1,82 @@ +# Spring +spring: + application: + # 应用名称 + name: ruoyi-system + main: + allow-bean-definition-overriding: true + profiles: + # 环境配置 + active: dev +--- +spring: + config: + activate: + on-profile: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.235:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 689e0f09-d102-460c-ac5c-5ea50a3174be + config: + # 配置中心地址 + server-addr: 192.168.110.235:8848 + namespace: 689e0f09-d102-460c-ac5c-5ea50a3174be + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} +--- +spring: + config: + activate: + on-profile: prod + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.188:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2 + config: + # 配置中心地址 + server-addr: 192.168.110.188:8848 + namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2 + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} +--- +spring: + config: + activate: + on-profile: test + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.188:8848 + service: ${spring.application.name} + group: DEFAULT_GROUP + namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce + config: + # 配置中心地址 + server-addr: 192.168.110.188:8848 + namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce + group: DEFAULT_GROUP + name: ${spring.application.name} + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-system/src/main/resources/logback.xml new file mode 100644 index 0000000..0154e28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/logback.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <!-- 日志存放路径 --> + <property name="log.path" value="logs/ruoyi-system" /> + <!-- 日志输出格式 --> + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> + + <!-- 控制台输出 --> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + </appender> + + <!-- 系统日志输出 --> + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/info.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>INFO</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/error.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>ERROR</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 系统模块日志级别控制 --> + <logger name="com.ruoyi" level="info" /> + <!-- Spring日志级别控制 --> + <logger name="org.springframework" level="warn" /> + + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--系统操作日志--> + <root level="info"> + <appender-ref ref="file_info" /> + <appender-ref ref="file_error" /> + </root> +</configuration> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/AgreementMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/AgreementMapper.xml new file mode 100644 index 0000000..237a23f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/AgreementMapper.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.AgreementMapper"> + +</mapper> diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/DelayTaskMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/DelayTaskMapper.xml new file mode 100644 index 0000000..5ff1188 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/DelayTaskMapper.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.config.DelayTaskMapper"> + + +</mapper> diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/MemberPointsMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/MemberPointsMapper.xml new file mode 100644 index 0000000..029ad7c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/MemberPointsMapper.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.member.mapper.MemberPointsMapper"> + +</mapper> diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000..da9735e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysConfigMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysConfig" id="SysConfigResult"> + <id property="configId" column="config_id" /> + <result property="configName" column="config_name" /> + <result property="configKey" column="config_key" /> + <result property="configValue" column="config_value" /> + <result property="configType" column="config_type" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectConfigVo"> + select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark + from sys_config + </sql> + + <!-- 查询条件 --> + <sql id="sqlwhereSearch"> + <where> + <if test="configId !=null"> + and config_id = #{configId} + </if> + <if test="configKey !=null and configKey != ''"> + and config_key = #{configKey} + </if> + </where> + </sql> + + <select id="selectConfig" parameterType="com.ruoyi.system.api.domain.SysConfig" resultMap="SysConfigResult"> + <include refid="selectConfigVo"/> + <include refid="sqlwhereSearch"/> + </select> + + <select id="selectConfigList" parameterType="com.ruoyi.system.api.domain.SysConfig" resultMap="SysConfigResult"> + <include refid="selectConfigVo"/> + <where> + <if test="configName != null and configName != ''"> + AND config_name like concat('%', #{configName}, '%') + </if> + <if test="configType != null and configType != ''"> + AND config_type = #{configType} + </if> + <if test="configKey != null and configKey != ''"> + AND config_key like concat('%', #{configKey}, '%') + </if> + <if test="params.beginTime != null and params.beginTime != ''"> + and date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"> + and date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + </where> + </select> + + <select id="selectConfigById" parameterType="Long" resultMap="SysConfigResult"> + <include refid="selectConfigVo"/> + where config_id = #{configId} + </select> + + <select id="checkConfigKeyUnique" parameterType="String" resultMap="SysConfigResult"> + <include refid="selectConfigVo"/> + where config_key = #{configKey} limit 1 + </select> + + <insert id="insertConfig" parameterType="com.ruoyi.system.api.domain.SysConfig"> + insert into sys_config ( + <if test="configName != null and configName != '' ">config_name,</if> + <if test="configKey != null and configKey != '' ">config_key,</if> + <if test="configValue != null and configValue != '' ">config_value,</if> + <if test="configType != null and configType != '' ">config_type,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + <if test="remark != null and remark != ''">remark,</if> + create_time + )values( + <if test="configName != null and configName != ''">#{configName},</if> + <if test="configKey != null and configKey != ''">#{configKey},</if> + <if test="configValue != null and configValue != ''">#{configValue},</if> + <if test="configType != null and configType != ''">#{configType},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + <if test="remark != null and remark != ''">#{remark},</if> + sysdate() + ) + </insert> + + <update id="updateConfig" parameterType="com.ruoyi.system.api.domain.SysConfig"> + update sys_config + <set> + <if test="configName != null and configName != ''">config_name = #{configName},</if> + <if test="configKey != null and configKey != ''">config_key = #{configKey},</if> + <if test="configValue != null and configValue != ''">config_value = #{configValue},</if> + <if test="configType != null and configType != ''">config_type = #{configType},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + <if test="remark != null">remark = #{remark},</if> + update_time = sysdate() + </set> + where config_id = #{configId} + </update> + + <delete id="deleteConfigById" parameterType="Long"> + delete from sys_config where config_id = #{configId} + </delete> + + <delete id="deleteConfigByIds" parameterType="Long"> + delete from sys_config where config_id in + <foreach item="configId" collection="array" open="(" separator="," close=")"> + #{configId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000..1e786d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysDeptMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysDept" id="SysDeptResult"> + <id property="deptId" column="dept_id" /> + <result property="parentId" column="parent_id" /> + <result property="ancestors" column="ancestors" /> + <result property="deptName" column="dept_name" /> + <result property="orderNum" column="order_num" /> + <result property="leader" column="leader" /> + <result property="phone" column="phone" /> + <result property="email" column="email" /> + <result property="status" column="status" /> + <result property="delFlag" column="del_flag" /> + <result property="parentName" column="parent_name" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectDeptVo"> + select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time + from sys_dept d + </sql> + + <select id="selectDeptList" parameterType="com.ruoyi.system.api.domain.SysDept" resultMap="SysDeptResult"> + <include refid="selectDeptVo"/> + where d.del_flag = '0' + <if test="deptId != null and deptId != 0"> + AND dept_id = #{deptId} + </if> + <if test="parentId != null and parentId != 0"> + AND parent_id = #{parentId} + </if> + <if test="deptName != null and deptName != ''"> + AND dept_name like concat('%', #{deptName}, '%') + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + <!-- 数据范围过滤 --> + ${params.dataScope} + order by d.parent_id, d.order_num + </select> + + <select id="selectDeptListByRoleId" resultType="Long"> + select d.dept_id + from sys_dept d + left join sys_role_dept rd on d.dept_id = rd.dept_id + where rd.role_id = #{roleId} + <if test="deptCheckStrictly"> + and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId}) + </if> + order by d.parent_id, d.order_num + </select> + + <select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult"> + <include refid="selectDeptVo"/> + where dept_id = #{deptId} + </select> + + <select id="checkDeptExistUser" parameterType="Long" resultType="int"> + select count(1) from sys_user where dept_id = #{deptId} and del_flag = '0' + </select> + + <select id="hasChildByDeptId" parameterType="Long" resultType="int"> + select count(1) from sys_dept + where del_flag = '0' and parent_id = #{deptId} limit 1 + </select> + + <select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult"> + select * from sys_dept where find_in_set(#{deptId}, ancestors) + </select> + + <select id="selectNormalChildrenDeptById" parameterType="Long" resultType="int"> + select count(*) from sys_dept where status = 0 and del_flag = '0' and find_in_set(#{deptId}, ancestors) + </select> + + <select id="checkDeptNameUnique" resultMap="SysDeptResult"> + <include refid="selectDeptVo"/> + where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1 + </select> + + <insert id="insertDept" parameterType="com.ruoyi.system.api.domain.SysDept"> + insert into sys_dept( + <if test="deptId != null and deptId != 0">dept_id,</if> + <if test="parentId != null and parentId != 0">parent_id,</if> + <if test="deptName != null and deptName != ''">dept_name,</if> + <if test="ancestors != null and ancestors != ''">ancestors,</if> + <if test="orderNum != null">order_num,</if> + <if test="leader != null and leader != ''">leader,</if> + <if test="phone != null and phone != ''">phone,</if> + <if test="email != null and email != ''">email,</if> + <if test="status != null">status,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="deptId != null and deptId != 0">#{deptId},</if> + <if test="parentId != null and parentId != 0">#{parentId},</if> + <if test="deptName != null and deptName != ''">#{deptName},</if> + <if test="ancestors != null and ancestors != ''">#{ancestors},</if> + <if test="orderNum != null">#{orderNum},</if> + <if test="leader != null and leader != ''">#{leader},</if> + <if test="phone != null and phone != ''">#{phone},</if> + <if test="email != null and email != ''">#{email},</if> + <if test="status != null">#{status},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateDept" parameterType="com.ruoyi.system.api.domain.SysDept"> + update sys_dept + <set> + <if test="parentId != null and parentId != 0">parent_id = #{parentId},</if> + <if test="deptName != null and deptName != ''">dept_name = #{deptName},</if> + <if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if> + <if test="orderNum != null">order_num = #{orderNum},</if> + <if test="leader != null">leader = #{leader},</if> + <if test="phone != null">phone = #{phone},</if> + <if test="email != null">email = #{email},</if> + <if test="status != null and status != ''">status = #{status},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where dept_id = #{deptId} + </update> + + <update id="updateDeptChildren" parameterType="java.util.List"> + update sys_dept set ancestors = + <foreach collection="depts" item="item" index="index" + separator=" " open="case dept_id" close="end"> + when #{item.deptId} then #{item.ancestors} + </foreach> + where dept_id in + <foreach collection="depts" item="item" index="index" + separator="," open="(" close=")"> + #{item.deptId} + </foreach> + </update> + + <update id="updateDeptStatusNormal" parameterType="Long"> + update sys_dept set status = '0' where dept_id in + <foreach collection="array" item="deptId" open="(" separator="," close=")"> + #{deptId} + </foreach> + </update> + + <delete id="deleteDeptById" parameterType="Long"> + update sys_dept set del_flag = '2' where dept_id = #{deptId} + </delete> + +</mapper> \ No newline at end of file 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 new file mode 100644 index 0000000..7f0d26d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysDictDataMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysDictData" id="SysDictDataResult"> + <id property="dictCode" column="dict_code" /> + <result property="dictSort" column="dict_sort" /> + <result property="dictLabel" column="dict_label" /> + <result property="dictValue" column="dict_value" /> + <result property="dictType" column="dict_type" /> + <result property="cssClass" column="css_class" /> + <result property="listClass" column="list_class" /> + <result property="isDefault" column="is_default" /> + <result property="status" column="status" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectDictDataVo"> + select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark + from sys_dict_data + </sql> + + <select id="selectDictDataList" parameterType="com.ruoyi.system.api.domain.SysDictData" resultMap="SysDictDataResult"> + <include refid="selectDictDataVo"/> + <where> + <if test="dictType != null and dictType != ''"> + AND dict_type = #{dictType} + </if> + <if test="dictLabel != null and dictLabel != ''"> + AND dict_label like concat('%', #{dictLabel}, '%') + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + </where> + order by dict_sort asc + </select> + + <select id="selectDictDataByType" parameterType="com.ruoyi.system.api.domain.SysDictData" resultMap="SysDictDataResult"> + <include refid="selectDictDataVo"/> + where status = '0' and dict_type = #{dictType} order by dict_sort asc + </select> + + <select id="selectDictLabel" resultType="String"> + select dict_label from sys_dict_data + where dict_type = #{dictType} and dict_value = #{dictValue} + </select> + + <select id="selectDictDataById" parameterType="Long" resultMap="SysDictDataResult"> + <include refid="selectDictDataVo"/> + where dict_code = #{dictCode} + </select> + + <select id="countDictDataByType" resultType="Integer"> + select count(1) from sys_dict_data where dict_type=#{dictType} + </select> + + <delete id="deleteDictDataById" parameterType="Long"> + delete from sys_dict_data where dict_code = #{dictCode} + </delete> + + <delete id="deleteDictDataByIds" parameterType="Long"> + delete from sys_dict_data where dict_code in + <foreach collection="array" item="dictCode" open="(" separator="," close=")"> + #{dictCode} + </foreach> + </delete> + + <update id="updateDictData" parameterType="com.ruoyi.system.api.domain.SysDictData"> + update sys_dict_data + <set> + <if test="dictSort != null">dict_sort = #{dictSort},</if> + <if test="dictLabel != null and dictLabel != ''">dict_label = #{dictLabel},</if> + <if test="dictValue != null and dictValue != ''">dict_value = #{dictValue},</if> + <if test="dictType != null and dictType != ''">dict_type = #{dictType},</if> + <if test="cssClass != null">css_class = #{cssClass},</if> + <if test="listClass != null">list_class = #{listClass},</if> + <if test="isDefault != null and isDefault != ''">is_default = #{isDefault},</if> + <if test="status != null">status = #{status},</if> + <if test="remark != null">remark = #{remark},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where dict_code = #{dictCode} + </update> + + <update id="updateDictDataType" parameterType="String"> + update sys_dict_data set dict_type = #{newDictType} where dict_type = #{oldDictType} + </update> + + <insert id="insertDictData" parameterType="com.ruoyi.system.api.domain.SysDictData"> + insert into sys_dict_data( + <if test="dictSort != null">dict_sort,</if> + <if test="dictLabel != null and dictLabel != ''">dict_label,</if> + <if test="dictValue != null and dictValue != ''">dict_value,</if> + <if test="dictType != null and dictType != ''">dict_type,</if> + <if test="cssClass != null and cssClass != ''">css_class,</if> + <if test="listClass != null and listClass != ''">list_class,</if> + <if test="isDefault != null and isDefault != ''">is_default,</if> + <if test="status != null">status,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="dictSort != null">#{dictSort},</if> + <if test="dictLabel != null and dictLabel != ''">#{dictLabel},</if> + <if test="dictValue != null and dictValue != ''">#{dictValue},</if> + <if test="dictType != null and dictType != ''">#{dictType},</if> + <if test="cssClass != null and cssClass != ''">#{cssClass},</if> + <if test="listClass != null and listClass != ''">#{listClass},</if> + <if test="isDefault != null and isDefault != ''">#{isDefault},</if> + <if test="status != null">#{status},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + +</mapper> \ 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 new file mode 100644 index 0000000..d8d2e4c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysDictTypeMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysDictType" id="SysDictTypeResult"> + <id property="dictId" column="dict_id" /> + <result property="dictName" column="dict_name" /> + <result property="dictType" column="dict_type" /> + <result property="status" column="status" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectDictTypeVo"> + select dict_id, dict_name, dict_type, status, create_by, create_time, remark + from sys_dict_type + </sql> + + <select id="selectDictTypeList" parameterType="com.ruoyi.system.api.domain.SysDictType" resultMap="SysDictTypeResult"> + <include refid="selectDictTypeVo"/> + <where> + <if test="dictName != null and dictName != ''"> + AND dict_name like concat('%', #{dictName}, '%') + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + <if test="dictType != null and dictType != ''"> + AND dict_type like concat('%', #{dictType}, '%') + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + and date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + and date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + </where> + </select> + + <select id="selectDictTypeAll" resultMap="SysDictTypeResult"> + <include refid="selectDictTypeVo"/> + </select> + + <select id="selectDictTypeById" parameterType="Long" resultMap="SysDictTypeResult"> + <include refid="selectDictTypeVo"/> + where dict_id = #{dictId} + </select> + + <select id="selectDictTypeByType" parameterType="String" resultMap="SysDictTypeResult"> + <include refid="selectDictTypeVo"/> + where dict_type = #{dictType} + </select> + + <select id="checkDictTypeUnique" parameterType="String" resultMap="SysDictTypeResult"> + <include refid="selectDictTypeVo"/> + where dict_type = #{dictType} limit 1 + </select> + + <delete id="deleteDictTypeById" parameterType="Long"> + delete from sys_dict_type where dict_id = #{dictId} + </delete> + + <delete id="deleteDictTypeByIds" parameterType="Long"> + delete from sys_dict_type where dict_id in + <foreach collection="array" item="dictId" open="(" separator="," close=")"> + #{dictId} + </foreach> + </delete> + + <update id="updateDictType" parameterType="com.ruoyi.system.api.domain.SysDictType"> + update sys_dict_type + <set> + <if test="dictName != null and dictName != ''">dict_name = #{dictName},</if> + <if test="dictType != null and dictType != ''">dict_type = #{dictType},</if> + <if test="status != null">status = #{status},</if> + <if test="remark != null">remark = #{remark},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where dict_id = #{dictId} + </update> + + <insert id="insertDictType" parameterType="com.ruoyi.system.api.domain.SysDictType"> + insert into sys_dict_type( + <if test="dictName != null and dictName != ''">dict_name,</if> + <if test="dictType != null and dictType != ''">dict_type,</if> + <if test="status != null">status,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="dictName != null and dictName != ''">#{dictName},</if> + <if test="dictType != null and dictType != ''">#{dictType},</if> + <if test="status != null">#{status},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml new file mode 100644 index 0000000..8c5a10e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysLogininforMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysLogininfor" id="SysLogininforResult"> + <id property="infoId" column="info_id" /> + <result property="userName" column="user_name" /> + <result property="status" column="status" /> + <result property="ipaddr" column="ipaddr" /> + <result property="msg" column="msg" /> + <result property="accessTime" column="access_time" /> + </resultMap> + + <insert id="insertLogininfor" parameterType="com.ruoyi.system.api.domain.SysLogininfor"> + insert into sys_logininfor (user_name, status, ipaddr, msg, access_time) + values (#{userName}, #{status}, #{ipaddr}, #{msg}, sysdate()) + </insert> + + <select id="selectLogininforList" parameterType="com.ruoyi.system.api.domain.SysLogininfor" resultMap="SysLogininforResult"> + select info_id, user_name, ipaddr, status, msg, access_time from sys_logininfor + <where> + <if test="ipaddr != null and ipaddr != ''"> + AND ipaddr like concat('%', #{ipaddr}, '%') + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + <if test="userName != null and userName != ''"> + AND user_name like concat('%', #{userName}, '%') + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + AND access_time >= #{params.beginTime} + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + AND access_time <= #{params.endTime} + </if> + </where> + order by info_id desc + </select> + + <delete id="deleteLogininforByIds" parameterType="Long"> + delete from sys_logininfor where info_id in + <foreach collection="array" item="infoId" open="(" separator="," close=")"> + #{infoId} + </foreach> + </delete> + + <update id="cleanLogininfor"> + truncate table sys_logininfor + </update> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000..106359f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,275 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper + PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysMenuMapper"> + + <resultMap type="com.ruoyi.system.domain.SysMenu" id="SysMenuResult"> + <id property="menuId" column="menu_id" /> + <result property="menuName" column="menu_name" /> + <result property="parentName" column="parent_name" /> + <result property="parentId" column="parent_id" /> + <result property="orderNum" column="order_num" /> + <result property="path" column="path" /> + <result property="component" column="component" /> + <result property="query" column="query" /> + <result property="isFrame" column="is_frame" /> + <result property="isCache" column="is_cache" /> + <result property="menuType" column="menu_type" /> + <result property="visible" column="visible" /> + <result property="status" column="status" /> + <result property="perms" column="perms" /> + <result property="icon" column="icon" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateTime" column="update_time" /> + <result property="updateBy" column="update_by" /> + <result property="remark" column="remark" /> + </resultMap> + + <sql id="selectMenuVo"> + select menu_id, menu_name, parent_id, order_num, path, component, `query`, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time + from sys_menu + </sql> + + <select id="selectMenuList" parameterType="com.ruoyi.system.domain.SysMenu" resultMap="SysMenuResult"> + <include refid="selectMenuVo"/> + <where> + <if test="menuName != null and menuName != ''"> + AND menu_name like concat('%', #{menuName}, '%') + </if> + <if test="visible != null and visible != ''"> + AND visible = #{visible} + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + </where> + order by parent_id, order_num + </select> + + <select id="selectMenuTreeAll" resultMap="SysMenuResult"> + select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time + from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0 + order by m.parent_id, m.order_num + </select> + + <select id="selectMenuListByUserId" parameterType="com.ruoyi.system.domain.SysMenu" resultMap="SysMenuResult"> + select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time + from sys_menu m + left join sys_role_menu rm on m.menu_id = rm.menu_id + left join sys_user_role ur on rm.role_id = ur.role_id + left join sys_role ro on ur.role_id = ro.role_id + where ur.user_id = #{params.userId} + <if test="menuName != null and menuName != ''"> + AND m.menu_name like concat('%', #{menuName}, '%') + </if> + <if test="visible != null and visible != ''"> + AND m.visible = #{visible} + </if> + <if test="status != null and status != ''"> + AND m.status = #{status} + </if> + order by m.parent_id, m.order_num + </select> + + <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult"> + select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time + from sys_menu m + left join sys_role_menu rm on m.menu_id = rm.menu_id + left join sys_user_role ur on rm.role_id = ur.role_id + left join sys_role ro on ur.role_id = ro.role_id + left join sys_user u on ur.user_id = u.user_id + where u.user_id = #{userId} and m.menu_type in ('M', 'C') and m.status = 0 AND ro.status = 0 + order by m.parent_id, m.order_num + </select> + + <select id="selectMenuListByRoleId" resultType="Long"> + select m.menu_id + from sys_menu m + left join sys_role_menu rm on m.menu_id = rm.menu_id + where rm.role_id = #{roleId} + <if test="menuCheckStrictly"> + and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId}) + </if> + order by m.parent_id, m.order_num + </select> + + <select id="selectMenuPerms" resultType="String"> + select distinct m.perms + from sys_menu m + left join sys_role_menu rm on m.menu_id = rm.menu_id + left join sys_user_role ur on rm.role_id = ur.role_id + </select> + + <select id="selectMenuPermsByUserId" parameterType="Long" resultType="String"> + select distinct m.perms + from sys_menu m + left join sys_role_menu rm on m.menu_id = rm.menu_id + left join sys_user_role ur on rm.role_id = ur.role_id + left join sys_role r on r.role_id = ur.role_id + where m.status = '0' and r.status = '0' and ur.user_id = #{userId} + </select> + + <select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String"> + select distinct m.perms + from sys_menu m + left join sys_role_menu rm on m.menu_id = rm.menu_id + where m.status = '0' and rm.role_id = #{roleId} + </select> + + <select id="selectMenuById" parameterType="Long" resultMap="SysMenuResult"> + <include refid="selectMenuVo"/> + where menu_id = #{menuId} + </select> + + <select id="hasChildByMenuId" resultType="Integer"> + select count(1) from sys_menu where parent_id = #{menuId} + </select> + + <select id="checkMenuNameUnique" parameterType="com.ruoyi.system.domain.SysMenu" resultMap="SysMenuResult"> + <include refid="selectMenuVo"/> + where menu_name=#{menuName} and parent_id = #{parentId} limit 1 + </select> + <select id="getAll" resultType="com.ruoyi.system.domain.SysMenus"> + select menu_id menuId, + menu_name menuName, + parent_id parentId, + order_num orderNum, + path, + component, + query, + is_frame isFram, + is_cache isCache, + menu_type menuType, + visible, + status, + perms, + icon, + create_by createBy, + + create_time createTime, + update_by updateBy, + update_time updateTime, + remark + from sys_menu + order by create_time asc + </select> + <select id="getAllInIds" resultType="com.ruoyi.system.domain.SysMenus"> + select menu_id menuId, + menu_name menuName, + parent_id parentId, + order_num orderNum, + path, + component, + query, + is_frame isFram, + is_cache isCache, + menu_type menuType, + visible, + status, + perms, + icon, + create_by createBy, + create_time createTime, + update_by updateBy, + update_time updateTime, + remark + from sys_menu where menu_id in + <foreach collection="menusId" close=")" index="index" item="id" open="(" separator=","> + #{id} + </foreach> + </select> + <select id="getAllOne" resultType="com.ruoyi.system.domain.SysMenus"> + select menu_id menuId, + menu_name menuName, + parent_id parentId, + order_num orderNum, + path, + component, + query, + is_frame isFram, + is_cache isCache, + menu_type menuType, + visible, + status, + perms, + icon, + create_by createBy, + + create_time createTime, + update_by updateBy, + update_time updateTime, + remark + from sys_menu where menu_id !=1074 and menu_id !=1075 and menu_id !=1193 and menu_id !=1194 + order by create_time desc + </select> + + <update id="updateMenu" parameterType="com.ruoyi.system.domain.SysMenu"> + update sys_menu + <set> + <if test="menuName != null and menuName != ''">menu_name = #{menuName},</if> + <if test="parentId != null">parent_id = #{parentId},</if> + <if test="orderNum != null">order_num = #{orderNum},</if> + <if test="path != null and path != ''">path = #{path},</if> + <if test="component != null">component = #{component},</if> + <if test="query != null">`query` = #{query},</if> + <if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if> + <if test="isCache != null and isCache != ''">is_cache = #{isCache},</if> + <if test="menuType != null and menuType != ''">menu_type = #{menuType},</if> + <if test="visible != null">visible = #{visible},</if> + <if test="status != null">status = #{status},</if> + <if test="perms !=null">perms = #{perms},</if> + <if test="icon !=null and icon != ''">icon = #{icon},</if> + <if test="remark != null and remark != ''">remark = #{remark},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where menu_id = #{menuId} + </update> + + <insert id="insertMenu" parameterType="com.ruoyi.system.domain.SysMenu"> + insert into sys_menu( + <if test="menuId != null and menuId != 0">menu_id,</if> + <if test="parentId != null and parentId != 0">parent_id,</if> + <if test="menuName != null and menuName != ''">menu_name,</if> + <if test="orderNum != null">order_num,</if> + <if test="path != null and path != ''">path,</if> + <if test="component != null and component != ''">component,</if> + <if test="query != null and query != ''">`query`,</if> + <if test="isFrame != null and isFrame != ''">is_frame,</if> + <if test="isCache != null and isCache != ''">is_cache,</if> + <if test="menuType != null and menuType != ''">menu_type,</if> + <if test="visible != null">visible,</if> + <if test="status != null">status,</if> + <if test="perms !=null and perms != ''">perms,</if> + <if test="icon != null and icon != ''">icon,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="menuId != null and menuId != 0">#{menuId},</if> + <if test="parentId != null and parentId != 0">#{parentId},</if> + <if test="menuName != null and menuName != ''">#{menuName},</if> + <if test="orderNum != null">#{orderNum},</if> + <if test="path != null and path != ''">#{path},</if> + <if test="component != null and component != ''">#{component},</if> + <if test="query != null and query != ''">#{query},</if> + <if test="isFrame != null and isFrame != ''">#{isFrame},</if> + <if test="isCache != null and isCache != ''">#{isCache},</if> + <if test="menuType != null and menuType != ''">#{menuType},</if> + <if test="visible != null">#{visible},</if> + <if test="status != null">#{status},</if> + <if test="perms !=null and perms != ''">#{perms},</if> + <if test="icon != null and icon != ''">#{icon},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <delete id="deleteMenuById" parameterType="Long"> + delete from sys_menu where menu_id = #{menuId} + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 0000000..9217602 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysNoticeMapper"> + + <resultMap type="com.ruoyi.system.domain.SysNotice" id="SysNoticeResult"> + <result property="noticeId" column="notice_id" /> + <result property="noticeTitle" column="notice_title" /> + <result property="noticeType" column="notice_type" /> + <result property="noticeContent" column="notice_content" /> + <result property="status" column="status" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + </resultMap> + + <sql id="selectNoticeVo"> + select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark + from sys_notice + </sql> + + <select id="selectNoticeById" parameterType="Long" resultMap="SysNoticeResult"> + <include refid="selectNoticeVo"/> + where notice_id = #{noticeId} + </select> + + <select id="selectNoticeList" parameterType="com.ruoyi.system.domain.SysNotice" resultMap="SysNoticeResult"> + <include refid="selectNoticeVo"/> + <where> + <if test="noticeTitle != null and noticeTitle != ''"> + AND notice_title like concat('%', #{noticeTitle}, '%') + </if> + <if test="noticeType != null and noticeType != ''"> + AND notice_type = #{noticeType} + </if> + <if test="createBy != null and createBy != ''"> + AND create_by like concat('%', #{createBy}, '%') + </if> + </where> + </select> + + <insert id="insertNotice" parameterType="com.ruoyi.system.domain.SysNotice"> + insert into sys_notice ( + <if test="noticeTitle != null and noticeTitle != '' ">notice_title, </if> + <if test="noticeType != null and noticeType != '' ">notice_type, </if> + <if test="noticeContent != null and noticeContent != '' ">notice_content, </if> + <if test="status != null and status != '' ">status, </if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="noticeTitle != null and noticeTitle != ''">#{noticeTitle}, </if> + <if test="noticeType != null and noticeType != ''">#{noticeType}, </if> + <if test="noticeContent != null and noticeContent != ''">#{noticeContent}, </if> + <if test="status != null and status != ''">#{status}, </if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateNotice" parameterType="com.ruoyi.system.domain.SysNotice"> + update sys_notice + <set> + <if test="noticeTitle != null and noticeTitle != ''">notice_title = #{noticeTitle}, </if> + <if test="noticeType != null and noticeType != ''">notice_type = #{noticeType}, </if> + <if test="noticeContent != null">notice_content = #{noticeContent}, </if> + <if test="status != null and status != ''">status = #{status}, </if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where notice_id = #{noticeId} + </update> + + <delete id="deleteNoticeById" parameterType="Long"> + delete from sys_notice where notice_id = #{noticeId} + </delete> + + <delete id="deleteNoticeByIds" parameterType="Long"> + delete from sys_notice where notice_id in + <foreach item="noticeId" collection="array" open="(" separator="," close=")"> + #{noticeId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 0000000..a6c5d52 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysOperLogMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysOperLog" id="SysOperLogResult"> + <id property="operId" column="oper_id" /> + <result property="title" column="title" /> + <result property="businessType" column="business_type" /> + <result property="method" column="method" /> + <result property="requestMethod" column="request_method" /> + <result property="operatorType" column="operator_type" /> + <result property="operName" column="oper_name" /> + <result property="deptName" column="dept_name" /> + <result property="operUrl" column="oper_url" /> + <result property="operIp" column="oper_ip" /> + <result property="operParam" column="oper_param" /> + <result property="jsonResult" column="json_result" /> + <result property="status" column="status" /> + <result property="errorMsg" column="error_msg" /> + <result property="operTime" column="oper_time" /> + <result property="costTime" column="cost_time" /> + </resultMap> + + <sql id="selectOperLogVo"> + select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_param, json_result, status, error_msg, oper_time, cost_time + from sys_oper_log + </sql> + + <insert id="insertOperlog" parameterType="com.ruoyi.system.api.domain.SysOperLog"> + insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_param, json_result, status, error_msg, cost_time, oper_time) + values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate()) + </insert> + + <select id="selectOperLogList" parameterType="com.ruoyi.system.api.domain.SysOperLog" resultMap="SysOperLogResult"> + <include refid="selectOperLogVo"/> + <where> + <if test="title != null and title != ''"> + AND title like concat('%', #{title}, '%') + </if> + <if test="businessType != null"> + AND business_type = #{businessType} + </if> + <if test="businessTypes != null and businessTypes.length > 0"> + AND business_type in + <foreach collection="businessTypes" item="businessType" open="(" separator="," close=")"> + #{businessType} + </foreach> + </if> + <if test="status != null"> + AND status = #{status} + </if> + <if test="operName != null and operName != ''"> + AND oper_name like concat('%', #{operName}, '%') + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + AND oper_time >= #{params.beginTime} + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + AND oper_time <= #{params.endTime} + </if> + </where> + order by oper_id desc + </select> + + <delete id="deleteOperLogByIds" parameterType="Long"> + delete from sys_oper_log where oper_id in + <foreach collection="array" item="operId" open="(" separator="," close=")"> + #{operId} + </foreach> + </delete> + + <select id="selectOperLogById" parameterType="Long" resultMap="SysOperLogResult"> + <include refid="selectOperLogVo"/> + where oper_id = #{operId} + </select> + + <update id="cleanOperLog"> + truncate table sys_oper_log + </update> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 0000000..4d38972 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysPostMapper"> + + <resultMap type="com.ruoyi.system.domain.SysPost" id="SysPostResult"> + <id property="postId" column="post_id" /> + <result property="postCode" column="post_code" /> + <result property="postName" column="post_name" /> + <result property="postSort" column="post_sort" /> + <result property="status" column="status" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + </resultMap> + + <sql id="selectPostVo"> + select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark + from sys_post + </sql> + + <select id="selectPostList" parameterType="com.ruoyi.system.domain.SysPost" resultMap="SysPostResult"> + <include refid="selectPostVo"/> + <where> + <if test="postCode != null and postCode != ''"> + AND post_code like concat('%', #{postCode}, '%') + </if> + <if test="status != null and status != ''"> + AND status = #{status} + </if> + <if test="postName != null and postName != ''"> + AND post_name like concat('%', #{postName}, '%') + </if> + </where> + </select> + + <select id="selectPostAll" resultMap="SysPostResult"> + <include refid="selectPostVo"/> + </select> + + <select id="selectPostById" parameterType="Long" resultMap="SysPostResult"> + <include refid="selectPostVo"/> + where post_id = #{postId} + </select> + + <select id="selectPostListByUserId" parameterType="Long" resultType="Long"> + select p.post_id + from sys_post p + left join sys_user_post up on up.post_id = p.post_id + left join sys_user u on u.user_id = up.user_id + where u.user_id = #{userId} + </select> + + <select id="selectPostsByUserName" parameterType="String" resultMap="SysPostResult"> + select p.post_id, p.post_name, p.post_code + from sys_post p + left join sys_user_post up on up.post_id = p.post_id + left join sys_user u on u.user_id = up.user_id + where u.user_name = #{userName} + </select> + + <select id="checkPostNameUnique" parameterType="String" resultMap="SysPostResult"> + <include refid="selectPostVo"/> + where post_name=#{postName} limit 1 + </select> + + <select id="checkPostCodeUnique" parameterType="String" resultMap="SysPostResult"> + <include refid="selectPostVo"/> + where post_code=#{postCode} limit 1 + </select> + + <update id="updatePost" parameterType="com.ruoyi.system.domain.SysPost"> + update sys_post + <set> + <if test="postCode != null and postCode != ''">post_code = #{postCode},</if> + <if test="postName != null and postName != ''">post_name = #{postName},</if> + <if test="postSort != null">post_sort = #{postSort},</if> + <if test="status != null and status != ''">status = #{status},</if> + <if test="remark != null">remark = #{remark},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + update_time = sysdate() + </set> + where post_id = #{postId} + </update> + + <insert id="insertPost" parameterType="com.ruoyi.system.domain.SysPost" useGeneratedKeys="true" keyProperty="postId"> + insert into sys_post( + <if test="postId != null and postId != 0">post_id,</if> + <if test="postCode != null and postCode != ''">post_code,</if> + <if test="postName != null and postName != ''">post_name,</if> + <if test="postSort != null">post_sort,</if> + <if test="status != null and status != ''">status,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="postId != null and postId != 0">#{postId},</if> + <if test="postCode != null and postCode != ''">#{postCode},</if> + <if test="postName != null and postName != ''">#{postName},</if> + <if test="postSort != null">#{postSort},</if> + <if test="status != null and status != ''">#{status},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <delete id="deletePostById" parameterType="Long"> + delete from sys_post where post_id = #{postId} + </delete> + + <delete id="deletePostByIds" parameterType="Long"> + delete from sys_post where post_id in + <foreach collection="array" item="postId" open="(" separator="," close=")"> + #{postId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 0000000..73c13e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysRoleDeptMapper"> + + <resultMap type="com.ruoyi.system.domain.SysRoleDept" id="SysRoleDeptResult"> + <result property="roleId" column="role_id" /> + <result property="deptId" column="dept_id" /> + </resultMap> + + <delete id="deleteRoleDeptByRoleId" parameterType="Long"> + delete from sys_role_dept where role_id=#{roleId} + </delete> + + <select id="selectCountRoleDeptByDeptId" resultType="Integer"> + select count(1) from sys_role_dept where dept_id=#{deptId} + </select> + + <delete id="deleteRoleDept" parameterType="Long"> + delete from sys_role_dept where role_id in + <foreach collection="array" item="roleId" open="(" separator="," close=")"> + #{roleId} + </foreach> + </delete> + + <insert id="batchRoleDept"> + insert into sys_role_dept(role_id, dept_id) values + <foreach item="item" index="index" collection="list" separator=","> + (#{item.roleId},#{item.deptId}) + </foreach> + </insert> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000..678bfec --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysRoleMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysRole" id="SysRoleResult"> + <id property="roleId" column="role_id" /> + <result property="roleName" column="role_name" /> + <result property="roleKey" column="role_key" /> + <result property="roleSort" column="role_sort" /> + <result property="dataScope" column="data_scope" /> + <result property="menuCheckStrictly" column="menu_check_strictly" /> + <result property="deptCheckStrictly" column="dept_check_strictly" /> + <result property="status" column="status" /> + <result property="delFlag" column="del_flag" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + </resultMap> + + <sql id="selectRoleVo"> + select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly, + r.status, + r.del_flag, + r.create_time, + r.remark + from sys_role r + left join sys_user_role ur on ur.role_id = r.role_id + left join sys_user u on u.user_id = ur.user_id + left join sys_dept d on u.dept_id = d.dept_id + </sql> + + <select id="selectRoleList" parameterType="com.ruoyi.system.api.domain.SysRole" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + where r.del_flag = '0' + <if test="roleId != null and roleId != 0"> + AND r.role_id = #{roleId} + </if> + <if test="roleName != null and roleName != ''"> + AND r.role_name like concat('%', #{roleName}, '%') + </if> + <if test="status != null and status != ''"> + AND r.status = #{status} + </if> + <if test="roleKey != null and roleKey != ''"> + AND r.role_key like concat('%', #{roleKey}, '%') + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + and date_format(r.create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + and date_format(r.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + <!-- 数据范围过滤 --> + ${params.dataScope} + order by r.role_sort + </select> + + <select id="selectRolePermissionByUserId" parameterType="Long" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + WHERE r.del_flag = '0' and ur.user_id = #{userId} + </select> + + <select id="selectRoleAll" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + </select> + + <select id="selectRoleListByUserId" parameterType="Long" resultType="Long"> + select r.role_id + from sys_role r + left join sys_user_role ur on ur.role_id = r.role_id + left join sys_user u on u.user_id = ur.user_id + where u.user_id = #{userId} + </select> + + <select id="selectRoleById" parameterType="Long" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + where r.role_id = #{roleId} + </select> + + <select id="selectRolesByUserName" parameterType="String" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + WHERE r.del_flag = '0' and u.user_name = #{userName} + </select> + + <select id="checkRoleNameUnique" parameterType="String" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + where r.role_name=#{roleName} and r.del_flag = '0' limit 1 + </select> + + <select id="checkRoleKeyUnique" parameterType="String" resultMap="SysRoleResult"> + <include refid="selectRoleVo"/> + where r.role_key=#{roleKey} and r.del_flag = '0' limit 1 + </select> + <select id="isExitUpdate" resultType="com.ruoyi.system.api.domain.SysRole"> + select role_name romeName + from sys_role + where role_name = #{roleName} + and role_id != #{roleId} + </select> + + <insert id="insertRole" parameterType="com.ruoyi.system.api.domain.SysRole" useGeneratedKeys="true" keyProperty="roleId"> + insert into sys_role( + <if test="roleId != null and roleId != 0">role_id,</if> + <if test="roleName != null and roleName != ''">role_name,</if> + <if test="roleKey != null and roleKey != ''">role_key,</if> + <if test="roleSort != null">role_sort,</if> + <if test="dataScope != null and dataScope != ''">data_scope,</if> + <if test="menuCheckStrictly != null">menu_check_strictly,</if> + <if test="deptCheckStrictly != null">dept_check_strictly,</if> + <if test="status != null and status != ''">status,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="roleId != null and roleId != 0">#{roleId},</if> + <if test="roleName != null and roleName != ''">#{roleName},</if> + <if test="roleKey != null and roleKey != ''">#{roleKey},</if> + <if test="roleSort != null">#{roleSort},</if> + <if test="dataScope != null and dataScope != ''">#{dataScope},</if> + <if test="menuCheckStrictly != null">#{menuCheckStrictly},</if> + <if test="deptCheckStrictly != null">#{deptCheckStrictly},</if> + <if test="status != null and status != ''">#{status},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateRole" parameterType="com.ruoyi.system.api.domain.SysRole"> + update sys_role + <set> + <if test="roleName != null and roleName != ''">role_name = #{roleName},</if> + <if test="roleKey != null and roleKey != ''">role_key = #{roleKey},</if> + <if test="roleSort != null">role_sort = #{roleSort},</if> + <if test="dataScope != null and dataScope != ''">data_scope = #{dataScope},</if> + <if test="menuCheckStrictly != null">menu_check_strictly = #{menuCheckStrictly},</if> + <if test="deptCheckStrictly != null">dept_check_strictly = #{deptCheckStrictly},</if> + <if test="status != null and status != ''">status = #{status},</if> + <if test="remark != null">remark = #{remark},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + <if test="delFlag != null and delFlag != ''">del_flag = #{delFlag},</if> + update_time = sysdate() + </set> + where role_id = #{roleId} + </update> + + <delete id="deleteRoleById" parameterType="Long"> + update sys_role set del_flag = '2' where role_id = #{roleId} + </delete> + + <delete id="deleteRoleByIds" parameterType="Long"> + update sys_role set del_flag = '2' where role_id in + <foreach collection="array" item="roleId" open="(" separator="," close=")"> + #{roleId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000..8a9a12d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysRoleMenuMapper"> + + <resultMap type="com.ruoyi.system.domain.SysRoleMenu" id="SysRoleMenuResult"> + <result property="roleId" column="role_id" /> + <result property="menuId" column="menu_id" /> + </resultMap> + + <select id="checkMenuExistRole" resultType="Integer"> + select count(1) from sys_role_menu where menu_id = #{menuId} + </select> + + <delete id="deleteRoleMenuByRoleId" parameterType="Long"> + delete from sys_role_menu where role_id=#{roleId} + </delete> + + <delete id="deleteRoleMenu" parameterType="Long"> + delete from sys_role_menu where role_id in + <foreach collection="array" item="roleId" open="(" separator="," close=")"> + #{roleId} + </foreach> + </delete> + + <insert id="batchRoleMenu"> + insert into sys_role_menu(role_id, menu_id) values + <foreach item="item" index="index" collection="list" separator=","> + (#{item.roleId},#{item.menuId}) + </foreach> + </insert> + +</mapper> \ 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 new file mode 100644 index 0000000..7471f7f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,260 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysUserMapper"> + + <resultMap type="com.ruoyi.system.api.domain.SysUser" id="SysUserResult"> + <id property="userId" column="user_id" /> + <result property="deptId" column="dept_id" /> + <result property="userName" column="user_name" /> + <result property="nickName" column="nick_name" /> + <result property="email" column="email" /> + <result property="phonenumber" column="phonenumber" /> + <result property="sex" column="sex" /> + <result property="avatar" column="avatar" /> + <result property="password" column="password" /> + <result property="status" column="status" /> + <result property="delFlag" column="del_flag" /> + <result property="loginIp" column="login_ip" /> + <result property="loginDate" column="login_date" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + <result property="roleType" column="roleType" /> + <result property="objectId" column="objectId" /> + <result property="userType" column="user_type"/> + <association property="dept" column="dept_id" javaType="com.ruoyi.system.api.domain.SysDept" resultMap="deptResult" /> + <collection property="roles" javaType="java.util.List" resultMap="RoleResult" /> + </resultMap> + + <resultMap id="deptResult" type="com.ruoyi.system.api.domain.SysDept"> + <id property="deptId" column="dept_id" /> + <result property="parentId" column="parent_id" /> + <result property="deptName" column="dept_name" /> + <result property="ancestors" column="ancestors" /> + <result property="orderNum" column="order_num" /> + <result property="leader" column="leader" /> + <result property="status" column="dept_status" /> + </resultMap> + + <resultMap id="RoleResult" type="com.ruoyi.system.api.domain.SysRole"> + <id property="roleId" column="role_id" /> + <result property="roleName" column="role_name" /> + <result property="roleKey" column="role_key" /> + <result property="roleSort" column="role_sort" /> + <result property="dataScope" column="data_scope" /> + <result property="status" column="role_status" /> + </resultMap> + + <sql id="selectUserVo"> + 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, + 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, + u.roleType as roleType, + u.objectId AS objectId, + u.user_type + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + 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 + </sql> + + <select id="selectUserList" parameterType="com.ruoyi.system.api.domain.SysUser" resultMap="SysUserResult"> + select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + where u.del_flag = '0' + <if test="phonenumber != null and phonenumber != ''"> + AND u.phonenumber like concat('%', #{phonenumber}, '%') + </if> + </select> + + <select id="selectAllocatedList" parameterType="com.ruoyi.system.api.domain.SysUser" resultMap="SysUserResult"> + select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + 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 + where u.del_flag = '0' and r.role_id = #{roleId} + <if test="userName != null and userName != ''"> + AND u.user_name like concat('%', #{userName}, '%') + </if> + <if test="phonenumber != null and phonenumber != ''"> + AND u.phonenumber like concat('%', #{phonenumber}, '%') + </if> + <!-- 数据范围过滤 --> + ${params.dataScope} + </select> + + <select id="selectUnallocatedList" parameterType="com.ruoyi.system.api.domain.SysUser" resultMap="SysUserResult"> + select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + 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 + where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL) + and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId}) + <if test="userName != null and userName != ''"> + AND u.user_name like concat('%', #{userName}, '%') + </if> + <if test="phonenumber != null and phonenumber != ''"> + AND u.phonenumber like concat('%', #{phonenumber}, '%') + </if> + <!-- 数据范围过滤 --> + ${params.dataScope} + </select> + + <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult"> + <include refid="selectUserVo"/> + where u.user_name = #{userName} and u.del_flag = '0' + </select> + + <select id="selectUserById" parameterType="Long" resultMap="SysUserResult"> + <include refid="selectUserVo"/> + where u.user_id = #{userId} + </select> + + <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult"> + select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1 + </select> + + <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult"> + select user_id, phonenumber + from sys_user + where phonenumber = #{phonenumber} + and del_flag = '0' + limit 1 + </select> + + <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult"> + select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1 + </select> + <select id="getList" resultType="com.ruoyi.system.api.domain.SysUser"> + select su.user_id userId,su.nick_name nickName,su.phonenumber,su.status,sr.role_name + roleName,sr.role_id roleId,case su.user_type when '01' then 2 + else 1 end as isAuctioneer + from + sys_user su left join sys_user_role sur on su.user_id = sur.user_id left join sys_role sr on + sr.role_id + = sur.role_id where 1=1 + <if test="nickName !=null and nickName !=''"> + and su.nick_name like concat("%", #{nickName},"%") + </if> + <if test="phonenumber !=null and phonenumber !=''"> + and su.phonenumber like concat("%", #{phonenumber},"%") + </if> + <if test="status !=null and status !=''"> + and su.status = #{status} + </if> + and su.del_flag = '0' and su.user_type in('00','01') + order by su.create_time desc + </select> + <select id="getAllList" resultType="com.ruoyi.system.api.domain.SysUser"> + select *,user_id userId,nick_name userName ,create_time createTime ,login_date loginDate from sys_user where roleType=3 and user_id in + + <foreach collection="ids" separator="," open="(" item="id" index="index" close=")" > + #{id} + </foreach> + order by create_time desc + </select> + <select id="getSysUserFromPhone" resultType="java.lang.Long"> + select user_id from sys_user where phonenumber =#{phoneNumber} + </select> + + <insert id="insertUser" parameterType="com.ruoyi.system.api.domain.SysUser" useGeneratedKeys="true" keyProperty="userId"> + insert into sys_user( + <if test="userId != null and userId != 0">user_id,</if> + <if test="deptId != null and deptId != 0">dept_id,</if> + <if test="userName != null and userName != ''">user_name,</if> + <if test="nickName != null and nickName != ''">nick_name,</if> + <if test="email != null and email != ''">email,</if> + <if test="avatar != null and avatar != ''">avatar,</if> + <if test="phonenumber != null and phonenumber != ''">phonenumber,</if> + <if test="sex != null and sex != ''">sex,</if> + <if test="password != null and password != ''">password,</if> + <if test="status != null and status != ''">status,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + <if test="roleType != null and roleType != ''">roleType,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="objectId != null and objectId != ''">objectId,</if> + <if test="userType != null and userType != ''">user_type,</if> + create_time + )values( + <if test="userId != null and userId != ''">#{userId},</if> + <if test="deptId != null and deptId != ''">#{deptId},</if> + <if test="userName != null and userName != ''">#{userName},</if> + <if test="nickName != null and nickName != ''">#{nickName},</if> + <if test="email != null and email != ''">#{email},</if> + <if test="avatar != null and avatar != ''">#{avatar},</if> + <if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if> + <if test="sex != null and sex != ''">#{sex},</if> + <if test="password != null and password != ''">#{password},</if> + <if test="status != null and status != ''">#{status},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + <if test="roleType != null and roleType != ''">#{roleType},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="objectId != null and objectId != ''">#{objectId},</if> + <if test="userType != null and userType != ''">#{userType},</if> + sysdate() + ) + </insert> + + <update id="updateUser" parameterType="com.ruoyi.system.api.domain.SysUser"> + update sys_user + <set> + <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if> + <if test="userName != null and userName != ''">user_name = #{userName},</if> + <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> + <if test="email != null ">email = #{email},</if> + <if test="phonenumber != null ">phonenumber = #{phonenumber},</if> + <if test="sex != null and sex != ''">sex = #{sex},</if> + <if test="avatar != null and avatar != ''">avatar = #{avatar},</if> + <if test="password != null and password != ''">password = #{password},</if> + <if test="status != null and status != ''">status = #{status},</if> + <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if> + <if test="loginDate != null">login_date = #{loginDate},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + <if test="remark != null">remark = #{remark},</if> + <if test="userType != null and userType != ''">user_type = #{userType},</if> + update_time = sysdate() + </set> + where user_id = #{userId} + </update> + + <update id="updateUserStatus" parameterType="com.ruoyi.system.api.domain.SysUser"> + update sys_user set status = #{status} where user_id = #{userId} + </update> + + <update id="updateUserAvatar" parameterType="com.ruoyi.system.api.domain.SysUser"> + update sys_user set avatar = #{avatar} where user_name = #{userName} + </update> + + <update id="resetUserPwd" parameterType="com.ruoyi.system.api.domain.SysUser"> + update sys_user set password = #{password} where user_name = #{userName} + </update> + + <delete id="deleteUserById" parameterType="Long"> + update sys_user set del_flag = '2' where user_id = #{userId} + </delete> + + <delete id="deleteUserByIds" parameterType="Long"> + update sys_user set del_flag = '2' where user_id in + <foreach collection="array" item="userId" open="(" separator="," close=")"> + #{userId} + </foreach> + </delete> + <delete id="deleteSysUser"> + delete from sys_user where user_id in + <foreach collection="userIds" separator="," open="(" item="id" close=")" > + #{id} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 0000000..f4ae46f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysUserPostMapper"> + + <resultMap type="com.ruoyi.system.domain.SysUserPost" id="SysUserPostResult"> + <result property="userId" column="user_id" /> + <result property="postId" column="post_id" /> + </resultMap> + + <delete id="deleteUserPostByUserId" parameterType="Long"> + delete from sys_user_post where user_id=#{userId} + </delete> + + <select id="countUserPostById" resultType="Integer"> + select count(1) from sys_user_post where post_id=#{postId} + </select> + + <delete id="deleteUserPost" parameterType="Long"> + delete from sys_user_post where user_id in + <foreach collection="array" item="userId" open="(" separator="," close=")"> + #{userId} + </foreach> + </delete> + + <insert id="batchUserPost"> + insert into sys_user_post(user_id, post_id) values + <foreach item="item" index="index" collection="list" separator=","> + (#{item.userId},#{item.postId}) + </foreach> + </insert> + +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000..83111a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE mapper +PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> +<mapper namespace="com.ruoyi.system.mapper.SysUserRoleMapper"> + + <resultMap type="com.ruoyi.system.domain.SysUserRole" id="SysUserRoleResult"> + <result property="userId" column="user_id" /> + <result property="roleId" column="role_id" /> + </resultMap> + + <sql id="selectSysUserRoleVo"> + select user_id, role_id from sys_user_role + </sql> + <delete id="deleteUserRoleByUserId" parameterType="Long"> + delete from sys_user_role where user_id=#{userId} + </delete> + + <select id="countUserRoleByRoleId" resultType="Integer"> + select count(1) from sys_user_role where role_id=#{roleId} + </select> + + <delete id="deleteUserRole" parameterType="Long"> + delete from sys_user_role where user_id in + <foreach collection="array" item="userId" open="(" separator="," close=")"> + #{userId} + </foreach> + </delete> + + <insert id="batchUserRole"> + insert into sys_user_role(user_id, role_id) values + <foreach item="item" index="index" collection="list" separator=","> + (#{item.userId},#{item.roleId}) + </foreach> + </insert> + + <delete id="deleteUserRoleInfo" parameterType="com.ruoyi.system.domain.SysUserRole"> + delete from sys_user_role where user_id=#{userId} and role_id=#{roleId} + </delete> + + <delete id="deleteUserRoleInfos"> + delete from sys_user_role where role_id=#{roleId} and user_id in + <foreach collection="userIds" item="userId" open="(" separator="," close=")"> + #{userId} + </foreach> + </delete> + <select id="selectSysUserRoleList" parameterType="com.ruoyi.system.domain.SysUserRole" resultMap="SysUserRoleResult"> + <include refid="selectSysUserRoleVo"/> + <where> + </where> + </select> + + <select id="selectSysUserRoleByUserId" parameterType="Long" resultMap="SysUserRoleResult"> + <include refid="selectSysUserRoleVo"/> + where user_id = #{userId} + </select> + + + + <insert id="insertSysUserRole" parameterType="com.ruoyi.system.domain.SysUserRole"> + insert into sys_user_role + <trim prefix="(" suffix=")" suffixOverrides=","> + <if test="userId != null">user_id,</if> + <if test="roleId != null">role_id,</if> + </trim> + <trim prefix="values (" suffix=")" suffixOverrides=","> + <if test="userId != null">#{userId},</if> + <if test="roleId != null">#{roleId},</if> + </trim> + </insert> + + <update id="updateSysUserRole" parameterType="com.ruoyi.system.domain.SysUserRole"> + update sys_user_role + <trim prefix="SET" suffixOverrides=","> + <if test="roleId != null">role_id = #{roleId},</if> + </trim> + where user_id = #{userId} + </update> + + <delete id="deleteSysUserRoleByUserId" parameterType="Long"> + delete from sys_user_role where user_id = #{userId} + </delete> + + <delete id="deleteSysUserRoleByUserIds" parameterType="String"> + delete from sys_user_role where user_id in + <foreach item="userId" collection="array" open="(" separator="," close=")"> + #{userId} + </foreach> + </delete> +</mapper> \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mybatis-config.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mybatis-config.xml new file mode 100644 index 0000000..7d487eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mybatis-config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> +<configuration> + + <settings> + <!-- 打印查询语句 不会写入到日志文件中--> + <setting name="logImpl" value="STDOUT_LOGGING"/> + <!--<setting name="logImpl" value="LOG4J" />--> + <!-- 控制全局缓存(二级缓存),按美团技术团队的说法,尽量别用缓存机制 emmmm.... --> + <setting name="cacheEnabled" value="true"/> + <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false --> + <!-- <setting name="lazyLoadingEnabled" value="true"/> --> + <setting name="mapUnderscoreToCamelCase" value="false"/><!--是否将map下划线方式转为驼峰式命名--> + <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖--> + <!-- <setting name="aggressiveLazyLoading" value="false"/>--> + <!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST --> + <!--<setting name="proxyFactory" value="CGLIB" />--> + <!-- 关于mybatis的一二级缓存 请参照:https://tech.meituan.com/2018/01/19/mybatis-cache.html --> + <!-- 一级缓存范围默认:SESSION ,此范围在复杂应用场景中可能会出现脏读数据--> + <!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 --> + <!--<setting name="localCacheScope" value="STATEMENT"/>--> + <setting name="localCacheScope" value="STATEMENT"/> + </settings> + +</configuration> diff --git a/ruoyi-visual/pom.xml b/ruoyi-visual/pom.xml new file mode 100644 index 0000000..933f254 --- /dev/null +++ b/ruoyi-visual/pom.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <modules> + <module>ruoyi-monitor</module> + </modules> + + <artifactId>ruoyi-visual</artifactId> + <packaging>pom</packaging> + + <description> + ruoyi-visual图形化管理模块 + </description> + +</project> diff --git a/ruoyi-visual/ruoyi-monitor/pom.xml b/ruoyi-visual/ruoyi-monitor/pom.xml new file mode 100644 index 0000000..2cc878e --- /dev/null +++ b/ruoyi-visual/ruoyi-monitor/pom.xml @@ -0,0 +1,75 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>com.ruoyi</groupId> + <artifactId>ruoyi-visual</artifactId> + <version>3.6.2</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>ruoyi-visual-monitor</artifactId> + + <description> + ruoyi-visual-monitor监控中心 + </description> + + <dependencies> + + <!-- SpringBoot Admin --> + <dependency> + <groupId>de.codecentric</groupId> + <artifactId>spring-boot-admin-starter-server</artifactId> + <version>${spring-boot-admin.version}</version> + </dependency> + + <!-- SpringCloud Alibaba Nacos --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Nacos Config --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> + </dependency> + + <!-- SpringCloud Alibaba Sentinel --> + <dependency> + <groupId>com.alibaba.cloud</groupId> + <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> + </dependency> + + <!-- SpringBoot Web --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + <!-- Spring Security --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java b/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java new file mode 100644 index 0000000..4ea0533 --- /dev/null +++ b/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java @@ -0,0 +1,30 @@ +package com.ruoyi.modules.monitor; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import de.codecentric.boot.admin.server.config.EnableAdminServer; + +/** + * 监控中心 + * + * @author ruoyi + */ +@EnableAdminServer +@SpringBootApplication +public class RuoYiMonitorApplication +{ + public static void main(String[] args) + { + SpringApplication.run(RuoYiMonitorApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 监控中心启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java b/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java new file mode 100644 index 0000000..4e3d7da --- /dev/null +++ b/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java @@ -0,0 +1,52 @@ +package com.ruoyi.modules.monitor.config; + +import de.codecentric.boot.admin.server.config.AdminServerProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; + +/** + * 监控权限配置 + * + * @author ruoyi + */ +@EnableWebSecurity +public class WebSecurityConfigurer +{ + private final String adminContextPath; + + public WebSecurityConfigurer(AdminServerProperties adminServerProperties) + { + this.adminContextPath = adminServerProperties.getContextPath(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception + { + SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); + successHandler.setTargetUrlParameter("redirectTo"); + successHandler.setDefaultTargetUrl(adminContextPath + "/"); + + return httpSecurity + .headers().frameOptions().disable() + .and().authorizeRequests() + .antMatchers(adminContextPath + "/assets/**" + , adminContextPath + "/login" + , adminContextPath + "/actuator/**" + , adminContextPath + "/instances/**" + , adminContextPath + "*/doc.html" + ).permitAll() + .anyRequest().authenticated() + .and() + .formLogin().loginPage(adminContextPath + "/login") + .successHandler(successHandler).and() + .logout().logoutUrl(adminContextPath + "/logout") + .and() + .httpBasic().and() + .csrf() + .disable() + .build(); + } +} diff --git a/ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt b/ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt new file mode 100644 index 0000000..ecaf8a4 --- /dev/null +++ b/ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ _ + (_) (_)| | + _ __ _ _ ___ _ _ _ ______ _ __ ___ ___ _ __ _ | |_ ___ _ __ +| '__|| | | | / _ \ | | | || ||______|| '_ ` _ \ / _ \ | '_ \ | || __| / _ \ | '__| +| | | |_| || (_) || |_| || | | | | | | || (_) || | | || || |_ | (_) || | +|_| \__,_| \___/ \__, ||_| |_| |_| |_| \___/ |_| |_||_| \__| \___/ |_| + __/ | + |___/ \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml b/ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..63ab2d4 --- /dev/null +++ b/ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml @@ -0,0 +1,25 @@ +# Tomcat +server: + port: 9100 + +# Spring +spring: + application: + # 应用名称 + name: ruoyi-monitor + profiles: + # 环境配置 + active: dev + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 192.168.110.188:8848 + config: + # 配置中心地址 + server-addr: 192.168.110.188:8848 + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} diff --git a/ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml b/ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml new file mode 100644 index 0000000..ab95c68 --- /dev/null +++ b/ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="60 seconds" debug="false"> + <!-- 日志存放路径 --> + <property name="log.path" value="logs/ruoyi-visual-monitor" /> + <!-- 日志输出格式 --> + <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> + + <!-- 控制台输出 --> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + </appender> + + <!-- 系统日志输出 --> + <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/info.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>INFO</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${log.path}/error.log</file> + <!-- 循环政策:基于时间创建日志文件 --> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <!-- 日志文件名格式 --> + <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> + <!-- 日志最大的历史 60天 --> + <maxHistory>60</maxHistory> + </rollingPolicy> + <encoder> + <pattern>${log.pattern}</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <!-- 过滤的级别 --> + <level>ERROR</level> + <!-- 匹配时的操作:接收(记录) --> + <onMatch>ACCEPT</onMatch> + <!-- 不匹配时的操作:拒绝(不记录) --> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- 系统模块日志级别控制 --> + <logger name="com.ruoyi" level="info" /> + <!-- Spring日志级别控制 --> + <logger name="org.springframework" level="warn" /> + + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--系统操作日志--> + <root level="info"> + <appender-ref ref="file_info" /> + <appender-ref ref="file_error" /> + </root> +</configuration> \ No newline at end of file -- Gitblit v1.7.1