From 4d4b13b37bc613d7bf047a273870ad03d203a2fc Mon Sep 17 00:00:00 2001 From: "kuang.yife" Date: Fri, 8 Mar 2024 15:10:30 +0800 Subject: [PATCH] init --- .gitignore | 46 + LICENSE | 20 + README.md | 102 + bin/clean.bat | 12 + bin/package.bat | 12 + bin/run.bat | 14 + .../framework/aspectj/DataScopeAspect.java | 172 + .../framework/aspectj/DataSourceAspect.java | 72 + .../playlet/framework/aspectj/LogAspect.java | 255 + .../framework/aspectj/PermissionsAspect.java | 30 + .../framework/config/ApplicationConfig.java | 20 + .../framework/config/CaptchaConfig.java | 83 + .../playlet/framework/config/DruidConfig.java | 128 + .../framework/config/FilterConfig.java | 44 + .../playlet/framework/config/I18nConfig.java | 43 + .../framework/config/KaptchaTextCreator.java | 76 + .../framework/config/MyBatisConfig.java | 132 + .../framework/config/ResourcesConfig.java | 58 + .../playlet/framework/config/ShiroConfig.java | 421 ++ .../config/properties/DruidProperties.java | 89 + .../datasource/DynamicDataSource.java | 27 + .../interceptor/RepeatSubmitInterceptor.java | 55 + .../impl/SameUrlDataInterceptor.java | 83 + .../framework/manager/AsyncManager.java | 55 + .../framework/manager/ShutdownManager.java | 87 + .../manager/factory/AsyncFactory.java | 136 + .../framework/shiro/realm/UserRealm.java | 158 + .../shiro/service/SysLoginService.java | 185 + .../shiro/service/SysPasswordService.java | 85 + .../shiro/service/SysRegisterService.java | 83 + .../shiro/service/SysShiroService.java | 62 + .../shiro/session/OnlineSession.java | 165 + .../shiro/session/OnlineSessionDAO.java | 117 + .../shiro/session/OnlineSessionFactory.java | 42 + .../shiro/util/AuthorizationUtils.java | 30 + .../web/CustomShiroFilterFactoryBean.java | 85 + .../shiro/web/filter/LogoutFilter.java | 90 + .../filter/captcha/CaptchaValidateFilter.java | 79 + .../filter/kickout/KickoutSessionFilter.java | 176 + .../filter/online/OnlineSessionFilter.java | 99 + .../filter/sync/SyncOnlineSessionFilter.java | 39 + .../web/session/OnlineWebSessionManager.java | 175 + .../SpringSessionValidationScheduler.java | 131 + .../playlet/framework/web/domain/Server.java | 241 + .../framework/web/domain/server/Cpu.java | 101 + .../framework/web/domain/server/Jvm.java | 130 + .../framework/web/domain/server/Mem.java | 61 + .../framework/web/domain/server/Sys.java | 84 + .../framework/web/domain/server/SysFile.java | 114 + .../web/exception/GlobalExceptionHandler.java | 141 + .../framework/web/service/CacheService.java | 83 + .../framework/web/service/ConfigService.java | 28 + .../framework/web/service/DictService.java | 46 + .../web/service/PermissionService.java | 262 + .../playlet/generator/config/GenConfig.java | 73 + .../generator/controller/GenController.java | 304 ++ .../playlet/generator/domain/GenTable.java | 372 ++ .../generator/domain/GenTableColumn.java | 373 ++ .../mapper/GenTableColumnMapper.java | 60 + .../generator/mapper/GenTableMapper.java | 91 + .../service/IGenTableColumnService.java | 44 + .../generator/service/IGenTableService.java | 129 + .../impl/GenTableColumnServiceImpl.java | 69 + .../service/impl/GenTableServiceImpl.java | 534 ++ .../com/playlet/generator/util/GenUtils.java | 252 + .../generator/util/VelocityInitializer.java | 34 + .../playlet/generator/util/VelocityUtils.java | 384 ++ .../playlet/quartz/config/ScheduleConfig.java | 57 + .../quartz/controller/SysJobController.java | 247 + .../controller/SysJobLogController.java | 103 + .../com/playlet/quartz/domain/SysJob.java | 169 + .../com/playlet/quartz/domain/SysJobLog.java | 155 + .../quartz/mapper/SysJobLogMapper.java | 64 + .../playlet/quartz/mapper/SysJobMapper.java | 67 + .../quartz/service/ISysJobLogService.java | 56 + .../quartz/service/ISysJobService.java | 102 + .../service/impl/SysJobLogServiceImpl.java | 88 + .../service/impl/SysJobServiceImpl.java | 263 + .../java/com/playlet/quartz/task/RyTask.java | 28 + .../quartz/util/AbstractQuartzJob.java | 107 + .../com/playlet/quartz/util/CronUtils.java | 94 + .../playlet/quartz/util/JobInvokeUtil.java | 182 + .../QuartzDisallowConcurrentExecution.java | 21 + .../quartz/util/QuartzJobExecution.java | 19 + .../playlet/quartz/util/ScheduleUtils.java | 141 + .../com/playlet/system/domain/SysConfig.java | 110 + .../playlet/system/domain/SysLogininfor.java | 159 + .../com/playlet/system/domain/SysNotice.java | 102 + .../com/playlet/system/domain/SysOperLog.java | 292 + .../com/playlet/system/domain/SysPost.java | 122 + .../playlet/system/domain/SysRoleDept.java | 46 + .../playlet/system/domain/SysRoleMenu.java | 46 + .../playlet/system/domain/SysUserOnline.java | 177 + .../playlet/system/domain/SysUserPost.java | 46 + .../playlet/system/domain/SysUserRole.java | 46 + .../system/mapper/SysConfigMapper.java | 76 + .../playlet/system/mapper/SysDeptMapper.java | 117 + .../system/mapper/SysDictDataMapper.java | 95 + .../system/mapper/SysDictTypeMapper.java | 83 + .../system/mapper/SysLogininforMapper.java | 42 + .../playlet/system/mapper/SysMenuMapper.java | 132 + .../system/mapper/SysNoticeMapper.java | 52 + .../system/mapper/SysOperLogMapper.java | 48 + .../playlet/system/mapper/SysPostMapper.java | 83 + .../system/mapper/SysRoleDeptMapper.java | 44 + .../playlet/system/mapper/SysRoleMapper.java | 84 + .../system/mapper/SysRoleMenuMapper.java | 44 + .../playlet/system/mapper/SysUserMapper.java | 124 + .../system/mapper/SysUserOnlineMapper.java | 52 + .../system/mapper/SysUserPostMapper.java | 44 + .../system/mapper/SysUserRoleMapper.java | 70 + .../system/service/ISysConfigService.java | 82 + .../system/service/ISysDeptService.java | 117 + .../system/service/ISysDictDataService.java | 60 + .../system/service/ISysDictTypeService.java | 107 + .../system/service/ISysLogininforService.java | 40 + .../system/service/ISysMenuService.java | 139 + .../system/service/ISysNoticeService.java | 52 + .../system/service/ISysOperLogService.java | 48 + .../system/service/ISysPostService.java | 91 + .../system/service/ISysRoleService.java | 166 + .../system/service/ISysUserOnlineService.java | 75 + .../system/service/ISysUserService.java | 214 + .../service/impl/SysConfigServiceImpl.java | 219 + .../service/impl/SysDeptServiceImpl.java | 328 ++ .../service/impl/SysDictDataServiceImpl.java | 113 + .../service/impl/SysDictTypeServiceImpl.java | 260 + .../impl/SysLogininforServiceImpl.java | 66 + .../service/impl/SysMenuServiceImpl.java | 410 ++ .../service/impl/SysNoticeServiceImpl.java | 82 + .../service/impl/SysOperLogServiceImpl.java | 77 + .../service/impl/SysPostServiceImpl.java | 181 + .../service/impl/SysRoleServiceImpl.java | 415 ++ .../impl/SysUserOnlineServiceImpl.java | 140 + .../service/impl/SysUserServiceImpl.java | 554 ++ sql/quartz.sql | 174 + sql/ruoyi.html | 2890 ++++++++++ sql/ruoyi.pdm | 4851 +++++++++++++++++ sql/ry_20240112.sql | 721 +++ 139 files changed, 25054 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bin/clean.bat create mode 100644 bin/package.bat create mode 100644 bin/run.bat create mode 100644 playlet-framework/src/main/java/com/playlet/framework/aspectj/DataScopeAspect.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/aspectj/DataSourceAspect.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/aspectj/LogAspect.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/aspectj/PermissionsAspect.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/ApplicationConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/CaptchaConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/DruidConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/FilterConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/I18nConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/KaptchaTextCreator.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/MyBatisConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/ResourcesConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/ShiroConfig.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/config/properties/DruidProperties.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/datasource/DynamicDataSource.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/interceptor/RepeatSubmitInterceptor.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/interceptor/impl/SameUrlDataInterceptor.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/manager/AsyncManager.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/manager/ShutdownManager.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/manager/factory/AsyncFactory.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/realm/UserRealm.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysLoginService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysPasswordService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysRegisterService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysShiroService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSession.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionDAO.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionFactory.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/util/AuthorizationUtils.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/CustomShiroFilterFactoryBean.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/LogoutFilter.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/kickout/KickoutSessionFilter.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/online/OnlineSessionFilter.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/OnlineWebSessionManager.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java create mode 100644 playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java create mode 100644 playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java create mode 100644 playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysPost.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java create mode 100644 playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysNoticeServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysOperLogServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysPostServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysRoleServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysUserOnlineServiceImpl.java create mode 100644 playlet-system/src/main/java/com/playlet/system/service/impl/SysUserServiceImpl.java create mode 100644 sql/quartz.sql create mode 100644 sql/ruoyi.html create mode 100644 sql/ruoyi.pdm create mode 100644 sql/ry_20240112.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09bdfea --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8564f29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 RuoYi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..73087cb --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +

+ logo +

+

RuoYi v4.7.8

+

基于SpringBoot开发的轻量级Java快速开发框架

+

+ + + +

+ +## 平台简介 + +一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。 + +性别男,若依是给女儿取的名字(寓意:你若不离不弃,我必生死相依) + +若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 + +* 前后端分离版本,请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) +* 感谢 [hplus](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。 +* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)   +* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)   + +## 内置功能 + +1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 +3. 岗位管理:配置系统用户所属担任职务。 +4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 +5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 +6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +7. 参数管理:对系统动态配置常用参数。 +8. 通知公告:系统通知公告信息发布维护。 +9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +10. 登录日志:系统登录日志记录查询包含登录异常。 +11. 在线用户:当前系统中活跃用户状态监控。 +12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 +13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 +14. 系统接口:根据业务代码自动生成相关的api接口文档。 +15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 +16. 缓存监控:对系统的缓存查询,删除、清空等操作。 +17. 在线构建器:拖动表单元素生成相应的HTML代码。 +18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 + +## 在线体验 + +- admin/admin123 +- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 + +演示地址:http://ruoyi.vip +文档地址:http://doc.ruoyi.vip + +## 演示图 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +## 若依交流群 + +QQ群: [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/已满-339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) [![加入QQ群](https://img.shields.io/badge/已满-130035985-blue.svg)](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) [![加入QQ群](https://img.shields.io/badge/已满-143151071-blue.svg)](https://jq.qq.com/?_wv=1027&k=4NsjKbtU) [![加入QQ群](https://img.shields.io/badge/已满-158781320-blue.svg)](https://jq.qq.com/?_wv=1027&k=VD2pkz2G) [![加入QQ群](https://img.shields.io/badge/已满-201531282-blue.svg)](https://jq.qq.com/?_wv=1027&k=HlshFwkJ) [![加入QQ群](https://img.shields.io/badge/已满-101526938-blue.svg)](https://jq.qq.com/?_wv=1027&k=0ARRrO9V) [![加入QQ群](https://img.shields.io/badge/已满-264355400-blue.svg)](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ) [![加入QQ群](https://img.shields.io/badge/已满-298522656-blue.svg)](https://jq.qq.com/?_wv=1027&k=540WfdEr) [![加入QQ群](https://img.shields.io/badge/已满-139845794-blue.svg)](https://jq.qq.com/?_wv=1027&k=ss91fC4t) [![加入QQ群](https://img.shields.io/badge/已满-185760789-blue.svg)](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [![加入QQ群](https://img.shields.io/badge/已满-175104288-blue.svg)](https://jq.qq.com/?_wv=1027&k=7FplYUnR) [![加入QQ群](https://img.shields.io/badge/174942938-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=lqMHu_5Fskm7H2S1vNAQTtzAUokVydwc&authKey=ptw0Fpch5pbNocML3CIJKKqZBaq2DI7cusKuzIgfMNiY3t9Pvd9hP%2BA8WYx3yaY1&noverify=0&group_code=174942938) \ No newline at end of file diff --git a/bin/clean.bat b/bin/clean.bat new file mode 100644 index 0000000..24c0974 --- /dev/null +++ b/bin/clean.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] target· +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean + +pause \ No newline at end of file diff --git a/bin/package.bat b/bin/package.bat new file mode 100644 index 0000000..c693ec0 --- /dev/null +++ b/bin/package.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] Weḅwar/jarļ +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean package -Dmaven.test.skip=true + +pause \ No newline at end of file diff --git a/bin/run.bat b/bin/run.bat new file mode 100644 index 0000000..41efbd0 --- /dev/null +++ b/bin/run.bat @@ -0,0 +1,14 @@ +@echo off +echo. +echo [Ϣ] ʹJarWeb̡ +echo. + +cd %~dp0 +cd ../ruoyi-admin/target + +set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m + +java -jar %JAVA_OPTS% ruoyi-admin.jar + +cd bin +pause \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/aspectj/DataScopeAspect.java b/playlet-framework/src/main/java/com/playlet/framework/aspectj/DataScopeAspect.java new file mode 100644 index 0000000..6752a02 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/aspectj/DataScopeAspect.java @@ -0,0 +1,172 @@ +package com.playlet.framework.aspectj; + +import java.util.ArrayList; +import java.util.List; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; +import com.playlet.common.annotation.DataScope; +import com.playlet.common.core.context.PermissionContextHolder; +import com.playlet.common.core.domain.BaseEntity; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.core.text.Convert; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; + +/** + * 数据过滤处理 + * + * @author ruoyi + */ +@Aspect +@Component +public class DataScopeAspect +{ + /** + * 全部数据权限 + */ + public static final String DATA_SCOPE_ALL = "1"; + + /** + * 自定数据权限 + */ + public static final String DATA_SCOPE_CUSTOM = "2"; + + /** + * 部门数据权限 + */ + public static final String DATA_SCOPE_DEPT = "3"; + + /** + * 部门及以下数据权限 + */ + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; + + /** + * 仅本人数据权限 + */ + public static final String DATA_SCOPE_SELF = "5"; + + /** + * 数据权限过滤关键字 + */ + public static final String DATA_SCOPE = "dataScope"; + + @Before("@annotation(controllerDataScope)") + public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable + { + clearDataScope(point); + handleDataScope(point, controllerDataScope); + } + + protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) + { + // 获取当前的用户 + SysUser currentUser = ShiroUtils.getSysUser(); + if (currentUser != null) + { + // 如果是超级管理员,则不过滤数据 + if (!currentUser.isAdmin()) + { + String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext()); + dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), + controllerDataScope.userAlias(), permission); + } + } + } + + /** + * 数据范围过滤 + * + * @param joinPoint 切点 + * @param user 用户 + * @param deptAlias 部门别名 + * @param userAlias 用户别名 + * @param permission 权限字符 + */ + public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission) + { + StringBuilder sqlString = new StringBuilder(); + List conditions = new ArrayList(); + + for (SysRole role : user.getRoles()) + { + String dataScope = role.getDataScope(); + if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope)) + { + continue; + } + if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions()) + && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) + { + continue; + } + if (DATA_SCOPE_ALL.equals(dataScope)) + { + sqlString = new StringBuilder(); + conditions.add(dataScope); + break; + } + else if (DATA_SCOPE_CUSTOM.equals(dataScope)) + { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, + role.getRoleId())); + } + else if (DATA_SCOPE_DEPT.equals(dataScope)) + { + sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); + } + else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) + { + sqlString.append(StringUtils.format( + " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", + deptAlias, user.getDeptId(), user.getDeptId())); + } + else if (DATA_SCOPE_SELF.equals(dataScope)) + { + if (StringUtils.isNotBlank(userAlias)) + { + sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId())); + } + else + { + // 数据权限为仅本人且没有userAlias别名不查询任何数据 + sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias)); + } + } + conditions.add(dataScope); + } + + // 多角色情况下,所有角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据 + if (StringUtils.isEmpty(conditions)) + { + sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias)); + } + + if (StringUtils.isNotBlank(sqlString.toString())) + { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) + { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); + } + } + } + + /** + * 拼接权限sql前先清空params.dataScope参数防止注入 + */ + private void clearDataScope(final JoinPoint joinPoint) + { + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) + { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, ""); + } + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/aspectj/DataSourceAspect.java b/playlet-framework/src/main/java/com/playlet/framework/aspectj/DataSourceAspect.java new file mode 100644 index 0000000..b0fa58d --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/aspectj/DataSourceAspect.java @@ -0,0 +1,72 @@ +package com.playlet.framework.aspectj; + +import java.util.Objects; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import com.playlet.common.annotation.DataSource; +import com.playlet.common.config.datasource.DynamicDataSourceContextHolder; +import com.playlet.common.utils.StringUtils; + +/** + * 多数据源处理 + * + * @author ruoyi + */ +@Aspect +@Order(1) +@Component +public class DataSourceAspect +{ + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("@annotation(com.playlet.common.annotation.DataSource)" + + "|| @within(com.playlet.common.annotation.DataSource)") + public void dsPointCut() + { + + } + + @Around("dsPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable + { + DataSource dataSource = getDataSource(point); + + if (StringUtils.isNotNull(dataSource)) + { + DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name()); + } + + try + { + return point.proceed(); + } + finally + { + // 销毁数据源 在执行方法之后 + DynamicDataSourceContextHolder.clearDataSourceType(); + } + } + + /** + * 获取需要切换的数据源 + */ + public DataSource getDataSource(ProceedingJoinPoint point) + { + MethodSignature signature = (MethodSignature) point.getSignature(); + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); + if (Objects.nonNull(dataSource)) + { + return dataSource; + } + + return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/aspectj/LogAspect.java b/playlet-framework/src/main/java/com/playlet/framework/aspectj/LogAspect.java new file mode 100644 index 0000000..004b4da --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/aspectj/LogAspect.java @@ -0,0 +1,255 @@ +package com.playlet.framework.aspectj; + +import java.util.Collection; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.ArrayUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.NamedThreadLocal; +import org.springframework.stereotype.Component; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.support.spring.PropertyPreFilters; +import com.playlet.common.annotation.Log; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.enums.BusinessStatus; +import com.playlet.common.utils.ServletUtils; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.framework.manager.AsyncManager; +import com.playlet.framework.manager.factory.AsyncFactory; +import com.playlet.system.domain.SysOperLog; + +/** + * 操作日志记录处理 + * + * @author ruoyi + */ +@Aspect +@Component +public class LogAspect +{ + private static final Logger log = LoggerFactory.getLogger(LogAspect.class); + + /** 排除敏感属性字段 */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + /** 计算操作消耗时间 */ + private static final ThreadLocal TIME_THREADLOCAL = new NamedThreadLocal("Cost Time"); + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(controllerLog)") + public void boBefore(JoinPoint joinPoint, Log controllerLog) + { + TIME_THREADLOCAL.set(System.currentTimeMillis()); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) + { + handleLog(joinPoint, controllerLog, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) + { + handleLog(joinPoint, controllerLog, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) + { + try + { + // 获取当前的用户 + SysUser currentUser = ShiroUtils.getSysUser(); + + // *========数据库日志=========*// + SysOperLog operLog = new SysOperLog(); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = ShiroUtils.getIp(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + if (currentUser != null) + { + operLog.setOperName(currentUser.getLoginName()); + if (StringUtils.isNotNull(currentUser.getDept()) + && StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) + { + operLog.setDeptName(currentUser.getDept().getDeptName()); + } + } + + if (e != null) + { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); + // 设置消耗时间 + operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get()); + // 保存数据库 + AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); + } + catch (Exception exp) + { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } + finally + { + TIME_THREADLOCAL.remove(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception + { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) + { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog, log.excludeParamNames()); + } + // 是否需要保存response,参数和值 + if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) + { + operLog.setJsonResult(StringUtils.substring(JSONObject.toJSONString(jsonResult), 0, 2000)); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception + { + Map map = ServletUtils.getRequest().getParameterMap(); + if (StringUtils.isNotEmpty(map)) + { + String params = JSONObject.toJSONString(map, excludePropertyPreFilter(excludeParamNames)); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + } + else + { + Object args = joinPoint.getArgs(); + if (StringUtils.isNotNull(args)) + { + String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + } + } + } + + /** + * 忽略敏感属性 + */ + public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter(String[] excludeParamNames) + { + return new PropertyPreFilters().addFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames)); + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) + { + String params = ""; + if (paramsArray != null && paramsArray.length > 0) + { + for (Object o : paramsArray) + { + if (StringUtils.isNotNull(o) && !isFilterObject(o)) + { + try + { + Object jsonObj = JSONObject.toJSONString(o, excludePropertyPreFilter(excludeParamNames)); + params += jsonObj.toString() + " "; + } + catch (Exception e) + { + } + } + } + } + return params.trim(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) + { + Class clazz = o.getClass(); + if (clazz.isArray()) + { + return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + } + else if (Collection.class.isAssignableFrom(clazz)) + { + Collection collection = (Collection) o; + for (Object value : collection) + { + return value instanceof MultipartFile; + } + } + else if (Map.class.isAssignableFrom(clazz)) + { + Map map = (Map) o; + for (Object value : map.entrySet()) + { + Map.Entry entry = (Map.Entry) value; + return entry.getValue() instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/aspectj/PermissionsAspect.java b/playlet-framework/src/main/java/com/playlet/framework/aspectj/PermissionsAspect.java new file mode 100644 index 0000000..6409f68 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/aspectj/PermissionsAspect.java @@ -0,0 +1,30 @@ +package com.playlet.framework.aspectj; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.stereotype.Component; +import com.playlet.common.core.context.PermissionContextHolder; +import com.playlet.common.utils.StringUtils; + +/** + * 自定义权限拦截器,将权限字符串放到当前请求中以便用于多个角色匹配符合要求的权限 + * + * @author ruoyi + */ +@Aspect +@Component +public class PermissionsAspect +{ + @Before("@annotation(controllerRequiresPermissions)") + public void doBefore(JoinPoint point, RequiresPermissions controllerRequiresPermissions) throws Throwable + { + handleRequiresPermissions(point, controllerRequiresPermissions); + } + + protected void handleRequiresPermissions(final JoinPoint joinPoint, RequiresPermissions requiresPermissions) + { + PermissionContextHolder.setContext(StringUtils.join(requiresPermissions.value(), ",")); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/ApplicationConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/ApplicationConfig.java new file mode 100644 index 0000000..debee1e --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/ApplicationConfig.java @@ -0,0 +1,20 @@ +package com.playlet.framework.config; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +/** + * 程序注解配置 + * + * @author ruoyi + */ +@Configuration +// 表示通过aop框架暴露该代理对象,AopContext能够访问 +@EnableAspectJAutoProxy(exposeProxy = true) +// 指定要扫描的Mapper类的包的路径 +@MapperScan("com.playlet.**.mapper") +public class ApplicationConfig +{ + +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/CaptchaConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/CaptchaConfig.java new file mode 100644 index 0000000..6008575 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/CaptchaConfig.java @@ -0,0 +1,83 @@ +package com.playlet.framework.config; + +import java.util.Properties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import static com.google.code.kaptcha.Constants.*; + +/** + * 验证码配置 + * + * @author ruoyi + */ +@Configuration +public class CaptchaConfig +{ + @Bean(name = "captchaProducer") + public DefaultKaptcha getKaptchaBean() + { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + + @Bean(name = "captchaProducerMath") + public DefaultKaptcha getKaptchaBeanMath() + { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 边框颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); + // 验证码文本生成器 + properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.playlet.framework.config.KaptchaTextCreator"); + // 验证码文本字符间距 默认为2 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 验证码噪点颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); + // 干扰实现类 + properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/DruidConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/DruidConfig.java new file mode 100644 index 0000000..2058ba3 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/DruidConfig.java @@ -0,0 +1,128 @@ +package com.playlet.framework.config; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.sql.DataSource; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; +import com.alibaba.druid.util.Utils; +import com.playlet.common.enums.DataSourceType; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.framework.config.properties.DruidProperties; +import com.playlet.framework.datasource.DynamicDataSource; + +/** + * druid 配置多数据源 + * + * @author ruoyi + */ +@Configuration +public class DruidConfig +{ + @Bean + @ConfigurationProperties("spring.datasource.druid.master") + public DataSource masterDataSource(DruidProperties druidProperties) + { + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + return druidProperties.dataSource(dataSource); + } + + @Bean + @ConfigurationProperties("spring.datasource.druid.slave") + @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") + public DataSource slaveDataSource(DruidProperties druidProperties) + { + DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); + return druidProperties.dataSource(dataSource); + } + + @Bean(name = "dynamicDataSource") + @Primary + public DynamicDataSource dataSource(DataSource masterDataSource) + { + Map targetDataSources = new HashMap<>(); + targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); + setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); + return new DynamicDataSource(masterDataSource, targetDataSources); + } + + /** + * 设置数据源 + * + * @param targetDataSources 备选数据源集合 + * @param sourceName 数据源名称 + * @param beanName bean名称 + */ + public void setDataSource(Map targetDataSources, String sourceName, String beanName) + { + try + { + DataSource dataSource = SpringUtils.getBean(beanName); + targetDataSources.put(sourceName, dataSource); + } + catch (Exception e) + { + } + } + + /** + * 去除监控页面底部的广告 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") + public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) + { + // 获取web监控页面的参数 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); + // 提取common.js的配置路径 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); + final String filePath = "support/http/resources/js/common.js"; + // 创建filter进行过滤 + Filter filter = new Filter() + { + @Override + public void init(javax.servlet.FilterConfig filterConfig) throws ServletException + { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + chain.doFilter(request, response); + // 重置缓冲区,响应头不会被重置 + response.resetBuffer(); + // 获取common.js + String text = Utils.readFromResource(filePath); + // 正则替换banner, 除去底部的广告信息 + text = text.replaceAll("
", ""); + text = text.replaceAll("powered.*?shrek.wang", ""); + response.getWriter().write(text); + } + + @Override + public void destroy() + { + } + }; + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(filter); + registrationBean.addUrlPatterns(commonJsPattern); + return registrationBean; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/FilterConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/FilterConfig.java new file mode 100644 index 0000000..34621fd --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/FilterConfig.java @@ -0,0 +1,44 @@ +package com.playlet.framework.config; + +import java.util.HashMap; +import java.util.Map; +import javax.servlet.DispatcherType; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.xss.XssFilter; + +/** + * Filter配置 + * + * @author ruoyi + */ +@Configuration +@ConditionalOnProperty(value = "xss.enabled", havingValue = "true") +public class FilterConfig +{ + @Value("${xss.excludes}") + private String excludes; + + @Value("${xss.urlPatterns}") + private String urlPatterns; + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + public FilterRegistrationBean xssFilterRegistration() + { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns(StringUtils.split(urlPatterns, ",")); + registration.setName("xssFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + Map initParameters = new HashMap(); + initParameters.put("excludes", excludes); + registration.setInitParameters(initParameters); + return registration; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/I18nConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/I18nConfig.java new file mode 100644 index 0000000..1865d06 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/I18nConfig.java @@ -0,0 +1,43 @@ +package com.playlet.framework.config; + +import java.util.Locale; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + +/** + * 资源文件配置加载 + * + * @author ruoyi + */ +@Configuration +public class I18nConfig implements WebMvcConfigurer +{ + @Bean + public LocaleResolver localeResolver() + { + SessionLocaleResolver slr = new SessionLocaleResolver(); + // 默认语言 + slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE); + return slr; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() + { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + // 参数名 + lci.setParamName("lang"); + return lci; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) + { + registry.addInterceptor(localeChangeInterceptor()); + } +} \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/KaptchaTextCreator.java b/playlet-framework/src/main/java/com/playlet/framework/config/KaptchaTextCreator.java new file mode 100644 index 0000000..422556c --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/KaptchaTextCreator.java @@ -0,0 +1,76 @@ +package com.playlet.framework.config; + +import java.security.SecureRandom; +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 SecureRandom(); + int x = random.nextInt(10); + int y = random.nextInt(10); + StringBuilder suChinese = new StringBuilder(); + int randomoperands = (int) Math.round(Math.random() * 2); + 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(); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/MyBatisConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/MyBatisConfig.java new file mode 100644 index 0000000..9a94b34 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/MyBatisConfig.java @@ -0,0 +1,132 @@ +package com.playlet.framework.config; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import javax.sql.DataSource; +import org.apache.ibatis.io.VFS; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.util.ClassUtils; +import com.playlet.common.utils.StringUtils; + +/** + * Mybatis支持*匹配扫描包 + * + * @author ruoyi + */ +//@Configuration +public class MyBatisConfig +{ +// @Autowired + private Environment env; + + static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; + + public static String setTypeAliasesPackage(String typeAliasesPackage) + { + ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); + MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); + List allResult = new ArrayList(); + try + { + for (String aliasesPackage : typeAliasesPackage.split(",")) + { + List result = new ArrayList(); + aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN; + Resource[] resources = resolver.getResources(aliasesPackage); + if (resources != null && resources.length > 0) + { + MetadataReader metadataReader = null; + for (Resource resource : resources) + { + if (resource.isReadable()) + { + metadataReader = metadataReaderFactory.getMetadataReader(resource); + try + { + result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); + } + catch (ClassNotFoundException e) + { + e.printStackTrace(); + } + } + } + } + if (result.size() > 0) + { + HashSet hashResult = new HashSet(result); + allResult.addAll(hashResult); + } + } + if (allResult.size() > 0) + { + typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); + } + else + { + throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); + } + } + catch (IOException e) + { + e.printStackTrace(); + } + return typeAliasesPackage; + } + + public Resource[] resolveMapperLocations(String[] mapperLocations) + { + ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + List resources = new ArrayList(); + if (mapperLocations != null) + { + for (String mapperLocation : mapperLocations) + { + try + { + Resource[] mappers = resourceResolver.getResources(mapperLocation); + resources.addAll(Arrays.asList(mappers)); + } + catch (IOException e) + { + // ignore + } + } + } + return resources.toArray(new Resource[resources.size()]); + } + + @Bean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception + { + String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); + String mapperLocations = env.getProperty("mybatis.mapperLocations"); + String configLocation = env.getProperty("mybatis.configLocation"); + typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); + VFS.addImplClass(SpringBootVFS.class); + + final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); + sessionFactory.setDataSource(dataSource); + sessionFactory.setTypeAliasesPackage(typeAliasesPackage); + sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ","))); + sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); + return sessionFactory.getObject(); + } +} \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/ResourcesConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/ResourcesConfig.java new file mode 100644 index 0000000..e99e76d --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/ResourcesConfig.java @@ -0,0 +1,58 @@ +package com.playlet.framework.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import com.playlet.common.config.RuoYiConfig; +import com.playlet.common.constant.Constants; +import com.playlet.framework.interceptor.RepeatSubmitInterceptor; + +/** + * 通用配置 + * + * @author ruoyi + */ +@Configuration +public class ResourcesConfig implements WebMvcConfigurer +{ + /** + * 首页地址 + */ + @Value("${shiro.user.indexUrl}") + private String indexUrl; + + @Autowired + private RepeatSubmitInterceptor repeatSubmitInterceptor; + + /** + * 默认首页的设置,当输入域名是可以自动跳转到默认指定的网页 + */ + @Override + public void addViewControllers(ViewControllerRegistry registry) + { + registry.addViewController("/").setViewName("forward:" + indexUrl); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) + { + /** 本地文件上传路径 */ + registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); + + /** swagger配置 */ + registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); + } + + /** + * 自定义拦截规则 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) + { + registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**"); + } +} \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/ShiroConfig.java b/playlet-framework/src/main/java/com/playlet/framework/config/ShiroConfig.java new file mode 100644 index 0000000..2a375d3 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/ShiroConfig.java @@ -0,0 +1,421 @@ +package com.playlet.framework.config; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.Filter; +import org.apache.commons.io.IOUtils; +import org.apache.shiro.cache.ehcache.EhCacheManager; +import org.apache.shiro.codec.Base64; +import org.apache.shiro.config.ConfigurationException; +import org.apache.shiro.io.ResourceUtils; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.CookieRememberMeManager; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.apache.shiro.web.servlet.SimpleCookie; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.playlet.common.constant.Constants; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.security.CipherUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.framework.shiro.realm.UserRealm; +import com.playlet.framework.shiro.session.OnlineSessionDAO; +import com.playlet.framework.shiro.session.OnlineSessionFactory; +import com.playlet.framework.shiro.web.CustomShiroFilterFactoryBean; +import com.playlet.framework.shiro.web.filter.LogoutFilter; +import com.playlet.framework.shiro.web.filter.captcha.CaptchaValidateFilter; +import com.playlet.framework.shiro.web.filter.kickout.KickoutSessionFilter; +import com.playlet.framework.shiro.web.filter.online.OnlineSessionFilter; +import com.playlet.framework.shiro.web.filter.sync.SyncOnlineSessionFilter; +import com.playlet.framework.shiro.web.session.OnlineWebSessionManager; +import com.playlet.framework.shiro.web.session.SpringSessionValidationScheduler; +import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; + +/** + * 权限配置加载 + * + * @author ruoyi + */ +@Configuration +public class ShiroConfig +{ + /** + * Session超时时间,单位为毫秒(默认30分钟) + */ + @Value("${shiro.session.expireTime}") + private int expireTime; + + /** + * 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 + */ + @Value("${shiro.session.validationInterval}") + private int validationInterval; + + /** + * 同一个用户最大会话数 + */ + @Value("${shiro.session.maxSession}") + private int maxSession; + + /** + * 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户 + */ + @Value("${shiro.session.kickoutAfter}") + private boolean kickoutAfter; + + /** + * 验证码开关 + */ + @Value("${shiro.user.captchaEnabled}") + private boolean captchaEnabled; + + /** + * 验证码类型 + */ + @Value("${shiro.user.captchaType}") + private String captchaType; + + /** + * 设置Cookie的域名 + */ + @Value("${shiro.cookie.domain}") + private String domain; + + /** + * 设置cookie的有效访问路径 + */ + @Value("${shiro.cookie.path}") + private String path; + + /** + * 设置HttpOnly属性 + */ + @Value("${shiro.cookie.httpOnly}") + private boolean httpOnly; + + /** + * 设置Cookie的过期时间,秒为单位 + */ + @Value("${shiro.cookie.maxAge}") + private int maxAge; + + /** + * 设置cipherKey密钥 + */ + @Value("${shiro.cookie.cipherKey}") + private String cipherKey; + + /** + * 登录地址 + */ + @Value("${shiro.user.loginUrl}") + private String loginUrl; + + /** + * 权限认证失败地址 + */ + @Value("${shiro.user.unauthorizedUrl}") + private String unauthorizedUrl; + + /** + * 是否开启记住我功能 + */ + @Value("${shiro.rememberMe.enabled: false}") + private boolean rememberMe; + + /** + * 缓存管理器 使用Ehcache实现 + */ + @Bean + public EhCacheManager getEhCacheManager() + { + net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); + EhCacheManager em = new EhCacheManager(); + if (StringUtils.isNull(cacheManager)) + { + em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); + return em; + } + else + { + em.setCacheManager(cacheManager); + return em; + } + } + + /** + * 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署 + */ + protected InputStream getCacheManagerConfigFileInputStream() + { + String configFile = "classpath:ehcache/ehcache-shiro.xml"; + InputStream inputStream = null; + try + { + inputStream = ResourceUtils.getInputStreamForPath(configFile); + byte[] b = IOUtils.toByteArray(inputStream); + InputStream in = new ByteArrayInputStream(b); + return in; + } + catch (IOException e) + { + throw new ConfigurationException( + "Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e); + } + finally + { + IOUtils.closeQuietly(inputStream); + } + } + + /** + * 自定义Realm + */ + @Bean + public UserRealm userRealm(EhCacheManager cacheManager) + { + UserRealm userRealm = new UserRealm(); + userRealm.setAuthorizationCacheName(Constants.SYS_AUTH_CACHE); + userRealm.setCacheManager(cacheManager); + return userRealm; + } + + /** + * 自定义sessionDAO会话 + */ + @Bean + public OnlineSessionDAO sessionDAO() + { + OnlineSessionDAO sessionDAO = new OnlineSessionDAO(); + return sessionDAO; + } + + /** + * 自定义sessionFactory会话 + */ + @Bean + public OnlineSessionFactory sessionFactory() + { + OnlineSessionFactory sessionFactory = new OnlineSessionFactory(); + return sessionFactory; + } + + /** + * 会话管理器 + */ + @Bean + public OnlineWebSessionManager sessionManager() + { + OnlineWebSessionManager manager = new OnlineWebSessionManager(); + // 加入缓存管理器 + manager.setCacheManager(getEhCacheManager()); + // 删除过期的session + manager.setDeleteInvalidSessions(true); + // 设置全局session超时时间 + manager.setGlobalSessionTimeout(expireTime * 60 * 1000); + // 去掉 JSESSIONID + manager.setSessionIdUrlRewritingEnabled(false); + // 定义要使用的无效的Session定时调度器 + manager.setSessionValidationScheduler(SpringUtils.getBean(SpringSessionValidationScheduler.class)); + // 是否定时检查session + manager.setSessionValidationSchedulerEnabled(true); + // 自定义SessionDao + manager.setSessionDAO(sessionDAO()); + // 自定义sessionFactory + manager.setSessionFactory(sessionFactory()); + return manager; + } + + /** + * 安全管理器 + */ + @Bean + public SecurityManager securityManager(UserRealm userRealm) + { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + // 设置realm. + securityManager.setRealm(userRealm); + // 记住我 + securityManager.setRememberMeManager(rememberMe ? rememberMeManager() : null); + // 注入缓存管理器; + securityManager.setCacheManager(getEhCacheManager()); + // session管理器 + securityManager.setSessionManager(sessionManager()); + return securityManager; + } + + /** + * 退出过滤器 + */ + public LogoutFilter logoutFilter() + { + LogoutFilter logoutFilter = new LogoutFilter(); + logoutFilter.setLoginUrl(loginUrl); + return logoutFilter; + } + + /** + * Shiro过滤器配置 + */ + @Bean + public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) + { + CustomShiroFilterFactoryBean shiroFilterFactoryBean = new CustomShiroFilterFactoryBean(); + // Shiro的核心安全接口,这个属性是必须的 + shiroFilterFactoryBean.setSecurityManager(securityManager); + // 身份认证失败,则跳转到登录页面的配置 + shiroFilterFactoryBean.setLoginUrl(loginUrl); + // 权限认证失败,则跳转到指定页面 + shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); + // Shiro连接约束配置,即过滤链的定义 + LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); + // 对静态资源设置匿名访问 + filterChainDefinitionMap.put("/favicon.ico**", "anon"); + filterChainDefinitionMap.put("/ruoyi.png**", "anon"); + filterChainDefinitionMap.put("/html/**", "anon"); + filterChainDefinitionMap.put("/css/**", "anon"); + filterChainDefinitionMap.put("/docs/**", "anon"); + filterChainDefinitionMap.put("/fonts/**", "anon"); + filterChainDefinitionMap.put("/img/**", "anon"); + filterChainDefinitionMap.put("/ajax/**", "anon"); + filterChainDefinitionMap.put("/js/**", "anon"); + filterChainDefinitionMap.put("/ruoyi/**", "anon"); + filterChainDefinitionMap.put("/captcha/captchaImage**", "anon"); + // 接口文档 + filterChainDefinitionMap.put("/tool/swagger", "anon"); + filterChainDefinitionMap.put("/tool/swagger/**", "anon"); + // oss文件接口 + filterChainDefinitionMap.put("/tool/oss/**", "anon"); + // 退出 logout地址,shiro去清除session + filterChainDefinitionMap.put("/logout", "logout"); + // 不需要拦截的访问 + filterChainDefinitionMap.put("/login", "anon,captchaValidate"); + // 注册相关 + filterChainDefinitionMap.put("/register", "anon,captchaValidate"); + // 系统权限列表 + // filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll()); + + Map filters = new LinkedHashMap(); + filters.put("onlineSession", onlineSessionFilter()); + filters.put("syncOnlineSession", syncOnlineSessionFilter()); + filters.put("captchaValidate", captchaValidateFilter()); + filters.put("kickout", kickoutSessionFilter()); + // 注销成功,则跳转到指定页面 + filters.put("logout", logoutFilter()); + shiroFilterFactoryBean.setFilters(filters); + + // 所有请求需要认证 + filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession"); + shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); + + return shiroFilterFactoryBean; + } + + /** + * 自定义在线用户处理过滤器 + */ + public OnlineSessionFilter onlineSessionFilter() + { + OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter(); + onlineSessionFilter.setLoginUrl(loginUrl); + onlineSessionFilter.setOnlineSessionDAO(sessionDAO()); + return onlineSessionFilter; + } + + /** + * 自定义在线用户同步过滤器 + */ + public SyncOnlineSessionFilter syncOnlineSessionFilter() + { + SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter(); + syncOnlineSessionFilter.setOnlineSessionDAO(sessionDAO()); + return syncOnlineSessionFilter; + } + + /** + * 自定义验证码过滤器 + */ + public CaptchaValidateFilter captchaValidateFilter() + { + CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter(); + captchaValidateFilter.setCaptchaEnabled(captchaEnabled); + captchaValidateFilter.setCaptchaType(captchaType); + return captchaValidateFilter; + } + + /** + * cookie 属性设置 + */ + public SimpleCookie rememberMeCookie() + { + SimpleCookie cookie = new SimpleCookie("rememberMe"); + cookie.setDomain(domain); + cookie.setPath(path); + cookie.setHttpOnly(httpOnly); + cookie.setMaxAge(maxAge * 24 * 60 * 60); + return cookie; + } + + /** + * 记住我 + */ + public CookieRememberMeManager rememberMeManager() + { + CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); + cookieRememberMeManager.setCookie(rememberMeCookie()); + if (StringUtils.isNotEmpty(cipherKey)) + { + cookieRememberMeManager.setCipherKey(Base64.decode(cipherKey)); + } + else + { + cookieRememberMeManager.setCipherKey(CipherUtils.generateNewKey(128, "AES").getEncoded()); + } + return cookieRememberMeManager; + } + + /** + * 同一个用户多设备登录限制 + */ + public KickoutSessionFilter kickoutSessionFilter() + { + KickoutSessionFilter kickoutSessionFilter = new KickoutSessionFilter(); + kickoutSessionFilter.setCacheManager(getEhCacheManager()); + kickoutSessionFilter.setSessionManager(sessionManager()); + // 同一个用户最大的会话数,默认-1无限制;比如2的意思是同一个用户允许最多同时两个人登录 + kickoutSessionFilter.setMaxSession(maxSession); + // 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序 + kickoutSessionFilter.setKickoutAfter(kickoutAfter); + // 被踢出后重定向到的地址; + kickoutSessionFilter.setKickoutUrl("/login?kickout=1"); + return kickoutSessionFilter; + } + + /** + * thymeleaf模板引擎和shiro框架的整合 + */ + @Bean + public ShiroDialect shiroDialect() + { + return new ShiroDialect(); + } + + /** + * 开启Shiro注解通知器 + */ + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( + @Qualifier("securityManager") SecurityManager securityManager) + { + AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); + authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); + return authorizationAttributeSourceAdvisor; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/config/properties/DruidProperties.java b/playlet-framework/src/main/java/com/playlet/framework/config/properties/DruidProperties.java new file mode 100644 index 0000000..a106223 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/config/properties/DruidProperties.java @@ -0,0 +1,89 @@ +package com.playlet.framework.config.properties; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import com.alibaba.druid.pool.DruidDataSource; + +/** + * druid 配置属性 + * + * @author ruoyi + */ +@Configuration +public class DruidProperties +{ + @Value("${spring.datasource.druid.initialSize}") + private int initialSize; + + @Value("${spring.datasource.druid.minIdle}") + private int minIdle; + + @Value("${spring.datasource.druid.maxActive}") + private int maxActive; + + @Value("${spring.datasource.druid.maxWait}") + private int maxWait; + + @Value("${spring.datasource.druid.connectTimeout}") + private int connectTimeout; + + @Value("${spring.datasource.druid.socketTimeout}") + private int socketTimeout; + + @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}") + private int timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}") + private int minEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}") + private int maxEvictableIdleTimeMillis; + + @Value("${spring.datasource.druid.validationQuery}") + private String validationQuery; + + @Value("${spring.datasource.druid.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${spring.datasource.druid.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${spring.datasource.druid.testOnReturn}") + private boolean testOnReturn; + + public DruidDataSource dataSource(DruidDataSource datasource) + { + /** 配置初始化大小、最小、最大 */ + datasource.setInitialSize(initialSize); + datasource.setMaxActive(maxActive); + datasource.setMinIdle(minIdle); + + /** 配置获取连接等待超时的时间 */ + datasource.setMaxWait(maxWait); + + /** 配置驱动连接超时时间,检测数据库建立连接的超时时间,单位是毫秒 */ + datasource.setConnectTimeout(connectTimeout); + + /** 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒 */ + datasource.setSocketTimeout(socketTimeout); + + /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */ + datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + + /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */ + datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis); + + /** + * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 + */ + datasource.setValidationQuery(validationQuery); + /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */ + datasource.setTestWhileIdle(testWhileIdle); + /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnBorrow(testOnBorrow); + /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */ + datasource.setTestOnReturn(testOnReturn); + return datasource; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/datasource/DynamicDataSource.java b/playlet-framework/src/main/java/com/playlet/framework/datasource/DynamicDataSource.java new file mode 100644 index 0000000..8a173b7 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/datasource/DynamicDataSource.java @@ -0,0 +1,27 @@ +package com.playlet.framework.datasource; + +import java.util.Map; +import javax.sql.DataSource; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; +import com.playlet.common.config.datasource.DynamicDataSourceContextHolder; + +/** + * 动态数据源 + * + * @author ruoyi + */ +public class DynamicDataSource extends AbstractRoutingDataSource +{ + public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) + { + super.setDefaultTargetDataSource(defaultTargetDataSource); + super.setTargetDataSources(targetDataSources); + super.afterPropertiesSet(); + } + + @Override + protected Object determineCurrentLookupKey() + { + return DynamicDataSourceContextHolder.getDataSourceType(); + } +} \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/interceptor/RepeatSubmitInterceptor.java b/playlet-framework/src/main/java/com/playlet/framework/interceptor/RepeatSubmitInterceptor.java new file mode 100644 index 0000000..8b2547f --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/interceptor/RepeatSubmitInterceptor.java @@ -0,0 +1,55 @@ +package com.playlet.framework.interceptor; + +import java.lang.reflect.Method; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import com.playlet.common.json.JSON; +import com.playlet.common.annotation.RepeatSubmit; +import com.playlet.common.core.domain.AjaxResult; +import com.playlet.common.utils.ServletUtils; + +/** + * 防止重复提交拦截器 + * + * @author ruoyi + */ +@Component +public abstract class RepeatSubmitInterceptor implements HandlerInterceptor +{ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception + { + if (handler instanceof HandlerMethod) + { + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); + if (annotation != null) + { + if (this.isRepeatSubmit(request, annotation)) + { + AjaxResult ajaxResult = AjaxResult.error(annotation.message()); + ServletUtils.renderString(response, JSON.marshal(ajaxResult)); + return false; + } + } + return true; + } + else + { + return true; + } + } + + /** + * 验证是否重复提交由子类实现具体的防重复提交的规则 + * + * @param request 请求对象 + * @param annotation 防复注解 + * @return 结果 + */ + public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception; +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/interceptor/impl/SameUrlDataInterceptor.java b/playlet-framework/src/main/java/com/playlet/framework/interceptor/impl/SameUrlDataInterceptor.java new file mode 100644 index 0000000..9a73b8f --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/interceptor/impl/SameUrlDataInterceptor.java @@ -0,0 +1,83 @@ +package com.playlet.framework.interceptor.impl; + +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import org.springframework.stereotype.Component; +import com.playlet.common.annotation.RepeatSubmit; +import com.playlet.common.json.JSON; +import com.playlet.framework.interceptor.RepeatSubmitInterceptor; + +/** + * 判断请求url和数据是否和上一次相同, + * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。 + * + * @author ruoyi + */ +@Component +public class SameUrlDataInterceptor extends RepeatSubmitInterceptor +{ + public final String REPEAT_PARAMS = "repeatParams"; + + public final String REPEAT_TIME = "repeatTime"; + + public final String SESSION_REPEAT_KEY = "repeatData"; + + @SuppressWarnings("unchecked") + @Override + public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception + { + // 本次参数及系统时间 + String nowParams = JSON.marshal(request.getParameterMap()); + Map nowDataMap = new HashMap(); + nowDataMap.put(REPEAT_PARAMS, nowParams); + nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); + + // 请求地址(作为存放session的key值) + String url = request.getRequestURI(); + + HttpSession session = request.getSession(); + Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY); + if (sessionObj != null) + { + Map sessionMap = (Map) sessionObj; + if (sessionMap.containsKey(url)) + { + Map preDataMap = (Map) sessionMap.get(url); + if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) + { + return true; + } + } + } + Map sessionMap = new HashMap(); + sessionMap.put(url, nowDataMap); + session.setAttribute(SESSION_REPEAT_KEY, sessionMap); + return false; + } + + /** + * 判断参数是否相同 + */ + private boolean compareParams(Map nowMap, Map preMap) + { + String nowParams = (String) nowMap.get(REPEAT_PARAMS); + String preParams = (String) preMap.get(REPEAT_PARAMS); + return nowParams.equals(preParams); + } + + /** + * 判断两次间隔时间 + */ + private boolean compareTime(Map nowMap, Map preMap, int interval) + { + long time1 = (Long) nowMap.get(REPEAT_TIME); + long time2 = (Long) preMap.get(REPEAT_TIME); + if ((time1 - time2) < interval) + { + return true; + } + return false; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/manager/AsyncManager.java b/playlet-framework/src/main/java/com/playlet/framework/manager/AsyncManager.java new file mode 100644 index 0000000..d5691aa --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/manager/AsyncManager.java @@ -0,0 +1,55 @@ +package com.playlet.framework.manager; + +import java.util.TimerTask; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import com.playlet.common.utils.Threads; +import com.playlet.common.utils.spring.SpringUtils; + +/** + * 异步任务管理器 + * + * @author liuhulu + */ +public class AsyncManager +{ + /** + * 操作延迟10毫秒 + */ + private final int OPERATE_DELAY_TIME = 10; + + /** + * 异步操作任务调度线程池 + */ + private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); + + /** + * 单例模式 + */ + private AsyncManager(){} + + private static AsyncManager me = new AsyncManager(); + + public static AsyncManager me() + { + return me; + } + + /** + * 执行任务 + * + * @param task 任务 + */ + public void execute(TimerTask task) + { + executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); + } + + /** + * 停止任务线程池 + */ + public void shutdown() + { + Threads.shutdownAndAwaitTermination(executor); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/manager/ShutdownManager.java b/playlet-framework/src/main/java/com/playlet/framework/manager/ShutdownManager.java new file mode 100644 index 0000000..526b2ed --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/manager/ShutdownManager.java @@ -0,0 +1,87 @@ +package com.playlet.framework.manager; + +import com.playlet.framework.shiro.web.session.SpringSessionValidationScheduler; +import net.sf.ehcache.CacheManager; +import org.apache.shiro.cache.ehcache.EhCacheManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.annotation.PreDestroy; + +/** + * 确保应用退出时能关闭后台线程 + * + * @author cj + */ +@Component +public class ShutdownManager +{ + private static final Logger logger = LoggerFactory.getLogger("sys-user"); + + @Autowired(required = false) + private SpringSessionValidationScheduler springSessionValidationScheduler; + + @Autowired(required = false) + private EhCacheManager ehCacheManager; + + @PreDestroy + public void destroy() + { + shutdownSpringSessionValidationScheduler(); + shutdownAsyncManager(); + shutdownEhCacheManager(); + } + + /** + * 停止Seesion会话检查 + */ + private void shutdownSpringSessionValidationScheduler() + { + if (springSessionValidationScheduler != null && springSessionValidationScheduler.isEnabled()) + { + try + { + logger.info("====关闭会话验证任务===="); + springSessionValidationScheduler.disableSessionValidation(); + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + } + } + } + + /** + * 停止异步执行任务 + */ + private void shutdownAsyncManager() + { + try + { + logger.info("====关闭后台任务任务线程池===="); + AsyncManager.me().shutdown(); + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + } + } + + private void shutdownEhCacheManager() + { + try + { + logger.info("====关闭缓存===="); + if (ehCacheManager != null) + { + CacheManager cacheManager = ehCacheManager.getCacheManager(); + cacheManager.shutdown(); + } + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + } + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/manager/factory/AsyncFactory.java b/playlet-framework/src/main/java/com/playlet/framework/manager/factory/AsyncFactory.java new file mode 100644 index 0000000..84e1650 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/manager/factory/AsyncFactory.java @@ -0,0 +1,136 @@ +package com.playlet.framework.manager.factory; + +import java.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.playlet.common.constant.Constants; +import com.playlet.common.utils.AddressUtils; +import com.playlet.common.utils.LogUtils; +import com.playlet.common.utils.ServletUtils; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.framework.shiro.session.OnlineSession; +import com.playlet.system.domain.SysLogininfor; +import com.playlet.system.domain.SysOperLog; +import com.playlet.system.domain.SysUserOnline; +import com.playlet.system.service.ISysOperLogService; +import com.playlet.system.service.ISysUserOnlineService; +import com.playlet.system.service.impl.SysLogininforServiceImpl; +import eu.bitwalker.useragentutils.UserAgent; + +/** + * 异步工厂(产生任务用) + * + * @author liuhulu + * + */ +public class AsyncFactory +{ + private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); + + /** + * 同步session到数据库 + * + * @param session 在线用户会话 + * @return 任务task + */ + public static TimerTask syncSessionToDb(final OnlineSession session) + { + return new TimerTask() + { + @Override + public void run() + { + SysUserOnline online = new SysUserOnline(); + online.setSessionId(String.valueOf(session.getId())); + online.setDeptName(session.getDeptName()); + online.setLoginName(session.getLoginName()); + online.setStartTimestamp(session.getStartTimestamp()); + online.setLastAccessTime(session.getLastAccessTime()); + online.setExpireTime(session.getTimeout()); + online.setIpaddr(session.getHost()); + online.setLoginLocation(AddressUtils.getRealAddressByIP(session.getHost())); + online.setBrowser(session.getBrowser()); + online.setOs(session.getOs()); + online.setStatus(session.getStatus()); + SpringUtils.getBean(ISysUserOnlineService.class).saveOnline(online); + + } + }; + } + + /** + * 操作日志记录 + * + * @param operLog 操作日志信息 + * @return 任务task + */ + public static TimerTask recordOper(final SysOperLog operLog) + { + return new TimerTask() + { + @Override + public void run() + { + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); + } + }; + } + + /** + * 记录登录信息 + * + * @param username 用户名 + * @param status 状态 + * @param message 消息 + * @param args 列表 + * @return 任务task + */ + public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args) + { + final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); + final String ip = ShiroUtils.getIp(); + return new TimerTask() + { + @Override + public void run() + { + String address = AddressUtils.getRealAddressByIP(ip); + StringBuilder s = new StringBuilder(); + s.append(LogUtils.getBlock(ip)); + s.append(address); + s.append(LogUtils.getBlock(username)); + s.append(LogUtils.getBlock(status)); + s.append(LogUtils.getBlock(message)); + // 打印信息到日志 + sys_user_logger.info(s.toString(), args); + // 获取客户端操作系统 + String os = userAgent.getOperatingSystem().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLogininfor logininfor = new SysLogininfor(); + logininfor.setLoginName(username); + logininfor.setIpaddr(ip); + logininfor.setLoginLocation(address); + logininfor.setBrowser(browser); + logininfor.setOs(os); + logininfor.setMsg(message); + // 日志状态 + if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) + { + logininfor.setStatus(Constants.SUCCESS); + } + else if (Constants.LOGIN_FAIL.equals(status)) + { + logininfor.setStatus(Constants.FAIL); + } + // 插入数据 + SpringUtils.getBean(SysLogininforServiceImpl.class).insertLogininfor(logininfor); + } + }; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/realm/UserRealm.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/realm/UserRealm.java new file mode 100644 index 0000000..f3c6cbe --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/realm/UserRealm.java @@ -0,0 +1,158 @@ +package com.playlet.framework.shiro.realm; + +import java.util.HashSet; +import java.util.Set; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.ExcessiveAttemptsException; +import org.apache.shiro.authc.IncorrectCredentialsException; +import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authc.UnknownAccountException; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.cache.Cache; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.exception.user.CaptchaException; +import com.playlet.common.exception.user.RoleBlockedException; +import com.playlet.common.exception.user.UserBlockedException; +import com.playlet.common.exception.user.UserNotExistsException; +import com.playlet.common.exception.user.UserPasswordNotMatchException; +import com.playlet.common.exception.user.UserPasswordRetryLimitExceedException; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.framework.shiro.service.SysLoginService; +import com.playlet.system.service.ISysMenuService; +import com.playlet.system.service.ISysRoleService; + +/** + * 自定义Realm 处理登录 权限 + * + * @author ruoyi + */ +public class UserRealm extends AuthorizingRealm +{ + private static final Logger log = LoggerFactory.getLogger(UserRealm.class); + + @Autowired + private ISysMenuService menuService; + + @Autowired + private ISysRoleService roleService; + + @Autowired + private SysLoginService loginService; + + /** + * 授权 + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) + { + SysUser user = ShiroUtils.getSysUser(); + // 角色列表 + Set roles = new HashSet(); + // 功能列表 + Set menus = new HashSet(); + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); + // 管理员拥有所有权限 + if (user.isAdmin()) + { + info.addRole("admin"); + info.addStringPermission("*:*:*"); + } + else + { + roles = roleService.selectRoleKeys(user.getUserId()); + menus = menuService.selectPermsByUserId(user.getUserId()); + // 角色加入AuthorizationInfo认证对象 + info.setRoles(roles); + // 权限加入AuthorizationInfo认证对象 + info.setStringPermissions(menus); + } + return info; + } + + /** + * 登录认证 + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException + { + UsernamePasswordToken upToken = (UsernamePasswordToken) token; + String username = upToken.getUsername(); + String password = ""; + if (upToken.getPassword() != null) + { + password = new String(upToken.getPassword()); + } + + SysUser user = null; + try + { + user = loginService.login(username, password); + } + catch (CaptchaException e) + { + throw new AuthenticationException(e.getMessage(), e); + } + catch (UserNotExistsException e) + { + throw new UnknownAccountException(e.getMessage(), e); + } + catch (UserPasswordNotMatchException e) + { + throw new IncorrectCredentialsException(e.getMessage(), e); + } + catch (UserPasswordRetryLimitExceedException e) + { + throw new ExcessiveAttemptsException(e.getMessage(), e); + } + catch (UserBlockedException e) + { + throw new LockedAccountException(e.getMessage(), e); + } + catch (RoleBlockedException e) + { + throw new LockedAccountException(e.getMessage(), e); + } + catch (Exception e) + { + log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage()); + throw new AuthenticationException(e.getMessage(), e); + } + SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); + return info; + } + + /** + * 清理指定用户授权信息缓存 + */ + public void clearCachedAuthorizationInfo(Object principal) + { + SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName()); + this.clearCachedAuthorizationInfo(principals); + } + + /** + * 清理所有用户授权信息缓存 + */ + public void clearAllCachedAuthorizationInfo() + { + Cache cache = getAuthorizationCache(); + if (cache != null) + { + for (Object key : cache.keys()) + { + cache.remove(key); + } + } + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysLoginService.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysLoginService.java new file mode 100644 index 0000000..3525efd --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysLoginService.java @@ -0,0 +1,185 @@ +package com.playlet.framework.shiro.service; + +import java.util.List; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.playlet.common.constant.Constants; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.enums.UserStatus; +import com.playlet.common.exception.user.BlackListException; +import com.playlet.common.exception.user.CaptchaException; +import com.playlet.common.exception.user.UserBlockedException; +import com.playlet.common.exception.user.UserDeleteException; +import com.playlet.common.exception.user.UserNotExistsException; +import com.playlet.common.exception.user.UserPasswordNotMatchException; +import com.playlet.common.utils.DateUtils; +import com.playlet.common.utils.IpUtils; +import com.playlet.common.utils.MessageUtils; +import com.playlet.common.utils.ServletUtils; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.framework.manager.AsyncManager; +import com.playlet.framework.manager.factory.AsyncFactory; +import com.playlet.system.service.ISysConfigService; +import com.playlet.system.service.ISysMenuService; +import com.playlet.system.service.ISysUserService; + +/** + * 登录校验方法 + * + * @author ruoyi + */ +@Component +public class SysLoginService +{ + @Autowired + private SysPasswordService passwordService; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysMenuService menuService; + + @Autowired + private ISysConfigService configService; + + /** + * 登录 + */ + public SysUser login(String username, String password) + { + // 验证码校验 + if (ShiroConstants.CAPTCHA_ERROR.equals(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); + throw new CaptchaException(); + } + // 用户名或密码为空 错误 + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); + throw new UserNotExistsException(); + } + // 密码如果不在指定范围内 错误 + if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + + // 用户名不在指定范围内 错误 + if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + + // IP黑名单校验 + String blackStr = configService.selectConfigByKey("sys.login.blackIPList"); + if (IpUtils.isMatchedIp(blackStr, ShiroUtils.getIp())) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked"))); + throw new BlackListException(); + } + + // 查询用户信息 + SysUser user = userService.selectUserByLoginName(username); + + /** + if (user == null && maybeMobilePhoneNumber(username)) + { + user = userService.selectUserByPhoneNumber(username); + } + + if (user == null && maybeEmail(username)) + { + user = userService.selectUserByEmail(username); + } + */ + + if (user == null) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists"))); + throw new UserNotExistsException(); + } + + if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete"))); + throw new UserDeleteException(); + } + + if (UserStatus.DISABLE.getCode().equals(user.getStatus())) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked"))); + throw new UserBlockedException(); + } + + passwordService.validate(user, password); + + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + setRolePermission(user); + recordLoginInfo(user.getUserId()); + return user; + } + + /** + private boolean maybeEmail(String username) + { + if (!username.matches(UserConstants.EMAIL_PATTERN)) + { + return false; + } + return true; + } + + private boolean maybeMobilePhoneNumber(String username) + { + if (!username.matches(UserConstants.MOBILE_PHONE_NUMBER_PATTERN)) + { + return false; + } + return true; + } + */ + + /** + * 设置角色权限 + * + * @param user 用户信息 + */ + public void setRolePermission(SysUser user) + { + List roles = user.getRoles(); + if (!roles.isEmpty() && roles.size() > 1) + { + // 多角色设置permissions属性,以便数据权限匹配权限 + for (SysRole role : roles) + { + Set rolePerms = menuService.selectPermsByRoleId(role.getRoleId()); + role.setPermissions(rolePerms); + } + } + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId) + { + SysUser user = new SysUser(); + user.setUserId(userId); + user.setLoginIp(ShiroUtils.getIp()); + user.setLoginDate(DateUtils.getNowDate()); + userService.updateUserInfo(user); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysPasswordService.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysPasswordService.java new file mode 100644 index 0000000..209dec8 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysPasswordService.java @@ -0,0 +1,85 @@ +package com.playlet.framework.shiro.service; + +import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.PostConstruct; +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.CacheManager; +import org.apache.shiro.crypto.hash.Md5Hash; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import com.playlet.common.constant.Constants; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.exception.user.UserPasswordNotMatchException; +import com.playlet.common.exception.user.UserPasswordRetryLimitExceedException; +import com.playlet.common.utils.MessageUtils; +import com.playlet.framework.manager.AsyncManager; +import com.playlet.framework.manager.factory.AsyncFactory; + +/** + * 登录密码方法 + * + * @author ruoyi + */ +@Component +public class SysPasswordService +{ + @Autowired + private CacheManager cacheManager; + + private Cache loginRecordCache; + + @Value(value = "${user.password.maxRetryCount}") + private String maxRetryCount; + + @PostConstruct + public void init() + { + loginRecordCache = cacheManager.getCache(ShiroConstants.LOGINRECORDCACHE); + } + + public void validate(SysUser user, String password) + { + String loginName = user.getLoginName(); + + AtomicInteger retryCount = loginRecordCache.get(loginName); + + if (retryCount == null) + { + retryCount = new AtomicInteger(0); + loginRecordCache.put(loginName, retryCount); + } + if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue()) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount))); + throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue()); + } + + if (!matches(user, password)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", retryCount))); + loginRecordCache.put(loginName, retryCount); + throw new UserPasswordNotMatchException(); + } + else + { + clearLoginRecordCache(loginName); + } + } + + public boolean matches(SysUser user, String newPassword) + { + return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt())); + } + + public void clearLoginRecordCache(String loginName) + { + loginRecordCache.remove(loginName); + } + + public String encryptPassword(String loginName, String password, String salt) + { + return new Md5Hash(loginName + password + salt).toHex(); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysRegisterService.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysRegisterService.java new file mode 100644 index 0000000..ce02281 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysRegisterService.java @@ -0,0 +1,83 @@ +package com.playlet.framework.shiro.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.playlet.common.constant.Constants; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.utils.DateUtils; +import com.playlet.common.utils.MessageUtils; +import com.playlet.common.utils.ServletUtils; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.framework.manager.AsyncManager; +import com.playlet.framework.manager.factory.AsyncFactory; +import com.playlet.system.service.ISysUserService; + +/** + * 注册校验方法 + * + * @author ruoyi + */ +@Component +public class SysRegisterService +{ + @Autowired + private ISysUserService userService; + + @Autowired + private SysPasswordService passwordService; + + /** + * 注册 + */ + public String register(SysUser user) + { + String msg = "", loginName = user.getLoginName(), password = user.getPassword(); + + if (ShiroConstants.CAPTCHA_ERROR.equals(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) + { + msg = "验证码错误"; + } + else if (StringUtils.isEmpty(loginName)) + { + msg = "用户名不能为空"; + } + else if (StringUtils.isEmpty(password)) + { + msg = "用户密码不能为空"; + } + else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + msg = "密码长度必须在5到20个字符之间"; + } + else if (loginName.length() < UserConstants.USERNAME_MIN_LENGTH + || loginName.length() > UserConstants.USERNAME_MAX_LENGTH) + { + msg = "账户长度必须在2到20个字符之间"; + } + else if (!userService.checkLoginNameUnique(user)) + { + msg = "保存用户'" + loginName + "'失败,注册账号已存在"; + } + else + { + user.setPwdUpdateDate(DateUtils.getNowDate()); + user.setUserName(loginName); + user.setSalt(ShiroUtils.randomSalt()); + user.setPassword(passwordService.encryptPassword(loginName, password, user.getSalt())); + boolean regFlag = userService.registerUser(user); + if (!regFlag) + { + msg = "注册失败,请联系系统管理人员"; + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.REGISTER, MessageUtils.message("user.register.success"))); + } + } + return msg; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysShiroService.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysShiroService.java new file mode 100644 index 0000000..9934f2a --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/service/SysShiroService.java @@ -0,0 +1,62 @@ +package com.playlet.framework.shiro.service; + +import java.io.Serializable; +import org.apache.shiro.session.Session; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.playlet.common.utils.StringUtils; +import com.playlet.framework.shiro.session.OnlineSession; +import com.playlet.system.domain.SysUserOnline; +import com.playlet.system.service.ISysUserOnlineService; + +/** + * 会话db操作处理 + * + * @author ruoyi + */ +@Component +public class SysShiroService +{ + @Autowired + private ISysUserOnlineService onlineService; + + /** + * 删除会话 + * + * @param onlineSession 会话信息 + */ + public void deleteSession(OnlineSession onlineSession) + { + onlineService.deleteOnlineById(String.valueOf(onlineSession.getId())); + } + + /** + * 获取会话信息 + * + * @param sessionId + * @return + */ + public Session getSession(Serializable sessionId) + { + SysUserOnline userOnline = onlineService.selectOnlineById(String.valueOf(sessionId)); + return StringUtils.isNull(userOnline) ? null : createSession(userOnline); + } + + public Session createSession(SysUserOnline userOnline) + { + OnlineSession onlineSession = new OnlineSession(); + if (StringUtils.isNotNull(userOnline)) + { + onlineSession.setId(userOnline.getSessionId()); + onlineSession.setHost(userOnline.getIpaddr()); + onlineSession.setBrowser(userOnline.getBrowser()); + onlineSession.setOs(userOnline.getOs()); + onlineSession.setDeptName(userOnline.getDeptName()); + onlineSession.setLoginName(userOnline.getLoginName()); + onlineSession.setStartTimestamp(userOnline.getStartTimestamp()); + onlineSession.setLastAccessTime(userOnline.getLastAccessTime()); + onlineSession.setTimeout(userOnline.getExpireTime()); + } + return onlineSession; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSession.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSession.java new file mode 100644 index 0000000..ef92d71 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSession.java @@ -0,0 +1,165 @@ +package com.playlet.framework.shiro.session; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.shiro.session.mgt.SimpleSession; +import com.playlet.common.enums.OnlineStatus; + +/** + * 在线用户会话属性 + * + * @author ruoyi + */ +public class OnlineSession extends SimpleSession +{ + private static final long serialVersionUID = 1L; + + /** 用户ID */ + private Long userId; + + /** 用户名称 */ + private String loginName; + + /** 部门名称 */ + private String deptName; + + /** 用户头像 */ + private String avatar; + + /** 登录IP地址 */ + private String host; + + /** 浏览器类型 */ + private String browser; + + /** 操作系统 */ + private String os; + + /** 在线状态 */ + private OnlineStatus status = OnlineStatus.on_line; + + /** 属性是否改变 优化session数据同步 */ + private transient boolean attributeChanged = false; + + @Override + public String getHost() + { + return host; + } + + @Override + public void setHost(String host) + { + this.host = host; + } + + 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 getUserId() + { + return userId; + } + + public void setUserId(Long userId) + { + this.userId = userId; + } + + public String getLoginName() + { + return loginName; + } + + public void setLoginName(String loginName) + { + this.loginName = loginName; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public OnlineStatus getStatus() + { + return status; + } + + public void setStatus(OnlineStatus status) + { + this.status = status; + } + + public void markAttributeChanged() + { + this.attributeChanged = true; + } + + public void resetAttributeChanged() + { + this.attributeChanged = false; + } + + public boolean isAttributeChanged() + { + return attributeChanged; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + @Override + public void setAttribute(Object key, Object value) + { + super.setAttribute(key, value); + } + + @Override + public Object removeAttribute(Object key) + { + return super.removeAttribute(key); + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("loginName", getLoginName()) + .append("deptName", getDeptName()) + .append("avatar", getAvatar()) + .append("host", getHost()) + .append("browser", getBrowser()) + .append("os", getOs()) + .append("status", getStatus()) + .append("attributeChanged", isAttributeChanged()) + .toString(); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionDAO.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionDAO.java new file mode 100644 index 0000000..42cd13e --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionDAO.java @@ -0,0 +1,117 @@ +package com.playlet.framework.shiro.session; + +import java.io.Serializable; +import java.util.Date; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.UnknownSessionException; +import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import com.playlet.common.enums.OnlineStatus; +import com.playlet.framework.manager.AsyncManager; +import com.playlet.framework.manager.factory.AsyncFactory; +import com.playlet.framework.shiro.service.SysShiroService; + +/** + * 针对自定义的ShiroSession的db操作 + * + * @author ruoyi + */ +public class OnlineSessionDAO extends EnterpriseCacheSessionDAO +{ + /** + * 同步session到数据库的周期 单位为毫秒(默认1分钟) + */ + @Value("${shiro.session.dbSyncPeriod}") + private int dbSyncPeriod; + + /** + * 上次同步数据库的时间戳 + */ + private static final String LAST_SYNC_DB_TIMESTAMP = OnlineSessionDAO.class.getName() + "LAST_SYNC_DB_TIMESTAMP"; + + @Autowired + private SysShiroService sysShiroService; + + public OnlineSessionDAO() + { + super(); + } + + public OnlineSessionDAO(long expireTime) + { + super(); + } + + /** + * 根据会话ID获取会话 + * + * @param sessionId 会话ID + * @return ShiroSession + */ + @Override + protected Session doReadSession(Serializable sessionId) + { + return sysShiroService.getSession(sessionId); + } + + @Override + public void update(Session session) throws UnknownSessionException + { + super.update(session); + } + + /** + * 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用 + */ + public void syncToDb(OnlineSession onlineSession) + { + Date lastSyncTimestamp = (Date) onlineSession.getAttribute(LAST_SYNC_DB_TIMESTAMP); + if (lastSyncTimestamp != null) + { + boolean needSync = true; + long deltaTime = onlineSession.getLastAccessTime().getTime() - lastSyncTimestamp.getTime(); + if (deltaTime < dbSyncPeriod * 60 * 1000) + { + // 时间差不足 无需同步 + needSync = false; + } + // isGuest = true 访客 + boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L; + + // session 数据变更了 同步 + if (!isGuest && onlineSession.isAttributeChanged()) + { + needSync = true; + } + + if (!needSync) + { + return; + } + } + // 更新上次同步数据库时间 + onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime()); + // 更新完后 重置标识 + if (onlineSession.isAttributeChanged()) + { + onlineSession.resetAttributeChanged(); + } + AsyncManager.me().execute(AsyncFactory.syncSessionToDb(onlineSession)); + } + + /** + * 当会话过期/停止(如用户退出时)属性等会调用 + */ + @Override + protected void doDelete(Session session) + { + OnlineSession onlineSession = (OnlineSession) session; + if (null == onlineSession) + { + return; + } + onlineSession.setStatus(OnlineStatus.off_line); + sysShiroService.deleteSession(onlineSession); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionFactory.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionFactory.java new file mode 100644 index 0000000..369ce7a --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/session/OnlineSessionFactory.java @@ -0,0 +1,42 @@ +package com.playlet.framework.shiro.session; + +import javax.servlet.http.HttpServletRequest; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.SessionContext; +import org.apache.shiro.session.mgt.SessionFactory; +import org.apache.shiro.web.session.mgt.WebSessionContext; +import org.springframework.stereotype.Component; +import com.playlet.common.utils.IpUtils; +import eu.bitwalker.useragentutils.UserAgent; + +/** + * 自定义sessionFactory会话 + * + * @author ruoyi + */ +@Component +public class OnlineSessionFactory implements SessionFactory +{ + @Override + public Session createSession(SessionContext initData) + { + OnlineSession session = new OnlineSession(); + if (initData != null && initData instanceof WebSessionContext) + { + WebSessionContext sessionContext = (WebSessionContext) initData; + HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest(); + if (request != null) + { + UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent")); + // 获取客户端操作系统 + String os = userAgent.getOperatingSystem().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + session.setHost(IpUtils.getIpAddr(request)); + session.setBrowser(browser); + session.setOs(os); + } + } + return session; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/util/AuthorizationUtils.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/util/AuthorizationUtils.java new file mode 100644 index 0000000..4eb6816 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/util/AuthorizationUtils.java @@ -0,0 +1,30 @@ +package com.playlet.framework.shiro.util; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.mgt.RealmSecurityManager; +import com.playlet.framework.shiro.realm.UserRealm; + +/** + * 用户授权信息 + * + * @author ruoyi + */ +public class AuthorizationUtils +{ + /** + * 清理所有用户授权信息缓存 + */ + public static void clearAllCachedAuthorizationInfo() + { + getUserRealm().clearAllCachedAuthorizationInfo(); + } + + /** + * 获取自定义Realm + */ + public static UserRealm getUserRealm() + { + RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager(); + return (UserRealm) rsm.getRealms().iterator().next(); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/CustomShiroFilterFactoryBean.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/CustomShiroFilterFactoryBean.java new file mode 100644 index 0000000..e9a7403 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/CustomShiroFilterFactoryBean.java @@ -0,0 +1,85 @@ +package com.playlet.framework.shiro.web; + +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.filter.InvalidRequestFilter; +import org.apache.shiro.web.filter.mgt.DefaultFilter; +import org.apache.shiro.web.filter.mgt.FilterChainManager; +import org.apache.shiro.web.filter.mgt.FilterChainResolver; +import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; +import org.apache.shiro.web.mgt.WebSecurityManager; +import org.apache.shiro.web.servlet.AbstractShiroFilter; +import org.apache.shiro.mgt.SecurityManager; +import org.springframework.beans.factory.BeanInitializationException; +import javax.servlet.Filter; +import java.util.Map; + +/** + * 自定义ShiroFilterFactoryBean解决资源中文路径问题 + * + * @author ruoyi + */ +public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean +{ + @Override + public Class getObjectType() + { + return MySpringShiroFilter.class; + } + + @Override + protected AbstractShiroFilter createInstance() throws Exception + { + + SecurityManager securityManager = getSecurityManager(); + if (securityManager == null) + { + String msg = "SecurityManager property must be set."; + throw new BeanInitializationException(msg); + } + + if (!(securityManager instanceof WebSecurityManager)) + { + String msg = "The security manager does not implement the WebSecurityManager interface."; + throw new BeanInitializationException(msg); + } + + FilterChainManager manager = createFilterChainManager(); + // Expose the constructed FilterChainManager by first wrapping it in a + // FilterChainResolver implementation. The AbstractShiroFilter implementations + // do not know about FilterChainManagers - only resolvers: + PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver(); + chainResolver.setFilterChainManager(manager); + + Map filterMap = manager.getFilters(); + Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); + if (invalidRequestFilter instanceof InvalidRequestFilter) + { + // 此处是关键,设置false跳过URL携带中文400,servletPath中文校验bug + ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false); + } + // Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built + // FilterChainResolver. It doesn't matter that the instance is an anonymous inner class + // here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts + // injection of the SecurityManager and FilterChainResolver: + return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver); + } + + private static final class MySpringShiroFilter extends AbstractShiroFilter + { + protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) + { + if (webSecurityManager == null) + { + throw new IllegalArgumentException("WebSecurityManager property cannot be null."); + } + else + { + this.setSecurityManager(webSecurityManager); + if (resolver != null) + { + this.setFilterChainResolver(resolver); + } + } + } + } +} \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/LogoutFilter.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/LogoutFilter.java new file mode 100644 index 0000000..87312bf --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/LogoutFilter.java @@ -0,0 +1,90 @@ +package com.playlet.framework.shiro.web.filter; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.shiro.session.SessionException; +import org.apache.shiro.subject.Subject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.playlet.common.constant.Constants; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.utils.MessageUtils; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.framework.manager.AsyncManager; +import com.playlet.framework.manager.factory.AsyncFactory; +import com.playlet.system.service.ISysUserOnlineService; + +/** + * 退出过滤器 + * + * @author ruoyi + */ +public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter +{ + private static final Logger log = LoggerFactory.getLogger(LogoutFilter.class); + + /** + * 退出后重定向的地址 + */ + private String loginUrl; + + public String getLoginUrl() + { + return loginUrl; + } + + public void setLoginUrl(String loginUrl) + { + this.loginUrl = loginUrl; + } + + @Override + protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception + { + try + { + Subject subject = getSubject(request, response); + String redirectUrl = getRedirectUrl(request, response, subject); + try + { + SysUser user = ShiroUtils.getSysUser(); + if (StringUtils.isNotNull(user)) + { + String loginName = user.getLoginName(); + // 记录用户退出日志 + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"))); + // 清理缓存 + SpringUtils.getBean(ISysUserOnlineService.class).removeUserCache(loginName, ShiroUtils.getSessionId()); + } + // 退出登录 + subject.logout(); + } + catch (SessionException ise) + { + log.error("logout fail.", ise); + } + issueRedirect(request, response, redirectUrl); + } + catch (Exception e) + { + log.error("Encountered session exception during logout. This can generally safely be ignored.", e); + } + return false; + } + + /** + * 退出跳转URL + */ + @Override + protected String getRedirectUrl(ServletRequest request, ServletResponse response, Subject subject) + { + String url = getLoginUrl(); + if (StringUtils.isNotEmpty(url)) + { + return url; + } + return super.getRedirectUrl(request, response, subject); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java new file mode 100644 index 0000000..410bb7c --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java @@ -0,0 +1,79 @@ +package com.playlet.framework.shiro.web.filter.captcha; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import org.apache.shiro.web.filter.AccessControlFilter; +import com.google.code.kaptcha.Constants; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; + +/** + * 验证码过滤器 + * + * @author ruoyi + */ +public class CaptchaValidateFilter extends AccessControlFilter +{ + /** + * 是否开启验证码 + */ + private boolean captchaEnabled = true; + + /** + * 验证码类型 + */ + private String captchaType = "math"; + + public void setCaptchaEnabled(boolean captchaEnabled) + { + this.captchaEnabled = captchaEnabled; + } + + public void setCaptchaType(String captchaType) + { + this.captchaType = captchaType; + } + + @Override + public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception + { + request.setAttribute(ShiroConstants.CURRENT_ENABLED, captchaEnabled); + request.setAttribute(ShiroConstants.CURRENT_TYPE, captchaType); + return super.onPreHandle(request, response, mappedValue); + } + + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) + throws Exception + { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + // 验证码禁用 或不是表单提交 允许访问 + if (captchaEnabled == false || !"post".equals(httpServletRequest.getMethod().toLowerCase())) + { + return true; + } + return validateResponse(httpServletRequest, httpServletRequest.getParameter(ShiroConstants.CURRENT_VALIDATECODE)); + } + + public boolean validateResponse(HttpServletRequest request, String validateCode) + { + Object obj = ShiroUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); + String code = String.valueOf(obj != null ? obj : ""); + // 验证码清除,防止多次使用。 + request.getSession().removeAttribute(Constants.KAPTCHA_SESSION_KEY); + if (StringUtils.isEmpty(validateCode) || !validateCode.equalsIgnoreCase(code)) + { + return false; + } + return true; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception + { + request.setAttribute(ShiroConstants.CURRENT_CAPTCHA, ShiroConstants.CAPTCHA_ERROR); + return true; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/kickout/KickoutSessionFilter.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/kickout/KickoutSessionFilter.java new file mode 100644 index 0000000..982fdc3 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/kickout/KickoutSessionFilter.java @@ -0,0 +1,176 @@ +package com.playlet.framework.shiro.web.filter.kickout; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayDeque; +import java.util.Deque; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.CacheManager; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.DefaultSessionKey; +import org.apache.shiro.session.mgt.SessionManager; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.web.filter.AccessControlFilter; +import org.apache.shiro.web.util.WebUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.core.domain.AjaxResult; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.utils.ServletUtils; +import com.playlet.common.utils.ShiroUtils; + +/** + * 登录帐号控制过滤器 + * + * @author ruoyi + */ +public class KickoutSessionFilter extends AccessControlFilter +{ + private final static ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 同一个用户最大会话数 + **/ + private int maxSession = -1; + + /** + * 踢出之前登录的/之后登录的用户 默认false踢出之前登录的用户 + **/ + private Boolean kickoutAfter = false; + + /** + * 踢出后到的地址 + **/ + private String kickoutUrl; + + private SessionManager sessionManager; + private Cache> cache; + + @Override + protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) + throws Exception + { + return false; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception + { + Subject subject = getSubject(request, response); + if (!subject.isAuthenticated() && !subject.isRemembered() || maxSession == -1) + { + // 如果没有登录或用户最大会话数为-1,直接进行之后的流程 + return true; + } + try + { + Session session = subject.getSession(); + // 当前登录用户 + SysUser user = ShiroUtils.getSysUser(); + String loginName = user.getLoginName(); + Serializable sessionId = session.getId(); + + // 读取缓存用户 没有就存入 + Deque deque = cache.get(loginName); + if (deque == null) + { + // 初始化队列 + deque = new ArrayDeque(); + } + + // 如果队列里没有此sessionId,且用户没有被踢出;放入队列 + if (!deque.contains(sessionId) && session.getAttribute("kickout") == null) + { + // 将sessionId存入队列 + deque.push(sessionId); + // 将用户的sessionId队列缓存 + cache.put(loginName, deque); + } + + // 如果队列里的sessionId数超出最大会话数,开始踢人 + while (deque.size() > maxSession) + { + // 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户; + Serializable kickoutSessionId = kickoutAfter ? deque.removeFirst() : deque.removeLast(); + // 踢出后再更新下缓存队列 + cache.put(loginName, deque); + + try + { + // 获取被踢出的sessionId的session对象 + Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId)); + if (null != kickoutSession) + { + // 设置会话的kickout属性表示踢出了 + kickoutSession.setAttribute("kickout", true); + } + } + catch (Exception e) + { + // 面对异常,我们选择忽略 + } + } + + // 如果被踢出了,(前者或后者)直接退出,重定向到踢出后的地址 + if (session.getAttribute("kickout") != null && (Boolean) session.getAttribute("kickout") == true) + { + // 退出登录 + subject.logout(); + saveRequest(request); + return isAjaxResponse(request, response); + } + return true; + } + catch (Exception e) + { + return isAjaxResponse(request, response); + } + } + + private boolean isAjaxResponse(ServletRequest request, ServletResponse response) throws IOException + { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse res = (HttpServletResponse) response; + if (ServletUtils.isAjaxRequest(req)) + { + AjaxResult ajaxResult = AjaxResult.error("您已在别处登录,请您修改密码或重新登录"); + ServletUtils.renderString(res, objectMapper.writeValueAsString(ajaxResult)); + } + else + { + WebUtils.issueRedirect(request, response, kickoutUrl); + } + return false; + } + + public void setMaxSession(int maxSession) + { + this.maxSession = maxSession; + } + + public void setKickoutAfter(boolean kickoutAfter) + { + this.kickoutAfter = kickoutAfter; + } + + public void setKickoutUrl(String kickoutUrl) + { + this.kickoutUrl = kickoutUrl; + } + + public void setSessionManager(SessionManager sessionManager) + { + this.sessionManager = sessionManager; + } + + // 设置Cache的key的前缀 + public void setCacheManager(CacheManager cacheManager) + { + // 必须和ehcache缓存配置中的缓存name一致 + this.cache = cacheManager.getCache(ShiroConstants.SYS_USERCACHE); + } +} \ No newline at end of file diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/online/OnlineSessionFilter.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/online/OnlineSessionFilter.java new file mode 100644 index 0000000..ad2df58 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/online/OnlineSessionFilter.java @@ -0,0 +1,99 @@ +package com.playlet.framework.shiro.web.filter.online; + +import java.io.IOException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.shiro.session.Session; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.web.filter.AccessControlFilter; +import org.apache.shiro.web.util.WebUtils; +import org.springframework.beans.factory.annotation.Value; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.enums.OnlineStatus; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.framework.shiro.session.OnlineSession; +import com.playlet.framework.shiro.session.OnlineSessionDAO; + +/** + * 自定义访问控制 + * + * @author ruoyi + */ +public class OnlineSessionFilter extends AccessControlFilter +{ + /** + * 强制退出后重定向的地址 + */ + @Value("${shiro.user.loginUrl}") + private String loginUrl; + + private OnlineSessionDAO onlineSessionDAO; + + /** + * 表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,如果允许访问返回true,否则false; + */ + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) + throws Exception + { + Subject subject = getSubject(request, response); + if (subject == null || subject.getSession() == null) + { + return true; + } + Session session = onlineSessionDAO.readSession(subject.getSession().getId()); + if (session != null && session instanceof OnlineSession) + { + OnlineSession onlineSession = (OnlineSession) session; + request.setAttribute(ShiroConstants.ONLINE_SESSION, onlineSession); + // 把user对象设置进去 + boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L; + if (isGuest == true) + { + SysUser user = ShiroUtils.getSysUser(); + if (user != null) + { + onlineSession.setUserId(user.getUserId()); + onlineSession.setLoginName(user.getLoginName()); + onlineSession.setAvatar(user.getAvatar()); + onlineSession.setDeptName(user.getDept().getDeptName()); + onlineSession.markAttributeChanged(); + } + } + + if (onlineSession.getStatus() == OnlineStatus.off_line) + { + return false; + } + } + return true; + } + + /** + * 表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。 + */ + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception + { + Subject subject = getSubject(request, response); + if (subject != null) + { + subject.logout(); + } + saveRequestAndRedirectToLogin(request, response); + return false; + } + + // 跳转到登录页 + @Override + protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException + { + WebUtils.issueRedirect(request, response, loginUrl); + } + + public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) + { + this.onlineSessionDAO = onlineSessionDAO; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java new file mode 100644 index 0000000..bbc56d7 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java @@ -0,0 +1,39 @@ +package com.playlet.framework.shiro.web.filter.sync; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.shiro.web.filter.PathMatchingFilter; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.framework.shiro.session.OnlineSession; +import com.playlet.framework.shiro.session.OnlineSessionDAO; + +/** + * 同步Session数据到Db + * + * @author ruoyi + */ +public class SyncOnlineSessionFilter extends PathMatchingFilter +{ + private OnlineSessionDAO onlineSessionDAO; + + /** + * 同步会话数据到DB 一次请求最多同步一次 防止过多处理 需要放到Shiro过滤器之前 + */ + @Override + protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception + { + OnlineSession session = (OnlineSession) request.getAttribute(ShiroConstants.ONLINE_SESSION); + // 如果session stop了 也不同步 + // session停止时间,如果stopTimestamp不为null,则代表已停止 + if (session != null && session.getUserId() != null && session.getStopTimestamp() == null) + { + onlineSessionDAO.syncToDb(session); + } + return true; + } + + public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) + { + this.onlineSessionDAO = onlineSessionDAO; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/OnlineWebSessionManager.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/OnlineWebSessionManager.java new file mode 100644 index 0000000..5e25964 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/OnlineWebSessionManager.java @@ -0,0 +1,175 @@ +package com.playlet.framework.shiro.web.session; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.shiro.session.ExpiredSessionException; +import org.apache.shiro.session.InvalidSessionException; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.DefaultSessionKey; +import org.apache.shiro.session.mgt.SessionKey; +import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.bean.BeanUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.framework.shiro.session.OnlineSession; +import com.playlet.system.domain.SysUserOnline; +import com.playlet.system.service.ISysUserOnlineService; + +/** + * 主要是在此如果会话的属性修改了 就标识下其修改了 然后方便 OnlineSessionDao同步 + * + * @author ruoyi + */ +public class OnlineWebSessionManager extends DefaultWebSessionManager +{ + private static final Logger log = LoggerFactory.getLogger(OnlineWebSessionManager.class); + + @Override + public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException + { + super.setAttribute(sessionKey, attributeKey, value); + if (value != null && needMarkAttributeChanged(attributeKey)) + { + OnlineSession session = getOnlineSession(sessionKey); + session.markAttributeChanged(); + } + } + + private boolean needMarkAttributeChanged(Object attributeKey) + { + if (attributeKey == null) + { + return false; + } + String attributeKeyStr = attributeKey.toString(); + // 优化 flash属性没必要持久化 + if (attributeKeyStr.startsWith("org.springframework")) + { + return false; + } + if (attributeKeyStr.startsWith("javax.servlet")) + { + return false; + } + if (attributeKeyStr.equals(ShiroConstants.CURRENT_USERNAME)) + { + return false; + } + return true; + } + + @Override + public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException + { + Object removed = super.removeAttribute(sessionKey, attributeKey); + if (removed != null) + { + OnlineSession s = getOnlineSession(sessionKey); + s.markAttributeChanged(); + } + + return removed; + } + + public OnlineSession getOnlineSession(SessionKey sessionKey) + { + OnlineSession session = null; + Object obj = doGetSession(sessionKey); + if (StringUtils.isNotNull(obj)) + { + session = new OnlineSession(); + BeanUtils.copyBeanProp(session, obj); + } + return session; + } + + /** + * 验证session是否有效 用于删除过期session + */ + @Override + public void validateSessions() + { + if (log.isInfoEnabled()) + { + log.info("invalidation sessions..."); + } + + int invalidCount = 0; + + int timeout = (int) this.getGlobalSessionTimeout(); + if (timeout < 0) + { + // 永不过期不进行处理 + return; + } + Date expiredDate = DateUtils.addMilliseconds(new Date(), 0 - timeout); + ISysUserOnlineService userOnlineService = SpringUtils.getBean(ISysUserOnlineService.class); + List userOnlineList = userOnlineService.selectOnlineByExpired(expiredDate); + // 批量过期删除 + List needOfflineIdList = new ArrayList(); + for (SysUserOnline userOnline : userOnlineList) + { + try + { + SessionKey key = new DefaultSessionKey(userOnline.getSessionId()); + Session session = retrieveSession(key); + if (session != null) + { + throw new InvalidSessionException(); + } + } + catch (InvalidSessionException e) + { + if (log.isDebugEnabled()) + { + boolean expired = (e instanceof ExpiredSessionException); + String msg = "Invalidated session with id [" + userOnline.getSessionId() + "]" + + (expired ? " (expired)" : " (stopped)"); + log.debug(msg); + } + invalidCount++; + needOfflineIdList.add(userOnline.getSessionId()); + userOnlineService.removeUserCache(userOnline.getLoginName(), userOnline.getSessionId()); + } + + } + if (needOfflineIdList.size() > 0) + { + try + { + userOnlineService.batchDeleteOnline(needOfflineIdList); + } + catch (Exception e) + { + log.error("batch delete db session error.", e); + } + } + + if (log.isInfoEnabled()) + { + String msg = "Finished invalidation session."; + if (invalidCount > 0) + { + msg += " [" + invalidCount + "] sessions were stopped."; + } + else + { + msg += " No sessions were stopped."; + } + log.info(msg); + } + + } + + @Override + protected Collection getActiveSessions() + { + throw new UnsupportedOperationException("getActiveSessions method not supported"); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java new file mode 100644 index 0000000..32c74e4 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java @@ -0,0 +1,131 @@ +package com.playlet.framework.shiro.web.session; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.shiro.session.mgt.DefaultSessionManager; +import org.apache.shiro.session.mgt.SessionValidationScheduler; +import org.apache.shiro.session.mgt.ValidatingSessionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; +import com.playlet.common.utils.Threads; + +/** + * 自定义任务调度器完成 + * + * @author ruoyi + */ +@Component +public class SpringSessionValidationScheduler implements SessionValidationScheduler +{ + private static final Logger log = LoggerFactory.getLogger(SpringSessionValidationScheduler.class); + + public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL; + + /** + * 定时器,用于处理超时的挂起请求,也用于连接断开时的重连。 + */ + @Autowired + @Qualifier("scheduledExecutorService") + private ScheduledExecutorService executorService; + + private volatile boolean enabled = false; + + /** + * 会话验证管理器 + */ + @Autowired + @Qualifier("sessionManager") + @Lazy + private ValidatingSessionManager sessionManager; + + // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 + @Value("${shiro.session.validationInterval}") + private long sessionValidationInterval; + + @Override + public boolean isEnabled() + { + return this.enabled; + } + + /** + * Specifies how frequently (in milliseconds) this Scheduler will call the + * {@link org.apache.shiro.session.mgt.ValidatingSessionManager#validateSessions() + * ValidatingSessionManager#validateSessions()} method. + * + *

+ * Unless this method is called, the default value is {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}. + * + * @param sessionValidationInterval + */ + public void setSessionValidationInterval(long sessionValidationInterval) + { + this.sessionValidationInterval = sessionValidationInterval; + } + + /** + * Starts session validation by creating a spring PeriodicTrigger. + */ + @Override + public void enableSessionValidation() + { + + enabled = true; + + if (log.isDebugEnabled()) + { + log.debug("Scheduling session validation job using Spring Scheduler with " + + "session validation interval of [" + sessionValidationInterval + "]ms..."); + } + + try + { + executorService.scheduleAtFixedRate(new Runnable() + { + @Override + public void run() + { + if (enabled) + { + sessionManager.validateSessions(); + } + } + }, 1000, sessionValidationInterval * 60 * 1000, TimeUnit.MILLISECONDS); + + this.enabled = true; + + if (log.isDebugEnabled()) + { + log.debug("Session validation job successfully scheduled with Spring Scheduler."); + } + + } + catch (Exception e) + { + if (log.isErrorEnabled()) + { + log.error("Error starting the Spring Scheduler session validation job. Session validation may not occur.", e); + } + } + } + + @Override + public void disableSessionValidation() + { + if (log.isDebugEnabled()) + { + log.debug("Stopping Spring Scheduler session validation job..."); + } + + if (this.enabled) + { + Threads.shutdownAndAwaitTermination(executorService); + } + this.enabled = false; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java new file mode 100644 index 0000000..0893564 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java @@ -0,0 +1,241 @@ +package com.playlet.framework.web.domain; + +import java.net.UnknownHostException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import com.playlet.common.utils.Arith; +import com.playlet.common.utils.IpUtils; +import com.playlet.framework.web.domain.server.Cpu; +import com.playlet.framework.web.domain.server.Jvm; +import com.playlet.framework.web.domain.server.Mem; +import com.playlet.framework.web.domain.server.Sys; +import com.playlet.framework.web.domain.server.SysFile; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.CentralProcessor.TickType; +import oshi.hardware.GlobalMemory; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.Util; + +/** + * 服务器相关信息 + * + * @author ruoyi + */ +public class Server +{ + + private static final int OSHI_WAIT_SECOND = 1000; + + /** + * CPU相关信息 + */ + private Cpu cpu = new Cpu(); + + /** + * 內存相关信息 + */ + private Mem mem = new Mem(); + + /** + * JVM相关信息 + */ + private Jvm jvm = new Jvm(); + + /** + * 服务器相关信息 + */ + private Sys sys = new Sys(); + + /** + * 磁盘相关信息 + */ + private List sysFiles = new LinkedList(); + + public Cpu getCpu() + { + return cpu; + } + + public void setCpu(Cpu cpu) + { + this.cpu = cpu; + } + + public Mem getMem() + { + return mem; + } + + public void setMem(Mem mem) + { + this.mem = mem; + } + + public Jvm getJvm() + { + return jvm; + } + + public void setJvm(Jvm jvm) + { + this.jvm = jvm; + } + + public Sys getSys() + { + return sys; + } + + public void setSys(Sys sys) + { + this.sys = sys; + } + + public List getSysFiles() + { + return sysFiles; + } + + public void setSysFiles(List sysFiles) + { + this.sysFiles = sysFiles; + } + + public void copyTo() throws Exception + { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + + setCpuInfo(hal.getProcessor()); + + setMemInfo(hal.getMemory()); + + setSysInfo(); + + setJvmInfo(); + + setSysFiles(si.getOperatingSystem()); + } + + /** + * 设置CPU信息 + */ + private void setCpuInfo(CentralProcessor processor) + { + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(OSHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()]; + long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()]; + long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()]; + long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()]; + long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()]; + long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()]; + long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()]; + long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + cpu.setCpuNum(processor.getLogicalProcessorCount()); + cpu.setTotal(totalCpu); + cpu.setSys(cSys); + cpu.setUsed(user); + cpu.setWait(iowait); + cpu.setFree(idle); + } + + /** + * 设置内存信息 + */ + private void setMemInfo(GlobalMemory memory) + { + mem.setTotal(memory.getTotal()); + mem.setUsed(memory.getTotal() - memory.getAvailable()); + mem.setFree(memory.getAvailable()); + } + + /** + * 设置服务器信息 + */ + private void setSysInfo() + { + Properties props = System.getProperties(); + sys.setComputerName(IpUtils.getHostName()); + sys.setComputerIp(IpUtils.getHostIp()); + sys.setOsName(props.getProperty("os.name")); + sys.setOsArch(props.getProperty("os.arch")); + sys.setUserDir(props.getProperty("user.dir")); + } + + /** + * 设置Java虚拟机 + */ + private void setJvmInfo() throws UnknownHostException + { + Properties props = System.getProperties(); + jvm.setTotal(Runtime.getRuntime().totalMemory()); + jvm.setMax(Runtime.getRuntime().maxMemory()); + jvm.setFree(Runtime.getRuntime().freeMemory()); + jvm.setVersion(props.getProperty("java.version")); + jvm.setHome(props.getProperty("java.home")); + } + + /** + * 设置磁盘信息 + */ + private void setSysFiles(OperatingSystem os) + { + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) + { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + SysFile sysFile = new SysFile(); + sysFile.setDirName(fs.getMount()); + sysFile.setSysTypeName(fs.getType()); + sysFile.setTypeName(fs.getName()); + sysFile.setTotal(convertFileSize(total)); + sysFile.setFree(convertFileSize(free)); + sysFile.setUsed(convertFileSize(used)); + sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100)); + sysFiles.add(sysFile); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public String convertFileSize(long size) + { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) + { + return String.format("%.1f GB", (float) size / gb); + } + else if (size >= mb) + { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } + else if (size >= kb) + { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } + else + { + return String.format("%d B", size); + } + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java new file mode 100644 index 0000000..a93c8b4 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java @@ -0,0 +1,101 @@ +package com.playlet.framework.web.domain.server; + +import com.playlet.common.utils.Arith; + +/** + * CPU相关信息 + * + * @author ruoyi + */ +public class Cpu +{ + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + public int getCpuNum() + { + return cpuNum; + } + + public void setCpuNum(int cpuNum) + { + this.cpuNum = cpuNum; + } + + public double getTotal() + { + return Arith.round(Arith.mul(total, 100), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getSys() + { + return Arith.round(Arith.mul(sys / total, 100), 2); + } + + public void setSys(double sys) + { + this.sys = sys; + } + + public double getUsed() + { + return Arith.round(Arith.mul(used / total, 100), 2); + } + + public void setUsed(double used) + { + this.used = used; + } + + public double getWait() + { + return Arith.round(Arith.mul(wait / total, 100), 2); + } + + public void setWait(double wait) + { + this.wait = wait; + } + + public double getFree() + { + return Arith.round(Arith.mul(free / total, 100), 2); + } + + public void setFree(double free) + { + this.free = free; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java new file mode 100644 index 0000000..5e107a4 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java @@ -0,0 +1,130 @@ +package com.playlet.framework.web.domain.server; + +import java.lang.management.ManagementFactory; +import com.playlet.common.utils.Arith; +import com.playlet.common.utils.DateUtils; + +/** + * JVM相关信息 + * + * @author ruoyi + */ +public class Jvm +{ + /** + * 当前JVM占用的内存总数(M) + */ + private double total; + + /** + * JVM最大可用内存总数(M) + */ + private double max; + + /** + * JVM空闲内存(M) + */ + private double free; + + /** + * JDK版本 + */ + private String version; + + /** + * JDK路径 + */ + private String home; + + public double getTotal() + { + return Arith.div(total, (1024 * 1024), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getMax() + { + return Arith.div(max, (1024 * 1024), 2); + } + + public void setMax(double max) + { + this.max = max; + } + + public double getFree() + { + return Arith.div(free, (1024 * 1024), 2); + } + + public void setFree(double free) + { + this.free = free; + } + + public double getUsed() + { + return Arith.div(total - free, (1024 * 1024), 2); + } + + public double getUsage() + { + return Arith.mul(Arith.div(total - free, total, 4), 100); + } + + /** + * 获取JDK名称 + */ + public String getName() + { + return ManagementFactory.getRuntimeMXBean().getVmName(); + } + + public String getVersion() + { + return version; + } + + public void setVersion(String version) + { + this.version = version; + } + + public String getHome() + { + return home; + } + + public void setHome(String home) + { + this.home = home; + } + + /** + * JDK启动时间 + */ + public String getStartTime() + { + return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate()); + } + + /** + * JDK运行时间 + */ + public String getRunTime() + { + return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate()); + } + + /** + * 运行参数 + */ + public String getInputArgs() + { + return ManagementFactory.getRuntimeMXBean().getInputArguments().toString(); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java new file mode 100644 index 0000000..cd20f94 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java @@ -0,0 +1,61 @@ +package com.playlet.framework.web.domain.server; + +import com.playlet.common.utils.Arith; + +/** + * 內存相关信息 + * + * @author ruoyi + */ +public class Mem +{ + /** + * 内存总量 + */ + private double total; + + /** + * 已用内存 + */ + private double used; + + /** + * 剩余内存 + */ + private double free; + + public double getTotal() + { + return Arith.div(total, (1024 * 1024 * 1024), 2); + } + + public void setTotal(long total) + { + this.total = total; + } + + public double getUsed() + { + return Arith.div(used, (1024 * 1024 * 1024), 2); + } + + public void setUsed(long used) + { + this.used = used; + } + + public double getFree() + { + return Arith.div(free, (1024 * 1024 * 1024), 2); + } + + public void setFree(long free) + { + this.free = free; + } + + public double getUsage() + { + return Arith.mul(Arith.div(used, total, 4), 100); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java new file mode 100644 index 0000000..cc0ef90 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java @@ -0,0 +1,84 @@ +package com.playlet.framework.web.domain.server; + +/** + * 系统相关信息 + * + * @author ruoyi + */ +public class Sys +{ + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器Ip + */ + private String computerIp; + + /** + * 项目路径 + */ + private String userDir; + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; + + public String getComputerName() + { + return computerName; + } + + public void setComputerName(String computerName) + { + this.computerName = computerName; + } + + public String getComputerIp() + { + return computerIp; + } + + public void setComputerIp(String computerIp) + { + this.computerIp = computerIp; + } + + public String getUserDir() + { + return userDir; + } + + public void setUserDir(String userDir) + { + this.userDir = userDir; + } + + public String getOsName() + { + return osName; + } + + public void setOsName(String osName) + { + this.osName = osName; + } + + public String getOsArch() + { + return osArch; + } + + public void setOsArch(String osArch) + { + this.osArch = osArch; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java new file mode 100644 index 0000000..ecf007b --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java @@ -0,0 +1,114 @@ +package com.playlet.framework.web.domain.server; + +/** + * 系统文件相关信息 + * + * @author ruoyi + */ +public class SysFile +{ + /** + * 盘符路径 + */ + private String dirName; + + /** + * 盘符类型 + */ + private String sysTypeName; + + /** + * 文件类型 + */ + private String typeName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private double usage; + + public String getDirName() + { + return dirName; + } + + public void setDirName(String dirName) + { + this.dirName = dirName; + } + + public String getSysTypeName() + { + return sysTypeName; + } + + public void setSysTypeName(String sysTypeName) + { + this.sysTypeName = sysTypeName; + } + + public String getTypeName() + { + return typeName; + } + + public void setTypeName(String typeName) + { + this.typeName = typeName; + } + + public String getTotal() + { + return total; + } + + public void setTotal(String total) + { + this.total = total; + } + + public String getFree() + { + return free; + } + + public void setFree(String free) + { + this.free = free; + } + + public String getUsed() + { + return used; + } + + public void setUsed(String used) + { + this.used = used; + } + + public double getUsage() + { + return usage; + } + + public void setUsage(double usage) + { + this.usage = usage; + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java b/playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..32b5d78 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java @@ -0,0 +1,141 @@ +package com.playlet.framework.web.exception; + +import javax.servlet.http.HttpServletRequest; +import org.apache.shiro.authz.AuthorizationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MissingPathVariableException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.ModelAndView; +import com.playlet.common.core.domain.AjaxResult; +import com.playlet.common.exception.DemoModeException; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.ServletUtils; +import com.playlet.common.utils.security.PermissionUtils; + +/** + * 全局异常处理器 + * + * @author ruoyi + */ +@RestControllerAdvice +public class GlobalExceptionHandler +{ + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + /** + * 权限校验异常(ajax请求返回json,redirect请求跳转页面) + */ + @ExceptionHandler(AuthorizationException.class) + public Object handleAuthorizationException(AuthorizationException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage()); + if (ServletUtils.isAjaxRequest(request)) + { + return AjaxResult.error(PermissionUtils.getMsg(e.getMessage())); + } + else + { + return new ModelAndView("error/unauth"); + } + } + + /** + * 请求方式不支持 + */ + @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(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(ServiceException.class) + public Object handleServiceException(ServiceException e, HttpServletRequest request) + { + log.error(e.getMessage(), e); + if (ServletUtils.isAjaxRequest(request)) + { + return AjaxResult.error(e.getMessage()); + } + else + { + return new ModelAndView("error/service", "errorMessage", e.getMessage()); + } + } + + /** + * 请求路径中缺少必需的路径变量 + */ + @ExceptionHandler(MissingPathVariableException.class) + public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName())); + } + + /** + * 请求参数类型不匹配 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, + HttpServletRequest request) + { + String requestURI = request.getRequestURI(); + log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e); + return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue())); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public AjaxResult handleBindException(BindException e) + { + log.error(e.getMessage(), e); + String message = e.getAllErrors().get(0).getDefaultMessage(); + return AjaxResult.error(message); + } + + /** + * 演示模式异常 + */ + @ExceptionHandler(DemoModeException.class) + public AjaxResult handleDemoModeException(DemoModeException e) + { + return AjaxResult.error("演示模式,不允许操作"); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java new file mode 100644 index 0000000..983e392 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java @@ -0,0 +1,83 @@ +package com.playlet.framework.web.service; + +import java.util.Set; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.stereotype.Service; +import com.playlet.common.constant.Constants; +import com.playlet.common.utils.CacheUtils; + +/** + * 缓存操作处理 + * + * @author ruoyi + */ +@Service +public class CacheService +{ + /** + * 获取所有缓存名称 + * + * @return 缓存列表 + */ + public String[] getCacheNames() + { + String[] cacheNames = CacheUtils.getCacheNames(); + return ArrayUtils.removeElement(cacheNames, Constants.SYS_AUTH_CACHE); + } + + /** + * 根据缓存名称获取所有键名 + * + * @param cacheName 缓存名称 + * @return 键名列表 + */ + public Set getCacheKeys(String cacheName) + { + return CacheUtils.getCache(cacheName).keys(); + } + + /** + * 根据缓存名称和键名获取内容值 + * + * @param cacheName 缓存名称 + * @param cacheKey 键名 + * @return 键值 + */ + public Object getCacheValue(String cacheName, String cacheKey) + { + return CacheUtils.get(cacheName, cacheKey); + } + + /** + * 根据名称删除缓存信息 + * + * @param cacheName 缓存名称 + */ + public void clearCacheName(String cacheName) + { + CacheUtils.removeAll(cacheName); + } + + /** + * 根据名称和键名删除缓存信息 + * + * @param cacheName 缓存名称 + * @param cacheKey 键名 + */ + public void clearCacheKey(String cacheName, String cacheKey) + { + CacheUtils.remove(cacheName, cacheKey); + } + + /** + * 清理所有缓存 + */ + public void clearAll() + { + String[] cacheNames = getCacheNames(); + for (String cacheName : cacheNames) + { + CacheUtils.removeAll(cacheName); + } + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java new file mode 100644 index 0000000..340ff64 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java @@ -0,0 +1,28 @@ +package com.playlet.framework.web.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.system.service.ISysConfigService; + +/** + * RuoYi首创 html调用 thymeleaf 实现参数管理 + * + * @author ruoyi + */ +@Service("config") +public class ConfigService +{ + @Autowired + private ISysConfigService configService; + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + public String getKey(String configKey) + { + return configService.selectConfigByKey(configKey); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java new file mode 100644 index 0000000..8e36188 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java @@ -0,0 +1,46 @@ +package com.playlet.framework.web.service; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.domain.entity.SysDictData; +import com.playlet.system.service.ISysDictDataService; +import com.playlet.system.service.ISysDictTypeService; + +/** + * RuoYi首创 html调用 thymeleaf 实现字典读取 + * + * @author ruoyi + */ +@Service("dict") +public class DictService +{ + @Autowired + private ISysDictTypeService dictTypeService; + + @Autowired + private ISysDictDataService dictDataService; + + /** + * 根据字典类型查询字典数据信息 + * + * @param dictType 字典类型 + * @return 参数键值 + */ + public List getType(String dictType) + { + return dictTypeService.selectDictDataByType(dictType); + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + public String getLabel(String dictType, String dictValue) + { + return dictDataService.selectDictLabel(dictType, dictValue); + } +} diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java new file mode 100644 index 0000000..2689d14 --- /dev/null +++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java @@ -0,0 +1,262 @@ +package com.playlet.framework.web.service; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import com.playlet.common.utils.StringUtils; + +/** + * RuoYi首创 js调用 thymeleaf 实现按钮权限可见性 + * + * @author ruoyi + */ +@Service("permission") +public class PermissionService +{ + private static final Logger log = LoggerFactory.getLogger(PermissionService.class); + + /** 没有权限,hidden用于前端隐藏按钮 */ + public static final String NOACCESS = "hidden"; + + private static final String ROLE_DELIMETER = ","; + + private static final String PERMISSION_DELIMETER = ","; + + /** + * 验证用户是否具备某权限,无权限返回hidden用于前端隐藏(如需返回Boolean使用isPermitted) + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public String hasPermi(String permission) + { + return isPermitted(permission) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否不具备某权限,与 hasPermi逻辑相反。无权限返回hidden用于前端隐藏(如需返回Boolean使用isLacksPermitted) + * + * @param permission 权限字符串 + * @return 用户是否不具备某权限 + */ + public String lacksPermi(String permission) + { + return isLacksPermitted(permission) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否具有以下任意一个权限,无权限返回hidden用于隐藏(如需返回Boolean使用hasAnyPermissions) + * + * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public String hasAnyPermi(String permissions) + { + return hasAnyPermissions(permissions, PERMISSION_DELIMETER) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否具备某角色,无权限返回hidden用于隐藏(如需返回Boolean使用isRole) + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ + public String hasRole(String role) + { + return isRole(role) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否不具备某角色,与hasRole逻辑相反。无权限返回hidden用于隐藏(如需返回Boolean使用isLacksRole) + * + * @param role 角色字符串 + * @return 用户是否不具备某角色 + */ + public String lacksRole(String role) + { + return isLacksRole(role) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否具有以下任意一个角色,无权限返回hidden用于隐藏(如需返回Boolean使用isAnyRoles) + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + public String hasAnyRoles(String roles) + { + return isAnyRoles(roles, ROLE_DELIMETER) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否认证通过或已记住的用户。 + * + * @return 用户是否认证通过或已记住的用户 + */ + public boolean isUser() + { + Subject subject = SecurityUtils.getSubject(); + return subject != null && subject.getPrincipal() != null; + } + + /** + * 判断用户是否拥有某个权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public boolean isPermitted(String permission) + { + return SecurityUtils.getSubject().isPermitted(permission); + } + + /** + * 判断用户是否不具备某权限,与 isPermitted逻辑相反。 + * + * @param permission 权限名称 + * @return 用户是否不具备某权限 + */ + public boolean isLacksPermitted(String permission) + { + return isPermitted(permission) != true; + } + + /** + * 验证用户是否具有以下任意一个权限。 + * + * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermissions(String permissions) + { + return hasAnyPermissions(permissions, PERMISSION_DELIMETER); + } + + /** + * 验证用户是否具有以下任意一个权限。 + * + * @param permissions 以 delimeter 为分隔符的权限列表 + * @param delimeter 权限列表分隔符 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermissions(String permissions, String delimeter) + { + Subject subject = SecurityUtils.getSubject(); + + if (subject != null) + { + if (delimeter == null || delimeter.length() == 0) + { + delimeter = PERMISSION_DELIMETER; + } + + for (String permission : permissions.split(delimeter)) + { + if (permission != null && subject.isPermitted(permission.trim()) == true) + { + return true; + } + } + } + + return false; + } + + /** + * 判断用户是否拥有某个角色 + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ + public boolean isRole(String role) + { + return SecurityUtils.getSubject().hasRole(role); + } + + /** + * 验证用户是否不具备某角色,与 isRole逻辑相反。 + * + * @param role 角色名称 + * @return 用户是否不具备某角色 + */ + public boolean isLacksRole(String role) + { + return isRole(role) != true; + } + + /** + * 验证用户是否具有以下任意一个角色。 + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + public boolean isAnyRoles(String roles) + { + return isAnyRoles(roles, ROLE_DELIMETER); + } + + /** + * 验证用户是否具有以下任意一个角色。 + * + * @param roles 以 delimeter 为分隔符的角色列表 + * @param delimeter 角色列表分隔符 + * @return 用户是否具有以下任意一个角色 + */ + public boolean isAnyRoles(String roles, String delimeter) + { + Subject subject = SecurityUtils.getSubject(); + if (subject != null) + { + if (delimeter == null || delimeter.length() == 0) + { + delimeter = ROLE_DELIMETER; + } + + for (String role : roles.split(delimeter)) + { + if (subject.hasRole(role.trim()) == true) + { + return true; + } + } + } + + return false; + } + + /** + * 返回用户属性值 + * + * @param property 属性名称 + * @return 用户属性值 + */ + public Object getPrincipalProperty(String property) + { + Subject subject = SecurityUtils.getSubject(); + if (subject != null) + { + Object principal = subject.getPrincipal(); + try + { + BeanInfo bi = Introspector.getBeanInfo(principal.getClass()); + for (PropertyDescriptor pd : bi.getPropertyDescriptors()) + { + if (pd.getName().equals(property) == true) + { + return pd.getReadMethod().invoke(principal, (Object[]) null); + } + } + } + catch (Exception e) + { + log.error("Error reading property [{}] from principal of type [{}]", property, principal.getClass().getName()); + } + } + return null; + } +} diff --git a/playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java b/playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java new file mode 100644 index 0000000..d27dfb5 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java @@ -0,0 +1,73 @@ +package com.playlet.generator.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * 读取代码生成相关配置 + * + * @author ruoyi + */ +@Component +@ConfigurationProperties(prefix = "gen") +@PropertySource(value = { "classpath:generator.yml" }) +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; + } + + @Value("${author}") + public void setAuthor(String author) + { + GenConfig.author = author; + } + + public static String getPackageName() + { + return packageName; + } + + @Value("${packageName}") + public void setPackageName(String packageName) + { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() + { + return autoRemovePre; + } + + @Value("${autoRemovePre}") + public void setAutoRemovePre(boolean autoRemovePre) + { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() + { + return tablePrefix; + } + + @Value("${tablePrefix}") + public void setTablePrefix(String tablePrefix) + { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java b/playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java new file mode 100644 index 0000000..4819f79 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java @@ -0,0 +1,304 @@ +package com.playlet.generator.controller; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +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.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.fastjson.JSON; +import com.playlet.common.annotation.Log; +import com.playlet.common.core.controller.BaseController; +import com.playlet.common.core.domain.AjaxResult; +import com.playlet.common.core.domain.CxSelect; +import com.playlet.common.core.page.TableDataInfo; +import com.playlet.common.core.text.Convert; +import com.playlet.common.enums.BusinessType; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.security.PermissionUtils; +import com.playlet.common.utils.sql.SqlUtil; +import com.playlet.generator.domain.GenTable; +import com.playlet.generator.domain.GenTableColumn; +import com.playlet.generator.service.IGenTableColumnService; +import com.playlet.generator.service.IGenTableService; + +/** + * 代码生成 操作处理 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/tool/gen") +public class GenController extends BaseController +{ + private String prefix = "tool/gen"; + + @Autowired + private IGenTableService genTableService; + + @Autowired + private IGenTableColumnService genTableColumnService; + + @RequiresPermissions("tool:gen:view") + @GetMapping() + public String gen() + { + return prefix + "/gen"; + } + + /** + * 查询代码生成列表 + */ + @RequiresPermissions("tool:gen:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo genList(GenTable genTable) + { + startPage(); + List list = genTableService.selectGenTableList(genTable); + return getDataTable(list); + } + + /** + * 查询数据库列表 + */ + @RequiresPermissions("tool:gen:list") + @PostMapping("/db/list") + @ResponseBody + public TableDataInfo dataList(GenTable genTable) + { + startPage(); + List list = genTableService.selectDbTableList(genTable); + return getDataTable(list); + } + + /** + * 查询数据表字段列表 + */ + @RequiresPermissions("tool:gen:list") + @PostMapping("/column/list") + @ResponseBody + public TableDataInfo columnList(GenTableColumn genTableColumn) + { + TableDataInfo dataInfo = new TableDataInfo(); + List list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn); + dataInfo.setRows(list); + dataInfo.setTotal(list.size()); + return dataInfo; + } + + /** + * 导入表结构 + */ + @RequiresPermissions("tool:gen:list") + @GetMapping("/importTable") + public String importTable() + { + return prefix + "/importTable"; + } + + /** + * 创建表结构 + */ + @GetMapping("/createTable") + public String createTable() + { + return prefix + "/createTable"; + } + + /** + * 导入表结构(保存) + */ + @RequiresPermissions("tool:gen:list") + @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + @ResponseBody + public AjaxResult importTableSave(String tables) + { + String[] tableNames = Convert.toStrArray(tables); + // 查询表信息 + List tableList = genTableService.selectDbTableListByNames(tableNames); + String operName = Convert.toStr(PermissionUtils.getPrincipalProperty("loginName")); + genTableService.importGenTable(tableList, operName); + return AjaxResult.success(); + } + + /** + * 修改代码生成业务 + */ + @RequiresPermissions("tool:gen:edit") + @GetMapping("/edit/{tableId}") + public String edit(@PathVariable("tableId") Long tableId, ModelMap mmap) + { + GenTable table = genTableService.selectGenTableById(tableId); + List genTables = genTableService.selectGenTableAll(); + List cxSelect = new ArrayList(); + for (GenTable genTable : genTables) + { + if (!StringUtils.equals(table.getTableName(), genTable.getTableName())) + { + CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + ':' + genTable.getTableComment()); + List cxColumns = new ArrayList(); + for (GenTableColumn tableColumn : genTable.getColumns()) + { + cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + ':' + tableColumn.getColumnComment())); + } + cxTable.setS(cxColumns); + cxSelect.add(cxTable); + } + } + mmap.put("table", table); + mmap.put("data", JSON.toJSON(cxSelect)); + return prefix + "/edit"; + } + + /** + * 修改保存代码生成业务 + */ + @RequiresPermissions("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(@Validated GenTable genTable) + { + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + return AjaxResult.success(); + } + + @RequiresPermissions("tool:gen:remove") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @PostMapping("/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + genTableService.deleteGenTableByIds(ids); + return AjaxResult.success(); + } + + @RequiresRoles("admin") + @Log(title = "创建表", businessType = BusinessType.OTHER) + @PostMapping("/createTable") + @ResponseBody + public AjaxResult create(String sql) + { + try + { + SqlUtil.filterKeyword(sql); + List sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql); + List tableNames = new ArrayList<>(); + for (SQLStatement sqlStatement : sqlStatements) + { + if (sqlStatement instanceof MySqlCreateTableStatement) + { + MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement; + if (genTableService.createTable(createTableStatement.toString())) + { + String tableName = createTableStatement.getTableName().replaceAll("`", ""); + tableNames.add(tableName); + } + } + } + List tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()])); + String operName = Convert.toStr(PermissionUtils.getPrincipalProperty("loginName")); + genTableService.importGenTable(tableList, operName); + return AjaxResult.success(); + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + return AjaxResult.error("创建表结构异常"); + } + } + + /** + * 预览代码 + */ + @RequiresPermissions("tool:gen:preview") + @GetMapping("/preview/{tableId}") + @ResponseBody + public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException + { + Map dataMap = genTableService.previewCode(tableId); + return AjaxResult.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}") + @ResponseBody + public AjaxResult genCode(@PathVariable("tableName") String tableName) + { + genTableService.generatorCode(tableName); + return AjaxResult.success(); + } + + /** + * 同步数据库 + */ + @RequiresPermissions("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @GetMapping("/synchDb/{tableName}") + @ResponseBody + public AjaxResult synchDb(@PathVariable("tableName") String tableName) + { + genTableService.synchDb(tableName); + return AjaxResult.success(); + } + + /** + * 批量生成代码 + */ + @RequiresPermissions("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/batchGenCode") + @ResponseBody + 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()); + } +} \ No newline at end of file diff --git a/playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java new file mode 100644 index 0000000..328ad23 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java @@ -0,0 +1,372 @@ +package com.playlet.generator.domain; + +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import org.apache.commons.lang3.ArrayUtils; +import com.playlet.common.constant.GenConstants; +import com.playlet.common.core.domain.BaseEntity; +import com.playlet.common.utils.StringUtils; + +/** + * 业务表 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 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 getColumns() + { + return columns; + } + + public void setColumns(List 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); + } +} \ No newline at end of file diff --git a/playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java new file mode 100644 index 0000000..ef0a1a2 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java @@ -0,0 +1,373 @@ +package com.playlet.generator.domain; + +import javax.validation.constraints.NotBlank; +import com.playlet.common.core.domain.BaseEntity; +import com.playlet.common.utils.StringUtils; + +/** + * 代码生成业务字段表 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日期控件、upload上传控件、summernote富文本控件) */ + 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/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java new file mode 100644 index 0000000..31d8ad5 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java @@ -0,0 +1,60 @@ +package com.playlet.generator.mapper; + +import java.util.List; +import com.playlet.generator.domain.GenTableColumn; + +/** + * 业务字段 数据层 + * + * @author ruoyi + */ +public interface GenTableColumnMapper +{ + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + public List selectDbTableColumnsByName(String tableName); + + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段 + * + * @param genTableColumns 列数据 + * @return 结果 + */ + public int deleteGenTableColumns(List genTableColumns); + + /** + * 批量删除业务字段 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(Long[] ids); +} diff --git a/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java new file mode 100644 index 0000000..d32ed22 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java @@ -0,0 +1,91 @@ +package com.playlet.generator.mapper; + +import java.util.List; +import com.playlet.generator.domain.GenTable; + +/** + * 业务 数据层 + * + * @author ruoyi + */ +public interface GenTableMapper +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List 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); + + /** + * 创建表 + * + * @param sql + * @return 结果 + */ + public int createTable(String sql); +} \ No newline at end of file diff --git a/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java new file mode 100644 index 0000000..74159fa --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java @@ -0,0 +1,44 @@ +package com.playlet.generator.service; + +import java.util.List; +import com.playlet.generator.domain.GenTableColumn; + +/** + * 业务字段 服务层 + * + * @author ruoyi + */ +public interface IGenTableColumnService +{ + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn); + + /** + * 新增业务字段 + * + * @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/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java new file mode 100644 index 0000000..e33b029 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java @@ -0,0 +1,129 @@ +package com.playlet.generator.service; + +import java.util.List; +import java.util.Map; +import com.playlet.generator.domain.GenTable; + +/** + * 业务 服务层 + * + * @author ruoyi + */ +public interface IGenTableService +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public void updateGenTable(GenTable genTable); + + /** + * 删除业务信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public void deleteGenTableByIds(String ids); + + /** + * 创建表 + * + * @param sql 创建表语句 + * @return 结果 + */ + public boolean createTable(String sql); + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + * @param operName 操作人员 + */ + public void importGenTable(List tableList, String operName); + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + public Map previewCode(Long tableId); + + /** + * 生成代码(下载方式) + * + * @param tableName 表名称 + * @return 数据 + */ + public byte[] downloadCode(String tableName); + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + 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/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java new file mode 100644 index 0000000..e926aa9 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java @@ -0,0 +1,69 @@ +package com.playlet.generator.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.text.Convert; +import com.playlet.generator.domain.GenTableColumn; +import com.playlet.generator.mapper.GenTableColumnMapper; +import com.playlet.generator.service.IGenTableColumnService; + +/** + * 业务字段 服务层实现 + * + * @author ruoyi + */ +@Service +public class GenTableColumnServiceImpl implements IGenTableColumnService +{ + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + @Override + public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn) + { + return genTableColumnMapper.selectGenTableColumnListByTableId(genTableColumn); + } + + /** + * 新增业务字段 + * + * @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/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java new file mode 100644 index 0000000..94e6eb1 --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java @@ -0,0 +1,534 @@ +package com.playlet.generator.service.impl; + +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.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.playlet.common.constant.Constants; +import com.playlet.common.constant.GenConstants; +import com.playlet.common.core.text.CharsetKit; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.StringUtils; +import com.playlet.generator.domain.GenTable; +import com.playlet.generator.domain.GenTableColumn; +import com.playlet.generator.mapper.GenTableColumnMapper; +import com.playlet.generator.mapper.GenTableMapper; +import com.playlet.generator.service.IGenTableService; +import com.playlet.generator.util.GenUtils; +import com.playlet.generator.util.VelocityInitializer; +import com.playlet.generator.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 selectGenTableList(GenTable genTable) + { + return genTableMapper.selectGenTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + @Override + public List selectDbTableList(GenTable genTable) + { + return genTableMapper.selectDbTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + @Override + public List selectDbTableListByNames(String[] tableNames) + { + return genTableMapper.selectDbTableListByNames(tableNames); + } + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() + { + return genTableMapper.selectGenTableAll(); + } + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + @Override + @Transactional + public void updateGenTable(GenTable genTable) + { + String options = JSON.toJSONString(genTable.getParams()); + genTable.setOptions(options); + int row = genTableMapper.updateGenTable(genTable); + if (row > 0) + { + for (GenTableColumn genTableColumn : genTable.getColumns()) + { + genTableColumnMapper.updateGenTableColumn(genTableColumn); + } + } + } + + /** + * 删除业务对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + @Transactional + public void deleteGenTableByIds(String ids) + { + genTableMapper.deleteGenTableByIds(Convert.toLongArray(ids)); + genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids)); + } + + /** + * 创建表 + * + * @param sql 创建表语句 + * @return 结果 + */ + @Override + public boolean createTable(String sql) + { + return genTableMapper.createTable(sql) == 0; + } + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + * @param operName 操作人员 + */ + @Override + @Transactional + public void importGenTable(List tableList, String operName) + { + try + { + for (GenTable table : tableList) + { + String tableName = table.getTableName(); + GenUtils.initTable(table, operName); + int row = genTableMapper.insertGenTable(table); + if (row > 0) + { + // 保存列信息 + List 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 previewCode(Long tableId) + { + Map dataMap = new LinkedHashMap<>(); + // 查询表信息 + GenTable table = genTableMapper.selectGenTableById(tableId); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List 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 templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) + { + if (!StringUtils.contains(template, "sql.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 + public void synchDb(String tableName) + { + GenTable table = genTableMapper.selectGenTableByName(tableName); + List tableColumns = table.getColumns(); + Map tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity())); + + List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + if (StringUtils.isEmpty(dbTableColumns)) + { + throw new ServiceException("同步数据失败,原表结构不存在"); + } + List 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 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 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 = JSONObject.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 = JSONObject.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); + } +} \ No newline at end of file diff --git a/playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java b/playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java new file mode 100644 index 0000000..6c39b2b --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java @@ -0,0 +1,252 @@ +package com.playlet.generator.util; + +import java.util.Arrays; +import org.apache.commons.lang3.RegExUtils; +import com.playlet.common.constant.GenConstants; +import com.playlet.common.utils.StringUtils; +import com.playlet.generator.config.GenConfig; +import com.playlet.generator.domain.GenTable; +import com.playlet.generator.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, "file")) + { + column.setHtmlType(GenConstants.HTML_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) + { + column.setHtmlType(GenConstants.HTML_SUMMERNOTE); + } + } + + /** + * 校验数组是否包含指定值 + * + * @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/playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java new file mode 100644 index 0000000..e5d743b --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java @@ -0,0 +1,34 @@ +package com.playlet.generator.util; + +import java.util.Properties; +import org.apache.velocity.app.Velocity; +import com.playlet.common.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/playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java new file mode 100644 index 0000000..8ea94ff --- /dev/null +++ b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java @@ -0,0 +1,384 @@ +package com.playlet.generator.util; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import org.apache.velocity.VelocityContext; +import com.alibaba.fastjson.JSONObject; +import com.playlet.common.constant.GenConstants; +import com.playlet.common.utils.DateUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.generator.config.GenConfig; +import com.playlet.generator.domain.GenTable; +import com.playlet.generator.domain.GenTableColumn; + +public class VelocityUtils +{ + /** 项目空间路径 */ + private static final String PROJECT_PATH = "main/java"; + + /** mybatis空间路径 */ + private static final String MYBATIS_PATH = "main/resources/mapper"; + + /** html空间路径 */ + private static final String TEMPLATES_PATH = "main/resources/templates"; + + /** 默认上级菜单,系统工具 */ + 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", 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); + 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 = JSONObject.parseObject(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSONObject.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 getTemplateList(String tplCategory) + { + List templates = new ArrayList(); + 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"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) + { + templates.add("vm/html/list.html.vm"); + } + else if (GenConstants.TPL_TREE.equals(tplCategory)) + { + templates.add("vm/html/tree.html.vm"); + templates.add("vm/html/list-tree.html.vm"); + } + else if (GenConstants.TPL_SUB.equals(tplCategory)) + { + templates.add("vm/html/list.html.vm"); + templates.add("vm/java/sub-domain.java.vm"); + } + templates.add("vm/html/add.html.vm"); + templates.add("vm/html/edit.html.vm"); + templates.add("vm/sql/sql.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 htmlPath = TEMPLATES_PATH + "/" + moduleName + "/" + businessName; + + 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("list.html.vm")) + { + fileName = StringUtils.format("{}/{}.html", htmlPath, businessName); + } + else if (template.contains("list-tree.html.vm")) + { + fileName = StringUtils.format("{}/{}.html", htmlPath, businessName); + } + else if (template.contains("tree.html.vm")) + { + fileName = StringUtils.format("{}/tree.html", htmlPath); + } + else if (template.contains("add.html.vm")) + { + fileName = StringUtils.format("{}/add.html", htmlPath); + } + else if (template.contains("edit.html.vm")) + { + fileName = StringUtils.format("{}/edit.html", htmlPath); + } + else if (template.contains("sql.vm")) + { + fileName = businessName + "Menu.sql"; + } + return fileName; + } + + /** + * 获取项目文件路径 + * + * @return 路径 + */ + public static String getProjectPath() + { + String packageName = GenConfig.getPackageName(); + StringBuffer projectPath = new StringBuffer(); + projectPath.append("main/java/"); + projectPath.append(packageName.replace(".", "/")); + projectPath.append("/"); + return projectPath.toString(); + } + + /** + * 获取包前缀 + * + * @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 getImportList(GenTable genTable) + { + List columns = genTable.getColumns(); + GenTable subGenTable = genTable.getSubTable(); + HashSet importList = new HashSet(); + 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 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 = JSONObject.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/playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java b/playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java new file mode 100644 index 0000000..260d56b --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java @@ -0,0 +1,57 @@ +//package com.playlet.quartz.config; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.scheduling.quartz.SchedulerFactoryBean; +//import javax.sql.DataSource; +//import java.util.Properties; +// +///** +// * 定时任务配置(单机部署建议默认走内存,如需集群需要创建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", "10"); +// 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/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java new file mode 100644 index 0000000..8036e5b --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java @@ -0,0 +1,247 @@ +package com.playlet.quartz.controller; + +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import com.playlet.common.annotation.Log; +import com.playlet.common.constant.Constants; +import com.playlet.common.core.controller.BaseController; +import com.playlet.common.core.domain.AjaxResult; +import com.playlet.common.core.page.TableDataInfo; +import com.playlet.common.enums.BusinessType; +import com.playlet.common.exception.job.TaskException; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.poi.ExcelUtil; +import com.playlet.quartz.domain.SysJob; +import com.playlet.quartz.service.ISysJobService; +import com.playlet.quartz.util.CronUtils; +import com.playlet.quartz.util.ScheduleUtils; + +/** + * 调度任务信息操作处理 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/monitor/job") +public class SysJobController extends BaseController +{ + private String prefix = "monitor/job"; + + @Autowired + private ISysJobService jobService; + + @RequiresPermissions("monitor:job:view") + @GetMapping() + public String job() + { + return prefix + "/job"; + } + + @RequiresPermissions("monitor:job:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(SysJob job) + { + startPage(); + List list = jobService.selectJobList(job); + return getDataTable(list); + } + + @Log(title = "定时任务", businessType = BusinessType.EXPORT) + @RequiresPermissions("monitor:job:export") + @PostMapping("/export") + @ResponseBody + public AjaxResult export(SysJob job) + { + List list = jobService.selectJobList(job); + ExcelUtil util = new ExcelUtil(SysJob.class); + return util.exportExcel(list, "定时任务"); + } + + @Log(title = "定时任务", businessType = BusinessType.DELETE) + @RequiresPermissions("monitor:job:remove") + @PostMapping("/remove") + @ResponseBody + public AjaxResult remove(String ids) throws SchedulerException + { + jobService.deleteJobByIds(ids); + return success(); + } + + @RequiresPermissions("monitor:job:detail") + @GetMapping("/detail/{jobId}") + public String detail(@PathVariable("jobId") Long jobId, ModelMap mmap) + { + mmap.put("name", "job"); + mmap.put("job", jobService.selectJobById(jobId)); + return prefix + "/detail"; + } + + /** + * 任务调度状态修改 + */ + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @RequiresPermissions("monitor:job:changeStatus") + @PostMapping("/changeStatus") + @ResponseBody + public AjaxResult changeStatus(SysJob job) throws SchedulerException + { + SysJob newJob = jobService.selectJobById(job.getJobId()); + newJob.setStatus(job.getStatus()); + return toAjax(jobService.changeStatus(newJob)); + } + + /** + * 任务调度立即执行一次 + */ + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @RequiresPermissions("monitor:job:changeStatus") + @PostMapping("/run") + @ResponseBody + public AjaxResult run(SysJob job) throws SchedulerException + { + boolean result = jobService.run(job); + return result ? success() : error("任务不存在或已过期!"); + } + + /** + * 新增调度 + */ + @GetMapping("/add") + public String add() + { + return prefix + "/add"; + } + + /** + * 新增保存调度 + */ + @Log(title = "定时任务", businessType = BusinessType.INSERT) + @RequiresPermissions("monitor:job:add") + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(@Validated 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(getLoginName()); + return toAjax(jobService.insertJob(job)); + } + + /** + * 修改调度 + */ + @RequiresPermissions("monitor:job:edit") + @GetMapping("/edit/{jobId}") + public String edit(@PathVariable("jobId") Long jobId, ModelMap mmap) + { + mmap.put("job", jobService.selectJobById(jobId)); + return prefix + "/edit"; + } + + /** + * 修改保存调度 + */ + @Log(title = "定时任务", businessType = BusinessType.UPDATE) + @RequiresPermissions("monitor:job:edit") + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(@Validated 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'调用"); + } + 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() + "'失败,目标字符串不在白名单内"); + } + return toAjax(jobService.updateJob(job)); + } + + /** + * 校验cron表达式是否有效 + */ + @PostMapping("/checkCronExpressionIsValid") + @ResponseBody + public boolean checkCronExpressionIsValid(SysJob job) + { + return jobService.checkCronExpressionIsValid(job.getCronExpression()); + } + + /** + * Cron表达式在线生成 + */ + @GetMapping("/cron") + public String cron() + { + return prefix + "/cron"; + } + + /** + * 查询cron表达式近5次的执行时间 + */ + @GetMapping("/queryCronExpression") + @ResponseBody + public AjaxResult queryCronExpression(@RequestParam(value = "cronExpression", required = false) String cronExpression) + { + if (jobService.checkCronExpressionIsValid(cronExpression)) + { + List dateList = CronUtils.getRecentTriggerTime(cronExpression); + return success(dateList); + } + else + { + return error("表达式无效"); + } + } +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java new file mode 100644 index 0000000..cce50ac --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java @@ -0,0 +1,103 @@ +package com.playlet.quartz.controller; + +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +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.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import com.playlet.common.annotation.Log; +import com.playlet.common.core.controller.BaseController; +import com.playlet.common.core.domain.AjaxResult; +import com.playlet.common.core.page.TableDataInfo; +import com.playlet.common.enums.BusinessType; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.poi.ExcelUtil; +import com.playlet.quartz.domain.SysJob; +import com.playlet.quartz.domain.SysJobLog; +import com.playlet.quartz.service.ISysJobLogService; +import com.playlet.quartz.service.ISysJobService; + +/** + * 调度日志操作处理 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/monitor/jobLog") +public class SysJobLogController extends BaseController +{ + private String prefix = "monitor/job"; + + @Autowired + private ISysJobService jobService; + + @Autowired + private ISysJobLogService jobLogService; + + @RequiresPermissions("monitor:job:view") + @GetMapping() + public String jobLog(@RequestParam(value = "jobId", required = false) Long jobId, ModelMap mmap) + { + if (StringUtils.isNotNull(jobId)) + { + SysJob job = jobService.selectJobById(jobId); + mmap.put("job", job); + } + return prefix + "/jobLog"; + } + + @RequiresPermissions("monitor:job:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(SysJobLog jobLog) + { + startPage(); + List list = jobLogService.selectJobLogList(jobLog); + return getDataTable(list); + } + + @Log(title = "调度日志", businessType = BusinessType.EXPORT) + @RequiresPermissions("monitor:job:export") + @PostMapping("/export") + @ResponseBody + public AjaxResult export(SysJobLog jobLog) + { + List list = jobLogService.selectJobLogList(jobLog); + ExcelUtil util = new ExcelUtil(SysJobLog.class); + return util.exportExcel(list, "调度日志"); + } + + @Log(title = "调度日志", businessType = BusinessType.DELETE) + @RequiresPermissions("monitor:job:remove") + @PostMapping("/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(jobLogService.deleteJobLogByIds(ids)); + } + + @RequiresPermissions("monitor:job:detail") + @GetMapping("/detail/{jobLogId}") + public String detail(@PathVariable("jobLogId") Long jobLogId, ModelMap mmap) + { + mmap.put("name", "jobLog"); + mmap.put("jobLog", jobLogService.selectJobLogById(jobLogId)); + return prefix + "/detail"; + } + + @Log(title = "调度日志", businessType = BusinessType.CLEAN) + @RequiresPermissions("monitor:job:remove") + @PostMapping("/clean") + @ResponseBody + public AjaxResult clean() + { + jobLogService.cleanJobLog(); + return success(); + } +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java new file mode 100644 index 0000000..bb5b11e --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java @@ -0,0 +1,169 @@ +package com.playlet.quartz.domain; + +import java.io.Serializable; +import java.util.Date; +import javax.validation.constraints.*; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.playlet.common.annotation.Excel; +import com.playlet.common.annotation.Excel.ColumnType; +import com.playlet.common.constant.ScheduleConstants; +import com.playlet.common.core.domain.BaseEntity; +import com.playlet.common.utils.StringUtils; +import com.playlet.quartz.util.CronUtils; + +/** + * 定时任务调度表 sys_job + * + * @author ruoyi + */ +public class SysJob extends BaseEntity implements Serializable +{ + 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 = 1000, 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; + } + + 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/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java new file mode 100644 index 0000000..5db9f06 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java @@ -0,0 +1,155 @@ +package com.playlet.quartz.domain; + +import java.util.Date; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.playlet.common.annotation.Excel; +import com.playlet.common.core.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 endTime; + + 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 getEndTime() + { + return endTime; + } + + public void setEndTime(Date endTime) + { + this.endTime = endTime; + } + + @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("endTime", getEndTime()) + .toString(); + } +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java new file mode 100644 index 0000000..6195939 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java @@ -0,0 +1,64 @@ +package com.playlet.quartz.mapper; + +import com.playlet.quartz.domain.SysJobLog; +import java.util.List; + +/** + * 调度任务日志信息 数据层 + * + * @author ruoyi + */ +public interface SysJobLogMapper +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public List selectJobLogList(SysJobLog jobLog); + + /** + * 查询所有调度任务日志 + * + * @return 调度任务日志列表 + */ + public List selectJobLogAll(); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + * @return 结果 + */ + public int insertJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteJobLogByIds(String[] ids); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java new file mode 100644 index 0000000..4ec961b --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java @@ -0,0 +1,67 @@ +package com.playlet.quartz.mapper; + +import com.playlet.quartz.domain.SysJob; +import java.util.List; + +/** + * 调度任务信息 数据层 + * + * @author ruoyi + */ +public interface SysJobMapper +{ + /** + * 查询调度任务日志集合 + * + * @param job 调度信息 + * @return 操作日志集合 + */ + public List selectJobList(SysJob job); + + /** + * 查询所有调度任务 + * + * @return 调度任务列表 + */ + public List 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/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java new file mode 100644 index 0000000..0463fa4 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java @@ -0,0 +1,56 @@ +package com.playlet.quartz.service; + +import java.util.List; +import com.playlet.quartz.domain.SysJobLog; + +/** + * 定时任务调度日志信息信息 服务层 + * + * @author ruoyi + */ +public interface ISysJobLogService +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public List selectJobLogList(SysJobLog jobLog); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + public void addJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteJobLogByIds(String ids); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java new file mode 100644 index 0000000..616ba4f --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java @@ -0,0 +1,102 @@ +package com.playlet.quartz.service; + +import java.util.List; +import org.quartz.SchedulerException; +import com.playlet.common.exception.job.TaskException; +import com.playlet.quartz.domain.SysJob; + +/** + * 定时任务调度信息信息 服务层 + * + * @author ruoyi + */ +public interface ISysJobService +{ + /** + * 获取quartz调度器的计划任务 + * + * @param job 调度信息 + * @return 调度任务集合 + */ + public List 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 ids 需要删除的数据ID + * @return 结果 + */ + public void deleteJobByIds(String ids) 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/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java new file mode 100644 index 0000000..3c3027c --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java @@ -0,0 +1,88 @@ +package com.playlet.quartz.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.text.Convert; +import com.playlet.quartz.domain.SysJobLog; +import com.playlet.quartz.mapper.SysJobLogMapper; +import com.playlet.quartz.service.ISysJobLogService; + +/** + * 定时任务调度日志信息 服务层 + * + * @author ruoyi + */ +@Service +public class SysJobLogServiceImpl implements ISysJobLogService +{ + @Autowired + private SysJobLogMapper jobLogMapper; + + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + @Override + public List 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 ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteJobLogByIds(String ids) + { + return jobLogMapper.deleteJobLogByIds(Convert.toStrArray(ids)); + } + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + */ + @Override + public int deleteJobLogById(Long jobId) + { + return jobLogMapper.deleteJobLogById(jobId); + } + + /** + * 清空任务日志 + */ + @Override + public void cleanJobLog() + { + jobLogMapper.cleanJobLog(); + } +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java new file mode 100644 index 0000000..663d04b --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java @@ -0,0 +1,263 @@ +package com.playlet.quartz.service.impl; + +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.playlet.common.constant.ScheduleConstants; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.job.TaskException; +import com.playlet.quartz.domain.SysJob; +import com.playlet.quartz.mapper.SysJobMapper; +import com.playlet.quartz.service.ISysJobService; +import com.playlet.quartz.util.CronUtils; +import com.playlet.quartz.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 jobList = jobMapper.selectJobAll(); + for (SysJob job : jobList) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + } + + /** + * 获取quartz调度器的计划任务列表 + * + * @param job 调度信息 + * @return + */ + @Override + public List 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 ids 需要删除的数据ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteJobByIds(String ids) throws SchedulerException + { + Long[] jobIds = Convert.toLongArray(ids); + 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(); + SysJob tmpObj = selectJobById(job.getJobId()); + // 参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(ScheduleConstants.TASK_PROPERTIES, tmpObj); + JobKey jobKey = ScheduleUtils.getJobKey(jobId, tmpObj.getJobGroup()); + 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/playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java b/playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java new file mode 100644 index 0000000..aea716e --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java @@ -0,0 +1,28 @@ +package com.playlet.quartz.task; + +import org.springframework.stereotype.Component; +import com.playlet.common.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/playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java new file mode 100644 index 0000000..613c7c0 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java @@ -0,0 +1,107 @@ +package com.playlet.quartz.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.playlet.common.constant.Constants; +import com.playlet.common.constant.ScheduleConstants; +import com.playlet.common.utils.ExceptionUtil; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.bean.BeanUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.quartz.domain.SysJob; +import com.playlet.quartz.domain.SysJobLog; +import com.playlet.quartz.service.ISysJobLogService; + +/** + * 抽象quartz调用 + * + * @author ruoyi + */ +public abstract class AbstractQuartzJob implements Job +{ + private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); + + /** + * 线程本地变量 + */ + private static ThreadLocal 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.setEndTime(new Date()); + long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime(); + sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); + if (e != null) + { + sysJobLog.setStatus(Constants.FAIL); + String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000); + sysJobLog.setExceptionInfo(errorMsg); + } + else + { + sysJobLog.setStatus(Constants.SUCCESS); + } + + // 写入数据库当中 + SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog); + } + + /** + * 执行方法,由子类重载 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + * @throws Exception 执行过程中的异常 + */ + protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception; +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java new file mode 100644 index 0000000..54365e0 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java @@ -0,0 +1,94 @@ +package com.playlet.quartz.util; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import org.quartz.CronExpression; +import org.quartz.TriggerUtils; +import org.quartz.impl.triggers.CronTriggerImpl; +import com.playlet.common.utils.DateUtils; + +/** + * 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()); + } + } + + /** + * 通过表达式获取近10次的执行时间 + * + * @param cron 表达式 + * @return 时间列表 + */ + public static List getRecentTriggerTime(String cron) + { + List list = new ArrayList(); + try + { + CronTriggerImpl cronTriggerImpl = new CronTriggerImpl(); + cronTriggerImpl.setCronExpression(cron); + List dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 10); + for (Date date : dates) + { + list.add(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, date)); + } + } + catch (ParseException e) + { + return null; + } + return list; + } +} diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java new file mode 100644 index 0000000..693f689 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java @@ -0,0 +1,182 @@ +package com.playlet.quartz.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.quartz.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 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 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 getMethodParams(String invokeTarget) + { + String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); + if (StringUtils.isEmpty(methodStr)) + { + return null; + } + String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); + List 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 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 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/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java new file mode 100644 index 0000000..df907b0 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java @@ -0,0 +1,21 @@ +package com.playlet.quartz.util; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import com.playlet.quartz.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/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java new file mode 100644 index 0000000..c7cd447 --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java @@ -0,0 +1,19 @@ +package com.playlet.quartz.util; + +import org.quartz.JobExecutionContext; +import com.playlet.quartz.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/playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java new file mode 100644 index 0000000..0c74cba --- /dev/null +++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java @@ -0,0 +1,141 @@ +package com.playlet.quartz.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.playlet.common.constant.Constants; +import com.playlet.common.constant.ScheduleConstants; +import com.playlet.common.exception.job.TaskException; +import com.playlet.common.exception.job.TaskException.Code; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.quartz.domain.SysJob; + +/** + * 定时任务工具类 + * + * @author ruoyi + * + */ +public class ScheduleUtils +{ + /** + * 得到quartz任务类 + * + * @param sysJob 执行计划 + * @return 具体执行任务类 + */ + private static Class 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 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]); + String beanPackageName = obj.getClass().getPackage().getName(); + return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR) + && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR); + } +} \ No newline at end of file diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java b/playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java new file mode 100644 index 0000000..3f2ae76 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java @@ -0,0 +1,110 @@ +package com.playlet.system.domain; + +import javax.validation.constraints.*; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.playlet.common.annotation.Excel; +import com.playlet.common.annotation.Excel.ColumnType; +import com.playlet.common.core.domain.BaseEntity; + +/** + * 参数配置表 sys_config + * + * @author ruoyi + */ +public class SysConfig extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 参数主键 */ + @Excel(name = "参数主键", cellType = ColumnType.NUMERIC) + private Long configId; + + /** 参数名称 */ + @Excel(name = "参数名称") + private String configName; + + /** 参数键名 */ + @Excel(name = "参数键名") + private String configKey; + + /** 参数键值 */ + @Excel(name = "参数键值") + private String configValue; + + /** 系统内置(Y是 N否) */ + @Excel(name = "系统内置", readConverterExp = "Y=是,N=否") + private String configType; + + public Long getConfigId() + { + return configId; + } + + public void setConfigId(Long configId) + { + this.configId = configId; + } + + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过100个字符") + public String getConfigName() + { + return configName; + } + + public void setConfigName(String configName) + { + this.configName = configName; + } + + @NotBlank(message = "参数键名长度不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过100个字符") + public String getConfigKey() + { + return configKey; + } + + public void setConfigKey(String configKey) + { + this.configKey = configKey; + } + + @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过500个字符") + public String getConfigValue() + { + return configValue; + } + + public void setConfigValue(String configValue) + { + this.configValue = configValue; + } + + public String getConfigType() + { + return configType; + } + + public void setConfigType(String configType) + { + this.configType = configType; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("configId", getConfigId()) + .append("configName", getConfigName()) + .append("configKey", getConfigKey()) + .append("configValue", getConfigValue()) + .append("configType", getConfigType()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java b/playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java new file mode 100644 index 0000000..b3c24fe --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java @@ -0,0 +1,159 @@ +package com.playlet.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import java.util.Date; +import com.playlet.common.annotation.Excel; +import com.playlet.common.annotation.Excel.ColumnType; +import com.playlet.common.core.domain.BaseEntity; + +/** + * 系统访问记录表 sys_logininfor + * + * @author ruoyi + */ +public class SysLogininfor extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + @Excel(name = "序号", cellType = ColumnType.NUMERIC) + private Long infoId; + + /** 用户账号 */ + @Excel(name = "用户账号") + private String loginName; + + /** 登录状态 0成功 1失败 */ + @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败") + private String status; + + /** 登录IP地址 */ + @Excel(name = "登录地址") + private String ipaddr; + + /** 登录地点 */ + @Excel(name = "登录地点") + private String loginLocation; + + /** 浏览器类型 */ + @Excel(name = "浏览器") + private String browser; + + /** 操作系统 */ + @Excel(name = "操作系统") + private String os; + + /** 提示消息 */ + @Excel(name = "提示消息") + private String msg; + + /** 访问时间 */ + @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date loginTime; + + public Long getInfoId() + { + return infoId; + } + + public void setInfoId(Long infoId) + { + this.infoId = infoId; + } + + public String getLoginName() + { + return loginName; + } + + public void setLoginName(String loginName) + { + this.loginName = loginName; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + 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 String getMsg() + { + return msg; + } + + public void setMsg(String msg) + { + this.msg = msg; + } + + public Date getLoginTime() + { + return loginTime; + } + + public void setLoginTime(Date loginTime) + { + this.loginTime = loginTime; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("infoId", getInfoId()) + .append("loginName", getLoginName()) + .append("ipaddr", getIpaddr()) + .append("loginLocation", getLoginLocation()) + .append("browser", getBrowser()) + .append("os", getOs()) + .append("status", getStatus()) + .append("msg", getMsg()) + .append("loginTime", getLoginTime()) + .toString(); + } +} \ No newline at end of file diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java b/playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java new file mode 100644 index 0000000..1a8cff4 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java @@ -0,0 +1,102 @@ +package com.playlet.system.domain; + +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.playlet.common.core.domain.BaseEntity; +import com.playlet.common.xss.Xss; + +/** + * 通知公告表 sys_notice + * + * @author ruoyi + */ +public class SysNotice extends BaseEntity +{ + 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; + } + + @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/playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java b/playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java new file mode 100644 index 0000000..9c4cb1c --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java @@ -0,0 +1,292 @@ +package com.playlet.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import java.util.Date; +import com.playlet.common.annotation.Excel; +import com.playlet.common.annotation.Excel.ColumnType; +import com.playlet.common.core.domain.BaseEntity; + +/** + * 操作日志记录表 oper_log + * + * @author ruoyi + */ +public class SysOperLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 日志主键 */ + @Excel(name = "操作序号", cellType = ColumnType.NUMERIC) + private Long operId; + + /** 操作模块 */ + @Excel(name = "操作模块") + private String title; + + /** 业务类型(0其它 1新增 2修改 3删除) */ + @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据") + private Integer businessType; + + /** 业务类型数组 */ + private Integer[] businessTypes; + + /** 请求方法 */ + @Excel(name = "请求方法") + private String method; + + /** 请求方式 */ + @Excel(name = "请求方式") + private String requestMethod; + + /** 操作类别(0其它 1后台用户 2手机端用户) */ + @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** 操作人员 */ + @Excel(name = "操作人员") + private String operName; + + /** 部门名称 */ + @Excel(name = "部门名称") + private String deptName; + + /** 请求url */ + @Excel(name = "请求地址") + private String operUrl; + + /** 操作地址 */ + @Excel(name = "操作地址") + private String operIp; + + /** 操作地点 */ + @Excel(name = "操作地点") + private String operLocation; + + /** 请求参数 */ + @Excel(name = "请求参数") + private String operParam; + + /** 返回参数 */ + @Excel(name = "返回参数") + private String jsonResult; + + /** 操作状态(0正常 1异常) */ + @Excel(name = "状态", readConverterExp = "0=正常,1=异常") + private Integer status; + + /** 错误消息 */ + @Excel(name = "错误消息") + private String errorMsg; + + /** 操作时间 */ + @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date operTime; + + /** 消耗时间 */ + @Excel(name = "消耗时间", suffix = "毫秒") + private Long costTime; + + public Long getOperId() + { + return operId; + } + + public void setOperId(Long operId) + { + this.operId = operId; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public Integer getBusinessType() + { + return businessType; + } + + public void setBusinessType(Integer businessType) + { + this.businessType = businessType; + } + + public Integer[] getBusinessTypes() + { + return businessTypes; + } + + public void setBusinessTypes(Integer[] businessTypes) + { + this.businessTypes = businessTypes; + } + + public String getMethod() + { + return method; + } + + public void setMethod(String method) + { + this.method = method; + } + + public String getRequestMethod() + { + return requestMethod; + } + + public void setRequestMethod(String requestMethod) + { + this.requestMethod = requestMethod; + } + + public Integer getOperatorType() + { + return operatorType; + } + + public void setOperatorType(Integer operatorType) + { + this.operatorType = operatorType; + } + + public String getOperName() + { + return operName; + } + + public void setOperName(String operName) + { + this.operName = operName; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public String getOperUrl() + { + return operUrl; + } + + public void setOperUrl(String operUrl) + { + this.operUrl = operUrl; + } + + public String getOperIp() + { + return operIp; + } + + public void setOperIp(String operIp) + { + this.operIp = operIp; + } + + public String getOperLocation() + { + return operLocation; + } + + public void setOperLocation(String operLocation) + { + this.operLocation = operLocation; + } + + public String getOperParam() + { + return operParam; + } + + public void setOperParam(String operParam) + { + this.operParam = operParam; + } + + public String getJsonResult() + { + return jsonResult; + } + + public void setJsonResult(String jsonResult) + { + this.jsonResult = jsonResult; + } + + public Integer getStatus() + { + return status; + } + + public void setStatus(Integer status) + { + this.status = status; + } + + public String getErrorMsg() + { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) + { + this.errorMsg = errorMsg; + } + + public Date getOperTime() + { + return operTime; + } + + public void setOperTime(Date operTime) + { + this.operTime = operTime; + } + + public Long getCostTime() + { + return costTime; + } + + public void setCostTime(Long costTime) + { + this.costTime = costTime; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("operId", getOperId()) + .append("title", getTitle()) + .append("businessType", getBusinessType()) + .append("businessTypes", getBusinessTypes()) + .append("method", getMethod()) + .append("requestMethod", getRequestMethod()) + .append("operatorType", getOperatorType()) + .append("operName", getOperName()) + .append("deptName", getDeptName()) + .append("operUrl", getOperUrl()) + .append("operIp", getOperIp()) + .append("operLocation", getOperLocation()) + .append("operParam", getOperParam()) + .append("status", getStatus()) + .append("errorMsg", getErrorMsg()) + .append("operTime", getOperTime()) + .append("costTime", getCostTime()) + .toString(); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysPost.java b/playlet-system/src/main/java/com/playlet/system/domain/SysPost.java new file mode 100644 index 0000000..bd72d07 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysPost.java @@ -0,0 +1,122 @@ +package com.playlet.system.domain; + +import javax.validation.constraints.*; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.playlet.common.annotation.Excel; +import com.playlet.common.annotation.Excel.ColumnType; +import com.playlet.common.core.domain.BaseEntity; + +/** + * 岗位表 sys_post + * + * @author ruoyi + */ +public class SysPost extends BaseEntity +{ + 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 = "岗位排序", cellType = ColumnType.NUMERIC) + private String 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; + } + + @NotBlank(message = "显示顺序不能为空") + public String getPostSort() + { + return postSort; + } + + public void setPostSort(String 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; + } + + @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/playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java new file mode 100644 index 0000000..ecca39c --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java @@ -0,0 +1,46 @@ +package com.playlet.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/playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java new file mode 100644 index 0000000..68aa87a --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java @@ -0,0 +1,46 @@ +package com.playlet.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author ruoyi + */ +public class SysRoleMenu +{ + /** 角色ID */ + private Long roleId; + + /** 菜单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/playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java b/playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java new file mode 100644 index 0000000..be63a8d --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java @@ -0,0 +1,177 @@ +package com.playlet.system.domain; + +import java.util.Date; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.playlet.common.core.domain.BaseEntity; +import com.playlet.common.enums.OnlineStatus; + +/** + * 当前在线会话 sys_user_online + * + * @author ruoyi + */ +public class SysUserOnline extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 用户会话id */ + private String sessionId; + + /** 部门名称 */ + private String deptName; + + /** 登录名称 */ + private String loginName; + + /** 登录IP地址 */ + private String ipaddr; + + /** 登录地址 */ + private String loginLocation; + + /** 浏览器类型 */ + private String browser; + + /** 操作系统 */ + private String os; + + /** session创建时间 */ + private Date startTimestamp; + + /** session最后访问时间 */ + private Date lastAccessTime; + + /** 超时时间,单位为分钟 */ + private Long expireTime; + + /** 在线状态 */ + private OnlineStatus status = OnlineStatus.on_line; + + public String getSessionId() + { + return sessionId; + } + + public void setSessionId(String sessionId) + { + this.sessionId = sessionId; + } + + public String getDeptName() + { + return deptName; + } + + public void setDeptName(String deptName) + { + this.deptName = deptName; + } + + public String getLoginName() + { + return loginName; + } + + public void setLoginName(String loginName) + { + this.loginName = loginName; + } + + 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 Date getStartTimestamp() + { + return startTimestamp; + } + + public void setStartTimestamp(Date startTimestamp) + { + this.startTimestamp = startTimestamp; + } + + public Date getLastAccessTime() + { + return lastAccessTime; + } + + public void setLastAccessTime(Date lastAccessTime) + { + this.lastAccessTime = lastAccessTime; + } + + public Long getExpireTime() + { + return expireTime; + } + + public void setExpireTime(Long expireTime) + { + this.expireTime = expireTime; + } + + public OnlineStatus getStatus() + { + return status; + } + + public void setStatus(OnlineStatus status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("sessionId", getSessionId()) + .append("loginName", getLoginName()) + .append("deptName", getDeptName()) + .append("ipaddr", getIpaddr()) + .append("loginLocation", getLoginLocation()) + .append("browser", getBrowser()) + .append("os", getOs()) + .append("status", getStatus()) + .append("startTimestamp", getStartTimestamp()) + .append("lastAccessTime", getLastAccessTime()) + .append("expireTime", getExpireTime()) + .toString(); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java b/playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java new file mode 100644 index 0000000..a0c327a --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java @@ -0,0 +1,46 @@ +package com.playlet.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/playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java b/playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java new file mode 100644 index 0000000..bad96b5 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java @@ -0,0 +1,46 @@ +package com.playlet.system.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 用户和角色关联 sys_user_role + * + * @author ruoyi + */ +public class SysUserRole +{ + /** 用户ID */ + private Long userId; + + /** 角色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/playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..e8b4274 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java @@ -0,0 +1,76 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysConfig; + +/** + * 参数配置 数据层 + * + * @author ruoyi + */ +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 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 参数主键 + * @return 结果 + */ + public int deleteConfigById(Long configId); + + /** + * 批量删除参数配置 + * + * @param configIds 需要删除的数据ID + * @return 结果 + */ + public int deleteConfigByIds(String[] configIds); +} \ No newline at end of file diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000..bdf163d --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java @@ -0,0 +1,117 @@ +package com.playlet.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.playlet.common.core.domain.entity.SysDept; + +/** + * 部门管理 数据层 + * + * @author ruoyi + */ +public interface SysDeptMapper +{ + /** + * 查询下级部门数量 + * + * @param dept 部门信息 + * @return 结果 + */ + public int selectDeptCount(SysDept dept); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 + */ + public int checkDeptExistUser(Long deptId); + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List selectDeptList(SysDept dept); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); + + /** + * 新增部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 修改子元素关系 + * + * @param depts 子元素 + * @return 结果 + */ + public int updateDeptChildren(@Param("depts") List depts); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param deptName 部门名称 + * @param parentId 父部门ID + * @return 结果 + */ + public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId); + + /** + * 根据角色ID查询部门 + * + * @param roleId 角色ID + * @return 部门列表 + */ + public List selectRoleDeptTree(Long roleId); + + /** + * 修改所在部门正常状态 + * + * @param deptIds 部门ID组 + */ + public void updateDeptStatusNormal(Long[] deptIds); + + /** + * 根据ID查询所有子部门 + * + * @param deptId 部门ID + * @return 部门列表 + */ + public List selectChildrenDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java new file mode 100644 index 0000000..cd963fb --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java @@ -0,0 +1,95 @@ +package com.playlet.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.playlet.common.core.domain.entity.SysDictData; + +/** + * 字典表 数据层 + * + * @author ruoyi + */ +public interface SysDictDataMapper +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List selectDictDataList(SysDictData dictData); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List 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 ids 需要删除的数据 + * @return 结果 + */ + public int deleteDictDataByIds(String[] ids); + + /** + * 新增字典数据信息 + * + * @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/playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000..ea2e2ee --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,83 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.common.core.domain.entity.SysDictType; + +/** + * 字典表 数据层 + * + * @author ruoyi + */ +public interface SysDictTypeMapper +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List 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 ids 需要删除的数据 + * @return 结果 + */ + public int deleteDictTypeByIds(Long[] ids); + + /** + * 新增字典类型信息 + * + * @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/playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000..b44a084 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java @@ -0,0 +1,42 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 数据层 + * + * @author ruoyi + */ +public interface SysLogininforMapper +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public void insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param ids 需要删除的数据 + * @return 结果 + */ + public int deleteLogininforByIds(String[] ids); + + /** + * 清空系统登录日志 + * + * @return 结果 + */ + public int cleanLogininfor(); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..7f1d789 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java @@ -0,0 +1,132 @@ +package com.playlet.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.playlet.common.core.domain.entity.SysMenu; + +/** + * 菜单表 数据层 + * + * @author ruoyi + */ +public interface SysMenuMapper +{ + /** + * 查询系统所有菜单(含按钮) + * + * @return 菜单列表 + */ + public List selectMenuAll(); + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuAllByUserId(Long userId); + + /** + * 查询系统正常显示菜单(不含按钮) + * + * @return 菜单列表 + */ + public List selectMenuNormalAll(); + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenusByUserId(Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public List selectPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public List selectPermsByRoleId(Long roleId); + + /** + * 根据角色ID查询菜单 + * + * @param roleId 角色ID + * @return 菜单列表 + */ + public List selectMenuTree(Long roleId); + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List selectMenuList(SysMenu menu); + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + public List selectMenuListByUserId(SysMenu menu); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 查询菜单数量 + * + * @param parentId 菜单父ID + * @return 结果 + */ + public int selectCountMenuByParentId(Long parentId); + + /** + * 新增菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 校验菜单名称是否唯一 + * + * @param menuName 菜单名称 + * @param parentId 父菜单ID + * @return 结果 + */ + public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000..9df5238 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java @@ -0,0 +1,52 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysNotice; + +/** + * 公告 数据层 + * + * @author ruoyi + */ +public interface SysNoticeMapper +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 批量删除公告 + * + * @param noticeIds 需要删除的数据ID + * @return 结果 + */ + public int deleteNoticeByIds(String[] noticeIds); +} \ No newline at end of file diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..dad2349 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java @@ -0,0 +1,48 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysOperLog; + +/** + * 操作日志 数据层 + * + * @author ruoyi + */ +public interface SysOperLogMapper +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public void insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param ids 需要删除的数据 + * @return 结果 + */ + public int deleteOperLogByIds(String[] ids); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java new file mode 100644 index 0000000..498feb5 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java @@ -0,0 +1,83 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysPost; + +/** + * 岗位信息 数据层 + * + * @author ruoyi + */ +public interface SysPostMapper +{ + /** + * 查询岗位数据集合 + * + * @param post 岗位信息 + * @return 岗位数据集合 + */ + public List selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List selectPostAll(); + + /** + * 根据用户ID查询岗位 + * + * @param userId 用户ID + * @return 岗位列表 + */ + public List selectPostsByUserId(Long userId); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deletePostByIds(Long[] ids); + + /** + * 修改岗位信息 + * + * @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/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000..ea4f0d6 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,44 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.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 roleDeptList); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..3d1d87a --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java @@ -0,0 +1,84 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.common.core.domain.entity.SysRole; + +/** + * 角色表 数据层 + * + * @author ruoyi + */ +public interface SysRoleMapper +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List selectRolesByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleById(Long roleId); + + /** + * 批量角色用户信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleByIds(Long[] ids); + + /** + * 修改角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 新增角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 校验角色名称是否唯一 + * + * @param roleName 角色名称 + * @return 角色信息 + */ + public SysRole checkRoleNameUnique(String roleName); + + /** + * 校验角色权限是否唯一 + * + * @param roleKey 角色权限 + * @return 角色信息 + */ + public SysRole checkRoleKeyUnique(String roleKey); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..4eb503e --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,44 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysRoleMenu; + +/** + * 角色与菜单关联表 数据层 + * + * @author ruoyi + */ +public interface SysRoleMenuMapper +{ + /** + * 通过角色ID删除角色和菜单关联 + * + * @param roleId 角色ID + * @return 结果 + */ + public int deleteRoleMenuByRoleId(Long roleId); + + /** + * 批量删除角色菜单关联信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteRoleMenu(Long[] ids); + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int selectCountRoleMenuByMenuId(Long menuId); + + /** + * 批量新增角色菜单信息 + * + * @param roleMenuList 角色菜单列表 + * @return 结果 + */ + public int batchRoleMenu(List roleMenuList); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..5dfce04 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java @@ -0,0 +1,124 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.common.core.domain.entity.SysUser; + +/** + * 用户表 数据层 + * + * @author ruoyi + */ +public interface SysUserMapper +{ + /** + * 根据条件分页查询用户列表 + * + * @param sysUser 用户信息 + * @return 用户信息集合信息 + */ + public List selectUserList(SysUser sysUser); + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByLoginName(String userName); + + /** + * 通过手机号码查询用户 + * + * @param phoneNumber 手机号码 + * @return 用户对象信息 + */ + public SysUser selectUserByPhoneNumber(String phoneNumber); + + /** + * 通过邮箱查询用户 + * + * @param email 邮箱 + * @return 用户对象信息 + */ + public SysUser selectUserByEmail(String email); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteUserByIds(Long[] ids); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 校验用户名称是否唯一 + * + * @param loginName 登录名称 + * @return 结果 + */ + public SysUser checkLoginNameUnique(String loginName); + + /** + * 校验手机号码是否唯一 + * + * @param phonenumber 手机号码 + * @return 结果 + */ + public SysUser checkPhoneUnique(String phonenumber); + + /** + * 校验email是否唯一 + * + * @param email 用户邮箱 + * @return 结果 + */ + public SysUser checkEmailUnique(String email); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java new file mode 100644 index 0000000..75360a2 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java @@ -0,0 +1,52 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.system.domain.SysUserOnline; + +/** + * 在线用户 数据层 + * + * @author ruoyi + */ +public interface SysUserOnlineMapper +{ + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineById(String sessionId); + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public int deleteOnlineById(String sessionId); + + /** + * 保存会话信息 + * + * @param online 会话信息 + * @return 结果 + */ + public int saveOnline(SysUserOnline online); + + /** + * 查询会话集合 + * + * @param userOnline 会话参数 + * @return 会话集合 + */ + public List selectUserOnlineList(SysUserOnline userOnline); + + /** + * 查询过期会话集合 + * + * @param lastAccessTime 过期时间 + * @return 会话集合 + */ + public List selectOnlineByExpired(String lastAccessTime); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000..4e19023 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java @@ -0,0 +1,44 @@ +package com.playlet.system.mapper; + +import java.util.List; +import com.playlet.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 userPostList); +} diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..44e04ef --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,70 @@ +package com.playlet.system.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.playlet.system.domain.SysUserRole; + +/** + * 用户与角色关联表 数据层 + * + * @author ruoyi + */ +public interface SysUserRoleMapper +{ + /** + * 通过用户ID查询用户和角色关联 + * + * @param userId 用户ID + * @return 用户和角色关联列表 + */ + public List selectUserRoleByUserId(Long userId); + + /** + * 通过用户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 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); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java new file mode 100644 index 0000000..cf276b2 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java @@ -0,0 +1,82 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.system.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 selectConfigList(SysConfig config); + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int insertConfig(SysConfig config); + + /** + * 修改参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + public int updateConfig(SysConfig config); + + /** + * 批量删除参数配置信息 + * + * @param ids 需要删除的数据ID + */ + public void deleteConfigByIds(String ids); + + /** + * 加载参数缓存数据 + */ + public void loadingConfigCache(); + + /** + * 清空参数缓存数据 + */ + public void clearConfigCache(); + + /** + * 重置参数缓存数据 + */ + public void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + public boolean checkConfigKeyUnique(SysConfig config); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java new file mode 100644 index 0000000..ac1e4f3 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java @@ -0,0 +1,117 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.common.core.domain.Ztree; +import com.playlet.common.core.domain.entity.SysDept; +import com.playlet.common.core.domain.entity.SysRole; + +/** + * 部门管理 服务层 + * + * @author ruoyi + */ +public interface ISysDeptService +{ + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + public List selectDeptList(SysDept dept); + + /** + * 查询部门管理树 + * + * @param dept 部门信息 + * @return 所有部门信息 + */ + public List selectDeptTree(SysDept dept); + + /** + * 查询部门管理树(排除下级) + * + * @param dept 部门信息 + * @return 所有部门信息 + */ + public List selectDeptTreeExcludeChild(SysDept dept); + + /** + * 根据角色ID查询菜单 + * + * @param role 角色对象 + * @return 菜单列表 + */ + public List roleDeptTreeData(SysRole role); + + /** + * 根据父部门ID查询下级部门数量 + * + * @param parentId 父部门ID + * @return 结果 + */ + public int selectDeptCount(Long parentId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + public boolean checkDeptExistUser(Long deptId); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + public int deleteDeptById(Long deptId); + + /** + * 新增保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int insertDept(SysDept dept); + + /** + * 修改保存部门信息 + * + * @param dept 部门信息 + * @return 结果 + */ + public int updateDept(SysDept dept); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + public SysDept selectDeptById(Long deptId); + + /** + * 根据ID查询所有子部门(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + public int selectNormalChildrenDeptById(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + public boolean checkDeptNameUnique(SysDept dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + public void checkDeptDataScope(Long deptId); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java new file mode 100644 index 0000000..5f98651 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java @@ -0,0 +1,60 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.common.core.domain.entity.SysDictData; + +/** + * 字典 业务层 + * + * @author ruoyi + */ +public interface ISysDictDataService +{ + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + public List 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 ids 需要删除的数据 + */ + public void deleteDictDataByIds(String ids); + + /** + * 新增保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int insertDictData(SysDictData dictData); + + /** + * 修改保存字典数据信息 + * + * @param dictData 字典数据信息 + * @return 结果 + */ + public int updateDictData(SysDictData dictData); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java new file mode 100644 index 0000000..eb2e93d --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java @@ -0,0 +1,107 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.common.core.domain.Ztree; +import com.playlet.common.core.domain.entity.SysDictData; +import com.playlet.common.core.domain.entity.SysDictType; + +/** + * 字典 业务层 + * + * @author ruoyi + */ +public interface ISysDictTypeService +{ + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + public List selectDictTypeList(SysDictType dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + public List selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + public List selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + public SysDictType selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + public SysDictType selectDictTypeByType(String dictType); + + /** + * 批量删除字典类型 + * + * @param ids 需要删除的数据 + */ + public void deleteDictTypeByIds(String ids); + + /** + * 加载字典缓存数据 + */ + 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); + + /** + * 查询字典类型树 + * + * @param dictType 字典类型 + * @return 所有字典类型 + */ + public List selectDictTree(SysDictType dictType); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java new file mode 100644 index 0000000..65fd514 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java @@ -0,0 +1,40 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.system.domain.SysLogininfor; + +/** + * 系统访问日志情况信息 服务层 + * + * @author ruoyi + */ +public interface ISysLogininforService +{ + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + public void insertLogininfor(SysLogininfor logininfor); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + public List selectLogininforList(SysLogininfor logininfor); + + /** + * 批量删除系统登录日志 + * + * @param ids 需要删除的数据 + * @return 结果 + */ + public int deleteLogininforByIds(String ids); + + /** + * 清空系统登录日志 + */ + public void cleanLogininfor(); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java new file mode 100644 index 0000000..cb2ab1e --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java @@ -0,0 +1,139 @@ +package com.playlet.system.service; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import com.playlet.common.core.domain.Ztree; +import com.playlet.common.core.domain.entity.SysMenu; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; + +/** + * 菜单 业务层 + * + * @author ruoyi + */ +public interface ISysMenuService +{ + /** + * 根据用户ID查询菜单 + * + * @param user 用户信息 + * @return 菜单列表 + */ + public List selectMenusByUser(SysUser user); + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + public List selectMenuList(SysMenu menu, Long userId); + + /** + * 查询菜单集合 + * + * @param userId 用户ID + * @return 所有菜单信息 + */ + public List selectMenuAll(Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set selectPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + public Set selectPermsByRoleId(Long roleId); + + /** + * 根据角色ID查询菜单 + * + * @param role 角色对象 + * @param userId 用户ID + * @return 菜单列表 + */ + public List roleMenuTreeData(SysRole role, Long userId); + + /** + * 查询所有菜单信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + public List menuTreeData(Long userId); + + /** + * 查询系统所有权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Map selectPermsAll(Long userId); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int deleteMenuById(Long menuId); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + public SysMenu selectMenuById(Long menuId); + + /** + * 查询菜单数量 + * + * @param parentId 菜单父ID + * @return 结果 + */ + public int selectCountMenuByParentId(Long parentId); + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + public int selectCountRoleMenuByMenuId(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int insertMenu(SysMenu menu); + + /** + * 修改保存菜单信息 + * + * @param menu 菜单信息 + * @return 结果 + */ + public int updateMenu(SysMenu menu); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + public boolean checkMenuNameUnique(SysMenu menu); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java new file mode 100644 index 0000000..21922b8 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java @@ -0,0 +1,52 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.system.domain.SysNotice; + +/** + * 公告 服务层 + * + * @author ruoyi + */ +public interface ISysNoticeService +{ + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + public SysNotice selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + public List selectNoticeList(SysNotice notice); + + /** + * 新增公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int insertNotice(SysNotice notice); + + /** + * 修改公告 + * + * @param notice 公告信息 + * @return 结果 + */ + public int updateNotice(SysNotice notice); + + /** + * 删除公告信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteNoticeByIds(String ids); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java new file mode 100644 index 0000000..746ac87 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java @@ -0,0 +1,48 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.system.domain.SysOperLog; + +/** + * 操作日志 服务层 + * + * @author ruoyi + */ +public interface ISysOperLogService +{ + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + public void insertOperlog(SysOperLog operLog); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + public List selectOperLogList(SysOperLog operLog); + + /** + * 批量删除系统操作日志 + * + * @param ids 需要删除的数据 + * @return 结果 + */ + public int deleteOperLogByIds(String ids); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + public SysOperLog selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + public void cleanOperLog(); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java new file mode 100644 index 0000000..ea99f7a --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java @@ -0,0 +1,91 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.system.domain.SysPost; + +/** + * 岗位信息 服务层 + * + * @author ruoyi + */ +public interface ISysPostService +{ + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + public List selectPostList(SysPost post); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + public List selectPostAll(); + + /** + * 根据用户ID查询岗位 + * + * @param userId 用户ID + * @return 岗位列表 + */ + public List selectPostsByUserId(Long userId); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + public SysPost selectPostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deletePostByIds(String ids); + + /** + * 新增保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int insertPost(SysPost post); + + /** + * 修改保存岗位信息 + * + * @param post 岗位信息 + * @return 结果 + */ + public int updatePost(SysPost post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + public int countUserPostById(Long postId); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostNameUnique(SysPost post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + public boolean checkPostCodeUnique(SysPost post); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java new file mode 100644 index 0000000..13b594f --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java @@ -0,0 +1,166 @@ +package com.playlet.system.service; + +import java.util.List; +import java.util.Set; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.system.domain.SysUserRole; + +/** + * 角色业务层 + * + * @author ruoyi + */ +public interface ISysRoleService +{ + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + public List selectRoleList(SysRole role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 权限列表 + */ + public Set selectRoleKeys(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 角色列表 + */ + public List selectRolesByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + public List selectRoleAll(); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + public SysRole selectRoleById(Long roleId); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + public boolean deleteRoleById(Long roleId); + + /** + * 批量删除角色用户信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + * @throws Exception 异常 + */ + public int deleteRoleByIds(String ids); + + /** + * 新增保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int insertRole(SysRole role); + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int updateRole(SysRole role); + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + public int authDataScope(SysRole role); + + /** + * 校验角色名称是否唯一 + * + * @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 changeStatus(SysRole role); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + public int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int deleteAuthUsers(Long roleId, String userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + public int insertAuthUsers(Long roleId, String userIds); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java new file mode 100644 index 0000000..ad05399 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java @@ -0,0 +1,75 @@ +package com.playlet.system.service; + +import java.util.Date; +import java.util.List; +import com.playlet.system.domain.SysUserOnline; + +/** + * 在线用户 服务层 + * + * @author ruoyi + */ +public interface ISysUserOnlineService +{ + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public SysUserOnline selectOnlineById(String sessionId); + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + public void deleteOnlineById(String sessionId); + + /** + * 通过会话序号删除信息 + * + * @param sessions 会话ID集合 + * @return 在线用户信息 + */ + public void batchDeleteOnline(List sessions); + + /** + * 保存会话信息 + * + * @param online 会话信息 + */ + public void saveOnline(SysUserOnline online); + + /** + * 查询会话集合 + * + * @param userOnline 分页参数 + * @return 会话集合 + */ + public List selectUserOnlineList(SysUserOnline userOnline); + + /** + * 强退用户 + * + * @param sessionId 会话ID + */ + public void forceLogout(String sessionId); + + /** + * 清理用户缓存 + * + * @param loginName 登录名称 + * @param sessionId 会话ID + */ + public void removeUserCache(String loginName, String sessionId); + + /** + * 查询会话集合 + * + * @param expiredDate 有效期 + * @return 会话集合 + */ + public List selectOnlineByExpired(Date expiredDate); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java new file mode 100644 index 0000000..65b20f4 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java @@ -0,0 +1,214 @@ +package com.playlet.system.service; + +import java.util.List; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.system.domain.SysUserRole; + +/** + * 用户 业务层 + * + * @author ruoyi + */ +public interface ISysUserService +{ + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUserList(SysUser user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectAllocatedList(SysUser user); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + public List selectUnallocatedList(SysUser user); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public SysUser selectUserByLoginName(String userName); + + /** + * 通过手机号码查询用户 + * + * @param phoneNumber 手机号码 + * @return 用户对象信息 + */ + public SysUser selectUserByPhoneNumber(String phoneNumber); + + /** + * 通过邮箱查询用户 + * + * @param email 邮箱 + * @return 用户对象信息 + */ + public SysUser selectUserByEmail(String email); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + public SysUser selectUserById(Long userId); + + /** + * 通过用户ID查询用户和角色关联 + * + * @param userId 用户ID + * @return 用户和角色关联列表 + */ + public List selectUserRoleByUserId(Long userId); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + public int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + * @throws Exception 异常 + */ + public int deleteUserByIds(String ids); + + /** + * 保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int insertUser(SysUser user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean registerUser(SysUser user); + + /** + * 保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUser(SysUser user); + + /** + * 修改用户详细信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int updateUserInfo(SysUser user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户密码信息 + * + * @param user 用户信息 + * @return 结果 + */ + public int resetUserPwd(SysUser user); + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + public boolean checkLoginNameUnique(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); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + public String selectUserRoleGroup(Long userId); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + public String selectUserPostGroup(Long userId); + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + public String importUser(List userList, Boolean isUpdateSupport, String operName); + + /** + * 用户状态修改 + * + * @param user 用户信息 + * @return 结果 + */ + public int changeStatus(SysUser user); +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..8b54a18 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,219 @@ +package com.playlet.system.service.impl; + +import java.util.List; +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.constant.Constants; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.CacheUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.system.domain.SysConfig; +import com.playlet.system.mapper.SysConfigMapper; +import com.playlet.system.service.ISysConfigService; + +/** + * 参数配置 服务层实现 + * + * @author ruoyi + */ +@Service +public class SysConfigServiceImpl implements ISysConfigService +{ + @Autowired + private SysConfigMapper configMapper; + + /** + * 项目启动时,初始化参数到缓存 + */ + @PostConstruct + public void init() + { + 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(CacheUtils.get(getCacheName(), getCacheKey(configKey))); + if (StringUtils.isNotEmpty(configValue)) + { + return configValue; + } + SysConfig config = new SysConfig(); + config.setConfigKey(configKey); + SysConfig retConfig = configMapper.selectConfig(config); + if (StringUtils.isNotNull(retConfig)) + { + CacheUtils.put(getCacheName(), getCacheKey(configKey), retConfig.getConfigValue()); + return retConfig.getConfigValue(); + } + return StringUtils.EMPTY; + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfig config) + { + return configMapper.selectConfigList(config); + } + + /** + * 新增参数配置 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public int insertConfig(SysConfig config) + { + int row = configMapper.insertConfig(config); + if (row > 0) + { + CacheUtils.put(getCacheName(), 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())) + { + CacheUtils.remove(getCacheName(), getCacheKey(temp.getConfigKey())); + } + + int row = configMapper.updateConfig(config); + if (row > 0) + { + CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + return row; + } + + /** + * 批量删除参数配置对象 + * + * @param ids 需要删除的数据ID + */ + @Override + public void deleteConfigByIds(String ids) + { + Long[] configIds = Convert.toLongArray(ids); + 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); + CacheUtils.remove(getCacheName(), getCacheKey(config.getConfigKey())); + } + } + + /** + * 加载参数缓存数据 + */ + @Override + public void loadingConfigCache() + { + List configsList = configMapper.selectConfigList(new SysConfig()); + for (SysConfig config : configsList) + { + CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue()); + } + } + + /** + * 清空参数缓存数据 + */ + @Override + public void clearConfigCache() + { + CacheUtils.removeAll(getCacheName()); + } + + /** + * 重置参数缓存数据 + */ + @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 name + * + * @return 缓存名 + */ + private String getCacheName() + { + return Constants.SYS_CONFIG_CACHE; + } + + /** + * 设置cache key + * + * @param configKey 参数键 + * @return 缓存键key + */ + private String getCacheKey(String configKey) + { + return Constants.SYS_CONFIG_KEY + configKey; + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000..5dc7e70 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,328 @@ +package com.playlet.system.service.impl; + +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.playlet.common.annotation.DataScope; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.Ztree; +import com.playlet.common.core.domain.entity.SysDept; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.system.mapper.SysDeptMapper; +import com.playlet.system.service.ISysDeptService; + +/** + * 部门管理 服务实现 + * + * @author ruoyi + */ +@Service +public class SysDeptServiceImpl implements ISysDeptService +{ + @Autowired + private SysDeptMapper deptMapper; + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + @DataScope(deptAlias = "d") + public List selectDeptList(SysDept dept) + { + return deptMapper.selectDeptList(dept); + } + + /** + * 查询部门管理树 + * + * @param dept 部门信息 + * @return 所有部门信息 + */ + @Override + @DataScope(deptAlias = "d") + public List selectDeptTree(SysDept dept) + { + List deptList = deptMapper.selectDeptList(dept); + List ztrees = initZtree(deptList); + return ztrees; + } + + /** + * 查询部门管理树(排除下级) + * + * @param deptId 部门ID + * @return 所有部门信息 + */ + @Override + @DataScope(deptAlias = "d") + public List selectDeptTreeExcludeChild(SysDept dept) + { + Long excludeId = dept.getExcludeId(); + List depts = deptMapper.selectDeptList(dept); + if (excludeId.intValue() > 0) + { + depts.removeIf(d -> d.getDeptId().intValue() == excludeId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), excludeId + "")); + } + List ztrees = initZtree(depts); + return ztrees; + } + + /** + * 根据角色ID查询部门(数据权限) + * + * @param role 角色对象 + * @return 部门列表(数据权限) + */ + @Override + public List roleDeptTreeData(SysRole role) + { + Long roleId = role.getRoleId(); + List ztrees = new ArrayList(); + List deptList = SpringUtils.getAopProxy(this).selectDeptList(new SysDept()); + if (StringUtils.isNotNull(roleId)) + { + List roleDeptList = deptMapper.selectRoleDeptTree(roleId); + ztrees = initZtree(deptList, roleDeptList); + } + else + { + ztrees = initZtree(deptList); + } + return ztrees; + } + + /** + * 对象转部门树 + * + * @param deptList 部门列表 + * @return 树结构列表 + */ + public List initZtree(List deptList) + { + return initZtree(deptList, null); + } + + /** + * 对象转部门树 + * + * @param deptList 部门列表 + * @param roleDeptList 角色已存在菜单列表 + * @return 树结构列表 + */ + public List initZtree(List deptList, List roleDeptList) + { + + List ztrees = new ArrayList(); + boolean isCheck = StringUtils.isNotNull(roleDeptList); + for (SysDept dept : deptList) + { + if (UserConstants.DEPT_NORMAL.equals(dept.getStatus())) + { + Ztree ztree = new Ztree(); + ztree.setId(dept.getDeptId()); + ztree.setpId(dept.getParentId()); + ztree.setName(dept.getDeptName()); + ztree.setTitle(dept.getDeptName()); + if (isCheck) + { + ztree.setChecked(roleDeptList.contains(dept.getDeptId() + dept.getDeptName())); + } + ztrees.add(ztree); + } + } + return ztrees; + } + + /** + * 根据父部门ID查询下级部门数量 + * + * @param parentId 部门ID + * @return 结果 + */ + @Override + public int selectDeptCount(Long parentId) + { + SysDept dept = new SysDept(); + dept.setParentId(parentId); + return deptMapper.selectDeptCount(dept); + } + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) + { + int result = deptMapper.checkDeptExistUser(deptId); + return result > 0; + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public int deleteDeptById(Long deptId) + { + return deptMapper.deleteDeptById(deptId); + } + + /** + * 新增保存部门信息 + * + * @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 + @Transactional + public int updateDept(SysDept dept) + { + SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId()); + SysDept oldDept = 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 children = deptMapper.selectChildrenDeptById(deptId); + for (SysDept child : children) + { + child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + } + if (children.size() > 0) + { + deptMapper.updateDeptChildren(children); + } + } + + /** + * 根据部门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 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(ShiroUtils.getUserId())) + { + SysDept dept = new SysDept(); + dept.setDeptId(deptId); + List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); + if (StringUtils.isEmpty(depts)) + { + throw new ServiceException("没有权限访问部门数据!"); + } + } + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000..c81861f --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,113 @@ +package com.playlet.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.domain.entity.SysDictData; +import com.playlet.common.core.text.Convert; +import com.playlet.common.utils.DictUtils; +import com.playlet.system.mapper.SysDictDataMapper; +import com.playlet.system.service.ISysDictDataService; + +/** + * 字典 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysDictDataServiceImpl implements ISysDictDataService +{ + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List 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 ids 需要删除的数据 + */ + @Override + public void deleteDictDataByIds(String ids) + { + Long[] dictCodes = Convert.toLongArray(ids); + for (Long dictCode : dictCodes) + { + SysDictData data = selectDictDataById(dictCode); + dictDataMapper.deleteDictDataById(dictCode); + List 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 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 dictDatas = dictDataMapper.selectDictDataByType(data.getDictType()); + DictUtils.setDictCache(data.getDictType(), dictDatas); + } + return row; + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..8fdcd23 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,260 @@ +package com.playlet.system.service.impl; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.Ztree; +import com.playlet.common.core.domain.entity.SysDictData; +import com.playlet.common.core.domain.entity.SysDictType; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.DictUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.system.mapper.SysDictDataMapper; +import com.playlet.system.mapper.SysDictTypeMapper; +import com.playlet.system.service.ISysDictTypeService; + +/** + * 字典 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService +{ + @Autowired + private SysDictTypeMapper dictTypeMapper; + + @Autowired + private SysDictDataMapper dictDataMapper; + + /** + * 项目启动时,初始化字典到缓存 + */ + @PostConstruct + public void init() + { + loadingDictCache(); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictType dictType) + { + return dictTypeMapper.selectDictTypeList(dictType); + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() + { + return dictTypeMapper.selectDictTypeAll(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataByType(String dictType) + { + List 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 ids 需要删除的数据 + */ + @Override + public void deleteDictTypeByIds(String ids) + { + Long[] dictIds = Convert.toLongArray(ids); + 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> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType)); + for (Map.Entry> entry : dictDataMap.entrySet()) + { + DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList())); + } + } + + /** + * 清空字典缓存数据 + */ + @Override + public void clearDictCache() + { + DictUtils.clearDictCache(); + } + + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() + { + clearDictCache(); + loadingDictCache(); + } + + /** + * 新增保存字典类型信息 + * + * @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 + 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 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; + } + + /** + * 查询字典类型树 + * + * @param dictType 字典类型 + * @return 所有字典类型 + */ + @Override + public List selectDictTree(SysDictType dictType) + { + List ztrees = new ArrayList(); + List dictList = dictTypeMapper.selectDictTypeList(dictType); + for (SysDictType dict : dictList) + { + if (UserConstants.DICT_NORMAL.equals(dict.getStatus())) + { + Ztree ztree = new Ztree(); + ztree.setId(dict.getDictId()); + ztree.setName(transDictName(dict)); + ztree.setTitle(dict.getDictType()); + ztrees.add(ztree); + } + } + return ztrees; + } + + public String transDictName(SysDictType dictType) + { + StringBuffer sb = new StringBuffer(); + sb.append("(" + dictType.getDictName() + ")"); + sb.append("   " + dictType.getDictType()); + return sb.toString(); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000..e382e32 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,66 @@ +package com.playlet.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.text.Convert; +import com.playlet.system.domain.SysLogininfor; +import com.playlet.system.mapper.SysLogininforMapper; +import com.playlet.system.service.ISysLogininforService; + +/** + * 系统访问日志情况信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysLogininforServiceImpl implements ISysLogininforService +{ + + @Autowired + private SysLogininforMapper logininforMapper; + + /** + * 新增系统登录日志 + * + * @param logininfor 访问日志对象 + */ + @Override + public void insertLogininfor(SysLogininfor logininfor) + { + logininforMapper.insertLogininfor(logininfor); + } + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLogininforList(SysLogininfor logininfor) + { + return logininforMapper.selectLogininforList(logininfor); + } + + /** + * 批量删除系统登录日志 + * + * @param ids 需要删除的数据 + * @return 结果 + */ + @Override + public int deleteLogininforByIds(String ids) + { + return logininforMapper.deleteLogininforByIds(Convert.toStrArray(ids)); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() + { + logininforMapper.cleanLogininfor(); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..df1d431 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,410 @@ +package com.playlet.system.service.impl; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.Ztree; +import com.playlet.common.core.domain.entity.SysMenu; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.utils.StringUtils; +import com.playlet.system.mapper.SysMenuMapper; +import com.playlet.system.mapper.SysRoleMenuMapper; +import com.playlet.system.service.ISysMenuService; + +/** + * 菜单 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysMenuServiceImpl implements ISysMenuService +{ + public static final String PREMISSION_STRING = "perms[\"{0}\"]"; + + @Autowired + private SysMenuMapper menuMapper; + + @Autowired + private SysRoleMenuMapper roleMenuMapper; + + /** + * 根据用户查询菜单 + * + * @param user 用户信息 + * @return 菜单列表 + */ + @Override + public List selectMenusByUser(SysUser user) + { + List menus = new LinkedList(); + // 管理员显示所有菜单信息 + if (user.isAdmin()) + { + menus = menuMapper.selectMenuNormalAll(); + } + else + { + menus = menuMapper.selectMenusByUserId(user.getUserId()); + } + return getChildPerms(menus, 0); + } + + /** + * 查询菜单集合 + * + * @return 所有菜单信息 + */ + @Override + public List selectMenuList(SysMenu menu, Long userId) + { + List menuList = null; + if (SysUser.isAdmin(userId)) + { + menuList = menuMapper.selectMenuList(menu); + } + else + { + menu.getParams().put("userId", userId); + menuList = menuMapper.selectMenuListByUserId(menu); + } + return menuList; + } + + /** + * 查询菜单集合 + * + * @return 所有菜单信息 + */ + @Override + public List selectMenuAll(Long userId) + { + List menuList = null; + if (SysUser.isAdmin(userId)) + { + menuList = menuMapper.selectMenuAll(); + } + else + { + menuList = menuMapper.selectMenuAllByUserId(userId); + } + return menuList; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectPermsByUserId(Long userId) + { + List perms = menuMapper.selectPermsByUserId(userId); + Set 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 selectPermsByRoleId(Long roleId) + { + List perms = menuMapper.selectPermsByRoleId(roleId); + Set permsSet = new HashSet<>(); + for (String perm : perms) + { + if (StringUtils.isNotEmpty(perm)) + { + permsSet.addAll(Arrays.asList(perm.trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据角色ID查询菜单 + * + * @param role 角色对象 + * @return 菜单列表 + */ + @Override + public List roleMenuTreeData(SysRole role, Long userId) + { + Long roleId = role.getRoleId(); + List ztrees = new ArrayList(); + List menuList = selectMenuAll(userId); + if (StringUtils.isNotNull(roleId)) + { + List roleMenuList = menuMapper.selectMenuTree(roleId); + ztrees = initZtree(menuList, roleMenuList, true); + } + else + { + ztrees = initZtree(menuList, null, true); + } + return ztrees; + } + + /** + * 查询所有菜单 + * + * @return 菜单列表 + */ + @Override + public List menuTreeData(Long userId) + { + List menuList = selectMenuAll(userId); + List ztrees = initZtree(menuList); + return ztrees; + } + + /** + * 查询系统所有权限 + * + * @return 权限列表 + */ + @Override + public LinkedHashMap selectPermsAll(Long userId) + { + LinkedHashMap section = new LinkedHashMap<>(); + List permissions = selectMenuAll(userId); + if (StringUtils.isNotEmpty(permissions)) + { + for (SysMenu menu : permissions) + { + section.put(menu.getUrl(), MessageFormat.format(PREMISSION_STRING, menu.getPerms())); + } + } + return section; + } + + /** + * 对象转菜单树 + * + * @param menuList 菜单列表 + * @return 树结构列表 + */ + public List initZtree(List menuList) + { + return initZtree(menuList, null, false); + } + + /** + * 对象转菜单树 + * + * @param menuList 菜单列表 + * @param roleMenuList 角色已存在菜单列表 + * @param permsFlag 是否需要显示权限标识 + * @return 树结构列表 + */ + public List initZtree(List menuList, List roleMenuList, boolean permsFlag) + { + List ztrees = new ArrayList(); + boolean isCheck = StringUtils.isNotNull(roleMenuList); + for (SysMenu menu : menuList) + { + Ztree ztree = new Ztree(); + ztree.setId(menu.getMenuId()); + ztree.setpId(menu.getParentId()); + ztree.setName(transMenuName(menu, permsFlag)); + ztree.setTitle(menu.getMenuName()); + if (isCheck) + { + ztree.setChecked(roleMenuList.contains(menu.getMenuId() + menu.getPerms())); + } + ztrees.add(ztree); + } + return ztrees; + } + + public String transMenuName(SysMenu menu, boolean permsFlag) + { + StringBuffer sb = new StringBuffer(); + sb.append(menu.getMenuName()); + if (permsFlag) + { + sb.append("   " + menu.getPerms() + ""); + } + return sb.toString(); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) + { + return menuMapper.deleteMenuById(menuId); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenu selectMenuById(Long menuId) + { + return menuMapper.selectMenuById(menuId); + } + + /** + * 查询子菜单数量 + * + * @param parentId 父级菜单ID + * @return 结果 + */ + @Override + public int selectCountMenuByParentId(Long parentId) + { + return menuMapper.selectCountMenuByParentId(parentId); + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int selectCountRoleMenuByMenuId(Long menuId) + { + return roleMenuMapper.selectCountRoleMenuByMenuId(menuId); + } + + /** + * 新增保存菜单信息 + * + * @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 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; + } + + /** + * 根据父节点的ID获取所有子节点 + * + * @param list 分类表 + * @param parentId 传入的父节点ID + * @return String + */ + public List getChildPerms(List list, int parentId) + { + List returnList = new ArrayList(); + for (Iterator 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 list, SysMenu t) + { + // 得到子节点列表 + List childList = getChildList(list, t); + t.setChildren(childList); + for (SysMenu tChild : childList) + { + if (hasChild(list, tChild)) + { + recursionFn(list, tChild); + } + } + } + + /** + * 得到子节点列表 + */ + private List getChildList(List list, SysMenu t) + { + List tlist = new ArrayList(); + Iterator 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 list, SysMenu t) + { + return getChildList(list, t).size() > 0; + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysNoticeServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000..29f6cbb --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,82 @@ +package com.playlet.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.text.Convert; +import com.playlet.system.domain.SysNotice; +import com.playlet.system.mapper.SysNoticeMapper; +import com.playlet.system.service.ISysNoticeService; + +/** + * 公告 服务层实现 + * + * @author ruoyi + * @date 2018-06-25 + */ +@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 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 ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(String ids) + { + return noticeMapper.deleteNoticeByIds(Convert.toStrArray(ids)); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysOperLogServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000..36d9c65 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,77 @@ +package com.playlet.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.core.text.Convert; +import com.playlet.system.domain.SysOperLog; +import com.playlet.system.mapper.SysOperLogMapper; +import com.playlet.system.service.ISysOperLogService; + +/** + * 操作日志 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysOperLogServiceImpl implements ISysOperLogService +{ + @Autowired + private SysOperLogMapper operLogMapper; + + /** + * 新增操作日志 + * + * @param operLog 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLog operLog) + { + operLogMapper.insertOperlog(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLog operLog) + { + return operLogMapper.selectOperLogList(operLog); + } + + /** + * 批量删除系统操作日志 + * + * @param ids 需要删除的数据 + * @return + */ + @Override + public int deleteOperLogByIds(String ids) + { + return operLogMapper.deleteOperLogByIds(Convert.toStrArray(ids)); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLog selectOperLogById(Long operId) + { + return operLogMapper.selectOperLogById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() + { + operLogMapper.cleanOperLog(); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysPostServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000..fbaf961 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,181 @@ +package com.playlet.system.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.StringUtils; +import com.playlet.system.domain.SysPost; +import com.playlet.system.mapper.SysPostMapper; +import com.playlet.system.mapper.SysUserPostMapper; +import com.playlet.system.service.ISysPostService; + +/** + * 岗位信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysPostServiceImpl implements ISysPostService +{ + @Autowired + private SysPostMapper postMapper; + + @Autowired + private SysUserPostMapper userPostMapper; + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPost post) + { + return postMapper.selectPostList(post); + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() + { + return postMapper.selectPostAll(); + } + + /** + * 根据用户ID查询岗位 + * + * @param userId 用户ID + * @return 岗位列表 + */ + @Override + public List selectPostsByUserId(Long userId) + { + List userPosts = postMapper.selectPostsByUserId(userId); + List posts = postMapper.selectPostAll(); + for (SysPost post : posts) + { + for (SysPost userRole : userPosts) + { + if (post.getPostId().longValue() == userRole.getPostId().longValue()) + { + post.setFlag(true); + break; + } + } + } + return posts; + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPost selectPostById(Long postId) + { + return postMapper.selectPostById(postId); + } + + /** + * 批量删除岗位信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deletePostByIds(String ids) + { + Long[] postIds = Convert.toLongArray(ids); + 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); + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int countUserPostById(Long postId) + { + return userPostMapper.countUserPostById(postId); + } + + /** + * 校验岗位名称是否唯一 + * + * @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; + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysRoleServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..aab0719 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,415 @@ +package com.playlet.system.service.impl; + +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; +import com.playlet.common.annotation.DataScope; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.system.domain.SysRoleDept; +import com.playlet.system.domain.SysRoleMenu; +import com.playlet.system.domain.SysUserRole; +import com.playlet.system.mapper.SysRoleDeptMapper; +import com.playlet.system.mapper.SysRoleMapper; +import com.playlet.system.mapper.SysRoleMenuMapper; +import com.playlet.system.mapper.SysUserRoleMapper; +import com.playlet.system.service.ISysRoleService; + +/** + * 角色 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysRoleServiceImpl 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 selectRoleList(SysRole role) + { + return roleMapper.selectRoleList(role); + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectRoleKeys(Long userId) + { + List perms = roleMapper.selectRolesByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRole perm : perms) + { + if (StringUtils.isNotNull(perm)) + { + permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(","))); + } + } + return permsSet; + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) + { + List userRoles = roleMapper.selectRolesByUserId(userId); + List roles = selectRoleAll(); + for (SysRole role : roles) + { + for (SysRole userRole : userRoles) + { + if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) + { + role.setFlag(true); + break; + } + } + } + return roles; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() + { + return SpringUtils.getAopProxy(this).selectRoleList(new SysRole()); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRole selectRoleById(Long roleId) + { + return roleMapper.selectRoleById(roleId); + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + @Transactional + public boolean deleteRoleById(Long roleId) + { + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(roleId); + // 删除角色与部门关联 + roleDeptMapper.deleteRoleDeptByRoleId(roleId); + return roleMapper.deleteRoleById(roleId) > 0 ? true : false; + } + + /** + * 批量删除角色信息 + * + * @param ids 需要删除的数据ID + * @throws Exception + */ + @Override + @Transactional + public int deleteRoleByIds(String ids) + { + Long[] roleIds = Convert.toLongArray(ids); + 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 role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int insertRole(SysRole role) + { + // 新增角色信息 + roleMapper.insertRole(role); + return insertRoleMenu(role); + } + + /** + * 修改保存角色信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + public int updateRole(SysRole role) + { + // 修改角色信息 + roleMapper.updateRole(role); + // 删除角色与菜单关联 + roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId()); + return insertRoleMenu(role); + } + + /** + * 修改数据权限信息 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + @Transactional + 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 list = new ArrayList(); + for (Long menuId : role.getMenuIds()) + { + 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 list = new ArrayList(); + 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; + } + + /** + * 校验角色名称是否唯一 + * + * @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(ShiroUtils.getUserId())) + { + SysRole role = new SysRole(); + role.setRoleId(roleId); + List roles = SpringUtils.getAopProxy(this).selectRoleList(role); + if (StringUtils.isEmpty(roles)) + { + throw new ServiceException("没有权限访问角色数据!"); + } + } + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public int countUserRoleByRoleId(Long roleId) + { + return userRoleMapper.countUserRoleByRoleId(roleId); + } + + /** + * 角色状态修改 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public int changeStatus(SysRole role) + { + return roleMapper.updateRole(role); + } + + /** + * 取消授权用户角色 + * + * @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, String userIds) + { + return userRoleMapper.deleteUserRoleInfos(roleId, Convert.toLongArray(userIds)); + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, String userIds) + { + Long[] users = Convert.toLongArray(userIds); + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long userId : users) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + return userRoleMapper.batchUserRole(list); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysUserOnlineServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysUserOnlineServiceImpl.java new file mode 100644 index 0000000..5d67e64 --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysUserOnlineServiceImpl.java @@ -0,0 +1,140 @@ +package com.playlet.system.service.impl; + +import java.io.Serializable; +import java.util.Date; +import java.util.Deque; +import java.util.List; +import com.playlet.common.utils.spring.SpringUtils; +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.ehcache.EhCacheManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.playlet.common.constant.ShiroConstants; +import com.playlet.common.utils.DateUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.system.domain.SysUserOnline; +import com.playlet.system.mapper.SysUserOnlineMapper; +import com.playlet.system.service.ISysUserOnlineService; + +/** + * 在线用户 服务层处理 + * + * @author ruoyi + */ +@Service +public class SysUserOnlineServiceImpl implements ISysUserOnlineService +{ + @Autowired + private SysUserOnlineMapper userOnlineDao; + + /** + * 通过会话序号查询信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + @Override + public SysUserOnline selectOnlineById(String sessionId) + { + return userOnlineDao.selectOnlineById(sessionId); + } + + /** + * 通过会话序号删除信息 + * + * @param sessionId 会话ID + * @return 在线用户信息 + */ + @Override + public void deleteOnlineById(String sessionId) + { + SysUserOnline userOnline = selectOnlineById(sessionId); + if (StringUtils.isNotNull(userOnline)) + { + userOnlineDao.deleteOnlineById(sessionId); + } + } + + /** + * 通过会话序号删除信息 + * + * @param sessions 会话ID集合 + * @return 在线用户信息 + */ + @Override + public void batchDeleteOnline(List sessions) + { + for (String sessionId : sessions) + { + SysUserOnline userOnline = selectOnlineById(sessionId); + if (StringUtils.isNotNull(userOnline)) + { + userOnlineDao.deleteOnlineById(sessionId); + } + } + } + + /** + * 保存会话信息 + * + * @param online 会话信息 + */ + @Override + public void saveOnline(SysUserOnline online) + { + userOnlineDao.saveOnline(online); + } + + /** + * 查询会话集合 + * + * @param userOnline 在线用户 + */ + @Override + public List selectUserOnlineList(SysUserOnline userOnline) + { + return userOnlineDao.selectUserOnlineList(userOnline); + } + + /** + * 强退用户 + * + * @param sessionId 会话ID + */ + @Override + public void forceLogout(String sessionId) + { + userOnlineDao.deleteOnlineById(sessionId); + } + + /** + * 清理用户缓存 + * + * @param loginName 登录名称 + * @param sessionId 会话ID + */ + @Override + public void removeUserCache(String loginName, String sessionId) + { + EhCacheManager ehCacheManager = SpringUtils.getBean(EhCacheManager.class); + Cache> cache = ehCacheManager.getCache(ShiroConstants.SYS_USERCACHE); + Deque deque = cache.get(loginName); + if (StringUtils.isEmpty(deque) || deque.size() == 0) + { + return; + } + deque.remove(sessionId); + } + + /** + * 查询会话集合 + * + * @param expiredDate 失效日期 + */ + @Override + public List selectOnlineByExpired(Date expiredDate) + { + String lastAccessTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, expiredDate); + return userOnlineDao.selectOnlineByExpired(lastAccessTime); + } +} diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysUserServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..a93e57f --- /dev/null +++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,554 @@ +package com.playlet.system.service.impl; + +import java.util.ArrayList; +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; +import com.playlet.common.annotation.DataScope; +import com.playlet.common.constant.UserConstants; +import com.playlet.common.core.domain.entity.SysRole; +import com.playlet.common.core.domain.entity.SysUser; +import com.playlet.common.core.text.Convert; +import com.playlet.common.exception.ServiceException; +import com.playlet.common.utils.ShiroUtils; +import com.playlet.common.utils.StringUtils; +import com.playlet.common.utils.bean.BeanValidators; +import com.playlet.common.utils.security.Md5Utils; +import com.playlet.common.utils.spring.SpringUtils; +import com.playlet.system.domain.SysPost; +import com.playlet.system.domain.SysUserPost; +import com.playlet.system.domain.SysUserRole; +import com.playlet.system.mapper.SysPostMapper; +import com.playlet.system.mapper.SysRoleMapper; +import com.playlet.system.mapper.SysUserMapper; +import com.playlet.system.mapper.SysUserPostMapper; +import com.playlet.system.mapper.SysUserRoleMapper; +import com.playlet.system.service.ISysConfigService; +import com.playlet.system.service.ISysUserService; + +/** + * 用户 业务层处理 + * + * @author ruoyi + */ +@Service +public class SysUserServiceImpl 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 SysUserPostMapper userPostMapper; + + @Autowired + private SysUserRoleMapper userRoleMapper; + + @Autowired + private ISysConfigService configService; + + @Autowired + protected Validator validator; + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectUserList(SysUser user) + { + return userMapper.selectUserList(user); + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectAllocatedList(SysUser user) + { + return userMapper.selectAllocatedList(user); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectUnallocatedList(SysUser user) + { + return userMapper.selectUnallocatedList(user); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByLoginName(String userName) + { + return userMapper.selectUserByLoginName(userName); + } + + /** + * 通过手机号码查询用户 + * + * @param phoneNumber 手机号码 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByPhoneNumber(String phoneNumber) + { + return userMapper.selectUserByPhoneNumber(phoneNumber); + } + + /** + * 通过邮箱查询用户 + * + * @param email 邮箱 + * @return 用户对象信息 + */ + @Override + public SysUser selectUserByEmail(String email) + { + return userMapper.selectUserByEmail(email); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUser selectUserById(Long userId) + { + return userMapper.selectUserById(userId); + } + + /** + * 通过用户ID查询用户和角色关联 + * + * @param userId 用户ID + * @return 用户和角色关联列表 + */ + @Override + public List selectUserRoleByUserId(Long userId) + { + return userRoleMapper.selectUserRoleByUserId(userId); + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional + public int deleteUserById(Long userId) + { + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 删除用户与岗位表 + userPostMapper.deleteUserPostByUserId(userId); + return userMapper.deleteUserById(userId); + } + + /** + * 批量删除用户信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + @Transactional + public int deleteUserByIds(String ids) + { + Long[] userIds = Convert.toLongArray(ids); + for (Long userId : userIds) + { + checkUserAllowed(new SysUser(userId)); + checkUserDataScope(userId); + } + // 删除用户与角色关联 + userRoleMapper.deleteUserRole(userIds); + // 删除用户与岗位关联 + userPostMapper.deleteUserPost(userIds); + return userMapper.deleteUserByIds(userIds); + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional + public int insertUser(SysUser user) + { + // 新增用户信息 + int rows = userMapper.insertUser(user); + // 新增用户岗位关联 + insertUserPost(user); + // 新增用户与角色管理 + insertUserRole(user.getUserId(), user.getRoleIds()); + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUser user) + { + user.setUserType(UserConstants.REGISTER_USER_TYPE); + return userMapper.insertUser(user) > 0; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional + public int updateUser(SysUser user) + { + Long userId = user.getUserId(); + // 删除用户与角色关联 + userRoleMapper.deleteUserRoleByUserId(userId); + // 新增用户与角色管理 + insertUserRole(user.getUserId(), user.getRoleIds()); + // 删除用户与岗位关联 + userPostMapper.deleteUserPostByUserId(userId); + // 新增用户与岗位管理 + insertUserPost(user); + return userMapper.updateUser(user); + } + + /** + * 修改用户个人详细信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int updateUserInfo(SysUser user) + { + return userMapper.updateUser(user); + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional + public void insertUserAuth(Long userId, Long[] roleIds) + { + userRoleMapper.deleteUserRoleByUserId(userId); + insertUserRole(userId, roleIds); + } + + /** + * 修改用户密码 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int resetUserPwd(SysUser user) + { + return updateUserInfo(user); + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + public void insertUserRole(Long userId, Long[] roleIds) + { + if (StringUtils.isNotNull(roleIds)) + { + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long roleId : roleIds) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + if (list.size() > 0) + { + userRoleMapper.batchUserRole(list); + } + } + } + + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + */ + public void insertUserPost(SysUser user) + { + Long[] posts = user.getPostIds(); + if (StringUtils.isNotNull(posts)) + { + // 新增用户与岗位管理 + List list = new ArrayList(); + for (Long postId : posts) + { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + list.add(up); + } + if (list.size() > 0) + { + userPostMapper.batchUserPost(list); + } + } + } + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkLoginNameUnique(SysUser user) + { + Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); + SysUser info = userMapper.checkLoginNameUnique(user.getLoginName()); + 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) && info.getUserId().longValue() != userId.longValue()) + { + 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(ShiroUtils.getUserId())) + { + SysUser user = new SysUser(); + user.setUserId(userId); + List users = SpringUtils.getAopProxy(this).selectUserList(user); + if (StringUtils.isEmpty(users)) + { + throw new ServiceException("没有权限访问用户数据!"); + } + } + } + + /** + * 查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserRoleGroup(Long userId) + { + List list = roleMapper.selectRolesByUserId(userId); + if (CollectionUtils.isEmpty(list)) + { + return StringUtils.EMPTY; + } + return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(",")); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserPostGroup(Long userId) + { + List list = postMapper.selectPostsByUserId(userId); + if (CollectionUtils.isEmpty(list)) + { + return StringUtils.EMPTY; + } + return list.stream().map(SysPost::getPostName).collect(Collectors.joining(",")); + } + + /** + * 导入用户数据 + * + * @param userList 用户数据列表 + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @param operName 操作用户 + * @return 结果 + */ + @Override + public String importUser(List 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.selectUserByLoginName(user.getLoginName()); + if (StringUtils.isNull(u)) + { + BeanValidators.validateWithException(validator, user); + user.setPassword(Md5Utils.hash(user.getLoginName() + password)); + user.setCreateBy(operName); + userMapper.insertUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getLoginName() + " 导入成功"); + } + 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("
" + successNum + "、账号 " + user.getLoginName() + " 更新成功"); + } + else + { + failureNum++; + failureMsg.append("
" + failureNum + "、账号 " + user.getLoginName() + " 已存在"); + } + } + catch (Exception e) + { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getLoginName() + " 导入失败:"; + 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(); + } + + /** + * 用户状态修改 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public int changeStatus(SysUser user) + { + return userMapper.updateUser(user); + } +} diff --git a/sql/quartz.sql b/sql/quartz.sql new file mode 100644 index 0000000..cee613b --- /dev/null +++ b/sql/quartz.sql @@ -0,0 +1,174 @@ +DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; +DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; +DROP TABLE IF EXISTS QRTZ_LOCKS; +DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; +DROP TABLE IF EXISTS QRTZ_CALENDARS; + +-- ---------------------------- +-- 1、存储每一个已配置的 jobDetail 的详细信息 +-- ---------------------------- +create table QRTZ_JOB_DETAILS ( + sched_name varchar(120) not null comment '调度名称', + job_name varchar(200) not null comment '任务名称', + job_group varchar(200) not null comment '任务组名', + description varchar(250) null comment '相关介绍', + job_class_name varchar(250) not null comment '执行任务类名称', + is_durable varchar(1) not null comment '是否持久化', + is_nonconcurrent varchar(1) not null comment '是否并发', + is_update_data varchar(1) not null comment '是否更新数据', + requests_recovery varchar(1) not null comment '是否接受恢复执行', + job_data blob null comment '存放持久化job对象', + primary key (sched_name, job_name, job_group) +) engine=innodb comment = '任务详细信息表'; + +-- ---------------------------- +-- 2、 存储已配置的 Trigger 的信息 +-- ---------------------------- +create table QRTZ_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment '触发器的名字', + trigger_group varchar(200) not null comment '触发器所属组的名字', + job_name varchar(200) not null comment 'qrtz_job_details表job_name的外键', + job_group varchar(200) not null comment 'qrtz_job_details表job_group的外键', + description varchar(250) null comment '相关介绍', + next_fire_time bigint(13) null comment '上一次触发时间(毫秒)', + prev_fire_time bigint(13) null comment '下一次触发时间(默认为-1表示不触发)', + priority integer null comment '优先级', + trigger_state varchar(16) not null comment '触发器状态', + trigger_type varchar(8) not null comment '触发器的类型', + start_time bigint(13) not null comment '开始时间', + end_time bigint(13) null comment '结束时间', + calendar_name varchar(200) null comment '日程表名称', + misfire_instr smallint(2) null comment '补偿执行的策略', + job_data blob null comment '存放持久化job对象', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, job_name, job_group) references QRTZ_JOB_DETAILS(sched_name, job_name, job_group) +) engine=innodb comment = '触发器详细信息表'; + +-- ---------------------------- +-- 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数 +-- ---------------------------- +create table QRTZ_SIMPLE_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + repeat_count bigint(7) not null comment '重复的次数统计', + repeat_interval bigint(12) not null comment '重复的间隔时间', + times_triggered bigint(10) not null comment '已经触发的次数', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = '简单触发器的信息表'; + +-- ---------------------------- +-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息 +-- ---------------------------- +create table QRTZ_CRON_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + cron_expression varchar(200) not null comment 'cron表达式', + time_zone_id varchar(80) comment '时区', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = 'Cron类型的触发器表'; + +-- ---------------------------- +-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候) +-- ---------------------------- +create table QRTZ_BLOB_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + blob_data blob null comment '存放持久化Trigger对象', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = 'Blob类型的触发器表'; + +-- ---------------------------- +-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围 +-- ---------------------------- +create table QRTZ_CALENDARS ( + sched_name varchar(120) not null comment '调度名称', + calendar_name varchar(200) not null comment '日历名称', + calendar blob not null comment '存放持久化calendar对象', + primary key (sched_name, calendar_name) +) engine=innodb comment = '日历信息表'; + +-- ---------------------------- +-- 7、 存储已暂停的 Trigger 组的信息 +-- ---------------------------- +create table QRTZ_PAUSED_TRIGGER_GRPS ( + sched_name varchar(120) not null comment '调度名称', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + primary key (sched_name, trigger_group) +) engine=innodb comment = '暂停的触发器表'; + +-- ---------------------------- +-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息 +-- ---------------------------- +create table QRTZ_FIRED_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + entry_id varchar(95) not null comment '调度器实例id', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + instance_name varchar(200) not null comment '调度器实例名', + fired_time bigint(13) not null comment '触发的时间', + sched_time bigint(13) not null comment '定时器制定的时间', + priority integer not null comment '优先级', + state varchar(16) not null comment '状态', + job_name varchar(200) null comment '任务名称', + job_group varchar(200) null comment '任务组名', + is_nonconcurrent varchar(1) null comment '是否并发', + requests_recovery varchar(1) null comment '是否接受恢复执行', + primary key (sched_name, entry_id) +) engine=innodb comment = '已触发的触发器表'; + +-- ---------------------------- +-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例 +-- ---------------------------- +create table QRTZ_SCHEDULER_STATE ( + sched_name varchar(120) not null comment '调度名称', + instance_name varchar(200) not null comment '实例名称', + last_checkin_time bigint(13) not null comment '上次检查时间', + checkin_interval bigint(13) not null comment '检查间隔时间', + primary key (sched_name, instance_name) +) engine=innodb comment = '调度器状态表'; + +-- ---------------------------- +-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁) +-- ---------------------------- +create table QRTZ_LOCKS ( + sched_name varchar(120) not null comment '调度名称', + lock_name varchar(40) not null comment '悲观锁名称', + primary key (sched_name, lock_name) +) engine=innodb comment = '存储的悲观锁信息表'; + +-- ---------------------------- +-- 11、 Quartz集群实现同步机制的行锁表 +-- ---------------------------- +create table QRTZ_SIMPROP_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + str_prop_1 varchar(512) null comment 'String类型的trigger的第一个参数', + str_prop_2 varchar(512) null comment 'String类型的trigger的第二个参数', + str_prop_3 varchar(512) null comment 'String类型的trigger的第三个参数', + int_prop_1 int null comment 'int类型的trigger的第一个参数', + int_prop_2 int null comment 'int类型的trigger的第二个参数', + long_prop_1 bigint null comment 'long类型的trigger的第一个参数', + long_prop_2 bigint null comment 'long类型的trigger的第二个参数', + dec_prop_1 numeric(13,4) null comment 'decimal类型的trigger的第一个参数', + dec_prop_2 numeric(13,4) null comment 'decimal类型的trigger的第二个参数', + bool_prop_1 varchar(1) null comment 'Boolean类型的trigger的第一个参数', + bool_prop_2 varchar(1) null comment 'Boolean类型的trigger的第二个参数', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = '同步机制的行锁表'; + +commit; \ No newline at end of file diff --git a/sql/ruoyi.html b/sql/ruoyi.html new file mode 100644 index 0000000..abd2596 --- /dev/null +++ b/sql/ruoyi.html @@ -0,0 +1,2890 @@ + + + + +RuoYi + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RuoYi + Move the mouse over tables & columns to read the comments. + + + + + + + Fk qrtz_blob_triggers_ibfk_1 +qrtz_blob_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group ) + + +sched_name,trigger_name,trigger_group + + + Fk qrtz_cron_triggers_ibfk_1 +qrtz_cron_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group ) + + +sched_name,trigger_name,trigger_group + + + Fk qrtz_simple_triggers_ibfk_1 +qrtz_simple_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group ) + + +sched_name,trigger_name,trigger_group + + + Fk qrtz_simprop_triggers_ibfk_1 +qrtz_simprop_triggers ref qrtz_triggers ( sched_name, trigger_name, trigger_group ) + + +sched_name,trigger_name,trigger_group + + + Fk qrtz_triggers_ibfk_1 +qrtz_triggers ref qrtz_job_details ( sched_name, job_name, job_group ) + + +sched_name,job_name,job_group + + + + + + + +qrtz_blob_triggersTable ry.qrtz_blob_triggers + Pk pk_qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) +sched_namesched_name +* varchar(120) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) +trigger_nametrigger_name +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) +trigger_grouptrigger_group +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + blob_datablob_data +blob +~ + + + + + + + +qrtz_calendarsTable ry.qrtz_calendars + Pk pk_qrtz_calendars ( sched_name, calendar_name ) +sched_namesched_name +* varchar(120) +t Pk pk_qrtz_calendars ( sched_name, calendar_name ) +calendar_namecalendar_name +* varchar(200) +t calendarcalendar +* blob +~ + + + + + + + +qrtz_cron_triggersTable ry.qrtz_cron_triggers + Pk pk_qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) +sched_namesched_name +* varchar(120) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) +trigger_nametrigger_name +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) +trigger_grouptrigger_group +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + cron_expressioncron_expression +* varchar(200) +t time_zone_idtime_zone_id +varchar(80) +t + + + + + + + +qrtz_job_detailsTable ry.qrtz_job_details + Pk pk_qrtz_job_details ( sched_name, job_name, job_group ) +sched_namesched_name +* varchar(120) +Referred by qrtz_triggers ( sched_name, job_name, job_group ) + Pk pk_qrtz_job_details ( sched_name, job_name, job_group ) +job_namejob_name +* varchar(200) +Referred by qrtz_triggers ( sched_name, job_name, job_group ) + Pk pk_qrtz_job_details ( sched_name, job_name, job_group ) +job_groupjob_group +* varchar(200) +Referred by qrtz_triggers ( sched_name, job_name, job_group ) + descriptiondescription +varchar(250) +t job_class_namejob_class_name +* varchar(250) +t is_durableis_durable +* varchar(1) +t is_nonconcurrentis_nonconcurrent +* varchar(1) +t is_update_datais_update_data +* varchar(1) +t requests_recoveryrequests_recovery +* varchar(1) +t job_datajob_data +blob +~ + + + + + + + +qrtz_locksTable ry.qrtz_locks + Pk pk_qrtz_locks ( sched_name, lock_name ) +sched_namesched_name +* varchar(120) +t Pk pk_qrtz_locks ( sched_name, lock_name ) +lock_namelock_name +* varchar(40) +t + + + + + + + +qrtz_scheduler_stateTable ry.qrtz_scheduler_state + Pk pk_qrtz_scheduler_state ( sched_name, instance_name ) +sched_namesched_name +* varchar(120) +t Pk pk_qrtz_scheduler_state ( sched_name, instance_name ) +instance_nameinstance_name +* varchar(200) +t last_checkin_timelast_checkin_time +* bigint +# checkin_intervalcheckin_interval +* bigint +# + + + + + + + +qrtz_simple_triggersTable ry.qrtz_simple_triggers + Pk pk_qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) +sched_namesched_name +* varchar(120) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) +trigger_nametrigger_name +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) +trigger_grouptrigger_group +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + repeat_countrepeat_count +* bigint +# repeat_intervalrepeat_interval +* bigint +# times_triggeredtimes_triggered +* bigint +# + + + + + + + +qrtz_simprop_triggersTable ry.qrtz_simprop_triggers + Pk pk_qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) +sched_namesched_name +* varchar(120) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) +trigger_nametrigger_name +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) +trigger_grouptrigger_group +* varchar(200) +References qrtz_triggers ( sched_name, trigger_name, trigger_group ) + str_prop_1str_prop_1 +varchar(512) +t str_prop_2str_prop_2 +varchar(512) +t str_prop_3str_prop_3 +varchar(512) +t int_prop_1int_prop_1 +int +# int_prop_2int_prop_2 +int +# long_prop_1long_prop_1 +bigint +# long_prop_2long_prop_2 +bigint +# dec_prop_1dec_prop_1 +decimal(13,4) +# dec_prop_2dec_prop_2 +decimal(13,4) +# bool_prop_1bool_prop_1 +varchar(1) +t bool_prop_2bool_prop_2 +varchar(1) +t + + + + + + + +qrtz_triggersTable ry.qrtz_triggers + Pk pk_qrtz_triggers ( sched_name, trigger_name, trigger_group ) sched_name ( sched_name, job_name, job_group ) +sched_namesched_name +* varchar(120) +References qrtz_job_details ( sched_name, job_name, job_group ) +Referred by qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_triggers ( sched_name, trigger_name, trigger_group ) +trigger_nametrigger_name +* varchar(200) +Referred by qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) + Pk pk_qrtz_triggers ( sched_name, trigger_name, trigger_group ) +trigger_grouptrigger_group +* varchar(200) +Referred by qrtz_blob_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_cron_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_simple_triggers ( sched_name, trigger_name, trigger_group ) +Referred by qrtz_simprop_triggers ( sched_name, trigger_name, trigger_group ) + sched_name ( sched_name, job_name, job_group ) +job_namejob_name +* varchar(200) +References qrtz_job_details ( sched_name, job_name, job_group ) + sched_name ( sched_name, job_name, job_group ) +job_groupjob_group +* varchar(200) +References qrtz_job_details ( sched_name, job_name, job_group ) + descriptiondescription +varchar(250) +t next_fire_timenext_fire_time +bigint +# prev_fire_timeprev_fire_time +bigint +# prioritypriority +int +# trigger_statetrigger_state +* varchar(16) +t trigger_typetrigger_type +* varchar(8) +t start_timestart_time +* bigint +# end_timeend_time +bigint +# calendar_namecalendar_name +varchar(200) +t misfire_instrmisfire_instr +smallint +# job_datajob_data +blob +~ + + + + + + + +sys_dict_dataTable ry.sys_dict_data + Pk pk_sys_dict_data ( dict_code ) +dict_codedict_code +* int +字典编码 +# dict_sortdict_sort +int default 0 +字典排序 +# dict_labeldict_label +varchar(100) default '' +字典标签 +t dict_valuedict_value +varchar(100) default '' +字典键值 +t dict_typedict_type +varchar(100) default '' +字典类型 +t statusstatus +int default 0 +状态(0正常 1禁用) +# create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d remarkremark +varchar(500) default '' +备注 +t + + + + + + + +sys_dict_typeTable ry.sys_dict_type + Pk pk_sys_dict_type ( dict_id ) +dict_iddict_id +* int +字典主键 +# dict_namedict_name +varchar(100) default '' +字典名称 +t Unq dict_type ( dict_type ) +dict_typedict_type +varchar(100) default '' +字典类型 +t statusstatus +int default 0 +状态(0正常 1禁用) +# create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d remarkremark +varchar(500) default '' +备注 +t + + + + + + + +sys_jobTable ry.sys_job + Pk pk_sys_job ( job_id, job_name, job_group ) +job_idjob_id +* int +任务ID +# Pk pk_sys_job ( job_id, job_name, job_group ) +job_namejob_name +* varchar(64) default '' +任务名称 +t Pk pk_sys_job ( job_id, job_name, job_group ) +job_groupjob_group +* varchar(64) default '' +任务组名 +t method_namemethod_name +varchar(500) default '' +任务方法 +t paramsparams +varchar(200) default '' +方法参数 +t cron_expressioncron_expression +varchar(255) default '' +cron执行表达式 +t statusstatus +int default 0 +状态(0正常 1暂停) +# create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d remarkremark +varchar(500) default '' +备注信息 +t + + + + + + + +sys_job_logTable ry.sys_job_log + Pk pk_sys_job_log ( job_log_id ) +job_log_idjob_log_id +* int +任务日志ID +# job_namejob_name +* varchar(64) +任务名称 +t job_groupjob_group +* varchar(64) +任务组名 +t method_namemethod_name +varchar(500) +任务方法 +t paramsparams +varchar(200) default '' +方法参数 +t job_messagejob_message +varchar(500) +日志信息 +t is_exceptionis_exception +int default 0 +是否异常 +# exception_infoexception_info +text +异常信息 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d + + + + + + + +sys_logininforTable ry.sys_logininfor + Pk pk_sys_logininfor ( info_id ) +info_idinfo_id +* int +访问ID +# login_namelogin_name +varchar(50) default '' +登录账号 +t ipaddripaddr +varchar(50) default '' +登录IP地址 +t browserbrowser +varchar(50) default '' +浏览器类型 +t osos +varchar(50) default '' +操作系统 +t statusstatus +int default 0 +登录状态 0成功 1失败 +# msgmsg +varchar(255) default '' +提示消息 +t login_timelogin_time +* timestamp default CURRENT_TIMESTAMP +访问时间 +d + + + + + + + +sys_menuTable ry.sys_menu + Pk pk_sys_menu ( menu_id ) +menu_idmenu_id +* int +菜单ID +# menu_namemenu_name +* varchar(50) +菜单名称 +t parent_idparent_id +int default 0 +父菜单ID +# order_numorder_num +int +显示顺序 +# urlurl +varchar(200) default '' +请求地址 +t menu_typemenu_type +char(1) default '' +类型:M目录,C菜单,F按钮 +c visiblevisible +int default 0 +菜单状态:0显示,1隐藏 +# permsperms +varchar(100) default '' +权限标识 +t iconicon +varchar(100) default '' +菜单图标 +t create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d remarkremark +varchar(500) default '' +备注 +t + + + + + + + +sys_oper_logTable ry.sys_oper_log + Pk pk_sys_oper_log ( oper_id ) +oper_idoper_id +* int +日志主键 +# titletitle +varchar(50) default '' +模块标题 +t actionaction +varchar(100) default '' +功能请求 +t methodmethod +varchar(100) default '' +方法名称 +t channelchannel +varchar(20) default '' +来源渠道 +t login_namelogin_name +varchar(50) default '' +登录账号 +t dept_namedept_name +varchar(50) default '' +部门名称 +t oper_urloper_url +varchar(255) default '' +请求URL +t oper_ipoper_ip +varchar(30) default '' +主机地址 +t oper_paramoper_param +varchar(255) default '' +请求参数 +t statusstatus +int default 0 +操作状态 0正常 1异常 +# error_msgerror_msg +varchar(2000) default '' +错误消息 +t oper_timeoper_time +* timestamp default CURRENT_TIMESTAMP +操作时间 +d + + + + + + + +sys_postTable ry.sys_post + Pk pk_sys_post ( post_id ) +post_idpost_id +* int +岗位ID +# post_codepost_code +* varchar(64) +岗位编码 +t post_namepost_name +* varchar(100) +岗位名称 +t post_sortpost_sort +* int +显示顺序 +# statusstatus +* int +状态(0正常 1停用) +# create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d remarkremark +varchar(500) default '' +备注 +t + + + + + + + +sys_roleTable ry.sys_role + Pk pk_sys_role ( role_id ) +role_idrole_id +* int +角色ID +# role_namerole_name +* varchar(30) +角色名称 +t role_keyrole_key +* varchar(100) +角色权限字符串 +t role_sortrole_sort +* int +显示顺序 +# statusstatus +int default 0 +角色状态:0正常,1禁用 +# create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d remarkremark +varchar(500) default '' +备注 +t + + + + + + + +sys_role_menuTable ry.sys_role_menu + Pk pk_sys_role_menu ( role_id, menu_id ) +role_idrole_id +* int +角色ID +# Pk pk_sys_role_menu ( role_id, menu_id ) +menu_idmenu_id +* int +菜单ID +# + + + + + + + +sys_userTable ry.sys_user + Pk pk_sys_user ( user_id ) +user_iduser_id +* int +用户ID +# dept_iddept_id +int +部门ID +# login_namelogin_name +varchar(30) default '' +登录账号 +t user_nameuser_name +varchar(30) default '' +用户昵称 +t emailemail +varchar(100) default '' +用户邮箱 +t phonenumberphonenumber +varchar(20) default '' +手机号码 +t passwordpassword +varchar(100) default '' +密码 +t saltsalt +varchar(100) default '' +盐加密 +t user_typeuser_type +char(1) default 'N' +类型:Y默认用户,N非默认用户 +c statusstatus +int default 0 +帐号状态:0正常,1禁用 +# refuse_desrefuse_des +varchar(500) default '' +拒绝登录描述 +t create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d + + + + + + + +sys_user_onlineTable ry.sys_user_online + Pk pk_sys_user_online ( sessionId ) +sessionIdsessionId +* varchar(50) default '' +用户会话id +t login_namelogin_name +varchar(50) default '' +登录账号 +t dept_namedept_name +varchar(50) default '' +部门名称 +t ipaddripaddr +varchar(50) default '' +登录IP地址 +t browserbrowser +varchar(50) default '' +浏览器类型 +t osos +varchar(50) default '' +操作系统 +t statusstatus +varchar(10) default '' +在线状态on_line在线off_line离线 +t start_timestampstart_timestamp +* timestamp default CURRENT_TIMESTAMP +session创建时间 +d last_access_timelast_access_time +* timestamp default '0000-00-00 00:00:00' +session最后访问时间 +d expire_timeexpire_time +int default 0 +超时时间,单位为分钟 +# + + + + + + + +sys_user_postTable ry.sys_user_post + Pk pk_sys_user_post ( user_id, post_id ) +user_iduser_id +* varchar(64) +用户ID +t Pk pk_sys_user_post ( user_id, post_id ) +post_idpost_id +* varchar(64) +岗位ID +t + + + + + + + +sys_user_roleTable ry.sys_user_role + Pk pk_sys_user_role ( user_id, role_id ) +user_iduser_id +* int +用户ID +# Pk pk_sys_user_role ( user_id, role_id ) +role_idrole_id +* int +角色ID +# + + + + + + + +sys_deptTable ry.sys_dept + Pk pk_sys_dept ( dept_id ) +dept_iddept_id +* int +部门id +# parent_idparent_id +int default 0 +父部门id +# dept_namedept_name +varchar(30) default '' +部门名称 +t order_numorder_num +int default 0 +显示顺序 +# leaderleader +varchar(20) default '' +负责人 +t phonephone +varchar(20) default '' +联系电话 +t emailemail +varchar(20) default '' +邮箱 +t statusstatus +int default 0 +部门状态:0正常,1停用 +# create_bycreate_by +varchar(64) default '' +创建者 +t create_timecreate_time +* timestamp default CURRENT_TIMESTAMP +创建时间 +d update_byupdate_by +varchar(64) default '' +更新者 +t update_timeupdate_time +* timestamp default '0000-00-00 00:00:00' +更新时间 +d + + + + + + + +qrtz_paused_trigger_grpsTable ry.qrtz_paused_trigger_grps + Pk pk_qrtz_paused_trigger_grps ( sched_name, trigger_group ) +sched_namesched_name +* varchar(120) +t Pk pk_qrtz_paused_trigger_grps ( sched_name, trigger_group ) +trigger_grouptrigger_group +* varchar(200) +t + + + + + + + +qrtz_fired_triggersTable ry.qrtz_fired_triggers + Pk pk_qrtz_fired_triggers ( sched_name, entry_id ) +sched_namesched_name +* varchar(120) +t Pk pk_qrtz_fired_triggers ( sched_name, entry_id ) +entry_identry_id +* varchar(95) +t trigger_nametrigger_name +* varchar(200) +t trigger_grouptrigger_group +* varchar(200) +t instance_nameinstance_name +* varchar(200) +t fired_timefired_time +* bigint +# sched_timesched_time +* bigint +# prioritypriority +* int +# statestate +* varchar(16) +t job_namejob_name +varchar(200) +t job_groupjob_group +varchar(200) +t is_nonconcurrentis_nonconcurrent +varchar(1) +t requests_recoveryrequests_recovery +varchar(1) +t +
+ + +

+

Table qrtz_blob_triggers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*trigger_name varchar( 200 )
*trigger_group varchar( 200 )
 blob_data blob
Indexes
pk_qrtz_blob_triggers ON sched_name, trigger_name, trigger_group
Foreign Keys
qrtz_blob_triggers_ibfk_1 ( sched_name, trigger_name, trigger_group ) ref qrtz_triggers (sched_name, trigger_name, trigger_group)
+ +

+

Table qrtz_calendars

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*calendar_name varchar( 200 )
*calendar blob
Indexes
pk_qrtz_calendars ON sched_name, calendar_name
+ +

+

Table qrtz_cron_triggers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*trigger_name varchar( 200 )
*trigger_group varchar( 200 )
*cron_expression varchar( 200 )
 time_zone_id varchar( 80 )
Indexes
pk_qrtz_cron_triggers ON sched_name, trigger_name, trigger_group
Foreign Keys
qrtz_cron_triggers_ibfk_1 ( sched_name, trigger_name, trigger_group ) ref qrtz_triggers (sched_name, trigger_name, trigger_group)
+ +

+

Table qrtz_fired_triggers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*entry_id varchar( 95 )
*trigger_name varchar( 200 )
*trigger_group varchar( 200 )
*instance_name varchar( 200 )
*fired_time bigint
*sched_time bigint
*priority int
*state varchar( 16 )
 job_name varchar( 200 )
 job_group varchar( 200 )
 is_nonconcurrent varchar( 1 )
 requests_recovery varchar( 1 )
Indexes
pk_qrtz_fired_triggers ON sched_name, entry_id
+ +

+

Table qrtz_job_details

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*job_name varchar( 200 )
*job_group varchar( 200 )
 description varchar( 250 )
*job_class_name varchar( 250 )
*is_durable varchar( 1 )
*is_nonconcurrent varchar( 1 )
*is_update_data varchar( 1 )
*requests_recovery varchar( 1 )
 job_data blob
Indexes
pk_qrtz_job_details ON sched_name, job_name, job_group
+ +

+

Table qrtz_locks

+ + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*lock_name varchar( 40 )
Indexes
pk_qrtz_locks ON sched_name, lock_name
+ +

+

Table qrtz_paused_trigger_grps

+ + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*trigger_group varchar( 200 )
Indexes
pk_qrtz_paused_trigger_grps ON sched_name, trigger_group
+ +

+

Table qrtz_scheduler_state

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*instance_name varchar( 200 )
*last_checkin_time bigint
*checkin_interval bigint
Indexes
pk_qrtz_scheduler_state ON sched_name, instance_name
+ +

+

Table qrtz_simple_triggers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*trigger_name varchar( 200 )
*trigger_group varchar( 200 )
*repeat_count bigint
*repeat_interval bigint
*times_triggered bigint
Indexes
pk_qrtz_simple_triggers ON sched_name, trigger_name, trigger_group
Foreign Keys
qrtz_simple_triggers_ibfk_1 ( sched_name, trigger_name, trigger_group ) ref qrtz_triggers (sched_name, trigger_name, trigger_group)
+ +

+

Table qrtz_simprop_triggers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*trigger_name varchar( 200 )
*trigger_group varchar( 200 )
 str_prop_1 varchar( 512 )
 str_prop_2 varchar( 512 )
 str_prop_3 varchar( 512 )
 int_prop_1 int
 int_prop_2 int
 long_prop_1 bigint
 long_prop_2 bigint
 dec_prop_1 decimal( 13, 4 )
 dec_prop_2 decimal( 13, 4 )
 bool_prop_1 varchar( 1 )
 bool_prop_2 varchar( 1 )
Indexes
pk_qrtz_simprop_triggers ON sched_name, trigger_name, trigger_group
Foreign Keys
qrtz_simprop_triggers_ibfk_1 ( sched_name, trigger_name, trigger_group ) ref qrtz_triggers (sched_name, trigger_name, trigger_group)
+ +

+

Table qrtz_triggers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sched_name varchar( 120 )
*trigger_name varchar( 200 )
*trigger_group varchar( 200 )
*job_name varchar( 200 )
*job_group varchar( 200 )
 description varchar( 250 )
 next_fire_time bigint
 prev_fire_time bigint
 priority int
*trigger_state varchar( 16 )
*trigger_type varchar( 8 )
*start_time bigint
 end_time bigint
 calendar_name varchar( 200 )
 misfire_instr smallint
 job_data blob
Indexes
pk_qrtz_triggers ON sched_name, trigger_name, trigger_group
sched_name ON sched_name, job_name, job_group
Foreign Keys
qrtz_triggers_ibfk_1 ( sched_name, job_name, job_group ) ref qrtz_job_details (sched_name, job_name, job_group)
+ +

+

Table sys_dept

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*dept_id int AUTOINCREMENT 部门id
 parent_id int DEFAULT 0 父部门id
 dept_name varchar( 30 ) DEFAULT '' 部门名称
 order_num int DEFAULT 0 显示顺序
 leader varchar( 20 ) DEFAULT '' 负责人
 phone varchar( 20 ) DEFAULT '' 联系电话
 email varchar( 20 ) DEFAULT '' 邮箱
 status int DEFAULT 0 部门状态:0正常,1停用
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
Indexes
pk_sys_dept ON dept_id
+ +

+

Table sys_dict_data

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*dict_code int AUTOINCREMENT 字典编码
 dict_sort int DEFAULT 0 字典排序
 dict_label varchar( 100 ) DEFAULT '' 字典标签
 dict_value varchar( 100 ) DEFAULT '' 字典键值
 dict_type varchar( 100 ) DEFAULT '' 字典类型
 status int DEFAULT 0 状态(0正常 1禁用)
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
 remark varchar( 500 ) DEFAULT '' 备注
Indexes
pk_sys_dict_data ON dict_code
+ +

+

Table sys_dict_type

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*dict_id int AUTOINCREMENT 字典主键
 dict_name varchar( 100 ) DEFAULT '' 字典名称
dict_type varchar( 100 ) DEFAULT '' 字典类型
 status int DEFAULT 0 状态(0正常 1禁用)
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
 remark varchar( 500 ) DEFAULT '' 备注
Indexes
pk_sys_dict_type ON dict_id
dict_type ON dict_type
+ +

+

Table sys_job

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*job_id int AUTOINCREMENT 任务ID
*job_name varchar( 64 ) DEFAULT '' 任务名称
*job_group varchar( 64 ) DEFAULT '' 任务组名
 method_name varchar( 500 ) DEFAULT '' 任务方法
 params varchar( 200 ) DEFAULT '' 方法参数
 cron_expression varchar( 255 ) DEFAULT '' cron执行表达式
 status int DEFAULT 0 状态(0正常 1暂停)
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
 remark varchar( 500 ) DEFAULT '' 备注信息
Indexes
pk_sys_job ON job_id, job_name, job_group
+ +

+

Table sys_job_log

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*job_log_id int AUTOINCREMENT 任务日志ID
*job_name varchar( 64 ) 任务名称
*job_group varchar( 64 ) 任务组名
 method_name varchar( 500 ) 任务方法
 params varchar( 200 ) DEFAULT '' 方法参数
 job_message varchar( 500 ) 日志信息
 is_exception int DEFAULT 0 是否异常
 exception_info text 异常信息
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
Indexes
pk_sys_job_log ON job_log_id
+ +

+

Table sys_logininfor

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*info_id int AUTOINCREMENT 访问ID
 login_name varchar( 50 ) DEFAULT '' 登录账号
 ipaddr varchar( 50 ) DEFAULT '' 登录IP地址
 browser varchar( 50 ) DEFAULT '' 浏览器类型
 os varchar( 50 ) DEFAULT '' 操作系统
 status int DEFAULT 0 登录状态 0成功 1失败
 msg varchar( 255 ) DEFAULT '' 提示消息
*login_time timestamp DEFAULT CURRENT_TIMESTAMP 访问时间
Indexes
pk_sys_logininfor ON info_id
+ +

+

Table sys_menu

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*menu_id int AUTOINCREMENT 菜单ID
*menu_name varchar( 50 ) 菜单名称
 parent_id int DEFAULT 0 父菜单ID
 order_num int 显示顺序
 url varchar( 200 ) DEFAULT '' 请求地址
 menu_type char( 1 ) DEFAULT '' 类型:M目录,C菜单,F按钮
 visible int DEFAULT 0 菜单状态:0显示,1隐藏
 perms varchar( 100 ) DEFAULT '' 权限标识
 icon varchar( 100 ) DEFAULT '' 菜单图标
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
 remark varchar( 500 ) DEFAULT '' 备注
Indexes
pk_sys_menu ON menu_id
+ +

+

Table sys_oper_log

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*oper_id int AUTOINCREMENT 日志主键
 title varchar( 50 ) DEFAULT '' 模块标题
 action varchar( 100 ) DEFAULT '' 功能请求
 method varchar( 100 ) DEFAULT '' 方法名称
 channel varchar( 20 ) DEFAULT '' 来源渠道
 login_name varchar( 50 ) DEFAULT '' 登录账号
 dept_name varchar( 50 ) DEFAULT '' 部门名称
 oper_url varchar( 255 ) DEFAULT '' 请求URL
 oper_ip varchar( 30 ) DEFAULT '' 主机地址
 oper_param varchar( 255 ) DEFAULT '' 请求参数
 status int DEFAULT 0 操作状态 0正常 1异常
 error_msg varchar( 2000 ) DEFAULT '' 错误消息
*oper_time timestamp DEFAULT CURRENT_TIMESTAMP 操作时间
Indexes
pk_sys_oper_log ON oper_id
+ +

+

Table sys_post

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*post_id int AUTOINCREMENT 岗位ID
*post_code varchar( 64 ) 岗位编码
*post_name varchar( 100 ) 岗位名称
*post_sort int 显示顺序
*status int 状态(0正常 1停用)
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
 remark varchar( 500 ) DEFAULT '' 备注
Indexes
pk_sys_post ON post_id
+ +

+

Table sys_role

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*role_id int AUTOINCREMENT 角色ID
*role_name varchar( 30 ) 角色名称
*role_key varchar( 100 ) 角色权限字符串
*role_sort int 显示顺序
 status int DEFAULT 0 角色状态:0正常,1禁用
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
 remark varchar( 500 ) DEFAULT '' 备注
Indexes
pk_sys_role ON role_id
+ +

+

Table sys_role_menu

+ + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*role_id int 角色ID
*menu_id int 菜单ID
Indexes
pk_sys_role_menu ON role_id, menu_id
+ +

+

Table sys_user

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*user_id int AUTOINCREMENT 用户ID
 dept_id int 部门ID
 login_name varchar( 30 ) DEFAULT '' 登录账号
 user_name varchar( 30 ) DEFAULT '' 用户昵称
 email varchar( 100 ) DEFAULT '' 用户邮箱
 phonenumber varchar( 20 ) DEFAULT '' 手机号码
 password varchar( 100 ) DEFAULT '' 密码
 salt varchar( 100 ) DEFAULT '' 盐加密
 user_type char( 1 ) DEFAULT 'N' 类型:Y默认用户,N非默认用户
 status int DEFAULT 0 帐号状态:0正常,1禁用
 refuse_des varchar( 500 ) DEFAULT '' 拒绝登录描述
 create_by varchar( 64 ) DEFAULT '' 创建者
*create_time timestamp DEFAULT CURRENT_TIMESTAMP 创建时间
 update_by varchar( 64 ) DEFAULT '' 更新者
*update_time timestamp DEFAULT '0000-00-00 00:00:00' 更新时间
Indexes
pk_sys_user ON user_id
+ +

+

Table sys_user_online

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*sessionId varchar( 50 ) DEFAULT '' 用户会话id
 login_name varchar( 50 ) DEFAULT '' 登录账号
 dept_name varchar( 50 ) DEFAULT '' 部门名称
 ipaddr varchar( 50 ) DEFAULT '' 登录IP地址
 browser varchar( 50 ) DEFAULT '' 浏览器类型
 os varchar( 50 ) DEFAULT '' 操作系统
 status varchar( 10 ) DEFAULT '' 在线状态on_line在线off_line离线
*start_timestsamp timestamp DEFAULT CURRENT_TIMESTAMP session创建时间
*last_access_time timestamp DEFAULT '0000-00-00 00:00:00' session最后访问时间
 expire_time int DEFAULT 0 超时时间,单位为分钟
Indexes
pk_sys_user_online ON sessionId
+ +

+

Table sys_user_post

+ + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*user_id varchar( 64 ) 用户ID
*post_id varchar( 64 ) 岗位ID
Indexes
pk_sys_user_post ON user_id, post_id
+ +

+

Table sys_user_role

+ + + + + + + + + + + + + + + + + + + + + + +
IndexesField NameData TypeDescription
*user_id int 用户ID
*role_id int 角色ID
Indexes
pk_sys_user_role ON user_id, role_id
+ +

Powered by DbSchema

\ No newline at end of file diff --git a/sql/ruoyi.pdm b/sql/ruoyi.pdm new file mode 100644 index 0000000..78d8504 --- /dev/null +++ b/sql/ruoyi.pdm @@ -0,0 +1,4851 @@ + + + + + + + + + +21C20947-ED50-4632-B638-DC1A02BD948A +ruoyi +ruoyi +1524449337 +Administrator +1538297587 +admin +[FolderOptions] + +[FolderOptions\Physical Objects] +GenerationCheckModel=Yes +GenerationPath= +GenerationOptions= +GenerationTasks= +GenerationTargets= +GenerationSelections= +RevPkey=Yes +RevFkey=Yes +RevAkey=Yes +RevCheck=Yes +RevIndx=Yes +RevOpts=Yes +RevViewAsTabl=No +RevViewOpts=Yes +RevSystAsTabl=Yes +RevTablPerm=No +RevViewPerm=No +RevProcPerm=No +RevDbpkPerm=No +RevSqncPerm=No +RevAdtPerm=No +RevUserPriv=No +RevUserOpts=No +RevGrpePriv=No +RevRolePriv=No +RevDtbsOpts=Yes +RevDtbsPerm=No +RevViewIndx=Yes +RevJidxOpts=Yes +RevStats=No +RevTspcPerm=No +RevCaseSensitive=No +GenTrgrStdMsg=Yes +GenTrgrMsgTab= +GenTrgrMsgNo= +GenTrgrMsgTxt= +TrgrPreserve=No +TrgrIns=Yes +TrgrUpd=Yes +TrgrDel=Yes +TrgrC2Ins=Yes +TrgrC2Upd=Yes +TrgrC3=Yes +TrgrC4=Yes +TrgrC5=Yes +TrgrC6=Yes +TrgrC7=Yes +TrgrC8=Yes +TrgrC9=Yes +TrgrC10=Yes +TrgrC11=Yes +TrgrC1=Yes +TrgrC12Ins=Yes +TrgrC12Upd=Yes +TrgrC13=Yes +UpdateTableStatistics=Yes +UpdateColumnStatistics=Yes + +[FolderOptions\Physical Objects\Database Generation] +GenScriptName=orders.sql +GenScriptName0=orders.sql +GenScriptName1=studentsystem.sql +GenScriptName2=NetCTOSS.sql +GenScriptName3=product.sql +GenScriptName4=voteSystem.sql +GenScriptName5=.sql +GenScriptName6=enterpriseManagement.sql +GenScriptName7=crebas.sql +GenScriptName8= +GenScriptName9= +GenPathName=C:\Users\Administrator\Desktop\ +GenSingleFile=Yes +GenODBC=No +GenCheckModel=Yes +GenScriptPrev=Yes +GenArchiveModel=No +GenUseSync=No +GenSyncChoice=0 +GenSyncArch= +GenSyncRmg=0 + +[FolderOptions\Physical Objects\Database Generation\Format] +GenScriptTitle=Yes +GenScriptNamLabl=No +GenScriptQDtbs=No +GenScriptQOwnr=Yes +GenScriptCase=0 +GenScriptEncoding=ANSI +GenScriptNAcct=No +IdentifierDelimiter=" + +[FolderOptions\Physical Objects\Database Generation\Database] +Create=Yes +Open=Yes +Close=Yes +Drop=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\Database\Create] +Physical Options=Yes +Header=Yes +Footer=Yes + +[FolderOptions\Physical Objects\Database Generation\Tablespace] +Create=Yes +Drop=Yes +Comment=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\Tablespace\Create] +Header=Yes +Footer=Yes + +[FolderOptions\Physical Objects\Database Generation\Storage] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\User] +Create=Yes +Grant=Yes +Drop=Yes +Comment=Yes +Privilege=No + +[FolderOptions\Physical Objects\Database Generation\User\Create] +Physical Options=No + +[FolderOptions\Physical Objects\Database Generation\Group] +Create=Yes +Drop=Yes +Comment=Yes +Privilege=No + +[FolderOptions\Physical Objects\Database Generation\Role] +Create=Yes +Drop=Yes +Privilege=No + +[FolderOptions\Physical Objects\Database Generation\UserDefinedDataType] +Create=Yes +Comment=Yes +Drop=Yes + +[FolderOptions\Physical Objects\Database Generation\UserDefinedDataType\Create] +Default value=Yes +Check=Yes + +[FolderOptions\Physical Objects\Database Generation\AbstractDataType] +Create=Yes +Header=Yes +Footer=Yes +Drop=Yes +Comment=Yes +Install JAVA class=Yes +Remove JAVA class=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\Rule] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Default] +Create=Yes +Comment=Yes +Drop=Yes + +[FolderOptions\Physical Objects\Database Generation\Sequence] +Create=Yes +Drop=Yes +Comment=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\Table&&Column] + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table] +Create=Yes +Drop=Yes +Comment=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table\Create] +Check=Yes +Physical Options=Yes +Header=Yes +Footer=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table\Create\Check] +Constraint declaration=No + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Column] +User datatype=No +Default value=Yes +Check=Yes +Physical Options=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Column\Check] +Constraint declaration=No + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key] + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Primary key] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Primary key\Create] +Constraint declaration=No +Physical Options=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Alternate key] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Alternate key\Create] +Constraint declaration=No +Physical Options=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Foreign key] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Foreign key\Create] +Constraint declaration=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index\Create] +Constraint declaration=Yes +Physical Options=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index\Filter] +Primary key=No +Foreign key=No +Alternate key=No +Cluster=Yes +Other=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Trigger] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Table&&Column\Trigger\Filter] +For insert=Yes +For update=Yes +For delete=Yes +For other=Yes + +[FolderOptions\Physical Objects\Database Generation\View] +Create=Yes +Drop=Yes +Comment=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\View\Create] +Force Column list=No +Physical Options=Yes +Header=Yes +Footer=Yes + +[FolderOptions\Physical Objects\Database Generation\View\ViewColumn] +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\View\ViewIndex] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\View\ViewIndex\Create] +Physical Options=Yes + +[FolderOptions\Physical Objects\Database Generation\View\ViewIndex\Filter] +Cluster=Yes +Other=Yes + +[FolderOptions\Physical Objects\Database Generation\View\Trigger] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\View\Trigger\Filter] +For insert=Yes +For update=Yes +For delete=Yes +For other=Yes + +[FolderOptions\Physical Objects\Database Generation\DBMSTrigger] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Synonym] +Create=Yes +Drop=Yes + +[FolderOptions\Physical Objects\Database Generation\Synonym\Filter] +Table=Yes +View=Yes +Proc=Yes +Synonym=Yes +Database Package=Yes +Sequence=Yes + +[FolderOptions\Physical Objects\Database Generation\JoinIndex] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\JoinIndex\Create] +Physical Options=Yes +Header=Yes +Footer=Yes + +[FolderOptions\Physical Objects\Database Generation\Procedure] +Create=Yes +Drop=Yes +Comment=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\Procedure\Create] +Header=Yes +Footer=Yes + +[FolderOptions\Physical Objects\Database Generation\DatabasePackage] +Create=Yes +Drop=Yes +Permission=No + +[FolderOptions\Physical Objects\Database Generation\WebService] +Create=Yes +Drop=Yes +Comment=Yes + +[FolderOptions\Physical Objects\Database Generation\Dimension] +Create=Yes +Drop=Yes + +[FolderOptions\Physical Objects\Database Generation\Synchronization] +GenBackupTabl=1 +GenKeepBackTabl=1 +GenTmpTablDrop=No +GenKeepTablOpts=No + +[FolderOptions\Physical Objects\Test Data] +GenDataPathName= +GenDataSinglefile=Yes +GenDataScriptName=testdata +GenDataScriptName0= +GenDataScriptName1= +GenDataScriptName2= +GenDataScriptName3= +GenDataScriptName4= +GenDataScriptName5= +GenDataScriptName6= +GenDataScriptName7= +GenDataScriptName8= +GenDataScriptName9= +GenDataOdbc=0 +GenDataDelOld=No +GenDataTitle=No +GenDataDefNumRows=20 +GenDataCommit=0 +GenDataPacket=0 +GenDataOwner=No +GenDataProfNumb= +GenDataProfChar= +GenDataProfDate= +GenDataCSVSeparator=, +GenDataFileFormat=CSV +GenDataUseWizard=No + +[FolderOptions\Pdm] +IndxIQName=%COLUMN%_%INDEXTYPE% +IndxPK=Yes +IndxFK=Yes +IndxAK=Yes +IndxPKName=%TABLE%_PK +IndxFKName=%REFR%_FK +IndxAKName=%AKEY%_AK +IndxPreserve=No +IndxThreshold=0 +IndxStats=No +RefrPreserve=No +JidxPreserve=No +RbldMultiFact=Yes +RbldMultiDim=Yes +RbldMultiJidx=Yes +CubePreserve=No +TablStProcPreserve=No +ProcDepPreserve=Yes +TrgrDepPreserve=Yes +CubeScriptPath= +CubeScriptCase=0 +CubeScriptEncoding=ANSI +CubeScriptNacct=No +CubeScriptHeader=No +CubeScriptExt=csv +CubeScriptExt0=txt +CubeScriptExt1= +CubeScriptExt2= +CubeScriptSep=, +CubeScriptDeli=" +DfltDomnName=D_%.U:VALUE% +DfltColnName=D_%.U:VALUE% +DfltReuse=Yes +DfltDrop=Yes +[ModelOptions] + +[ModelOptions\Physical Objects] +CaseSensitive=No +DisplayName=Yes +EnableTrans=No +EnableRequirements=No +DefaultDttp= +IgnoreOwner=No +RebuildTrigger=Yes +RefrUnique=No +RefrAutoMigrate=Yes +RefrMigrateReuse=Yes +RefrMigrateDomain=Yes +RefrMigrateCheck=Yes +RefrMigrateRule=Yes +RefrMigrateExtd=No +RefrMigrDefaultLink=No +RefrDfltImpl=D +RefrPrgtColn=No +RefrMigrateToEnd=No +RebuildTriggerDep=No +ColnFKName=%.3:PARENT%_%COLUMN% +ColnFKNameUse=No +DomnCopyDttp=Yes +DomnCopyChck=No +DomnCopyRule=No +DomnCopyMand=No +DomnCopyExtd=No +DomnCopyProf=No +Notation=0 +DomnDefaultMandatory=No +ColnDefaultMandatory=No +TablDefaultOwner= +ViewDefaultOwner= +TrgrDefaultOwnerTabl= +TrgrDefaultOwnerView= +IdxDefaultOwnerTabl= +IdxDefaultOwnerView= +JdxDefaultOwner= +DBPackDefaultOwner= +SeqDefaultOwner= +ProcDefaultOwner= +DBMSTrgrDefaultOwner= +Currency=USD +RefrDeleteConstraint=1 +RefrUpdateConstraint=1 +RefrParentMandatory=No +RefrParentChangeAllow=Yes +RefrCheckOnCommit=No + +[ModelOptions\Physical Objects\NamingOptionsTemplates] + +[ModelOptions\Physical Objects\ClssNamingOptions] + +[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG] + +[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN] + +[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\TABL] + +[ModelOptions\Physical Objects\ClssNamingOptions\TABL\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\TABL\Code] +Template= +MaxLen=64 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\COLN] + +[ModelOptions\Physical Objects\ClssNamingOptions\COLN\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\COLN\Code] +Template= +MaxLen=64 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\INDX] + +[ModelOptions\Physical Objects\ClssNamingOptions\INDX\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\INDX\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\REFR] + +[ModelOptions\Physical Objects\ClssNamingOptions\REFR\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\REFR\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\VREF] + +[ModelOptions\Physical Objects\ClssNamingOptions\VREF\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\VREF\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\VIEW] + +[ModelOptions\Physical Objects\ClssNamingOptions\VIEW\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\VIEW\Code] +Template= +MaxLen=64 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC] + +[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV] + +[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV\Code] +Template= +MaxLen=254 +Case=M +ValidChar='a'-'z','A'-'Z','0'-'9',"/-_.!~*'()" +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP] + +[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP\Code] +Template= +MaxLen=254 +Case=M +ValidChar='a'-'z','A'-'Z','0'-'9',"/-_.!~*'()" +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM] + +[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FACT] + +[ModelOptions\Physical Objects\ClssNamingOptions\FACT\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FACT\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\DIMN] + +[ModelOptions\Physical Objects\ClssNamingOptions\DIMN\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\DIMN\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\CUBE] + +[ModelOptions\Physical Objects\ClssNamingOptions\CUBE\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\CUBE\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\MEAS] + +[ModelOptions\Physical Objects\ClssNamingOptions\MEAS\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\MEAS\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\DATTR] + +[ModelOptions\Physical Objects\ClssNamingOptions\DATTR\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\DATTR\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FILO] + +[ModelOptions\Physical Objects\ClssNamingOptions\FILO\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FILO\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ] + +[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK] + +[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass] + +[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass\Name] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass\Code] +Template= +MaxLen=254 +Case=M +ValidChar= +InvldChar= +AllValid=Yes +NoAccent=No +DefaultChar= +Script= +ConvTable= +ConvTablePath=%_HOME%\Resource Files\Conversion Tables + +[ModelOptions\Connection] + +[ModelOptions\Pdm] + +[ModelOptions\Generate] + +[ModelOptions\Generate\Pdm] +RRMapping=No + +[ModelOptions\Generate\Cdm] +CheckModel=Yes +SaveLinks=Yes +NameToCode=No +Notation=2 + +[ModelOptions\Generate\Oom] +CheckModel=Yes +SaveLinks=Yes +ORMapping=No +NameToCode=Yes +ClassPrefix= + +[ModelOptions\Generate\Xsm] +CheckModel=Yes +SaveLinks=Yes +ORMapping=No +NameToCode=No + +[ModelOptions\Generate\Ldm] +CheckModel=Yes +SaveLinks=Yes +NameToCode=No + +[ModelOptions\Default Opts] + +[ModelOptions\Default Opts\TABL] +PhysOpts= + +[ModelOptions\Default Opts\COLN] +PhysOpts= + +[ModelOptions\Default Opts\INDX] +PhysOpts= + +[ModelOptions\Default Opts\AKEY] +PhysOpts= + +[ModelOptions\Default Opts\PKEY] +PhysOpts= + +[ModelOptions\Default Opts\STOR] +PhysOpts= + +[ModelOptions\Default Opts\TSPC] +PhysOpts= + +[ModelOptions\Default Opts\SQNC] +PhysOpts= + +[ModelOptions\Default Opts\DTBS] +PhysOpts= + +[ModelOptions\Default Opts\USER] +PhysOpts= + +[ModelOptions\Default Opts\JIDX] +PhysOpts= + + +AFAD9ECF-F417-4FCE-BEA4-884857D4C1A9 +MySQL 5.0 +MYSQL50 +1524449337 +Administrator +1524449337 +Administrator + +F4F16ECD-F2F1-4006-AF6F-638D5C65F35E +4BA9F647-DAB1-11D1-9944-006097355D9B + + + + +B6C2C4A4-6A8A-41F3-909D-C7B514E1EAE2 +PhysicalDiagram_1 +PhysicalDiagram_1 +1524449325 +Administrator +1538297386 +admin +[DisplayPreferences] + +[DisplayPreferences\PDM] + +[DisplayPreferences\General] +Adjust to text=Yes +Snap Grid=No +Constrain Labels=Yes +Display Grid=No +Show Page Delimiter=Yes +Grid size=0 +Graphic unit=2 +Window color=255, 255, 255 +Background image= +Background mode=8 +Watermark image= +Watermark mode=8 +Show watermark on screen=No +Gradient mode=0 +Gradient end color=255, 255, 255 +Show Swimlane=No +SwimlaneVert=Yes +TreeVert=No +CompDark=0 + +[DisplayPreferences\Object] +Mode=0 +Trunc Length=80 +Word Length=80 +Word Text=!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~ +Shortcut IntIcon=Yes +Shortcut IntLoct=Yes +Shortcut IntFullPath=No +Shortcut IntLastPackage=Yes +Shortcut ExtIcon=Yes +Shortcut ExtLoct=No +Shortcut ExtFullPath=No +Shortcut ExtLastPackage=Yes +Shortcut ExtIncludeModl=Yes +EObjShowStrn=Yes +ExtendedObject.Comment=No +ExtendedObject.IconPicture=No +ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> +ELnkShowStrn=Yes +ELnkShowName=Yes +ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> +FileObject.Stereotype=No +FileObject.DisplayName=Yes +FileObject.LocationOrName=No +FileObject.IconPicture=No +FileObject.IconMode=Yes +FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> +PckgShowStrn=Yes +Package.Comment=No +Package.IconPicture=No +Package_SymbolLayout= +Display Model Version=Yes +Table.Stereotype=Yes +Table.DisplayName=Yes +Table.OwnerDisplayName=No +Table.Columns=Yes +Table.Columns._Filter=""PDMCOLNALL +Table.Columns._Columns=Stereotype DataType KeyIndicator +Table.Columns._Limit=-5 +Table.Keys=No +Table.Keys._Columns=Stereotype Indicator +Table.Indexes=No +Table.Indexes._Columns=Stereotype +Table.Triggers=No +Table.Triggers._Columns=Stereotype +Table.Comment=No +Table.IconPicture=No +Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;PRIM \&quot;TRUE\&quot; TRUE&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;KEYS \&quot;TRUE\&quot; TRUE&quot;" HasLimit="Yes" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> +View.Stereotype=Yes +View.DisplayName=Yes +View.OwnerDisplayName=No +View.Columns=Yes +View.Columns._Columns=DisplayName +View.Columns._Limit=-5 +View.TemporaryVTables=Yes +View.Indexes=No +View.Comment=No +View.IconPicture=No +View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> +Procedure.Stereotype=No +Procedure.DisplayName=Yes +Procedure.OwnerDisplayName=No +Procedure.Comment=No +Procedure.IconPicture=No +Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> +Reference.Cardinality=No +Reference.ImplementationType=No +Reference.ChildRole=Yes +Reference.Stereotype=Yes +Reference.DisplayName=No +Reference.ForeignKeyConstraintName=Yes +Reference.JoinExpression=No +Reference.Integrity=No +Reference.ParentRole=Yes +Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> +ViewReference.ChildRole=Yes +ViewReference.Stereotype=Yes +ViewReference.DisplayName=No +ViewReference.JoinExpression=No +ViewReference.ParentRole=Yes +ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> +File Location=No +PckgStrn=Yes +ColnMode=0 +ColnMax=5 +TablOwnr=No +ColnDttp=Yes +ColnDomn=No +ColnShowDomn=No +ColnKey=Yes +ColnIndx=No +ColnMand=No +ColnStrn=Yes +VColName=Yes +VColExpr=No +VColDttp=No +VColIndx=No +VColCMod=0 +VColCMax=5 +ProcOwnr=No +KeyStrn=Yes +IndxStrn=Yes +TrgrStrn=Yes + +[DisplayPreferences\Symbol] + +[DisplayPreferences\Symbol\FRMEOBJ] +STRNFont=新宋体,8,N +STRNFont color=0, 0, 0 +DISPNAMEFont=新宋体,8,N +DISPNAMEFont color=0, 0, 0 +LABLFont=新宋体,8,N +LABLFont color=0, 0, 0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Width=6000 +Height=2000 +Brush color=255 255 255 +Fill Color=Yes +Brush style=6 +Brush bitmap mode=12 +Brush gradient mode=64 +Brush gradient color=192 192 192 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 255 128 128 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\FRMELNK] +CENTERFont=新宋体,8,N +CENTERFont color=0, 0, 0 +Line style=0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Brush color=255 255 255 +Fill Color=Yes +Brush style=1 +Brush bitmap mode=12 +Brush gradient mode=0 +Brush gradient color=118 118 118 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 128 128 255 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\FILO] +OBJSTRNFont=新宋体,8,N +OBJSTRNFont color=0, 0, 0 +DISPNAMEFont=新宋体,8,N +DISPNAMEFont color=0, 0, 0 +LCNMFont=新宋体,8,N +LCNMFont color=0, 0, 0 +AutoAdjustToText=Yes +Keep aspect=Yes +Keep center=Yes +Keep size=No +Width=2400 +Height=2400 +Brush color=255 255 255 +Fill Color=No +Brush style=1 +Brush bitmap mode=12 +Brush gradient mode=0 +Brush gradient color=118 118 118 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 0 0 255 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\PDMPCKG] +STRNFont=新宋体,8,N +STRNFont color=0, 0, 0 +DISPNAMEFont=新宋体,8,N +DISPNAMEFont color=0, 0, 0 +LABLFont=新宋体,8,N +LABLFont color=0, 0, 0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Width=4800 +Height=3600 +Brush color=255 255 192 +Fill Color=Yes +Brush style=6 +Brush bitmap mode=12 +Brush gradient mode=65 +Brush gradient color=255 255 255 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 178 178 178 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\TABL] +STRNFont=新宋体,8,N +STRNFont color=0, 0, 0 +DISPNAMEFont=新宋体,8,N +DISPNAMEFont color=0, 0, 0 +OWNRDISPNAMEFont=新宋体,8,N +OWNRDISPNAMEFont color=0, 0, 0 +ColumnsFont=新宋体,8,N +ColumnsFont color=0, 0, 0 +TablePkColumnsFont=新宋体,8,U +TablePkColumnsFont color=0, 0, 0 +TableFkColumnsFont=新宋体,8,N +TableFkColumnsFont color=0, 0, 0 +KeysFont=新宋体,8,N +KeysFont color=0, 0, 0 +IndexesFont=新宋体,8,N +IndexesFont color=0, 0, 0 +TriggersFont=新宋体,8,N +TriggersFont color=0, 0, 0 +LABLFont=新宋体,8,N +LABLFont color=0, 0, 0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Width=4800 +Height=4000 +Brush color=178 214 252 +Fill Color=Yes +Brush style=6 +Brush bitmap mode=12 +Brush gradient mode=65 +Brush gradient color=255 255 255 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 0 128 192 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\VIEW] +STRNFont=新宋体,8,N +STRNFont color=0, 0, 0 +DISPNAMEFont=新宋体,8,N +DISPNAMEFont color=0, 0, 0 +OWNRDISPNAMEFont=新宋体,8,N +OWNRDISPNAMEFont color=0, 0, 0 +ColumnsFont=新宋体,8,N +ColumnsFont color=0, 0, 0 +TablePkColumnsFont=新宋体,8,U +TablePkColumnsFont color=0, 0, 0 +TableFkColumnsFont=新宋体,8,N +TableFkColumnsFont color=0, 0, 0 +TemporaryVTablesFont=新宋体,8,N +TemporaryVTablesFont color=0, 0, 0 +IndexesFont=新宋体,8,N +IndexesFont color=0, 0, 0 +LABLFont=新宋体,8,N +LABLFont color=0, 0, 0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Width=4800 +Height=4000 +Brush color=208 208 255 +Fill Color=Yes +Brush style=6 +Brush bitmap mode=12 +Brush gradient mode=65 +Brush gradient color=255 255 255 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 128 128 192 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\PROC] +STRNFont=新宋体,8,N +STRNFont color=0, 0, 0 +DISPNAMEFont=新宋体,8,N +DISPNAMEFont color=0, 0, 0 +OWNRDISPNAMEFont=新宋体,8,N +OWNRDISPNAMEFont color=0, 0, 0 +LABLFont=新宋体,8,N +LABLFont color=0, 0, 0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Width=4000 +Height=1000 +Brush color=255 255 192 +Fill Color=Yes +Brush style=6 +Brush bitmap mode=12 +Brush gradient mode=65 +Brush gradient color=255 255 255 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 128 108 0 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\REFR] +SOURCEFont=新宋体,8,N +SOURCEFont color=0, 0, 0 +CENTERFont=新宋体,8,N +CENTERFont color=0, 0, 0 +DESTINATIONFont=新宋体,8,N +DESTINATIONFont color=0, 0, 0 +Line style=0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Brush color=255 255 255 +Fill Color=Yes +Brush style=1 +Brush bitmap mode=12 +Brush gradient mode=0 +Brush gradient color=118 118 118 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 0 128 192 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\VREF] +SOURCEFont=新宋体,8,N +SOURCEFont color=0, 0, 0 +CENTERFont=新宋体,8,N +CENTERFont color=0, 0, 0 +DESTINATIONFont=新宋体,8,N +DESTINATIONFont color=0, 0, 0 +Line style=0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Brush color=255 255 255 +Fill Color=Yes +Brush style=1 +Brush bitmap mode=12 +Brush gradient mode=0 +Brush gradient color=118 118 118 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 128 128 192 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\USRDEPD] +OBJXSTRFont=新宋体,8,N +OBJXSTRFont color=0, 0, 0 +Line style=0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Brush color=255 255 255 +Fill Color=Yes +Brush style=1 +Brush bitmap mode=12 +Brush gradient mode=0 +Brush gradient color=118 118 118 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=2 0 128 128 255 +Shadow color=192 192 192 +Shadow=0 + +[DisplayPreferences\Symbol\Free Symbol] +Free TextFont=新宋体,8,N +Free TextFont color=0, 0, 0 +Line style=0 +AutoAdjustToText=Yes +Keep aspect=No +Keep center=No +Keep size=No +Brush color=255 255 255 +Fill Color=Yes +Brush style=1 +Brush bitmap mode=12 +Brush gradient mode=0 +Brush gradient color=118 118 118 +Brush background image= +Custom shape= +Custom text mode=0 +Pen=1 0 0 0 255 +Shadow color=192 192 192 +Shadow=0 +(8268, 11693) +((315,354), (433,354)) +1 +15 + + +1524449375 +1538296407 +-1 +((-38123,15297), (-26435,28269)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1524449886 +-1 +((-23935,12010), (-11861,28282)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296409 +-1 +((-9361,18172), (2713,27845)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1524449886 +-1 +((5214,16547), (17288,27869)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296412 +-1 +((19788,14872), (31862,27845)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296204 +-1 +((-37598,8498), (-29000,12497)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296205 +-1 +((-37674,3548), (-29076,7547)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296308 +-1 +((-37528,-6452), (-28929,-2453)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296401 +-1 +((-24280,-1775), (-11048,10373)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296599 +-1 +((-9182,625), (2892,10298)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538296612 +-1 +((5017,-2538), (17091,10434)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538297772 +-1 +((-39520,-17440), (-26288,-8592)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538297770 +-1 +((-24744,-19106), (-10738,-8608)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538297380 +-1 +((-9749,-20696), (3870,-8548)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1524449375 +1538297383 +-1 +((5261,-17623), (18494,-8774)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1538296083 +1538296211 +-1 +((-37675,-1349), (-29076,2650)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +1538296587 +1538296608 +-1 +((19570,-987), (32030,8687)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + +config_id +1538296632 +1538297253 +((-13950,-17175), (73200,19575)) +4130 +1 +0 +7 +16777215 +16777215 +新宋体,8,N + + +1538297386 +1538297498 +-1 +((19859,-18262), (33092,-8589)) +12615680 +16570034 +12632256 +STRN 0 新宋体,8,N +DISPNAME 0 新宋体,8,N +OWNRDISPNAME 0 新宋体,8,N +Columns 0 新宋体,8,N +TablePkColumns 0 新宋体,8,U +TableFkColumns 0 新宋体,8,N +Keys 0 新宋体,8,N +Indexes 0 新宋体,8,N +Triggers 0 新宋体,8,N +LABL 0 新宋体,8,N +6 +65 +16777215 + + + + + + + + + + + + +BB11FFF9-9DBB-4648-87AA-9A50E1214549 +sys_dept +sys_dept +1524449375 +Administrator +1538297518 +admin +部门表 + + + +00C66282-419A-4915-8509-DFFFE6352DE8 +dept_id +dept_id +1524449375 +Administrator +1524449375 +Administrator +部门id +int(11) +11 +1 +1 + + +5B6FB0B1-5B1E-4E86-AF2A-72C49EBB315E +parent_id +parent_id +1524449375 +Administrator +1524449375 +Administrator +父部门id +0 +int(11) +11 + + +065E33A5-6AB5-44F1-8FEC-A72311EECD66 +ancestors +ancestors +1538295690 +admin +1538295792 +admin +varchar(50) +50 + + +EBB59EC8-AFD4-40E3-B811-DD5040728D91 +dept_name +dept_name +1524449375 +Administrator +1524449375 +Administrator +部门名称 +'' +varchar(30) +30 + + +2F26C025-82B0-4AC5-AEE0-32BA07B7B529 +order_num +order_num +1524449375 +Administrator +1524449375 +Administrator +显示顺序 +0 +int(4) +4 + + +CA504E09-528C-482E-A0C7-F86C559AA3A6 +leader +leader +1524449375 +Administrator +1524449375 +Administrator +负责人 +'' +varchar(20) +20 + + +9CFC55C4-DF2B-4A90-A789-C3839FAA43A8 +phone +phone +1524449375 +Administrator +1524449375 +Administrator +联系电话 +'' +varchar(20) +20 + + +1A9407E5-D74E-4CE9-9078-C4EC25393F7B +email +email +1524449375 +Administrator +1524449375 +Administrator +邮箱 +'' +varchar(20) +20 + + +B6772812-4B69-4248-871D-FA1B4BA0E5F7 +status +status +1524449375 +Administrator +1538295792 +admin +部门状态:0正常,1停用 +0 +char(1) +1 + + +6EBD2BFF-861E-4247-BAAB-B37CCBAF6F8D +del_flag +del_flag +1538295690 +admin +1538295792 +admin +char(1) +1 + + +2504A090-F6D6-493F-855E-5154E01AF0CA +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +D866AE9E-E7FF-47B2-BF3D-9BC1605A2F39 +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +7C6C9836-FC23-4492-8CF1-A4439E01B57C +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +FCED770D-005C-4531-A9D7-D1FD0A054719 +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + + + +15C1774B-9F17-48B6-A61F-728A25220B30 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +AA56FD91-4450-4282-8F31-AE302DF6AFEC +sys_user +sys_user +1524449375 +Administrator +1538297540 +admin +用户信息表 + + + +4A920BCE-4040-4F12-89D2-7DF345B90321 +user_id +user_id +1524449375 +Administrator +1524449375 +Administrator +用户ID +int(11) +11 +1 +1 + + +174E10B2-4A4D-40FF-80B8-B4D285561E42 +dept_id +dept_id +1524449375 +Administrator +1538297552 +admin +部门ID +NULL +int(11) +11 + + +1D4908A9-5416-4252-BA09-FA122D0194C3 +login_name +login_name +1524449375 +Administrator +1524449375 +Administrator +登录账号 +'' +varchar(30) +30 + + +2EF63346-9E82-4746-81B7-AB67D727446D +user_name +user_name +1524449375 +Administrator +1524449375 +Administrator +用户昵称 +'' +varchar(30) +30 + + +477EA57C-0E0B-4596-9A85-EC91E72F5160 +user_type +user_type +1524449375 +Administrator +1524449375 +Administrator +类型:Y默认用户,N非默认用户 +N +char(1) +1 + + +CD16FFF4-F214-473B-A9A8-FA30A3E357D1 +email +email +1524449375 +Administrator +1524449375 +Administrator +用户邮箱 +'' +varchar(100) +100 + + +61603FA5-3EBC-4389-AED7-1B54D238A563 +phonenumber +phonenumber +1524449375 +Administrator +1524449375 +Administrator +手机号码 +'' +varchar(20) +20 + + +65E9DE55-ED58-4BD9-B96C-7C081D1119B2 +sex +sex +1538295815 +admin +1538295948 +admin +char(1) +1 + + +E5E35061-221A-4BB9-AA22-3CF20F1FCCF6 +avatar +avatar +1538295815 +admin +1538295948 +admin +varchar(100) +100 + + +4ED1C2BF-B826-4A82-9464-EEBF271F4054 +password +password +1524449375 +Administrator +1524449375 +Administrator +密码 +'' +varchar(100) +100 + + +53E6BB49-3435-46E0-832F-BCAFE1A021CB +salt +salt +1524449375 +Administrator +1524449375 +Administrator +盐加密 +'' +varchar(100) +100 + + +245CAD53-B33B-4EED-8CFA-7AA10ED943B8 +status +status +1524449375 +Administrator +1538297540 +admin +帐号状态:0正常,1禁用 +0 +char(1) +1 + + +7F851464-6CC5-445B-9413-2A89B9CE90CB +del_flag +del_flag +1524449375 +Administrator +1538295948 +admin +拒绝登录描述 +'' +char(1) +1 + + +3DC8EC79-D75A-4BF8-8FBC-152E938AC14F +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +48C8C936-7A34-4A97-AACA-A6F07751FFAD +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +6050B4F3-9B26-4B40-AB4C-BA483F179958 +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +CD1E7E11-8EB6-4C9C-A69C-39CBCF10573E +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +F9F55D4C-13E6-49A0-BFDB-E0AFE0FA5501 +remark +remark +1538295815 +admin +1538295948 +admin +varchar(500) +500 + + + + +2E35FD67-A7A7-4B10-85E4-85115AD0E143 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +2711A520-532C-4F14-A034-BFF047C9CD6B +sys_post +sys_post +1524449375 +Administrator +1538297571 +admin +岗位信息表 + + + +FB04D29E-41F0-49A3-BFDB-58E222843F21 +post_id +post_id +1524449375 +Administrator +1524449375 +Administrator +岗位ID +int(11) +11 +1 +1 + + +50010C4E-4F59-47B9-8F08-05E8E071E8B1 +post_code +post_code +1524449375 +Administrator +1524449375 +Administrator +岗位编码 +varchar(64) +64 +1 + + +0F929250-051E-4344-B22A-C30E071A543B +post_name +post_name +1524449375 +Administrator +1524449375 +Administrator +岗位名称 +varchar(100) +100 +1 + + +2BC9005E-350F-46BE-98D6-9B13060F1B20 +post_sort +post_sort +1524449375 +Administrator +1524449375 +Administrator +显示顺序 +int(4) +4 +1 + + +F6D7AD3E-5EA0-4759-B6BF-6334B7105B78 +status +status +1524449375 +Administrator +1538297565 +admin +状态(0正常 1停用) +char(1) +1 +1 + + +CED01369-5063-479D-A444-32936369A486 +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +A29528FF-A2B9-4149-B997-1B0204D42E40 +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +6026A05D-0C1E-497E-8EAF-FDB704BE6A52 +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +DF516F5F-CD82-4347-AC57-BDCB4E5DD75E +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +539CEC34-49F0-49A0-9B7C-B84655FD2233 +remark +remark +1524449375 +Administrator +1524449375 +Administrator +备注 +'' +varchar(500) +500 + + + + +14E893B1-D0BA-46A7-A905-F0FFA089B65A +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +11337551-BA45-43CD-9148-92BE60E2F8F5 +sys_role +sys_role +1524449375 +Administrator +1538297608 +admin +角色信息表 + + + +A420E2C9-8FE3-452A-9047-C7BEACE8490C +role_id +role_id +1524449375 +Administrator +1524449375 +Administrator +角色ID +int(10) +10 +1 +1 + + +9342763D-5B89-4440-965B-2B55DB4ACD86 +role_name +role_name +1524449375 +Administrator +1524449375 +Administrator +角色名称 +varchar(30) +30 +1 + + +54480009-0C7E-40F2-AA76-CD914A6D66C5 +role_key +role_key +1524449375 +Administrator +1524449375 +Administrator +角色权限字符串 +varchar(100) +100 +1 + + +E73F4D0E-12A0-42B5-B3CE-B573D499DD6C +role_sort +role_sort +1524449375 +Administrator +1538296031 +admin +显示顺序 +int(10) +10 + + +5F836F54-9EBD-4768-AA3C-F268F5FAFE8D +data_scope +data_scope +1538295973 +admin +1538296031 +admin +char(1) +1 + + +424ED799-E4C1-44AD-A172-C2B3C405E9C5 +status +status +1524449375 +Administrator +1538297608 +admin +角色状态:0正常,1禁用 +0 +char(1) +1 + + +8E034C76-5966-4246-B81B-7B12F37D96A7 +del_flag +del_flag +1538295973 +admin +1538296031 +admin +char(1) +1 + + +214F6E1F-28B1-454B-ABF0-D1C43220129D +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +1A6D5791-0353-4ABC-8BC2-921BB87A2E5A +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +D6394880-A49C-4B83-B43A-5FDBAA918AA3 +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +34285DF5-8E36-452B-A3AA-9F4290C20F7E +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +2FAB98F7-68A2-460B-8A20-5D5DA73F5103 +remark +remark +1524449375 +Administrator +1524449375 +Administrator +备注 +'' +varchar(500) +500 + + + + +4342E67F-D33C-435F-9865-973E053B6075 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +FBC2A590-443B-43C9-82D5-687B850C8B3D +sys_menu +sys_menu +1524449375 +Administrator +1538297627 +admin +菜单权限表 + + + +BB061292-3B99-432E-9B96-5362AAD918B9 +menu_id +menu_id +1524449375 +Administrator +1524449375 +Administrator +菜单ID +int(11) +11 +1 +1 + + +EA8422AB-37B1-4D60-A3C9-A4BF9039A9D4 +menu_name +menu_name +1524449375 +Administrator +1524449375 +Administrator +菜单名称 +varchar(50) +50 +1 + + +E56E04A8-63F6-4271-92E3-974DC84DD536 +parent_id +parent_id +1524449375 +Administrator +1524449375 +Administrator +父菜单ID +0 +int(11) +11 + + +1809914E-6B09-4CD2-8916-E603D6717557 +order_num +order_num +1524449375 +Administrator +1524449375 +Administrator +显示顺序 +NULL +int(4) +4 + + +FCB44D46-3C21-40CB-B942-57823E52E5B1 +url +url +1524449375 +Administrator +1524449375 +Administrator +请求地址 +'' +varchar(200) +200 + + +667EE044-6805-4668-BAF4-E78B3052051F +menu_type +menu_type +1524449375 +Administrator +1524449375 +Administrator +类型:M目录,C菜单,F按钮 +'' +char(1) +1 + + +F7658083-BCAB-46F7-AF31-8A4B1D8749EF +visible +visible +1524449375 +Administrator +1538297627 +admin +菜单状态:0显示,1隐藏 +0 +char(1) +1 + + +528611C8-C319-430F-8F00-68FBA60F310B +perms +perms +1524449375 +Administrator +1524449375 +Administrator +权限标识 +'' +varchar(100) +100 + + +38004CD7-8DD0-43F1-9E59-B50132CB6F1A +icon +icon +1524449375 +Administrator +1524449375 +Administrator +菜单图标 +'' +varchar(100) +100 + + +6927665F-EC42-4E1F-A275-4B27F442B6B8 +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +1A6A4D0F-0B0B-4522-B4DA-3F1D592CB889 +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +605D7776-4820-4BA9-91E8-AD837B73AEFB +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +4CFF26BB-8736-4864-855E-C7C1B133370B +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +67C6E46C-DF06-480A-BC74-E927406E5D26 +remark +remark +1524449375 +Administrator +1524449375 +Administrator +备注 +'' +varchar(500) +500 + + + + +08EBE713-9E4D-4312-AA7D-2E4E439734E5 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +F8CB66D1-3632-4509-97C4-17016BE261FC +sys_user_role +sys_user_role +1524449375 +Administrator +1538297676 +admin +用户和角色关联表 + + + +73701F72-C45B-4CA0-8A62-632890E3DEF0 +user_id +user_id +1524449375 +Administrator +1524449375 +Administrator +用户ID +int(11) +11 +1 + + +CABD458B-DA59-46A8-99C3-088AD8D34097 +role_id +role_id +1524449375 +Administrator +1524449375 +Administrator +角色ID +int(11) +11 +1 + + + + +37C3213B-EF22-4CD4-A91F-9A9A2503FB2A +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + + +9F8C6A9F-3221-410E-AEA4-D1A80026397E +sys_role_menu +sys_role_menu +1524449375 +Administrator +1538297683 +admin +角色和菜单关联表 + + + +D2E151A5-6156-46EF-844E-0ADC3070293B +role_id +role_id +1524449375 +Administrator +1524449375 +Administrator +角色ID +int(11) +11 +1 + + +6B8C1E62-FD8B-4504-8FA0-F69917722FBD +menu_id +menu_id +1524449375 +Administrator +1524449375 +Administrator +菜单ID +int(11) +11 +1 + + + + +2E72304F-91F0-4392-BAE8-BBF7A4346B7D +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + + +726CB18E-7D5B-4E2E-9CF8-047AD5AF89E3 +sys_user_post +sys_user_post +1524449375 +Administrator +1538297694 +admin +用户与岗位关联表 + + + +E4A1CAB6-0F63-4917-ACEF-418DE7F894BA +user_id +user_id +1524449375 +Administrator +1538296306 +admin +用户ID +int(11) +11 +1 + + +8E7188D5-B3A5-4F1D-B6CB-D77D652414DE +post_id +post_id +1524449375 +Administrator +1538296306 +admin +岗位ID +int(11) +11 +1 + + + + +4091B7D3-2404-4C20-BBCD-B63E22A5E960 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + + +FE347A45-D8EC-423B-9B38-4D315A3ABE42 +sys_oper_log +sys_oper_log +1524449375 +Administrator +1538297699 +admin +操作日志记录 + + + +F5FC8AC1-7415-4A57-BA2C-EE2E7B9E1EFC +oper_id +oper_id +1524449375 +Administrator +1524449375 +Administrator +日志主键 +int(11) +11 +1 +1 + + +2103BC5C-E28D-4369-8369-E898B218587A +title +title +1524449375 +Administrator +1524449375 +Administrator +模块标题 +'' +varchar(50) +50 + + +6816377B-3DB6-424A-99ED-1D20FEB30ED4 +business_type +business_type +1524449375 +Administrator +1538296397 +admin +功能请求 +'' +int(2) +2 + + +9CA3B7C3-F52C-4E2E-893F-8E6EBA7B2667 +method +method +1524449375 +Administrator +1524449375 +Administrator +方法名称 +'' +varchar(100) +100 + + +A5744803-C050-4108-9D15-7A0B95F03642 +operator_type +operator_type +1524449375 +Administrator +1538296397 +admin +来源渠道 +'' +int(1) +1 + + +B0DF8235-6BC1-452C-8B30-A56F0430E4F5 +oper_name +oper_name +1524449375 +Administrator +1538296397 +admin +登录账号 +'' +varchar(50) +50 + + +25315A12-4EB9-4B67-9E2C-9F40F8EF7FAB +dept_name +dept_name +1524449375 +Administrator +1524449375 +Administrator +部门名称 +'' +varchar(50) +50 + + +7AF8602B-A1DA-4EA3-BFB2-7638F96A86C0 +oper_url +oper_url +1524449375 +Administrator +1524449375 +Administrator +请求URL +'' +varchar(255) +255 + + +F2A56B63-7A56-43FA-8099-411F3578B30D +oper_ip +oper_ip +1524449375 +Administrator +1524449375 +Administrator +主机地址 +'' +varchar(30) +30 + + +1EF1BAF6-F5C1-496C-98E0-8B10C37279A1 +oper_param +oper_param +1524449375 +Administrator +1524449375 +Administrator +请求参数 +'' +varchar(255) +255 + + +AA3F3A4E-D375-4232-B152-01DCFB8F6B6D +status +status +1524449375 +Administrator +1524449375 +Administrator +操作状态 0正常 1异常 +0 +int(1) +1 + + +29E44D4A-6AC7-4220-A502-4BFC8746397A +error_msg +error_msg +1524449375 +Administrator +1524449375 +Administrator +错误消息 +'' +varchar(2000) +2000 + + +22343C35-D913-485B-862E-2CEF579AAF22 +oper_time +oper_time +1524449375 +Administrator +1524449375 +Administrator +操作时间 +timestamp + + + + +C0561C20-CC22-471B-A764-414C0D378FD6 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +AA2CFBA5-FA97-4AF1-92FE-645370B5848D +sys_dict_type +sys_dict_type +1524449375 +Administrator +1538297703 +admin +字典类型表 + + + +79CB7D43-B999-4D92-9477-D3AFEBD94248 +dict_id +dict_id +1524449375 +Administrator +1524449375 +Administrator +字典主键 +int(11) +11 +1 +1 + + +2490B755-3E0A-4935-97F0-2EFDF9A72D05 +dict_name +dict_name +1524449375 +Administrator +1524449375 +Administrator +字典名称 +'' +varchar(100) +100 + + +7421238A-82DB-4992-AA28-41726AB6A5D6 +dict_type +dict_type +1524449375 +Administrator +1524449375 +Administrator +字典类型 +'' +varchar(100) +100 + + +971D2FBD-1A24-4EE4-B943-9367609C7472 +status +status +1524449375 +Administrator +1538296458 +admin +状态(0正常 1禁用) +0 +char(1) +1 + + +B8876246-5BBA-4A03-86D7-98CA4EBEE342 +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +5237CED2-0853-41DE-ACF4-BE442BC9E112 +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +2CACFBC0-8349-4B3A-9183-208B18C9F56F +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +ABEE7806-4F61-4B97-980C-CA081F61CA7C +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +3966B558-B911-45DE-86C6-57F3DB9267BA +remark +remark +1524449375 +Administrator +1524449375 +Administrator +备注 +'' +varchar(500) +500 + + +AFC0A0ED-A469-40B2-A6C4-4616444830AA +unique +unique +1524449375 +Administrator +1524449375 +Administrator +(dict_type) + + + + +BAD40D8E-BC11-44F5-918E-B27CABBCB051 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +493D6B25-21D0-45B1-BBA0-764B9C09B57D +sys_dict_data +sys_dict_data +1524449375 +Administrator +1538297709 +admin +字典数据表 + + + +CFDB23A8-AE38-4051-973A-2DABAC8283F9 +dict_code +dict_code +1524449375 +Administrator +1524449375 +Administrator +字典编码 +int(11) +11 +1 +1 + + +EAA405BD-12A8-472F-A42D-CDA6A82E291A +dict_sort +dict_sort +1524449375 +Administrator +1524449375 +Administrator +字典排序 +0 +int(4) +4 + + +F13017F5-2AA0-4DE9-9DC2-A9A3D73A98E6 +dict_label +dict_label +1524449375 +Administrator +1524449375 +Administrator +字典标签 +'' +varchar(100) +100 + + +EEEC4136-823D-4892-9BB9-BB0B4ADD83E3 +dict_value +dict_value +1524449375 +Administrator +1524449375 +Administrator +字典键值 +'' +varchar(100) +100 + + +ADF5A383-D055-40BE-BBFC-06E2B93D4E6A +dict_type +dict_type +1524449375 +Administrator +1524449375 +Administrator +字典类型 +'' +varchar(100) +100 + + +A0B2DDF2-251D-4701-9B00-6893C74CC449 +css_class +css_class +1538296497 +admin +1538296556 +admin +varchar(100) +100 + + +3CBFBA8E-7609-458D-9E53-A825C3F307A2 +list_class +list_class +1538296497 +admin +1538296556 +admin +varchar(100) +100 + + +BA974839-DEE0-4684-BBEF-6D7776C34354 +is_default +is_default +1538296497 +admin +1538296556 +admin +char(1) +1 + + +1676CDF5-01CA-4749-BA1D-6E5399257BD0 +status +status +1524449375 +Administrator +1524449375 +Administrator +状态(0正常 1禁用) +0 +int(1) +1 + + +8798B094-1AAF-4A23-B2F1-4C19DACF1AA3 +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +D1CB9293-D762-403C-85CB-4B974ACF7328 +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +5A34AF87-B25E-4349-9713-69DC50F6F5F2 +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +3204FBAC-1F61-4571-ADC4-BF1BE9CED85A +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +B7DE1842-809C-4401-9C80-C9A37DF9B053 +remark +remark +1524449375 +Administrator +1524449375 +Administrator +备注 +'' +varchar(500) +500 + + + + +2809F417-7FA5-48DA-B613-662C7C28061E +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +0A7C2F56-6E3B-4E70-A549-0EC60779D180 +sys_logininfor +sys_logininfor +1524449375 +Administrator +1538297756 +admin +系统访问记录 + + + +5CB5D942-D52B-487D-BC86-476481B0FB8D +info_id +info_id +1524449375 +Administrator +1524449375 +Administrator +访问ID +int(11) +11 +1 +1 + + +A1C66DBC-9DB7-428B-9275-3D014B6CE388 +login_name +login_name +1524449375 +Administrator +1524449375 +Administrator +登录账号 +'' +varchar(50) +50 + + +8E0F50A6-F98D-48B0-8D9D-78F3A76ED171 +ipaddr +ipaddr +1524449375 +Administrator +1524449375 +Administrator +登录IP地址 +'' +varchar(50) +50 + + +91B70723-1A7E-4277-A100-63B775A504B3 +login_location +login_location +1538297350 +admin +1538297369 +admin +varchar(255) +255 + + +AA04F533-A044-428B-80F8-515B6BB1A302 +browser +browser +1524449375 +Administrator +1524449375 +Administrator +浏览器类型 +'' +varchar(50) +50 + + +D37570E9-9EEE-4349-B875-494A5415C736 +os +os +1524449375 +Administrator +1524449375 +Administrator +操作系统 +'' +varchar(50) +50 + + +CF10A80C-123E-42F3-A2DD-1B770E5F9D86 +status +status +1524449375 +Administrator +1524449375 +Administrator +登录状态 0成功 1失败 +0 +int(1) +1 + + +9113784E-932A-4FAF-82CB-A75B8C827309 +msg +msg +1524449375 +Administrator +1524449375 +Administrator +提示消息 +'' +varchar(255) +255 + + +BCA519C6-19C9-45DF-A0B5-F88E9E6D3557 +login_time +login_time +1524449375 +Administrator +1524449375 +Administrator +访问时间 +timestamp + + + + +C14E656C-0645-49EB-8B42-AD82232E0416 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +4DCA223F-E98B-4D8B-A71C-CFB438C15488 +sys_user_online +sys_user_online +1524449375 +Administrator +1538297754 +admin +在线用户记录 + + + +7FCC57CE-47DD-4948-B949-10401B2FC7B1 +sessionId +sessionId +1524449375 +Administrator +1524449375 +Administrator +用户会话id +'' +varchar(50) +50 +1 + + +FDE5B59D-8CF7-4AAE-987F-3FF2AEBE22CB +login_name +login_name +1524449375 +Administrator +1524449375 +Administrator +登录账号 +'' +varchar(50) +50 + + +AB65FF92-33A0-42C8-8B3F-454A1FAD5615 +dept_name +dept_name +1524449375 +Administrator +1524449375 +Administrator +部门名称 +'' +varchar(50) +50 + + +C4DAF2D0-9CDC-476B-A011-FF5D302371EB +ipaddr +ipaddr +1524449375 +Administrator +1524449375 +Administrator +登录IP地址 +'' +varchar(50) +50 + + +C8243FB0-425B-4A74-9ADA-C93B15E713EA +login_location +login_location +1538297178 +admin +1538297216 +admin +varchar(255) +255 + + +89EC40B0-0C22-4811-90BB-BEA385ACDF20 +browser +browser +1524449375 +Administrator +1524449375 +Administrator +浏览器类型 +'' +varchar(50) +50 + + +AC455631-CFE0-45BB-A0C5-788D695E4B6C +os +os +1524449375 +Administrator +1524449375 +Administrator +操作系统 +'' +varchar(50) +50 + + +5C56E3C9-4591-4762-89E1-C9BBFECB5F11 +status +status +1524449375 +Administrator +1524449375 +Administrator +在线状态on_line在线off_line离线 +'' +varchar(10) +10 + + +0CAF2F1F-459F-4F78-9075-D95F924A4FF7 +start_timestamp +start_timestamp +1524449375 +Administrator +1524449375 +Administrator +session创建时间 +timestamp + + +6AE6BDED-823E-4455-9A9F-338EC6F7BDB9 +last_access_time +last_access_time +1524449375 +Administrator +1524449375 +Administrator +session最后访问时间 +timestamp + + +CE390924-4628-421C-979F-002C2952E99E +expire_time +expire_time +1524449375 +Administrator +1524449375 +Administrator +超时时间,单位为分钟 +0 +int(5) +5 + + + + +365CC94D-6124-42C7-96BD-376B84B709F7 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +AFCBF4DB-07EC-42D1-ACA7-56B5038F5AC5 +sys_job +sys_job +1524449375 +Administrator +1538297732 +admin +定时任务调度表 + + + +1658CED4-3885-4094-AB70-F35408EBCD5E +job_id +job_id +1524449375 +Administrator +1524449375 +Administrator +任务ID +int(11) +11 +1 +1 + + +731E7147-E3A4-4D93-8C7C-BB1C6D94DB9E +job_name +job_name +1524449375 +Administrator +1524449375 +Administrator +任务名称 +'' +varchar(64) +64 +1 + + +C64B3655-C240-44F0-83B4-F42FB76C8BEA +job_group +job_group +1524449375 +Administrator +1524449375 +Administrator +任务组名 +'' +varchar(64) +64 +1 + + +9F7E735D-B823-4ADA-BA3D-8FFFFEC92F5C +method_name +method_name +1524449375 +Administrator +1524449375 +Administrator +任务方法 +'' +varchar(500) +500 + + +28EEE4F4-E8E7-4052-8F10-88D6C74C595D +method_params +method_params +1524449375 +Administrator +1538297298 +admin +方法参数 +'' +varchar(200) +200 + + +C8986FAD-E2E7-4364-9E8B-B75366B9A4ED +cron_expression +cron_expression +1524449375 +Administrator +1524449375 +Administrator +cron执行表达式 +'' +varchar(255) +255 + + +FD188167-AC02-4161-BE89-D63E61412313 +misfire_policy +misfire_policy +1538297273 +admin +1538297298 +admin +varchar(20) +20 + + +2D4B6C8F-EEE8-4474-9D20-8206A7E80362 +status +status +1524449375 +Administrator +1524449375 +Administrator +状态(0正常 1暂停) +0 +int(1) +1 + + +CA78AC7F-19E7-47BC-BF7B-9F31EFB02702 +create_by +create_by +1524449375 +Administrator +1524449375 +Administrator +创建者 +'' +varchar(64) +64 + + +B8F807AE-9F19-4FCA-BA98-7BF71DD0CA02 +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + +3FBB42FA-ED0F-4D7C-99D0-5F7AF7B0F1DD +update_by +update_by +1524449375 +Administrator +1524449375 +Administrator +更新者 +'' +varchar(64) +64 + + +1C5863D2-A8B9-43DB-AA06-F8BE3E01093B +update_time +update_time +1524449375 +Administrator +1524449375 +Administrator +更新时间 +timestamp + + +889C3FF9-BB1E-4EB1-AFE9-1D1155984915 +remark +remark +1524449375 +Administrator +1524449375 +Administrator +备注信息 +'' +varchar(500) +500 + + + + +38106F1A-4FFB-4EC0-B979-55BD6C6C6FF7 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + + + +CF7C8958-5494-48C6-BE05-83F2CF8C7513 +sys_job_log +sys_job_log +1524449375 +Administrator +1538297742 +admin +定时任务调度日志表 + + + +308F32A1-A8EC-4002-9993-DF9234A303B7 +job_log_id +job_log_id +1524449375 +Administrator +1524449375 +Administrator +任务日志ID +int(11) +11 +1 +1 + + +F4D55B65-BB6B-4182-A6D6-F9CAABC19110 +job_name +job_name +1524449375 +Administrator +1524449375 +Administrator +任务名称 +varchar(64) +64 +1 + + +8AF383A0-01C0-4947-8384-FF0F13AC00AE +job_group +job_group +1524449375 +Administrator +1524449375 +Administrator +任务组名 +varchar(64) +64 +1 + + +96582B76-F1E9-4473-BA51-01B87B5F459E +method_name +method_name +1524449375 +Administrator +1524449375 +Administrator +任务方法 +varchar(500) +500 + + +2AB02ABA-02E3-4F72-95BA-4261A7F5729A +method_params +method_params +1524449375 +Administrator +1538297325 +admin +方法参数 +'' +varchar(200) +200 + + +8EB39444-CBFF-43AA-AA37-49217EF545B6 +job_message +job_message +1524449375 +Administrator +1524449375 +Administrator +日志信息 +varchar(500) +500 + + +18CD263C-0F57-4EDF-999E-1B5A7EE2BFF9 +is_exception +is_exception +1524449375 +Administrator +1538297325 +admin +是否异常 +0 +char(1) +1 + + +634ECD78-2251-43EB-B6CF-DF7FA9DA4354 +exception_info +exception_info +1524449375 +Administrator +1524449375 +Administrator +异常信息 +text + + +4EC075CC-507B-43D7-860F-34DAAEB1DBBF +create_time +create_time +1524449375 +Administrator +1524449375 +Administrator +创建时间 +timestamp + + + + +A87DCE10-894A-4CF7-B39C-AF18202C7F86 +Key_1 +Key_1 +1524449375 +Administrator +1524449375 +Administrator + + + + + + + + + + +FD6284E8-B6D4-43AF-A038-9C97DCD403DC +sys_role_dept +sys_role_dept +1538296083 +admin +1538297689 +admin +角色和部门关联表 + + + +2BC66204-4193-42E6-BB7B-7AD57C9E5BEF +role_id +role_id +1538296083 +admin +1538296150 +admin +用户ID +int(11) +11 +1 + + +A32BC025-6437-41AB-BAA4-3A150E406781 +dept_id +dept_id +1538296083 +admin +1538296150 +admin +岗位ID +int(11) +11 +1 + + + + +315FFED5-B0A0-4649-8255-2283896340C9 +Key_1 +Key_1 +1538296083 +admin +1538296083 +admin + + + + + + + + + + + +45EB995C-F5F6-4818-AEB1-2038DEBA9CEE +sys_config +sys_config +1538296587 +admin +1538297714 +admin +参数配置表 + + + +667C4616-146B-475C-8111-4720375D762C +config_id +config_id +1538296587 +admin +1538296691 +admin +字典编码 +int(5) +5 +1 +1 + + +EA798E0B-0CBE-4897-B0AF-1F2D3CD6DEF4 +config_name +config_name +1538296587 +admin +1538296691 +admin +字典排序 +0 +varchar(100) +100 + + +A9A2A6E0-C914-4516-AE4C-F33CE71B92E8 +config_key +config_key +1538296587 +admin +1538296691 +admin +字典标签 +'' +varchar(100) +100 + + +24CCA897-8671-402E-8229-9ED0C80C176A +config_value +config_value +1538296587 +admin +1538296691 +admin +字典键值 +'' +varchar(100) +100 + + +B4E76B1D-BFAF-42F3-8CCA-8B5A8CC7CBFF +config_type +config_type +1538296587 +admin +1538296691 +admin +字典类型 +'' +char(1) +1 + + +A6AC1891-F5C4-45B3-8CAB-8F4CE8B8BF08 +create_by +create_by +1538296587 +admin +1538296587 +admin +创建者 +'' +varchar(64) +64 + + +CC1E0367-A079-49A0-8F0A-FE5F7B3EB6EA +create_time +create_time +1538296587 +admin +1538296587 +admin +创建时间 +timestamp + + +081CD54E-AE38-4696-A326-F829B8EA5737 +update_by +update_by +1538296587 +admin +1538296587 +admin +更新者 +'' +varchar(64) +64 + + +E2118ECE-8F52-4FBA-B18A-F30FFB2BDD20 +update_time +update_time +1538296587 +admin +1538296587 +admin +更新时间 +timestamp + + +55A16121-8932-465E-8427-EBDA39B2B900 +remark +remark +1538296587 +admin +1538296587 +admin +备注 +'' +varchar(500) +500 + + + + +0F331278-2804-496A-A87B-B0944C80FB82 +Key_1 +Key_1 +1538296587 +admin +1538296587 +admin + + + + + + + + + + +F33DE1D6-C12D-43DB-A502-83BD1615F081 +sys_notice +sys_notice +1538297386 +admin +1538297746 +admin +通知公告表 + + + +FF4A9744-D7CA-450E-8AD7-B3E7E90075CE +notice_id +notice_id +1538297386 +admin +1538297496 +admin +任务日志ID +int(4) +4 +1 +1 + + +E2B08825-4C94-4209-80B2-21A7AD8CBF2D +notice_title +notice_title +1538297386 +admin +1538297496 +admin +任务名称 +varchar(50) +50 +1 + + +04414862-9ABC-4431-B1B7-B44ECC08CB6E +notice_type +notice_type +1538297386 +admin +1538297496 +admin +任务组名 +char(2) +2 +1 + + +E829DAD1-E3F9-4AED-A3DE-59CE4340333E +notice_content +notice_content +1538297386 +admin +1538297496 +admin +任务方法 +varchar(500) +500 + + +2EABC8DB-6700-4717-89A3-31461C4CB2D5 +status +status +1538297386 +admin +1538297496 +admin +方法参数 +'' +char(1) +1 + + +448D3EB6-DE24-4BE3-9C29-1FC3C71B0E8D +create_by +create_by +1538297386 +admin +1538297496 +admin +日志信息 +varchar(64) +64 + + +770ED87D-D4D7-499C-A266-7A54051B1A84 +create_time1 +create_time1 +1538297386 +admin +1538297496 +admin +是否异常 +0 +datetime + + +12DDF399-7CCB-4117-8B05-6AA9BEE845E5 +update_by +update_by +1538297386 +admin +1538297496 +admin +异常信息 +varchar(64) +64 + + +FE101CE4-9B66-4097-944D-36B01A9E2219 +update_time1 +update_time1 +1538297400 +admin +1538297496 +admin +datetime + + +D5F1728C-01D0-4C00-9AD6-AAA14228104B +remark +remark +1538297386 +admin +1538297496 +admin +创建时间 +varchar(255) +255 + + + + +43C7AC1D-CE7A-4B55-A474-8CB2376D446F +Key_1 +Key_1 +1538297386 +admin +1538297386 +admin + + + + + + + + + + + + +F2EBEA5B-F352-45CB-B349-39158064CEE8 +PUBLIC +PUBLIC +1524449325 +Administrator +1524449325 +Administrator + + + + +41740AEF-D7FB-4738-ABDF-47C3287A6AF6 +MySQL 5.0 +MYSQL50 +1524449337 +Administrator +1538295558 +admin +file:///%_DBMS%/mysql50.xdb +F4F16ECD-F2F1-4006-AF6F-638D5C65F35E +4BA9F647-DAB1-11D1-9944-006097355D9B + + + + + + + + + + \ No newline at end of file diff --git a/sql/ry_20240112.sql b/sql/ry_20240112.sql new file mode 100644 index 0000000..eab64b0 --- /dev/null +++ b/sql/ry_20240112.sql @@ -0,0 +1,721 @@ +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +drop table if exists sys_dept; +create table sys_dept ( + dept_id bigint(20) not null auto_increment comment '部门id', + parent_id bigint(20) default 0 comment '父部门id', + ancestors varchar(50) default '' comment '祖级列表', + dept_name varchar(30) default '' comment '部门名称', + order_num int(4) default 0 comment '显示顺序', + leader varchar(20) default null comment '负责人', + phone varchar(11) default null comment '联系电话', + email varchar(50) default null comment '邮箱', + status char(1) default '0' comment '部门状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + primary key (dept_id) +) engine=innodb auto_increment=200 comment = '部门表'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- +insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +drop table if exists sys_user; +create table sys_user ( + user_id bigint(20) not null auto_increment comment '用户ID', + dept_id bigint(20) default null comment '部门ID', + login_name varchar(30) not null comment '登录账号', + user_name varchar(30) default '' comment '用户昵称', + user_type varchar(2) default '00' comment '用户类型(00系统用户 01注册用户)', + email varchar(50) default '' comment '用户邮箱', + phonenumber varchar(11) default '' comment '手机号码', + sex char(1) default '0' comment '用户性别(0男 1女 2未知)', + avatar varchar(100) default '' comment '头像路径', + password varchar(50) default '' comment '密码', + salt varchar(20) default '' comment '盐加密', + status char(1) default '0' comment '帐号状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + login_ip varchar(128) default '' comment '最后登录IP', + login_date datetime comment '最后登录时间', + pwd_update_date datetime comment '密码最后更新时间', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (user_id) +) engine=innodb auto_increment=100 comment = '用户信息表'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', null, null, 'admin', sysdate(), '', null, '管理员'); +insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', null, null, 'admin', sysdate(), '', null, '测试员'); + + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +drop table if exists sys_post; +create table sys_post +( + post_id bigint(20) not null auto_increment comment '岗位ID', + post_code varchar(64) not null comment '岗位编码', + post_name varchar(50) not null comment '岗位名称', + post_sort int(4) not null comment '显示顺序', + status char(1) not null comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (post_id) +) engine=innodb comment = '岗位信息表'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +drop table if exists sys_role; +create table sys_role ( + role_id bigint(20) not null auto_increment comment '角色ID', + role_name varchar(30) not null comment '角色名称', + role_key varchar(100) not null comment '角色权限字符串', + role_sort int(4) not null comment '显示顺序', + data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + status char(1) not null comment '角色状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (role_id) +) engine=innodb auto_increment=100 comment = '角色信息表'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '超级管理员', 'admin', 1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员'); +insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', sysdate(), '', null, '普通角色'); + + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +drop table if exists sys_menu; +create table sys_menu ( + menu_id bigint(20) not null auto_increment comment '菜单ID', + menu_name varchar(50) not null comment '菜单名称', + parent_id bigint(20) default 0 comment '父菜单ID', + order_num int(4) default 0 comment '显示顺序', + url varchar(200) default '#' comment '请求地址', + target varchar(20) default '' comment '打开方式(menuItem页签 menuBlank新窗口)', + menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)', + visible char(1) default 0 comment '菜单状态(0显示 1隐藏)', + is_refresh char(1) default 1 comment '是否刷新(0刷新 1不刷新)', + perms varchar(100) default null comment '权限标识', + icon varchar(100) default '#' comment '菜单图标', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注', + primary key (menu_id) +) engine=innodb auto_increment=2000 comment = '菜单权限表'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', '#', '', 'M', '0', '1', '', 'fa fa-gear', 'admin', sysdate(), '', null, '系统管理目录'); +insert into sys_menu values('2', '系统监控', '0', '2', '#', '', 'M', '0', '1', '', 'fa fa-video-camera', 'admin', sysdate(), '', null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '3', '#', '', 'M', '0', '1', '', 'fa fa-bars', 'admin', sysdate(), '', null, '系统工具目录'); +insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', 'menuBlank', 'C', '0', '1', '', 'fa fa-location-arrow', 'admin', sysdate(), '', null, '若依官网地址'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', '/system/user', '', 'C', '0', '1', 'system:user:view', 'fa fa-user-o', 'admin', sysdate(), '', null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', '/system/role', '', 'C', '0', '1', 'system:role:view', 'fa fa-user-secret', 'admin', sysdate(), '', null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', '/system/menu', '', 'C', '0', '1', 'system:menu:view', 'fa fa-th-list', 'admin', sysdate(), '', null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', '/system/dept', '', 'C', '0', '1', 'system:dept:view', 'fa fa-outdent', 'admin', sysdate(), '', null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', '/system/post', '', 'C', '0', '1', 'system:post:view', 'fa fa-address-card-o', 'admin', sysdate(), '', null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', '/system/dict', '', 'C', '0', '1', 'system:dict:view', 'fa fa-bookmark-o', 'admin', sysdate(), '', null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', '/system/config', '', 'C', '0', '1', 'system:config:view', 'fa fa-sun-o', 'admin', sysdate(), '', null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', '/system/notice', '', 'C', '0', '1', 'system:notice:view', 'fa fa-bullhorn', 'admin', sysdate(), '', null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', '#', '', 'M', '0', '1', '', 'fa fa-pencil-square-o', 'admin', sysdate(), '', null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', '/monitor/online', '', 'C', '0', '1', 'monitor:online:view', 'fa fa-user-circle', 'admin', sysdate(), '', null, '在线用户菜单'); +insert into sys_menu values('110', '定时任务', '2', '2', '/monitor/job', '', 'C', '0', '1', 'monitor:job:view', 'fa fa-tasks', 'admin', sysdate(), '', null, '定时任务菜单'); +insert into sys_menu values('111', '数据监控', '2', '3', '/monitor/data', '', 'C', '0', '1', 'monitor:data:view', 'fa fa-bug', 'admin', sysdate(), '', null, '数据监控菜单'); +insert into sys_menu values('112', '服务监控', '2', '4', '/monitor/server', '', 'C', '0', '1', 'monitor:server:view', 'fa fa-server', 'admin', sysdate(), '', null, '服务监控菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', '/monitor/cache', '', 'C', '0', '1', 'monitor:cache:view', 'fa fa-cube', 'admin', sysdate(), '', null, '缓存监控菜单'); +insert into sys_menu values('114', '表单构建', '3', '1', '/tool/build', '', 'C', '0', '1', 'tool:build:view', 'fa fa-wpforms', 'admin', sysdate(), '', null, '表单构建菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', '/tool/gen', '', 'C', '0', '1', 'tool:gen:view', 'fa fa-code', 'admin', sysdate(), '', null, '代码生成菜单'); +insert into sys_menu values('116', '系统接口', '3', '3', '/tool/swagger', '', 'C', '0', '1', 'tool:swagger:view', 'fa fa-gg', 'admin', sysdate(), '', null, '系统接口菜单'); +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', '/monitor/operlog', '', 'C', '0', '1', 'monitor:operlog:view', 'fa fa-address-book', 'admin', sysdate(), '', null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', '/monitor/logininfor', '', 'C', '0', '1', 'monitor:logininfor:view', 'fa fa-file-image-o', 'admin', sysdate(), '', null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1000', '用户查询', '100', '1', '#', '', 'F', '0', '1', 'system:user:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1001', '用户新增', '100', '2', '#', '', 'F', '0', '1', 'system:user:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1002', '用户修改', '100', '3', '#', '', 'F', '0', '1', 'system:user:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1003', '用户删除', '100', '4', '#', '', 'F', '0', '1', 'system:user:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1004', '用户导出', '100', '5', '#', '', 'F', '0', '1', 'system:user:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1005', '用户导入', '100', '6', '#', '', 'F', '0', '1', 'system:user:import', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1006', '重置密码', '100', '7', '#', '', 'F', '0', '1', 'system:user:resetPwd', '#', 'admin', sysdate(), '', null, ''); +-- 角色管理按钮 +insert into sys_menu values('1007', '角色查询', '101', '1', '#', '', 'F', '0', '1', 'system:role:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1008', '角色新增', '101', '2', '#', '', 'F', '0', '1', 'system:role:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1009', '角色修改', '101', '3', '#', '', 'F', '0', '1', 'system:role:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1010', '角色删除', '101', '4', '#', '', 'F', '0', '1', 'system:role:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1011', '角色导出', '101', '5', '#', '', 'F', '0', '1', 'system:role:export', '#', 'admin', sysdate(), '', null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1012', '菜单查询', '102', '1', '#', '', 'F', '0', '1', 'system:menu:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1013', '菜单新增', '102', '2', '#', '', 'F', '0', '1', 'system:menu:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1014', '菜单修改', '102', '3', '#', '', 'F', '0', '1', 'system:menu:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1015', '菜单删除', '102', '4', '#', '', 'F', '0', '1', 'system:menu:remove', '#', 'admin', sysdate(), '', null, ''); +-- 部门管理按钮 +insert into sys_menu values('1016', '部门查询', '103', '1', '#', '', 'F', '0', '1', 'system:dept:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1017', '部门新增', '103', '2', '#', '', 'F', '0', '1', 'system:dept:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1018', '部门修改', '103', '3', '#', '', 'F', '0', '1', 'system:dept:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1019', '部门删除', '103', '4', '#', '', 'F', '0', '1', 'system:dept:remove', '#', 'admin', sysdate(), '', null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1020', '岗位查询', '104', '1', '#', '', 'F', '0', '1', 'system:post:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1021', '岗位新增', '104', '2', '#', '', 'F', '0', '1', 'system:post:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1022', '岗位修改', '104', '3', '#', '', 'F', '0', '1', 'system:post:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1023', '岗位删除', '104', '4', '#', '', 'F', '0', '1', 'system:post:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1024', '岗位导出', '104', '5', '#', '', 'F', '0', '1', 'system:post:export', '#', 'admin', sysdate(), '', null, ''); +-- 字典管理按钮 +insert into sys_menu values('1025', '字典查询', '105', '1', '#', '', 'F', '0', '1', 'system:dict:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1026', '字典新增', '105', '2', '#', '', 'F', '0', '1', 'system:dict:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1027', '字典修改', '105', '3', '#', '', 'F', '0', '1', 'system:dict:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1028', '字典删除', '105', '4', '#', '', 'F', '0', '1', 'system:dict:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1029', '字典导出', '105', '5', '#', '', 'F', '0', '1', 'system:dict:export', '#', 'admin', sysdate(), '', null, ''); +-- 参数设置按钮 +insert into sys_menu values('1030', '参数查询', '106', '1', '#', '', 'F', '0', '1', 'system:config:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1031', '参数新增', '106', '2', '#', '', 'F', '0', '1', 'system:config:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1032', '参数修改', '106', '3', '#', '', 'F', '0', '1', 'system:config:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1033', '参数删除', '106', '4', '#', '', 'F', '0', '1', 'system:config:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1034', '参数导出', '106', '5', '#', '', 'F', '0', '1', 'system:config:export', '#', 'admin', sysdate(), '', null, ''); +-- 通知公告按钮 +insert into sys_menu values('1035', '公告查询', '107', '1', '#', '', 'F', '0', '1', 'system:notice:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1036', '公告新增', '107', '2', '#', '', 'F', '0', '1', 'system:notice:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1037', '公告修改', '107', '3', '#', '', 'F', '0', '1', 'system:notice:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1038', '公告删除', '107', '4', '#', '', 'F', '0', '1', 'system:notice:remove', '#', 'admin', sysdate(), '', null, ''); +-- 操作日志按钮 +insert into sys_menu values('1039', '操作查询', '500', '1', '#', '', 'F', '0', '1', 'monitor:operlog:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1040', '操作删除', '500', '2', '#', '', 'F', '0', '1', 'monitor:operlog:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1041', '详细信息', '500', '3', '#', '', 'F', '0', '1', 'monitor:operlog:detail', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', 'F', '0', '1', 'monitor:operlog:export', '#', 'admin', sysdate(), '', null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', 'F', '0', '1', 'monitor:logininfor:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', 'F', '0', '1', 'monitor:logininfor:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', 'F', '0', '1', 'monitor:logininfor:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1046', '账户解锁', '501', '4', '#', '', 'F', '0', '1', 'monitor:logininfor:unlock', '#', 'admin', sysdate(), '', null, ''); +-- 在线用户按钮 +insert into sys_menu values('1047', '在线查询', '109', '1', '#', '', 'F', '0', '1', 'monitor:online:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1048', '批量强退', '109', '2', '#', '', 'F', '0', '1', 'monitor:online:batchForceLogout', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1049', '单条强退', '109', '3', '#', '', 'F', '0', '1', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, ''); +-- 定时任务按钮 +insert into sys_menu values('1050', '任务查询', '110', '1', '#', '', 'F', '0', '1', 'monitor:job:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1051', '任务新增', '110', '2', '#', '', 'F', '0', '1', 'monitor:job:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1052', '任务修改', '110', '3', '#', '', 'F', '0', '1', 'monitor:job:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1053', '任务删除', '110', '4', '#', '', 'F', '0', '1', 'monitor:job:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1054', '状态修改', '110', '5', '#', '', 'F', '0', '1', 'monitor:job:changeStatus', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1055', '任务详细', '110', '6', '#', '', 'F', '0', '1', 'monitor:job:detail', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1056', '任务导出', '110', '7', '#', '', 'F', '0', '1', 'monitor:job:export', '#', 'admin', sysdate(), '', null, ''); +-- 代码生成按钮 +insert into sys_menu values('1057', '生成查询', '115', '1', '#', '', 'F', '0', '1', 'tool:gen:list', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1058', '生成修改', '115', '2', '#', '', 'F', '0', '1', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1059', '生成删除', '115', '3', '#', '', 'F', '0', '1', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1060', '预览代码', '115', '4', '#', '', 'F', '0', '1', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1061', '生成代码', '115', '5', '#', '', 'F', '0', '1', 'tool:gen:code', '#', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +drop table if exists sys_user_role; +create table sys_user_role ( + user_id bigint(20) not null comment '用户ID', + role_id bigint(20) not null comment '角色ID', + primary key(user_id, role_id) +) engine=innodb comment = '用户和角色关联表'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('2', '2'); + + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +drop table if exists sys_role_menu; +create table sys_role_menu ( + role_id bigint(20) not null comment '角色ID', + menu_id bigint(20) not null comment '菜单ID', + primary key(role_id, menu_id) +) engine=innodb comment = '角色和菜单关联表'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('2', '1'); +insert into sys_role_menu values ('2', '2'); +insert into sys_role_menu values ('2', '3'); +insert into sys_role_menu values ('2', '4'); +insert into sys_role_menu values ('2', '100'); +insert into sys_role_menu values ('2', '101'); +insert into sys_role_menu values ('2', '102'); +insert into sys_role_menu values ('2', '103'); +insert into sys_role_menu values ('2', '104'); +insert into sys_role_menu values ('2', '105'); +insert into sys_role_menu values ('2', '106'); +insert into sys_role_menu values ('2', '107'); +insert into sys_role_menu values ('2', '108'); +insert into sys_role_menu values ('2', '109'); +insert into sys_role_menu values ('2', '110'); +insert into sys_role_menu values ('2', '111'); +insert into sys_role_menu values ('2', '112'); +insert into sys_role_menu values ('2', '113'); +insert into sys_role_menu values ('2', '114'); +insert into sys_role_menu values ('2', '115'); +insert into sys_role_menu values ('2', '116'); +insert into sys_role_menu values ('2', '500'); +insert into sys_role_menu values ('2', '501'); +insert into sys_role_menu values ('2', '1000'); +insert into sys_role_menu values ('2', '1001'); +insert into sys_role_menu values ('2', '1002'); +insert into sys_role_menu values ('2', '1003'); +insert into sys_role_menu values ('2', '1004'); +insert into sys_role_menu values ('2', '1005'); +insert into sys_role_menu values ('2', '1006'); +insert into sys_role_menu values ('2', '1007'); +insert into sys_role_menu values ('2', '1008'); +insert into sys_role_menu values ('2', '1009'); +insert into sys_role_menu values ('2', '1010'); +insert into sys_role_menu values ('2', '1011'); +insert into sys_role_menu values ('2', '1012'); +insert into sys_role_menu values ('2', '1013'); +insert into sys_role_menu values ('2', '1014'); +insert into sys_role_menu values ('2', '1015'); +insert into sys_role_menu values ('2', '1016'); +insert into sys_role_menu values ('2', '1017'); +insert into sys_role_menu values ('2', '1018'); +insert into sys_role_menu values ('2', '1019'); +insert into sys_role_menu values ('2', '1020'); +insert into sys_role_menu values ('2', '1021'); +insert into sys_role_menu values ('2', '1022'); +insert into sys_role_menu values ('2', '1023'); +insert into sys_role_menu values ('2', '1024'); +insert into sys_role_menu values ('2', '1025'); +insert into sys_role_menu values ('2', '1026'); +insert into sys_role_menu values ('2', '1027'); +insert into sys_role_menu values ('2', '1028'); +insert into sys_role_menu values ('2', '1029'); +insert into sys_role_menu values ('2', '1030'); +insert into sys_role_menu values ('2', '1031'); +insert into sys_role_menu values ('2', '1032'); +insert into sys_role_menu values ('2', '1033'); +insert into sys_role_menu values ('2', '1034'); +insert into sys_role_menu values ('2', '1035'); +insert into sys_role_menu values ('2', '1036'); +insert into sys_role_menu values ('2', '1037'); +insert into sys_role_menu values ('2', '1038'); +insert into sys_role_menu values ('2', '1039'); +insert into sys_role_menu values ('2', '1040'); +insert into sys_role_menu values ('2', '1041'); +insert into sys_role_menu values ('2', '1042'); +insert into sys_role_menu values ('2', '1043'); +insert into sys_role_menu values ('2', '1044'); +insert into sys_role_menu values ('2', '1045'); +insert into sys_role_menu values ('2', '1046'); +insert into sys_role_menu values ('2', '1047'); +insert into sys_role_menu values ('2', '1048'); +insert into sys_role_menu values ('2', '1049'); +insert into sys_role_menu values ('2', '1050'); +insert into sys_role_menu values ('2', '1051'); +insert into sys_role_menu values ('2', '1052'); +insert into sys_role_menu values ('2', '1053'); +insert into sys_role_menu values ('2', '1054'); +insert into sys_role_menu values ('2', '1055'); +insert into sys_role_menu values ('2', '1056'); +insert into sys_role_menu values ('2', '1057'); +insert into sys_role_menu values ('2', '1058'); +insert into sys_role_menu values ('2', '1059'); +insert into sys_role_menu values ('2', '1060'); +insert into sys_role_menu values ('2', '1061'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +drop table if exists sys_role_dept; +create table sys_role_dept ( + role_id bigint(20) not null comment '角色ID', + dept_id bigint(20) not null comment '部门ID', + primary key(role_id, dept_id) +) engine=innodb comment = '角色和部门关联表'; + +-- ---------------------------- +-- 初始化-角色和部门关联表数据 +-- ---------------------------- +insert into sys_role_dept values ('2', '100'); +insert into sys_role_dept values ('2', '101'); +insert into sys_role_dept values ('2', '105'); + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +drop table if exists sys_user_post; +create table sys_user_post +( + user_id bigint(20) not null comment '用户ID', + post_id bigint(20) not null comment '岗位ID', + primary key (user_id, post_id) +) engine=innodb comment = '用户与岗位关联表'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); +insert into sys_user_post values ('2', '2'); + + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +drop table if exists sys_oper_log; +create table sys_oper_log ( + oper_id bigint(20) not null auto_increment comment '日志主键', + title varchar(50) default '' comment '模块标题', + business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' comment '方法名称', + request_method varchar(10) default '' comment '请求方式', + operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' comment '操作人员', + dept_name varchar(50) default '' comment '部门名称', + oper_url varchar(255) default '' comment '请求URL', + oper_ip varchar(128) default '' comment '主机地址', + oper_location varchar(255) default '' comment '操作地点', + oper_param varchar(2000) default '' comment '请求参数', + json_result varchar(2000) default '' comment '返回参数', + status int(1) default 0 comment '操作状态(0正常 1异常)', + error_msg varchar(2000) default '' comment '错误消息', + oper_time datetime comment '操作时间', + cost_time bigint(20) default 0 comment '消耗时间', + primary key (oper_id), + key idx_sys_oper_log_bt (business_type), + key idx_sys_oper_log_s (status), + key idx_sys_oper_log_ot (oper_time) +) engine=innodb auto_increment=100 comment = '操作日志记录'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +drop table if exists sys_dict_type; +create table sys_dict_type +( + dict_id bigint(20) not null auto_increment comment '字典主键', + dict_name varchar(100) default '' comment '字典名称', + dict_type varchar(100) default '' comment '字典类型', + status char(1) default '0' comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_id), + unique (dict_type) +) engine=innodb auto_increment=100 comment = '字典类型表'; + +insert into sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', sysdate(), '', null, '用户性别列表'); +insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', sysdate(), '', null, '菜单状态列表'); +insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', sysdate(), '', null, '系统开关列表'); +insert into sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', sysdate(), '', null, '任务状态列表'); +insert into sys_dict_type values(5, '任务分组', 'sys_job_group', '0', 'admin', sysdate(), '', null, '任务分组列表'); +insert into sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', sysdate(), '', null, '系统是否列表'); +insert into sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', sysdate(), '', null, '通知类型列表'); +insert into sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', sysdate(), '', null, '通知状态列表'); +insert into sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', sysdate(), '', null, '操作类型列表'); +insert into sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', sysdate(), '', null, '登录状态列表'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +drop table if exists sys_dict_data; +create table sys_dict_data +( + dict_code bigint(20) not null auto_increment comment '字典编码', + dict_sort int(4) default 0 comment '字典排序', + dict_label varchar(100) default '' comment '字典标签', + dict_value varchar(100) default '' comment '字典键值', + dict_type varchar(100) default '' comment '字典类型', + css_class varchar(100) default null comment '样式属性(其他样式扩展)', + list_class varchar(100) default null comment '表格回显样式', + is_default char(1) default 'N' comment '是否默认(Y是 N否)', + status char(1) default '0' comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_code) +) engine=innodb auto_increment=100 comment = '字典数据表'; + +insert into sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', sysdate(), '', null, '性别男'); +insert into sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别女'); +insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别未知'); +insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单'); +insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '隐藏菜单'); +insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); +insert into sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); +insert into sys_dict_data values(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', sysdate(), '', null, '默认分组'); +insert into sys_dict_data values(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', sysdate(), '', null, '系统分组'); +insert into sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是'); +insert into sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '系统默认否'); +insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知'); +insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '公告'); +insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '关闭状态'); +insert into sys_dict_data values(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '其他操作'); +insert into sys_dict_data values(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '新增操作'); +insert into sys_dict_data values(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '修改操作'); +insert into sys_dict_data values(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '删除操作'); +insert into sys_dict_data values(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作'); +insert into sys_dict_data values(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作'); +insert into sys_dict_data values(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作'); +insert into sys_dict_data values(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '强退操作'); +insert into sys_dict_data values(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作'); +insert into sys_dict_data values(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '清空操作'); +insert into sys_dict_data values(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +drop table if exists sys_config; +create table sys_config ( + config_id int(5) not null auto_increment comment '参数主键', + config_name varchar(100) default '' comment '参数名称', + config_key varchar(100) default '' comment '参数键名', + config_value varchar(500) default '' comment '参数键值', + config_type char(1) default 'N' comment '系统内置(Y是 N否)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (config_id) +) engine=innodb auto_increment=100 comment = '参数配置表'; + +insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456'); +insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深黑主题theme-dark,浅色主题theme-light,深蓝主题theme-blue'); +insert into sys_config values(4, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(5, '用户管理-密码字符范围', 'sys.account.chrtype', '0', 'Y', 'admin', sysdate(), '', null, '默认任意字符范围,0任意(密码可以输入任意字符),1数字(密码只能为0-9数字),2英文字母(密码只能为a-z和A-Z字母),3字母和数字(密码必须包含字母,数字),4字母数字和特殊字符(目前支持的特殊字符包括:~!@#$%^&*()-=_+)'); +insert into sys_config values(6, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', sysdate(), '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框'); +insert into sys_config values(7, '用户管理-账号密码更新周期', 'sys.account.passwordValidateDays', '0', 'Y', 'admin', sysdate(), '', null, '密码更新周期(填写数字,数据初始化值为0不限制,若修改必须为大于0小于365的正整数),如果超过这个周期登录系统时,则在登录时就会提醒修改密码对话框'); +insert into sys_config values(8, '主框架页-菜单导航显示风格', 'sys.index.menuStyle', 'default', 'Y', 'admin', sysdate(), '', null, '菜单导航显示风格(default为左侧导航菜单,topnav为顶部导航菜单)'); +insert into sys_config values(9, '主框架页-是否开启页脚', 'sys.index.footer', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启底部页脚显示(true显示,false隐藏)'); +insert into sys_config values(10, '主框架页-是否开启页签', 'sys.index.tagsView', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启菜单多页签显示(true显示,false隐藏)'); +insert into sys_config values(11, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +drop table if exists sys_logininfor; +create table sys_logininfor ( + info_id bigint(20) not null auto_increment comment '访问ID', + login_name varchar(50) default '' comment '登录账号', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status char(1) default '0' comment '登录状态(0成功 1失败)', + msg varchar(255) default '' comment '提示消息', + login_time datetime comment '访问时间', + primary key (info_id), + key idx_sys_logininfor_s (status), + key idx_sys_logininfor_lt (login_time) +) engine=innodb auto_increment=100 comment = '系统访问记录'; + + +-- ---------------------------- +-- 15、在线用户记录 +-- ---------------------------- +drop table if exists sys_user_online; +create table sys_user_online ( + sessionId varchar(50) default '' comment '用户会话id', + login_name varchar(50) default '' comment '登录账号', + dept_name varchar(50) default '' comment '部门名称', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status varchar(10) default '' comment '在线状态on_line在线off_line离线', + start_timestamp datetime comment 'session创建时间', + last_access_time datetime comment 'session最后访问时间', + expire_time int(5) default 0 comment '超时时间,单位为分钟', + primary key (sessionId) +) engine=innodb comment = '在线用户记录'; + + +-- ---------------------------- +-- 16、定时任务调度表 +-- ---------------------------- +drop table if exists sys_job; +create table sys_job ( + job_id bigint(20) not null auto_increment comment '任务ID', + job_name varchar(64) default '' comment '任务名称', + job_group varchar(64) default 'DEFAULT' comment '任务组名', + invoke_target varchar(500) not null comment '调用目标字符串', + cron_expression varchar(255) default '' comment 'cron执行表达式', + misfire_policy varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + concurrent char(1) default '1' comment '是否并发执行(0允许 1禁止)', + status char(1) default '0' comment '状态(0正常 1暂停)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注信息', + primary key (job_id, job_name, job_group) +) engine=innodb auto_increment=100 comment = '定时任务调度表'; + +insert into sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, ''); +insert into sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, ''); +insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 17、定时任务调度日志表 +-- ---------------------------- +drop table if exists sys_job_log; +create table sys_job_log ( + job_log_id bigint(20) not null auto_increment comment '任务日志ID', + job_name varchar(64) not null comment '任务名称', + job_group varchar(64) not null comment '任务组名', + invoke_target varchar(500) not null comment '调用目标字符串', + job_message varchar(500) comment '日志信息', + status char(1) default '0' comment '执行状态(0正常 1失败)', + exception_info varchar(2000) default '' comment '异常信息', + create_time datetime comment '创建时间', + primary key (job_log_id) +) engine=innodb comment = '定时任务调度日志表'; + + +-- ---------------------------- +-- 18、通知公告表 +-- ---------------------------- +drop table if exists sys_notice; +create table sys_notice ( + notice_id int(4) not null auto_increment comment '公告ID', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content longblob default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb auto_increment=10 comment = '通知公告表'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '温馨提醒:2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员'); +insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', sysdate(), '', null, '管理员'); +insert into sys_notice values('3', '若依开源框架介绍', '1', '

项目介绍

RuoYi开源项目是为企业用户定制的后台脚手架框架,为企业打造的一站式解决方案,降低企业开发成本,提升开发效率。主要包括用户管理、角色管理、部门管理、菜单管理、参数管理、字典管理、岗位管理、定时任务服务监控、登录日志、操作日志、代码生成等功能。其中,还支持多数据源、数据权限、国际化、Redis缓存、Docker部署、滑动验证码、第三方认证登录、分布式事务、分布式文件存储、分库分表处理等技术特点。


官网及演示

若依官网地址: http://ruoyi.vip

若依文档地址: http://doc.ruoyi.vip

演示地址【不分离版】: http://demo.ruoyi.vip

演示地址【分离版本】: http://vue.ruoyi.vip

演示地址【微服务版】: http://cloud.ruoyi.vip

演示地址【移动端版】: http://h5.ruoyi.vip


', '0', 'admin', sysdate(), '', null, '管理员'); + + +-- ---------------------------- +-- 19、代码生成业务表 +-- ---------------------------- +drop table if exists gen_table; +create table gen_table ( + table_id bigint(20) not null auto_increment comment '编号', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作 sub主子表操作)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb auto_increment=1 comment = '代码生成业务表'; + + +-- ---------------------------- +-- 20、代码生成业务表字段 +-- ---------------------------- +drop table if exists gen_table_column; +create table gen_table_column ( + column_id bigint(20) not null auto_increment comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb auto_increment=1 comment = '代码生成业务表字段'; \ No newline at end of file