mirror of
				https://github.com/dromara/RuoYi-Vue-Plus.git
				synced 2025-10-22 18:03:44 +08:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			e1e3843ec0
			...
			v3.3.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | afbe1c98e6 | ||
|  | c0e4e27dcc | ||
|  | 85762f7c92 | ||
|  | c6963e1a96 | ||
|  | ed7e8d0e5c | ||
|  | b47a38d9d8 | ||
|  | c2efaa5c3c | 
| @@ -10,7 +10,7 @@ end_of_line = lf | ||||
| trim_trailing_whitespace = true | ||||
| insert_final_newline = true | ||||
|  | ||||
| [*.{json,yml,yaml}] | ||||
| [*.{json,yml}] | ||||
| indent_size = 2 | ||||
|  | ||||
| [*.md] | ||||
|   | ||||
| @@ -1,51 +0,0 @@ | ||||
| name: Bug 反馈 | ||||
| description: 当你使用过程中发现了一个 Bug,导致应用崩溃或抛出异常,或者有一个组件存在问题,或者某些地方看起来不对劲,请在这里反馈。 | ||||
| title: "[Bug]: " | ||||
| labels: ["bug"] | ||||
| body: | ||||
|   - type: textarea | ||||
|     id: version | ||||
|     attributes: | ||||
|       label: 版本 | ||||
|       description: 你当前正在使用我们软件的哪个版本(pom文件内的版本号)? | ||||
|       value: | | ||||
|         注意: 未填写版本号不予处理直接关闭或删除 | ||||
|         jdk版本(带上尾号): | ||||
|         框架版本(项目启动时输出的版本号): | ||||
|         其他依赖版本(你觉得有必要的): | ||||
|     validations: | ||||
|       required: true | ||||
|   - type: checkboxes | ||||
|     attributes: | ||||
|       label: 功能不好用不会用是否已经看过项目文档? | ||||
|       options: | ||||
|         - label: https://plus-doc.dromara.org | ||||
|           required: true | ||||
|   - type: checkboxes | ||||
|     attributes: | ||||
|       label: 这个问题是否已经存在? | ||||
|       options: | ||||
|         - label: 我已经搜索过现有的问题 (https://gitee.com/dromara/RuoYi-Vue-Plus/issues) | ||||
|           required: true | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: 希望结果 | ||||
|       description: 想知道你觉得怎么样是正常或者合理的。 | ||||
|     validations: | ||||
|       required: true | ||||
|   - type: markdown | ||||
|     attributes: | ||||
|       label: 如何复现 | ||||
|       description: 请详细告诉我们如何复现你遇到的问题。 | ||||
|       value: | | ||||
|         如涉及代码,可提供一个最小代码示例,并使用```附上它,或者截图均可,越详细越好。<br> | ||||
|         大多数问题都是:代码编写错误问题,逻辑问题,或者用法错误等问题。 | ||||
|     validations: | ||||
|       required: true | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: 相关代码与报错信息(请勿发混乱格式) | ||||
|       description: 如果可以的话,上传任何关于 bug 的截图。 | ||||
|       value: | | ||||
|         [在这里上传图片] | ||||
|  | ||||
| @@ -1,5 +0,0 @@ | ||||
| blank_issues_enabled: false | ||||
| contact_links: | ||||
|   - name: RuoYi-Vue-Plus 文档中心 | ||||
|     url: https://plus-doc.dromara.org | ||||
|     about: 提供 RuoYi-Vue-Plus 搭建使用指南、平台基本开发使用方式、介绍、基础知识和常见问题解答 | ||||
| @@ -1,43 +0,0 @@ | ||||
| name: 功能建议 | ||||
| description: 对本项目提出一个功能建议。 | ||||
| title: "[功能建议]: " | ||||
| labels: ["enhancement"] | ||||
| body: | ||||
|   - type: markdown | ||||
|     attributes: | ||||
|       value: | | ||||
|         感谢提出功能建议,我们将仔细考虑!请持续关注该issues,在加入计划后我们会有贡献者设置为负责人,同时状态成为进行中。 | ||||
|   - type: textarea | ||||
|     id: related-problem | ||||
|     attributes: | ||||
|       label: 你的功能建议是否和某个问题相关? | ||||
|       description: 清晰并简洁地描述问题是什么,例如,当我...时,我总是感到困扰。 | ||||
|     validations: | ||||
|       required: false | ||||
|   - type: textarea | ||||
|     id: desired-solution | ||||
|     attributes: | ||||
|       label: 你希望看到什么解决方案? | ||||
|       description: 清晰并简洁地描述你希望发生的事情。 | ||||
|     validations: | ||||
|       required: true | ||||
|   - type: textarea | ||||
|     id: alternatives | ||||
|     attributes: | ||||
|       label: 你考虑过哪些替代方案? | ||||
|       description: 清晰并简洁地描述你考虑过的任何替代解决方案或功能。 | ||||
|     validations: | ||||
|       required: false | ||||
|   - type: textarea | ||||
|     id: additional-context | ||||
|     attributes: | ||||
|       label: 你有其他上下文或截图吗? | ||||
|       description: 在此处添加有关功能请求的任何其他上下文或截图。 | ||||
|     validations: | ||||
|       required: false | ||||
|   - type: checkboxes | ||||
|     attributes: | ||||
|       label: 意向参与贡献 | ||||
|       options: | ||||
|         - label: 我有意向参与具体功能的开发实现并将代码贡献回到上游社区。 | ||||
|           required: false | ||||
| @@ -1,7 +0,0 @@ | ||||
| ### 更改目的 解决了什么问题(请提交到dev分支) | ||||
|  | ||||
|  | ||||
| ### 改动逻辑 这么写的思路(让作者更好的理解你的意图) | ||||
|  | ||||
|  | ||||
| ### 测试 都做了哪些测试(未经过测试不采纳) | ||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -25,9 +25,6 @@ target/ | ||||
| *.iml | ||||
| *.ipr | ||||
|  | ||||
| ### JRebel ### | ||||
| rebel.xml | ||||
|  | ||||
| ### NetBeans ### | ||||
| nbproject/private/ | ||||
| build/* | ||||
| @@ -44,5 +41,3 @@ nbdist/ | ||||
| !*/build/*.java | ||||
| !*/build/*.html | ||||
| !*/build/*.xml | ||||
|  | ||||
| .flattened-pom.xml | ||||
|   | ||||
| @@ -1,12 +0,0 @@ | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> | ||||
|     <deployment type="dockerfile"> | ||||
|       <settings> | ||||
|         <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.3.1" /> | ||||
|         <option name="buildOnly" value="true" /> | ||||
|         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" /> | ||||
|       </settings> | ||||
|     </deployment> | ||||
|     <method v="2" /> | ||||
|   </configuration> | ||||
| </component> | ||||
| @@ -1,12 +0,0 @@ | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> | ||||
|     <deployment type="dockerfile"> | ||||
|       <settings> | ||||
|         <option name="imageTag" value="ruoyi/ruoyi-server:5.3.1" /> | ||||
|         <option name="buildOnly" value="true" /> | ||||
|         <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" /> | ||||
|       </settings> | ||||
|     </deployment> | ||||
|     <method v="2" /> | ||||
|   </configuration> | ||||
| </component> | ||||
| @@ -1,12 +0,0 @@ | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> | ||||
|     <deployment type="dockerfile"> | ||||
|       <settings> | ||||
|         <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.3.1" /> | ||||
|         <option name="buildOnly" value="true" /> | ||||
|         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" /> | ||||
|       </settings> | ||||
|     </deployment> | ||||
|     <method v="2" /> | ||||
|   </configuration> | ||||
| </component> | ||||
							
								
								
									
										293
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										293
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,185 +1,152 @@ | ||||
| <img src="https://foruda.gitee.com/images/1679673773341074847/178e8451_1766278.png" width="50%" height="50%"> | ||||
| <div style="height: 10px; clear: both;"></div> | ||||
|  | ||||
| - - - | ||||
| ## 平台简介 | ||||
|  | ||||
| [](https://gitee.com/dromara/RuoYi-Vue-Plus) | ||||
| [](https://github.com/dromara/RuoYi-Vue-Plus) | ||||
| [](https://gitcode.com/dromara/RuoYi-Vue-Plus) | ||||
| [](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE) | ||||
| [](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) | ||||
| [](https://github.com/JavaLionLi/RuoYi-Vue-Plus) | ||||
| [](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE) | ||||
| [](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) | ||||
| <br> | ||||
| [](https://gitee.com/dromara/RuoYi-Vue-Plus) | ||||
| []() | ||||
| [](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) | ||||
| []() | ||||
| []() | ||||
| []() | ||||
| []() | ||||
| []() | ||||
|  | ||||
| > Dromara RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) | ||||
| RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 `分布式集群` 场景升级(不兼容原框架) | ||||
|  | ||||
| > 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可<br> | ||||
| 活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 | ||||
|  | ||||
| > 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system) | ||||
|  | ||||
| > 官方前端项目地址: [plus-ui](https://gitee.com/JavaLionLi/plus-ui)<br> | ||||
| > 成员前端项目地址: 基于vben5 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5) | ||||
|  | ||||
| > 文档地址: [plus-doc](https://plus-doc.dromara.org) | ||||
|  | ||||
| ## 赞助商 | ||||
|  | ||||
| MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey <br> | ||||
| CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br> | ||||
| 数舵科技 软件定制开发APP小程序等 - http://www.shuduokeji.com/ <br> | ||||
| 引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc <br> | ||||
| <font color="red">**启山商城系统 多租户商城源码可免费商用可二次开发 - https://www.73app.cn/** </font><br> | ||||
| Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11 <br> | ||||
| [如何成为赞助商 加群联系作者详谈](https://plus-doc.dromara.org/#/common/add_group) | ||||
|  | ||||
| # 本框架与RuoYi的功能差异 | ||||
|  | ||||
| | 功能          | 本框架                                                                                                               | RuoYi                                                                              | | ||||
| |-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| | ||||
| | 前端项目        | 采用 Vue3 + TS + ElementPlus 重写                                                                                     | 基于Vue2/Vue3 + JS                                                                   |  | ||||
| | 后端项目结构      | 采用插件化 + 扩展包形式 结构解耦 易于扩展                                                                                           | 模块相互注入耦合严重难以扩展                                                                     |  | ||||
| | 后端代码风格      | 严格遵守Alibaba规范与项目统一配置的代码格式化                                                                                        | 代码书写与常规结构不同阅读障碍大                                                                   | | ||||
| | Web容器       | 采用 Undertow 基于 XNIO 的高性能容器                                                                                        | 采用 Tomcat                                                                          | | ||||
| | 权限认证        | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展                                                                                  | Spring Security 配置繁琐扩展性极差                                                          | | ||||
| | 权限注解        | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验<br/>角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式        | 只支持是否存在匹配                                                                          | | ||||
| | 三方鉴权        | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证                                                                               | 无                                                                                  | | ||||
| | 关系数据库支持     | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer<br/>可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例)      | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换                                                    | | ||||
| | 缓存数据库       | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列                                                                             | Redis 简单 get set 支持                                                                | | ||||
| | Redis客户端    | 采用 Redisson Redis官方推荐 基于Netty的客户端工具<br/>支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan<br/>支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐<br/>连接池采用 common-pool Bug多经常性出问题              | | ||||
| | 缓存注解        | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能<br/>例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存                                      | 需手动编写Redis代码逻辑                                                                     | | ||||
| | ORM框架       | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多<br/>例如多租户插件 分页插件 乐观锁插件等等                                             | 采用 Mybatis 基于XML需要手写SQL                                                            | | ||||
| | SQL监控       | 采用 p6spy 可输出完整SQL与执行时间监控                                                                                          | log输出 需手动拼接sql与参数无法快速查看调试问题                                                        | | ||||
| | 数据分页        | 采用 Mybatis-Plus 分页插件<br/>框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序                                                  | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好                               | | ||||
| | 数据权限        | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤<br/>只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色                                           | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展<br/>生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | | ||||
| | 数据脱敏        | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件<br/>支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展                                        | 无                                                                                  | | ||||
| | 数据加解密       | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密<br/>支持多种策略 如BASE64、AES、RSA、SM2、SM4等                                              | 无                                                                                  | | ||||
| | 接口传输加密      | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性                                                                     | 无                                                                                  | | ||||
| | 数据翻译        | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译<br/>支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现                   | 无                                                                                  | | ||||
| | 多数据源框架      | 采用 dynamic-datasource 支持市面大部分数据库<br/>通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源<br/>支持spel表达式从请求头参数等条件切换数据源            | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差                                                     | | ||||
| | 多数据源事务      | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚                                                                          | 不支持                                                                                | | ||||
| | 数据库连接池      | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下                                                                        | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般                                               | | ||||
| | 数据库主键       | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁                                                                  | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一                                                     | | ||||
| | WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物                                                         | 无                                                                                  | | ||||
| | SSE推送       | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步                                                                               | 无                                                                                  | | ||||
| | 序列化         | 采用 Jackson Spring官方内置序列化 靠谱!!!                                                                                    | 采用 fastjson bugjson 远近闻名                                                           |  | ||||
| | 分布式幂等       | 参考美团GTIS防重系统简化实现(细节可看文档)                                                                                          | 手动编写注解基于aop实现                                                                      | | ||||
| | 分布式锁        | 采用 Lock4j 底层基于 Redisson                                                                                           | 无                                                                                  | | ||||
| | 分布式任务调度     | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等                                                                 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造                                                   |  | ||||
| | 文件存储        | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储<br/>支持权限管理 安全可靠 文件可加密存储                                                     | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应                                                    | | ||||
| | 云存储         | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家                                                                          | 不支持                                                                                | | ||||
| | 短信          | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用                                                                 | 不支持                                                                                | | ||||
| | 邮件          | 采用 mail-api 通用协议支持大部分邮件厂商                                                                                         | 不支持                                                                                | | ||||
| | 接口文档        | 采用 SpringDoc、javadoc 无注解零入侵基于java注释<br/>只需把注释写好 无需再写一大堆的文档注解了                                                     | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成                                                |  | ||||
| | 校验框架        | 采用 Validation 支持注解与工具类校验 注解支持国际化                                                                                  | 仅支持注解 且注解不支持国际化                                                                    | | ||||
| | Excel框架     | 采用 FastExcel(原Alibaba EasyExcel) 基于插件化<br/>框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等                                   | 基于 POI 手写实现 功能有限 复杂 扩展性差                                                           | | ||||
| | 工作流支持       | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能                                                                                   | 无                                                                                  | | ||||
| | 工具类框架       | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码                                                       | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等                                            |  | ||||
| | 监控框架        | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制<br/>实时监控服务状态 框架还为其扩展了在线日志查看监控                                    | 无                                                                                  |  | ||||
| | 链路追踪        | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗<br/>用了它即可实时查看请求经过的每一处每一个节点                                            | 无                                                                                  | | ||||
| | 代码生成器       | 只需设计好表结构 一键生成所有crud代码与页面<br/>降低80%的开发量 把精力都投入到业务设计上<br/>框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成                    | 代码生成原生结构 只支持单数据源生成                                                                 | | ||||
| | 部署方式        | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼                                                                           | 原生jar部署 其他环境需手动下载安装 自行搭建                                                           |  | ||||
| | 项目路径修改      | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的                                                                              | 需要做很多改造 文档说明有限                                                                     | | ||||
| | 国际化         | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化                                                                     | 只提供基础功能 其他需自行编写扩展                                                                  | | ||||
| | 代码单例测试      | 提供单例测试 使用方式编写方法与maven多环境单测插件                                                                                      | 只提供基础功能 其他需自行编写扩展                                                                  | | ||||
| | Demo案例      | 提供框架功能的实际使用案例 单独一个模块提供了很多很全                                                                                       | 无                                                                                  | | ||||
|  | ||||
|  | ||||
| ## 本框架与RuoYi的业务差异 | ||||
|  | ||||
| | 业务     | 功能说明                                                                 | 本框架 | RuoYi            | | ||||
| |--------|----------------------------------------------------------------------|-----|------------------| | ||||
| | 租户管理   | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等                                      | 支持  | 无                | | ||||
| | 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等                                          | 支持  | 无                | | ||||
| | 客户端管理  | 系统内对接的所有客户端管理 如: pc端、小程序端等<br>支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持  | 无                | | ||||
| | 用户管理   | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等                                       | 支持  | 支持               | | ||||
| | 部门管理   | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限                                       | 支持  | 支持               | | ||||
| | 岗位管理   | 配置系统用户所属担任职务                                                         | 支持  | 支持               | | ||||
| | 菜单管理   | 配置系统菜单、操作权限、按钮权限标识等                                                  | 支持  | 支持               | | ||||
| | 角色管理   | 角色菜单权限分配、设置角色按机构进行数据范围权限划分                                           | 支持  | 支持               | | ||||
| | 字典管理   | 对系统中经常使用的一些较为固定的数据进行维护                                               | 支持  | 支持               | | ||||
| | 参数管理   | 对系统动态配置常用参数                                                          | 支持  | 支持               | | ||||
| | 通知公告   | 系统通知公告信息发布维护                                                         | 支持  | 支持               | | ||||
| | 操作日志   | 系统正常操作日志记录和查询 系统异常信息日志记录和查询                                          | 支持  | 支持               | | ||||
| | 登录日志   | 系统登录日志记录查询包含登录异常                                                     | 支持  | 支持               | | ||||
| | 文件管理   | 系统文件展示、上传、下载、删除等管理                                                   | 支持  | 无                | | ||||
| | 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理                                       | 支持  | 无                | | ||||
| | 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作                                                | 支持  | 支持               | | ||||
| | 定时任务   | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等                                      | 支持  | 仅支持任务与日志管理       | | ||||
| | 代码生成   | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载                              | 支持  | 仅支持单数据源          | | ||||
| | 系统接口   | 根据业务代码自动生成相关的api接口文档                                                 | 支持  | 支持               | | ||||
| | 服务监控   | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等                                  | 支持  | 仅支持单机CPU、内存、磁盘监控 | | ||||
| | 缓存监控   | 对系统的缓存信息查询,命令统计等。                                                    | 支持  | 支持               | | ||||
| | 使用案例   | 系统的一些功能案例                                                            | 支持  | 不支持              | | ||||
| | 功能介绍 | 使用技术 | 文档地址 | 特性注意事项 | | ||||
| |---|---|---|---| | ||||
| | 当前框架 | RuoYi-Vue-Plus | [RuoYi-Vue-Plus文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) | 重写RuoYi-Vue全方位升级(不兼容原框架) | | ||||
| | satoken分支 | RuoYi-Vue-Plus-satoken | [satoken分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/) | 使用satoken重构权限鉴权(仅供学习不推荐上生产) | | ||||
| | 单体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | 单体应用结构 | | ||||
| | 原框架 | RuoYi-Vue | [RuoYi-Vue官网](http://ruoyi.vip/) | 定期同步需要的功能 | | ||||
| | 前端开发框架 | Vue、Element UI | [Element UI官网](https://element.eleme.cn/#/zh-CN) | | | ||||
| | 后端开发框架 | SpringBoot | [SpringBoot官网](https://spring.io/projects/spring-boot/#learn) | | | ||||
| | 容器框架 | Undertow | [Undertow官网](https://undertow.io/) | 基于 Netty 的高性能容器 | | ||||
| | 权限认证框架 | Spring Security、Jwt | [SpringSecurity官网](https://spring.io/projects/spring-security#learn) | 支持多终端认证系统 | | ||||
| | 关系数据库 | MySQL | [MySQL官网](https://dev.mysql.com/) | 适配 8.X 最低 5.7 | | ||||
| | 缓存数据库 | Redis | [Redis官网](https://redis.io/) | 适配 6.X 最低 4.X | | ||||
| | 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 | | ||||
| | 数据库框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | 更强劲的 SQL 分析 | | ||||
| | 多数据源框架 | dynamic-datasource | [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/content) | 支持主从与多种类数据库异构 | | ||||
| | 序列化框架 | Jackson | [Jackson官网](https://github.com/FasterXML/jackson) | 统一使用 jackson 高效可靠 | | ||||
| | 网络框架 | Feign、OkHttp3 | [Feign官网](https://github.com/OpenFeign/feign) | 接口化管理 HTTP 请求 | | ||||
| | Redis客户端 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 支持单机、集群配置 | | ||||
| | 分布式限流 | Redisson | [Redisson文档](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) | 全局、请求IP、集群ID 多种限流 | | ||||
| | 分布式锁 | Lock4j | [Lock4j官网](https://gitee.com/baomidou/lock4j) | 注解锁、工具锁 多种多样 | | ||||
| | 分布式幂等 | Lock4j | [Lock4j文档](https://gitee.com/baomidou/lock4j) | 基于分布式锁实现 | | ||||
| | 分布式日志 | TLog | [TLog文档](https://yomahub.com/tlog/docs) | 支持跟踪链路日志记录、性能分析、链路排查 | | ||||
| | 分布式任务调度 | Xxl-Job | [Xxl-Job官网](https://www.xuxueli.com/xxl-job/) | 高性能 高可靠 易扩展 | | ||||
| | 文件存储 | Minio | [Minio文档](https://docs.min.io/) | 本地存储 | | ||||
| | 文件存储 | 七牛、阿里、腾讯 | [OSS使用文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4359146&doc_id=1469725) | 云存储 | | ||||
| | 监控框架 | SpringBoot-Admin | [SpringBoot-Admin文档](https://codecentric.github.io/spring-boot-admin/current/) | 全方位服务监控 | | ||||
| | 校验框架 | Validation | [Validation文档](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/) | 增强接口安全性、严谨性 | | ||||
| | Excel框架 | Alibaba EasyExcel | [EasyExcel文档](https://www.yuque.com/easyexcel/doc/easyexcel) | 性能优异 扩展性强 | | ||||
| | 文档框架 | Knife4j | [Knife4j文档](https://doc.xiaominfo.com/knife4j/documentation/) | 美化接口文档 | | ||||
| | 工具类框架 | Hutool、Lombok | [Hutool文档](https://www.hutool.cn/docs/) | 减少代码冗余 增加安全性 | | ||||
| | 代码生成器 | 适配MP、Knife4j规范化代码 | [Hutool文档](https://www.hutool.cn/docs/) | 一键生成前后端代码 | | ||||
| | 部署方式 | Docker | [Docker文档](https://docs.docker.com/) | 容器编排 一键部署业务集群 | | ||||
| | 国际化 | SpringMessage | [SpringMVC文档](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc) | Spring标准国际化方案 | | ||||
|  | ||||
| ## 参考文档 | ||||
|  | ||||
| 使用框架前请仔细阅读文档重点注意事项 | ||||
| <br> | ||||
| >[初始化项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) | ||||
| >>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) | ||||
| > | ||||
| >[专栏与视频 入门必看](https://plus-doc.dromara.org/#/common/column) | ||||
| >>[https://plus-doc.dromara.org/#/common/column](https://plus-doc.dromara.org/#/common/column) | ||||
| > | ||||
| >[部署项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) | ||||
| >>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) | ||||
| > | ||||
| >[如何加群](https://plus-doc.dromara.org/#/common/add_group) | ||||
| >>[https://plus-doc.dromara.org/#/common/add_group](https://plus-doc.dromara.org/#/common/add_group) | ||||
| > | ||||
| >[参考文档 Wiki](https://plus-doc.dromara.org) | ||||
| >>[https://plus-doc.dromara.org](https://plus-doc.dromara.org) | ||||
| >[初始化项目 必看](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117) | ||||
| >>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于初始化项目?sort_id=4164117) | ||||
| >  | ||||
| >[部署项目 必看](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382) | ||||
| >>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/关于应用部署?sort_id=4219382) | ||||
| >  | ||||
| >[参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) | ||||
| >>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) | ||||
|  | ||||
| ## 软件架构图 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ## 如何参与贡献 | ||||
| ## 贡献代码 | ||||
|  | ||||
| [参与贡献的方式 https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution) | ||||
| 欢迎各路英雄豪杰 `PR` 代码 请提交到 `dev` 开发分支 统一测试发版 | ||||
|  | ||||
| 框架定位为 `通用后台管理系统(分布式集群强化)` 原则上不接受业务 `PR` | ||||
|  | ||||
| ### 其他 | ||||
|  | ||||
| * 同步升级 RuoYi-Vue | ||||
| * GitHub 地址 [RuoYi-Vue-Plus-github](https://github.com/JavaLionLi/RuoYi-Vue-Plus) | ||||
| * 单模块 fast 分支 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | ||||
| * satoken 分支 [RuoYi-Vue-Plus-satoken](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/satoken/) | ||||
| * 用户扩展项目 [扩展项目列表](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4478302&doc_id=1469725) | ||||
|  | ||||
| ## 加群与捐献 | ||||
| >[加群与捐献](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598) | ||||
| >>[https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/加群与捐献?sort_id=4104598) | ||||
|  | ||||
| ## 捐献作者 | ||||
| 作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭   | ||||
| <img src="https://foruda.gitee.com/images/1678975784848381069/d8661ed9_1766278.png" width="300px" height="450px" /> | ||||
| <img src="https://foruda.gitee.com/images/1678975801230205215/6f96229d_1766278.png" width="300px" height="450px" /> | ||||
| <img src="https://images.gitee.com/uploads/images/2021/0525/101654_451e4523_1766278.jpeg" width="300px" height="450px" /> | ||||
| <img src="https://images.gitee.com/uploads/images/2021/0525/101713_3d18b119_1766278.jpeg" width="300px" height="450px" /> | ||||
|  | ||||
| ## 业务功能 | ||||
|  | ||||
| | 功能 | 介绍 | | ||||
| |---|---| | ||||
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置。 | | ||||
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 | | ||||
| | 岗位管理 | 配置系统用户所属担任职务。 | | ||||
| | 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等。 | | ||||
| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分。 | | ||||
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护。 | | ||||
| | 参数管理 | 对系统动态配置常用参数。 | | ||||
| | 通知公告 | 系统通知公告信息发布维护。 | | ||||
| | 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询。 | | ||||
| | 登录日志 | 系统登录日志记录查询包含登录异常。 | | ||||
| | 文件管理 | 系统文件上传、下载等管理。 | | ||||
| | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志。 | | ||||
| | 代码生成 | 前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 | | ||||
| | 系统接口 | 根据业务代码自动生成相关的api接口文档。 | | ||||
| | 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等。 | | ||||
| | 缓存监控 | 对系统的缓存信息查询,命令统计等。 | | ||||
| | 在线构建器 | 拖动表单元素生成相应的HTML代码。 | | ||||
| | 连接池监视 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 | | ||||
| | 使用案例 | 系统的一些功能案例 | | ||||
|  | ||||
| ## 演示图例 | ||||
|  | ||||
| |                                                                                            |                                                                                            | | ||||
| |--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
| |  |  | | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| <table border="1" cellpadding="1" cellspacing="1" style="width:500px"> | ||||
| 	<tbody> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-972235bcbe3518dedd351ff0e2ee7d1031c.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-5e0097702fa91e2e36391de8127676a7fa1.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td> | ||||
| 			<p><img src="https://oscimg.oschina.net/oscnet/up-e56e3828f48cd9886d88731766f06d5f3c1.png" width="1920" /></p> | ||||
| 			</td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-0715990ea1a9f254ec2138fcd063c1f556a.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-eaf5417ccf921bb64abb959e3d8e290467f.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-fc285cf33095ebf8318de6999af0f473861.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-60c83fd8bd61c29df6dbf47c88355e9c272.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-7f731948c8b73c7d90f67f9e1c7a534d5c3.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-e4de89b5e2d20c52d3c3a47f9eb88eb8526.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-8791d823a508eb90e67c604f36f57491a67.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-4589afd99982ead331785299b894174feb6.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-8ea177cdacaea20995daf2f596b15232561.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-32d1d04c55c11f74c9129fbbc58399728c4.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-04fa118f7631b7ae6fd72299ca0a1430a63.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 		<tr> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-fe7e85b65827802bfaadf3acd42568b58c7.png" width="1920" /></td> | ||||
| 			<td><img src="https://oscimg.oschina.net/oscnet/up-eff2b02a54f8188022d8498cfe6af6fcc06.png" width="1920" /></td> | ||||
| 		</tr> | ||||
| 	</tbody> | ||||
| </table> | ||||
|   | ||||
							
								
								
									
										547
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										547
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -2,101 +2,60 @@ | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||
|          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <groupId>org.dromara</groupId> | ||||
|     <groupId>com.ruoyi</groupId> | ||||
|     <artifactId>ruoyi-vue-plus</artifactId> | ||||
|     <version>${revision}</version> | ||||
|     <version>3.3.0</version> | ||||
|  | ||||
|     <name>RuoYi-Vue-Plus</name> | ||||
|     <url>https://gitee.com/dromara/RuoYi-Vue-Plus</url> | ||||
|     <description>Dromara RuoYi-Vue-Plus多租户管理系统</description> | ||||
|     <url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url> | ||||
|     <description>RuoYi-Vue-Plus后台管理系统</description> | ||||
|  | ||||
|     <properties> | ||||
|         <revision>5.3.1</revision> | ||||
|         <spring-boot.version>3.4.5</spring-boot.version> | ||||
|         <ruoyi-vue-plus.version>3.3.0</ruoyi-vue-plus.version> | ||||
|         <spring-boot.version>2.5.6</spring-boot.version> | ||||
|         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
|         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||||
|         <java.version>17</java.version> | ||||
|         <mybatis.version>3.5.16</mybatis.version> | ||||
|         <springdoc.version>2.8.5</springdoc.version> | ||||
|         <therapi-javadoc.version>0.15.0</therapi-javadoc.version> | ||||
|         <fastexcel.version>1.2.0</fastexcel.version> | ||||
|         <velocity.version>2.3</velocity.version> | ||||
|         <satoken.version>1.42.0</satoken.version> | ||||
|         <mybatis-plus.version>3.5.11</mybatis-plus.version> | ||||
|         <java.version>1.8</java.version> | ||||
|         <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version> | ||||
|         <druid.version>1.2.8</druid.version> | ||||
|         <knife4j.version>3.0.3</knife4j.version> | ||||
|         <swagger-annotations.version>1.5.22</swagger-annotations.version> | ||||
|         <poi.version>4.1.2</poi.version> | ||||
|         <easyexcel.version>2.2.11</easyexcel.version> | ||||
|         <velocity.version>1.7</velocity.version> | ||||
|         <jwt.version>0.9.1</jwt.version> | ||||
|         <mybatis-plus.version>3.4.3.4</mybatis-plus.version> | ||||
|         <p6spy.version>3.9.1</p6spy.version> | ||||
|         <hutool.version>5.8.35</hutool.version> | ||||
|         <spring-boot-admin.version>3.4.5</spring-boot-admin.version> | ||||
|         <redisson.version>3.45.1</redisson.version> | ||||
|         <lock4j.version>2.2.7</lock4j.version> | ||||
|         <dynamic-ds.version>4.3.1</dynamic-ds.version> | ||||
|         <snailjob.version>1.4.0</snailjob.version> | ||||
|         <mapstruct-plus.version>1.4.6</mapstruct-plus.version> | ||||
|         <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version> | ||||
|         <lombok.version>1.18.36</lombok.version> | ||||
|         <bouncycastle.version>1.80</bouncycastle.version> | ||||
|         <justauth.version>1.16.7</justauth.version> | ||||
|         <!-- 离线IP地址定位库 --> | ||||
|         <ip2region.version>2.7.0</ip2region.version> | ||||
|         <hutool.version>5.7.15</hutool.version> | ||||
|         <feign.version>3.0.3</feign.version> | ||||
|         <feign-okhttp.version>11.6</feign-okhttp.version> | ||||
|         <okhttp.version>4.9.1</okhttp.version> | ||||
|         <spring-boot-admin.version>2.5.2</spring-boot-admin.version> | ||||
|         <redisson.version>3.16.3</redisson.version> | ||||
|         <lock4j.version>2.2.1</lock4j.version> | ||||
|         <dynamic-ds.version>3.4.1</dynamic-ds.version> | ||||
|         <tlog.version>1.3.3</tlog.version> | ||||
|         <xxl-job.version>2.3.0</xxl-job.version> | ||||
|  | ||||
|         <!-- jdk11 缺失依赖 jaxb--> | ||||
|         <jaxb.version>3.0.1</jaxb.version> | ||||
|  | ||||
|         <!-- OSS 配置 --> | ||||
|         <aws.sdk.version>2.28.22</aws.sdk.version> | ||||
|         <!-- SMS 配置 --> | ||||
|         <sms4j.version>3.3.4</sms4j.version> | ||||
|         <!-- 限制框架中的fastjson版本 --> | ||||
|         <fastjson.version>1.2.83</fastjson.version> | ||||
|         <!-- 面向运行时的D-ORM依赖 --> | ||||
|         <anyline.version>8.7.2-20250101</anyline.version> | ||||
|         <!--工作流配置--> | ||||
|         <warm-flow.version>1.6.10</warm-flow.version> | ||||
|         <qiniu.version>7.8.0</qiniu.version> | ||||
|         <aliyun.oss.version>3.13.1</aliyun.oss.version> | ||||
|         <qcloud.cos.version>5.6.58</qcloud.cos.version> | ||||
|         <minio.version>8.3.3</minio.version> | ||||
|  | ||||
|         <!-- docker 配置 --> | ||||
|         <docker.registry.url>localhost</docker.registry.url> | ||||
|         <docker.registry.host>http://${docker.registry.url}:2375</docker.registry.host> | ||||
|         <docker.namespace>ruoyi</docker.namespace> | ||||
|         <docker.plugin.version>1.2.2</docker.plugin.version> | ||||
|  | ||||
|         <!-- 插件版本 --> | ||||
|         <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version> | ||||
|         <maven-war-plugin.version>3.2.2</maven-war-plugin.version> | ||||
|         <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version> | ||||
|         <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version> | ||||
|         <flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version> | ||||
|         <!-- 打包默认跳过测试 --> | ||||
|         <skipTests>true</skipTests> | ||||
|     </properties> | ||||
|  | ||||
|     <profiles> | ||||
|         <profile> | ||||
|             <id>local</id> | ||||
|             <properties> | ||||
|                 <!-- 环境标识,需要与配置文件的名称相对应 --> | ||||
|                 <profiles.active>local</profiles.active> | ||||
|                 <logging.level>info</logging.level> | ||||
|                 <monitor.username>ruoyi</monitor.username> | ||||
|                 <monitor.password>123456</monitor.password> | ||||
|             </properties> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>dev</id> | ||||
|             <properties> | ||||
|                 <!-- 环境标识,需要与配置文件的名称相对应 --> | ||||
|                 <profiles.active>dev</profiles.active> | ||||
|                 <logging.level>info</logging.level> | ||||
|                 <monitor.username>ruoyi</monitor.username> | ||||
|                 <monitor.password>123456</monitor.password> | ||||
|             </properties> | ||||
|             <activation> | ||||
|                 <!-- 默认环境 --> | ||||
|                 <activeByDefault>true</activeByDefault> | ||||
|             </activation> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>prod</id> | ||||
|             <properties> | ||||
|                 <profiles.active>prod</profiles.active> | ||||
|                 <logging.level>warn</logging.level> | ||||
|                 <monitor.username>ruoyi</monitor.username> | ||||
|                 <monitor.password>123456</monitor.password> | ||||
|             </properties> | ||||
|         </profile> | ||||
|     </profiles> | ||||
|  | ||||
|     <!-- 依赖声明 --> | ||||
|     <dependencyManagement> | ||||
|         <dependencies> | ||||
| @@ -110,129 +69,92 @@ | ||||
|                 <scope>import</scope> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- hutool 的依赖配置--> | ||||
|             <!-- 阿里数据库连接池 --> | ||||
|             <dependency> | ||||
|                 <groupId>cn.hutool</groupId> | ||||
|                 <artifactId>hutool-bom</artifactId> | ||||
|                 <version>${hutool.version}</version> | ||||
|                 <type>pom</type> | ||||
|                 <scope>import</scope> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- Warm-Flow国产工作流引擎, 在线文档:http://warm-flow.cn/ --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara.warm</groupId> | ||||
|                 <artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId> | ||||
|                 <version>${warm-flow.version}</version> | ||||
|             </dependency> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara.warm</groupId> | ||||
|                 <artifactId>warm-flow-plugin-ui-sb-web</artifactId> | ||||
|                 <version>${warm-flow.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- JustAuth 的依赖配置--> | ||||
|             <dependency> | ||||
|                 <groupId>me.zhyd.oauth</groupId> | ||||
|                 <artifactId>JustAuth</artifactId> | ||||
|                 <version>${justauth.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- common 的依赖配置--> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-bom</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|                 <type>pom</type> | ||||
|                 <scope>import</scope> | ||||
|                 <groupId>com.alibaba</groupId> | ||||
|                 <artifactId>druid-spring-boot-starter</artifactId> | ||||
|                 <version>${druid.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.springdoc</groupId> | ||||
|                 <artifactId>springdoc-openapi-starter-webmvc-api</artifactId> | ||||
|                 <version>${springdoc.version}</version> | ||||
|                 <groupId>com.github.xiaoymin</groupId> | ||||
|                 <artifactId>knife4j-spring-boot-starter</artifactId> | ||||
|                 <version>${knife4j.version}</version> | ||||
|                 <exclusions> | ||||
|                     <exclusion> | ||||
|                         <artifactId>swagger-annotations</artifactId> | ||||
|                         <groupId>io.swagger</groupId> | ||||
|                     </exclusion> | ||||
|                 </exclusions> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>com.github.therapi</groupId> | ||||
|                 <artifactId>therapi-runtime-javadoc</artifactId> | ||||
|                 <version>${therapi-javadoc.version}</version> | ||||
|                 <groupId>io.swagger</groupId> | ||||
|                 <artifactId>swagger-annotations</artifactId> | ||||
|                 <version>${swagger-annotations.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- excel工具 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.apache.poi</groupId> | ||||
|                 <artifactId>poi-ooxml</artifactId> | ||||
|                 <version>${poi.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.projectlombok</groupId> | ||||
|                 <artifactId>lombok</artifactId> | ||||
|                 <version>${lombok.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>cn.idev.excel</groupId> | ||||
|                 <artifactId>fastexcel</artifactId> | ||||
|                 <version>${fastexcel.version}</version> | ||||
|                 <groupId>com.alibaba</groupId> | ||||
|                 <artifactId>easyexcel</artifactId> | ||||
|                 <version>${easyexcel.version}</version> | ||||
|                 <exclusions> | ||||
|                     <exclusion> | ||||
|                         <groupId>org.apache.poi</groupId> | ||||
|                         <artifactId>poi</artifactId> | ||||
|                     </exclusion> | ||||
|                     <exclusion> | ||||
|                         <groupId>org.apache.poi</groupId> | ||||
|                         <artifactId>poi-ooxml-schemas</artifactId> | ||||
|                     </exclusion> | ||||
|                 </exclusions> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- velocity代码生成使用模板 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.apache.velocity</groupId> | ||||
|                 <artifactId>velocity-engine-core</artifactId> | ||||
|                 <artifactId>velocity</artifactId> | ||||
|                 <version>${velocity.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ --> | ||||
|             <!-- Token生成与解析--> | ||||
|             <dependency> | ||||
|                 <groupId>cn.dev33</groupId> | ||||
|                 <artifactId>sa-token-spring-boot3-starter</artifactId> | ||||
|                 <version>${satoken.version}</version> | ||||
|                 <groupId>io.jsonwebtoken</groupId> | ||||
|                 <artifactId>jjwt</artifactId> | ||||
|                 <version>${jwt.version}</version> | ||||
|             </dependency> | ||||
|             <!-- Sa-Token 整合 jwt --> | ||||
|  | ||||
|             <!-- jdk11 缺失依赖 jaxb--> | ||||
|             <dependency> | ||||
|                 <groupId>cn.dev33</groupId> | ||||
|                 <artifactId>sa-token-jwt</artifactId> | ||||
|                 <version>${satoken.version}</version> | ||||
|                 <exclusions> | ||||
|                     <exclusion> | ||||
|                         <groupId>cn.hutool</groupId> | ||||
|                         <artifactId>hutool-all</artifactId> | ||||
|                     </exclusion> | ||||
|                 </exclusions> | ||||
|             </dependency> | ||||
|             <dependency> | ||||
|                 <groupId>cn.dev33</groupId> | ||||
|                 <artifactId>sa-token-core</artifactId> | ||||
|                 <version>${satoken.version}</version> | ||||
|                 <groupId>com.sun.xml.bind</groupId> | ||||
|                 <artifactId>jaxb-impl</artifactId> | ||||
|                 <version>${jaxb.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- dynamic-datasource 多数据源--> | ||||
|             <dependency> | ||||
|                 <groupId>com.baomidou</groupId> | ||||
|                 <artifactId>dynamic-datasource-spring-boot3-starter</artifactId> | ||||
|                 <artifactId>dynamic-datasource-spring-boot-starter</artifactId> | ||||
|                 <version>${dynamic-ds.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.mybatis</groupId> | ||||
|                 <artifactId>mybatis</artifactId> | ||||
|                 <version>${mybatis.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>com.baomidou</groupId> | ||||
|                 <artifactId>mybatis-plus-spring-boot3-starter</artifactId> | ||||
|                 <artifactId>mybatis-plus-boot-starter</artifactId> | ||||
|                 <version>${mybatis-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>com.baomidou</groupId> | ||||
|                 <artifactId>mybatis-plus-jsqlparser</artifactId> | ||||
|                 <artifactId>mybatis-plus-extension</artifactId> | ||||
|                 <version>${mybatis-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>com.baomidou</groupId> | ||||
|                 <artifactId>mybatis-plus-annotation</artifactId> | ||||
|                 <version>${mybatis-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- sql性能分析插件 --> | ||||
|             <dependency> | ||||
|                 <groupId>p6spy</groupId> | ||||
| @@ -240,29 +162,35 @@ | ||||
|                 <version>${p6spy.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!--  AWS SDK for Java 2.x  --> | ||||
|             <dependency> | ||||
|                 <groupId>software.amazon.awssdk</groupId> | ||||
|                 <artifactId>s3</artifactId> | ||||
|                 <version>${aws.sdk.version}</version> | ||||
|                 <groupId>cn.hutool</groupId> | ||||
|                 <artifactId>hutool-all</artifactId> | ||||
|                 <version>${hutool.version}</version> | ||||
|             </dependency> | ||||
|             <!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 --> | ||||
|  | ||||
|             <!-- @deprecated 由于使用人数较少 决定与 3.4.0 版本移除 --> | ||||
|             <dependency> | ||||
|                 <groupId>software.amazon.awssdk</groupId> | ||||
|                 <artifactId>s3-transfer-manager</artifactId> | ||||
|                 <version>${aws.sdk.version}</version> | ||||
|                 <groupId>org.springframework.cloud</groupId> | ||||
|                 <artifactId>spring-cloud-starter-openfeign</artifactId> | ||||
|                 <version>${feign.version}</version> | ||||
|                 <exclusions> | ||||
|                     <exclusion> | ||||
|                         <artifactId>feign-core</artifactId> | ||||
|                         <groupId>io.github.openfeign</groupId> | ||||
|                     </exclusion> | ||||
|                 </exclusions> | ||||
|             </dependency> | ||||
|             <!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 --> | ||||
|             <!-- @deprecated 由于使用人数较少 决定与 3.4.0 版本移除 --> | ||||
|             <dependency> | ||||
|                 <groupId>software.amazon.awssdk</groupId> | ||||
|                 <artifactId>netty-nio-client</artifactId> | ||||
|                 <version>${aws.sdk.version}</version> | ||||
|                 <groupId>io.github.openfeign</groupId> | ||||
|                 <artifactId>feign-okhttp</artifactId> | ||||
|                 <version>${feign-okhttp.version}</version> | ||||
|             </dependency> | ||||
|             <!--短信sms4j--> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara.sms4j</groupId> | ||||
|                 <artifactId>sms4j-spring-boot-starter</artifactId> | ||||
|                 <version>${sms4j.version}</version> | ||||
|                 <groupId>com.squareup.okhttp3</groupId> | ||||
|                 <artifactId>okhttp</artifactId> | ||||
|                 <version>${okhttp.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
| @@ -282,80 +210,107 @@ | ||||
|                 <artifactId>redisson-spring-boot-starter</artifactId> | ||||
|                 <version>${redisson.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>com.baomidou</groupId> | ||||
|                 <artifactId>lock4j-redisson-spring-boot-starter</artifactId> | ||||
|                 <version>${lock4j.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- SnailJob Client --> | ||||
|             <!-- xxl-job-core --> | ||||
|             <dependency> | ||||
|                 <groupId>com.aizuda</groupId> | ||||
|                 <artifactId>snail-job-client-starter</artifactId> | ||||
|                 <version>${snailjob.version}</version> | ||||
|             </dependency> | ||||
|             <dependency> | ||||
|                 <groupId>com.aizuda</groupId> | ||||
|                 <artifactId>snail-job-client-job-core</artifactId> | ||||
|                 <version>${snailjob.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 加密包引入 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.bouncycastle</groupId> | ||||
|                 <artifactId>bcprov-jdk15to18</artifactId> | ||||
|                 <version>${bouncycastle.version}</version> | ||||
|                 <groupId>com.xuxueli</groupId> | ||||
|                 <artifactId>xxl-job-core</artifactId> | ||||
|                 <version>${xxl-job.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>io.github.linpeilie</groupId> | ||||
|                 <artifactId>mapstruct-plus-spring-boot-starter</artifactId> | ||||
|                 <version>${mapstruct-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 离线IP地址定位库 ip2region --> | ||||
|             <dependency> | ||||
|                 <groupId>org.lionsoul</groupId> | ||||
|                 <artifactId>ip2region</artifactId> | ||||
|                 <version>${ip2region.version}</version> | ||||
|                 <groupId>com.yomahub</groupId> | ||||
|                 <artifactId>tlog-spring-boot-configuration</artifactId> | ||||
|                 <version>${tlog.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>com.alibaba</groupId> | ||||
|                 <artifactId>fastjson</artifactId> | ||||
|                 <version>${fastjson.version}</version> | ||||
|                 <groupId>com.yomahub</groupId> | ||||
|                 <artifactId>tlog-webroot</artifactId> | ||||
|                 <version>${tlog.version}</version> | ||||
|                 <exclusions> | ||||
|                     <exclusion> | ||||
|                         <artifactId>javassist</artifactId> | ||||
|                         <groupId>org.javassist</groupId> | ||||
|                     </exclusion> | ||||
|                     <exclusion> | ||||
|                         <artifactId>guava</artifactId> | ||||
|                         <groupId>com.google.guava</groupId> | ||||
|                     </exclusion> | ||||
|                 </exclusions> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-system</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|                 <groupId>com.yomahub</groupId> | ||||
|                 <artifactId>tlog-feign</artifactId> | ||||
|                 <version>${tlog.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <groupId>com.yomahub</groupId> | ||||
|                 <artifactId>tlog-xxl-job</artifactId> | ||||
|                 <version>${tlog.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 定时任务 @deprecated 3.4.0删除 迁移至xxl-job --> | ||||
|             <dependency> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-quartz</artifactId> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 定时任务 --> | ||||
|             <dependency> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-job</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 代码生成--> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-generator</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 核心模块--> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-framework</artifactId> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 系统模块--> | ||||
|             <dependency> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-system</artifactId> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 通用工具--> | ||||
|             <dependency> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-common</artifactId> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- OSS对象存储模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-oss</artifactId> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- demo模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>com.ruoyi</groupId> | ||||
|                 <artifactId>ruoyi-demo</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!--  工作流模块  --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-workflow</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|                 <version>${ruoyi-vue-plus.version}</version> | ||||
|             </dependency> | ||||
|  | ||||
|         </dependencies> | ||||
| @@ -363,9 +318,15 @@ | ||||
|  | ||||
|     <modules> | ||||
|         <module>ruoyi-admin</module> | ||||
|         <module>ruoyi-framework</module> | ||||
|         <module>ruoyi-system</module> | ||||
|         <module>ruoyi-quartz</module> | ||||
|         <module>ruoyi-job</module> | ||||
|         <module>ruoyi-generator</module> | ||||
|         <module>ruoyi-common</module> | ||||
|         <module>ruoyi-demo</module> | ||||
|         <module>ruoyi-extend</module> | ||||
|         <module>ruoyi-modules</module> | ||||
|         <module>ruoyi-oss</module> | ||||
|     </modules> | ||||
|     <packaging>pom</packaging> | ||||
|  | ||||
| @@ -374,97 +335,18 @@ | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <version>${maven-compiler-plugin.version}</version> | ||||
|                 <version>3.1</version> | ||||
|                 <configuration> | ||||
|                     <source>${java.version}</source> | ||||
|                     <target>${java.version}</target> | ||||
|                     <encoding>${project.build.sourceEncoding}</encoding> | ||||
|                     <annotationProcessorPaths> | ||||
|                         <path> | ||||
|                             <groupId>com.github.therapi</groupId> | ||||
|                             <artifactId>therapi-runtime-javadoc-scribe</artifactId> | ||||
|                             <version>${therapi-javadoc.version}</version> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>org.projectlombok</groupId> | ||||
|                             <artifactId>lombok</artifactId> | ||||
|                             <version>${lombok.version}</version> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>org.springframework.boot</groupId> | ||||
|                             <artifactId>spring-boot-configuration-processor</artifactId> | ||||
|                             <version>${spring-boot.version}</version> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>io.github.linpeilie</groupId> | ||||
|                             <artifactId>mapstruct-plus-processor</artifactId> | ||||
|                             <version>${mapstruct-plus.version}</version> | ||||
|                         </path> | ||||
|                         <path> | ||||
|                             <groupId>org.projectlombok</groupId> | ||||
|                             <artifactId>lombok-mapstruct-binding</artifactId> | ||||
|                             <version>${mapstruct-plus.lombok.version}</version> | ||||
|                         </path> | ||||
|                     </annotationProcessorPaths> | ||||
|                     <compilerArgs> | ||||
|                         <arg>-parameters</arg> | ||||
|                     </compilerArgs> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|             <!-- 单元测试使用 --> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-surefire-plugin</artifactId> | ||||
|                 <version>${maven-surefire-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <argLine>-Dfile.encoding=UTF-8</argLine> | ||||
|                     <!-- 根据打包环境执行对应的@Tag测试方法 --> | ||||
|                     <groups>${profiles.active}</groups> | ||||
|                     <!-- 排除标签 --> | ||||
|                     <excludedGroups>exclude</excludedGroups> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|             <!-- 统一版本号管理 --> | ||||
|             <plugin> | ||||
|                 <groupId>org.codehaus.mojo</groupId> | ||||
|                 <artifactId>flatten-maven-plugin</artifactId> | ||||
|                 <version>${flatten-maven-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <updatePomFile>true</updatePomFile> | ||||
|                     <flattenMode>resolveCiFriendliesOnly</flattenMode> | ||||
|                 </configuration> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <id>flatten</id> | ||||
|                         <phase>process-resources</phase> | ||||
|                         <goals> | ||||
|                             <goal>flatten</goal> | ||||
|                         </goals> | ||||
|                     </execution> | ||||
|                     <execution> | ||||
|                         <id>flatten.clean</id> | ||||
|                         <phase>clean</phase> | ||||
|                         <goals> | ||||
|                             <goal>clean</goal> | ||||
|                         </goals> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|         <resources> | ||||
|             <resource> | ||||
|                 <!--打包该目录下的 application.yml --> | ||||
|                 <directory>src/main/resources</directory> | ||||
|                 <!-- 关闭过滤 --> | ||||
|                 <filtering>false</filtering> | ||||
|             </resource> | ||||
|             <resource> | ||||
|                 <directory>src/main/resources</directory> | ||||
|                 <!-- 引入所有 匹配文件进行过滤 --> | ||||
|                 <includes> | ||||
|                     <include>application*</include> | ||||
|                     <include>bootstrap*</include> | ||||
|                     <include>banner*</include> | ||||
|                 </includes> | ||||
|                 <!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 --> | ||||
|                 <filtering>true</filtering> | ||||
|             </resource> | ||||
| @@ -474,8 +356,8 @@ | ||||
|     <repositories> | ||||
|         <repository> | ||||
|             <id>public</id> | ||||
|             <name>huawei nexus</name> | ||||
|             <url>https://mirrors.huaweicloud.com/repository/maven/</url> | ||||
|             <name>aliyun nexus</name> | ||||
|             <url>https://maven.aliyun.com/repository/public/</url> | ||||
|             <releases> | ||||
|                 <enabled>true</enabled> | ||||
|             </releases> | ||||
| @@ -485,8 +367,8 @@ | ||||
|     <pluginRepositories> | ||||
|         <pluginRepository> | ||||
|             <id>public</id> | ||||
|             <name>huawei nexus</name> | ||||
|             <url>https://mirrors.huaweicloud.com/repository/maven/</url> | ||||
|             <name>aliyun nexus</name> | ||||
|             <url>https://maven.aliyun.com/repository/public/</url> | ||||
|             <releases> | ||||
|                 <enabled>true</enabled> | ||||
|             </releases> | ||||
| @@ -496,6 +378,37 @@ | ||||
|         </pluginRepository> | ||||
|     </pluginRepositories> | ||||
|  | ||||
|     <profiles> | ||||
|         <profile> | ||||
|             <id>local</id> | ||||
|             <properties> | ||||
|                 <!-- 环境标识,需要与配置文件的名称相对应 --> | ||||
|                 <profiles.active>local</profiles.active> | ||||
|                 <logging.level>debug</logging.level> | ||||
|                 <endpoints.include>'*'</endpoints.include> | ||||
|             </properties> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>dev</id> | ||||
|             <properties> | ||||
|                 <!-- 环境标识,需要与配置文件的名称相对应 --> | ||||
|                 <profiles.active>dev</profiles.active> | ||||
|                 <logging.level>debug</logging.level> | ||||
|                 <endpoints.include>'*'</endpoints.include> | ||||
|             </properties> | ||||
|             <activation> | ||||
|                 <!-- 默认环境 --> | ||||
|                 <activeByDefault>true</activeByDefault> | ||||
|             </activation> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>prod</id> | ||||
|             <properties> | ||||
|                 <profiles.active>prod</profiles.active> | ||||
|                 <logging.level>warn</logging.level> | ||||
|                 <endpoints.include>health, info, logfile</endpoints.include> | ||||
|             </properties> | ||||
|         </profile> | ||||
|     </profiles> | ||||
|  | ||||
| </project> | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,33 +1,14 @@ | ||||
| # 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ | ||||
| FROM bellsoft/liberica-openjdk-debian:17.0.11-cds | ||||
| #FROM bellsoft/liberica-openjdk-debian:21.0.5-cds | ||||
| #FROM findepi/graalvm:java17-native | ||||
| FROM anapsix/alpine-java:8_server-jre_unlimited | ||||
|  | ||||
| LABEL maintainer="Lion Li" | ||||
| MAINTAINER Lion Li | ||||
|  | ||||
| RUN mkdir -p /ruoyi/server/logs \ | ||||
|     /ruoyi/server/temp \ | ||||
|     /ruoyi/skywalking/agent | ||||
| RUN mkdir -p /ruoyi/server | ||||
| RUN mkdir -p /ruoyi/server/logs | ||||
|  | ||||
| WORKDIR /ruoyi/server | ||||
|  | ||||
| ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" | ||||
|  | ||||
| EXPOSE ${SERVER_PORT} | ||||
| # 暴露 snail job 客户端端口 用于定时任务调度中心通信 | ||||
| EXPOSE ${SNAIL_PORT} | ||||
| EXPOSE 8080 | ||||
|  | ||||
| ADD ./target/ruoyi-admin.jar ./app.jar | ||||
| # 工作流字体文件 | ||||
| ADD ./zhFonts/ /usr/share/fonts/zhFonts/ | ||||
|  | ||||
| SHELL ["/bin/bash", "-c"] | ||||
|  | ||||
| ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ | ||||
|            -Dsnail-job.port=${SNAIL_PORT} \ | ||||
|            # 应用名称 如果想区分集群节点监控 改成不同的名称即可 | ||||
|            #-Dskywalking.agent.service_name=ruoyi-server \ | ||||
|            #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ | ||||
|            -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ | ||||
|            -jar app.jar | ||||
|  | ||||
| ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <parent> | ||||
|         <artifactId>ruoyi-vue-plus</artifactId> | ||||
|         <groupId>org.dromara</groupId> | ||||
|         <version>${revision}</version> | ||||
|         <groupId>com.ruoyi</groupId> | ||||
|         <version>3.3.0</version> | ||||
|     </parent> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <packaging>jar</packaging> | ||||
| @@ -17,105 +17,58 @@ | ||||
|  | ||||
|     <dependencies> | ||||
|  | ||||
|         <!-- spring-boot-devtools --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-devtools</artifactId> | ||||
|             <optional>true</optional> <!-- 表示依赖不会传递 --> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Mysql驱动包 --> | ||||
|         <dependency> | ||||
|             <groupId>com.mysql</groupId> | ||||
|             <artifactId>mysql-connector-j</artifactId> | ||||
|             <groupId>mysql</groupId> | ||||
|             <artifactId>mysql-connector-java</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
| <!--        <!– mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 –>--> | ||||
| <!--        <!– Oracle –>--> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>com.oracle.database.jdbc</groupId>--> | ||||
| <!--            <artifactId>ojdbc8</artifactId>--> | ||||
| <!--        </dependency>--> | ||||
| <!--        <!– 兼容oracle低版本 –>--> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>com.oracle.database.nls</groupId>--> | ||||
| <!--            <artifactId>orai18n</artifactId>--> | ||||
| <!--        </dependency>--> | ||||
| <!--        <!– PostgreSql –>--> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>org.postgresql</groupId>--> | ||||
| <!--            <artifactId>postgresql</artifactId>--> | ||||
| <!--        </dependency>--> | ||||
| <!--        <!– SqlServer –>--> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>com.microsoft.sqlserver</groupId>--> | ||||
| <!--            <artifactId>mssql-jdbc</artifactId>--> | ||||
| <!--        </dependency>--> | ||||
|  | ||||
|         <!-- 核心模块--> | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <artifactId>ruoyi-common-doc</artifactId> | ||||
|             <groupId>com.ruoyi</groupId> | ||||
|             <artifactId>ruoyi-framework</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <artifactId>ruoyi-common-social</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <artifactId>ruoyi-common-ratelimiter</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <artifactId>ruoyi-common-mail</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <groupId>com.ruoyi</groupId> | ||||
|             <artifactId>ruoyi-system</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 定时任务 @deprecated 3.4.0删除 迁移至xxl-job --> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>com.ruoyi</groupId>--> | ||||
| <!--            <artifactId>ruoyi-quartz</artifactId>--> | ||||
| <!--        </dependency>--> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <groupId>com.ruoyi</groupId> | ||||
|             <artifactId>ruoyi-job</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.ruoyi</groupId> | ||||
|             <artifactId>ruoyi-oss</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 代码生成--> | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <groupId>com.ruoyi</groupId> | ||||
|             <artifactId>ruoyi-generator</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--  demo模块  --> | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <groupId>com.ruoyi</groupId> | ||||
|             <artifactId>ruoyi-demo</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--  工作流模块  --> | ||||
|         <dependency> | ||||
|             <groupId>org.dromara</groupId> | ||||
|             <artifactId>ruoyi-workflow</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>de.codecentric</groupId> | ||||
|             <artifactId>spring-boot-admin-starter-client</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-test</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- skywalking 整合 logback --> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>org.apache.skywalking</groupId>--> | ||||
| <!--            <artifactId>apm-toolkit-logback-1.x</artifactId>--> | ||||
| <!--            <version>${与你的agent探针版本保持一致}</version>--> | ||||
| <!--        </dependency>--> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>org.apache.skywalking</groupId>--> | ||||
| <!--            <artifactId>apm-toolkit-trace</artifactId>--> | ||||
| <!--            <version>${与你的agent探针版本保持一致}</version>--> | ||||
| <!--        </dependency>--> | ||||
|  | ||||
|     </dependencies> | ||||
|  | ||||
|     <build> | ||||
| @@ -125,6 +78,9 @@ | ||||
|                 <groupId>org.springframework.boot</groupId> | ||||
|                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||
|                 <version>${spring-boot.version}</version> | ||||
|                 <configuration> | ||||
|                     <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 --> | ||||
|                 </configuration> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <goals> | ||||
| @@ -133,20 +89,34 @@ | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-jar-plugin</artifactId> | ||||
|                 <version>${maven-jar-plugin.version}</version> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-war-plugin</artifactId> | ||||
|                 <version>${maven-war-plugin.version}</version> | ||||
|                 <version>3.2.0</version> | ||||
|                 <configuration> | ||||
|                     <failOnMissingWebXml>false</failOnMissingWebXml> | ||||
|                     <warName>${project.artifactId}</warName> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>com.spotify</groupId> | ||||
|                 <artifactId>docker-maven-plugin</artifactId> | ||||
|                 <version>${docker.plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <imageName>${docker.namespace}/ruoyi-server:${project.version}</imageName> | ||||
|                     <dockerDirectory>${project.basedir}</dockerDirectory> | ||||
|                     <dockerHost>${docker.registry.host}</dockerHost> | ||||
|                     <registryUrl>${docker.registry.url}</registryUrl> | ||||
|                     <serverId>${docker.registry.url}</serverId> | ||||
|                     <resources> | ||||
|                         <resource> | ||||
|                             <targetPath>/</targetPath> | ||||
|                             <directory>${project.build.directory}</directory> | ||||
|                             <include>${project.build.finalName}.jar</include> | ||||
|                         </resource> | ||||
|                     </resources> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
|  | ||||
|   | ||||
							
								
								
									
										21
									
								
								ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| package com.ruoyi; | ||||
|  | ||||
| import org.springframework.boot.SpringApplication; | ||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
|  | ||||
| /** | ||||
|  * 启动程序 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
|  | ||||
| @SpringBootApplication | ||||
| public class RuoYiApplication { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         System.setProperty("spring.devtools.restart.enabled", "false"); | ||||
|         SpringApplication.run(RuoYiApplication.class, args); | ||||
|         System.out.println("(♥◠‿◠)ノ゙  RuoYi-Vue-Plus启动成功   ლ(´ڡ`ლ)゙"); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| package org.dromara; | ||||
| package com.ruoyi; | ||||
| 
 | ||||
| import org.springframework.boot.builder.SpringApplicationBuilder; | ||||
| import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; | ||||
| @@ -6,13 +6,13 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer | ||||
| /** | ||||
|  * web容器中进行部署 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class DromaraServletInitializer extends SpringBootServletInitializer { | ||||
| public class RuoYiServletInitializer extends SpringBootServletInitializer { | ||||
| 
 | ||||
|     @Override | ||||
|     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { | ||||
|         return application.sources(DromaraApplication.class); | ||||
|         return application.sources(RuoYiApplication.class); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @@ -0,0 +1,87 @@ | ||||
| package com.ruoyi.web.controller.common; | ||||
|  | ||||
| import cn.hutool.captcha.AbstractCaptcha; | ||||
| import cn.hutool.captcha.generator.CodeGenerator; | ||||
| import cn.hutool.core.convert.Convert; | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| import com.ruoyi.common.constant.Constants; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.enums.CaptchaType; | ||||
| import com.ruoyi.common.utils.RedisUtils; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.common.utils.reflect.ReflectUtils; | ||||
| import com.ruoyi.common.utils.spring.SpringUtils; | ||||
| import com.ruoyi.framework.config.properties.CaptchaProperties; | ||||
| import com.ruoyi.system.service.ISysConfigService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|  * 验证码操作处理 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Api(value = "验证码操作处理", tags = {"验证码管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| public class CaptchaController { | ||||
|  | ||||
|     private final CaptchaProperties captchaProperties; | ||||
|     private final ISysConfigService configService; | ||||
|  | ||||
|     /** | ||||
|      * 生成验证码 | ||||
|      */ | ||||
|     @ApiOperation("生成验证码") | ||||
|     @GetMapping("/captchaImage") | ||||
|     public AjaxResult<Map<String, Object>> getCode() { | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         boolean captchaOnOff = configService.selectCaptchaOnOff(); | ||||
|         ajax.put("captchaOnOff", captchaOnOff); | ||||
|         if (!captchaOnOff) { | ||||
|             return AjaxResult.success(ajax); | ||||
|         } | ||||
|         // 保存验证码信息 | ||||
|         String uuid = IdUtil.simpleUUID(); | ||||
|         String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; | ||||
|         // 生成验证码 | ||||
|         CaptchaType captchaType = captchaProperties.getType(); | ||||
|         boolean isMath = CaptchaType.MATH == captchaType; | ||||
|         Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); | ||||
|         CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); | ||||
|         AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); | ||||
|         captcha.setGenerator(codeGenerator); | ||||
|         captcha.createCode(); | ||||
|         String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode(); | ||||
|         RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); | ||||
|         ajax.put("uuid", uuid); | ||||
|         ajax.put("img", captcha.getImageBase64()); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     private String getCodeResult(String capStr) { | ||||
|         int numberLength = captchaProperties.getNumberLength(); | ||||
|         int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim()); | ||||
|         char operator = capStr.charAt(numberLength); | ||||
|         int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim()); | ||||
|         switch (operator) { | ||||
|             case '*': | ||||
|                 return Convert.toStr(a * b); | ||||
|             case '+': | ||||
|                 return Convert.toStr(a + b); | ||||
|             case '-': | ||||
|                 return Convert.toStr(a - b); | ||||
|             default: | ||||
|                 return StringUtils.EMPTY; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,57 @@ | ||||
| package com.ruoyi.web.controller.monitor; | ||||
|  | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.data.redis.connection.RedisServerCommands; | ||||
| import org.springframework.data.redis.core.RedisCallback; | ||||
| import org.springframework.data.redis.core.RedisTemplate; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import java.util.*; | ||||
|  | ||||
| /** | ||||
|  * 缓存监控 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Api(value = "缓存监控", tags = {"缓存监控管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/monitor/cache") | ||||
| public class CacheController { | ||||
|  | ||||
|     private final RedisTemplate<String, String> redisTemplate; | ||||
|  | ||||
|     @ApiOperation("获取缓存监控详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:cache:list')") | ||||
|     @GetMapping() | ||||
|     public AjaxResult<Map<String, Object>> getInfo() throws Exception { | ||||
|         Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info); | ||||
|         Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats")); | ||||
|         Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize); | ||||
|  | ||||
|         Map<String, Object> result = new HashMap<>(3); | ||||
|         result.put("info", info); | ||||
|         result.put("dbSize", dbSize); | ||||
|  | ||||
|         List<Map<String, String>> pieList = new ArrayList<>(); | ||||
|         if (commandStats != null) { | ||||
|             commandStats.stringPropertyNames().forEach(key -> { | ||||
|                 Map<String, String> data = new HashMap<>(2); | ||||
|                 String property = commandStats.getProperty(key); | ||||
|                 data.put("name", StringUtils.removeStart(key, "cmdstat_")); | ||||
|                 data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); | ||||
|                 pieList.add(data); | ||||
|             }); | ||||
|         } | ||||
|         result.put("commandStats", pieList); | ||||
|         return AjaxResult.success(result); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,68 @@ | ||||
| package com.ruoyi.web.controller.monitor; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.domain.SysLogininfor; | ||||
| import com.ruoyi.system.service.ISysLogininforService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 系统访问记录 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "系统访问记录", tags = {"系统访问记录管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/monitor/logininfor") | ||||
| public class SysLogininforController extends BaseController { | ||||
|  | ||||
|     private final ISysLogininforService logininforService; | ||||
|  | ||||
|     @ApiOperation("查询系统访问记录列表") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysLogininfor> list(SysLogininfor logininfor) { | ||||
|         return logininforService.selectPageLogininforList(logininfor); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出系统访问记录列表") | ||||
|     @Log(title = "登录日志", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysLogininfor logininfor, HttpServletResponse response) { | ||||
|         List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); | ||||
|         ExcelUtil.exportExcel(list, "登录日志", SysLogininfor.class, response); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("删除系统访问记录") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") | ||||
|     @Log(title = "登录日志", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{infoIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] infoIds) { | ||||
|         return toAjax(logininforService.deleteLogininforByIds(infoIds)); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("清空系统访问记录") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") | ||||
|     @Log(title = "登录日志", businessType = BusinessType.CLEAN) | ||||
|     @DeleteMapping("/clean") | ||||
|     public AjaxResult<Void> clean() { | ||||
|         logininforService.cleanLogininfor(); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,68 @@ | ||||
| package com.ruoyi.web.controller.monitor; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.domain.SysOperLog; | ||||
| import com.ruoyi.system.service.ISysOperLogService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 操作日志记录 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "操作日志记录", tags = {"操作日志记录管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/monitor/operlog") | ||||
| public class SysOperlogController extends BaseController { | ||||
|  | ||||
|     private final ISysOperLogService operLogService; | ||||
|  | ||||
|     @ApiOperation("查询操作日志记录列表") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:operlog:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysOperLog> list(SysOperLog operLog) { | ||||
|         return operLogService.selectPageOperLogList(operLog); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出操作日志记录列表") | ||||
|     @Log(title = "操作日志", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:operlog:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysOperLog operLog, HttpServletResponse response) { | ||||
|         List<SysOperLog> list = operLogService.selectOperLogList(operLog); | ||||
|         ExcelUtil.exportExcel(list, "操作日志", SysOperLog.class, response); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("删除操作日志记录") | ||||
|     @Log(title = "操作日志", businessType = BusinessType.DELETE) | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") | ||||
|     @DeleteMapping("/{operIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] operIds) { | ||||
|         return toAjax(operLogService.deleteOperLogByIds(operIds)); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("清空操作日志记录") | ||||
|     @Log(title = "操作日志", businessType = BusinessType.CLEAN) | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") | ||||
|     @DeleteMapping("/clean") | ||||
|     public AjaxResult<Void> clean() { | ||||
|         operLogService.cleanOperLog(); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,80 @@ | ||||
| package com.ruoyi.web.controller.monitor; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.Constants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.model.LoginUser; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.PageUtils; | ||||
| import com.ruoyi.common.utils.RedisUtils; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.system.domain.SysUserOnline; | ||||
| import com.ruoyi.system.service.ISysUserOnlineService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 在线用户监控 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Api(value = "在线用户监控", tags = {"在线用户监控管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/monitor/online") | ||||
| public class SysUserOnlineController extends BaseController { | ||||
|  | ||||
|     private final ISysUserOnlineService userOnlineService; | ||||
|  | ||||
|     @ApiOperation("在线用户列表") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:online:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) { | ||||
|         Collection<String> keys = RedisUtils.keys(Constants.LOGIN_TOKEN_KEY + "*"); | ||||
|         List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>(); | ||||
|         for (String key : keys) { | ||||
|             LoginUser user = RedisUtils.getCacheObject(key); | ||||
|             if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { | ||||
|                 if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) { | ||||
|                     userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user)); | ||||
|                 } | ||||
|             } else if (StringUtils.isNotEmpty(ipaddr)) { | ||||
|                 if (StringUtils.equals(ipaddr, user.getIpaddr())) { | ||||
|                     userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user)); | ||||
|                 } | ||||
|             } else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) { | ||||
|                 if (StringUtils.equals(userName, user.getUsername())) { | ||||
|                     userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); | ||||
|                 } | ||||
|             } else { | ||||
|                 userOnlineList.add(userOnlineService.loginUserToUserOnline(user)); | ||||
|             } | ||||
|         } | ||||
|         Collections.reverse(userOnlineList); | ||||
|         userOnlineList.removeAll(Collections.singleton(null)); | ||||
|         return PageUtils.buildDataInfo(userOnlineList); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 强退用户 | ||||
|      */ | ||||
|     @ApiOperation("强退用户") | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')") | ||||
|     @Log(title = "在线用户", businessType = BusinessType.FORCE) | ||||
|     @DeleteMapping("/{tokenId}") | ||||
|     public AjaxResult<Void> forceLogout(@PathVariable String tokenId) { | ||||
|         RedisUtils.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,128 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.annotation.RepeatSubmit; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.domain.SysConfig; | ||||
| import com.ruoyi.system.service.ISysConfigService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 参数配置 信息操作处理 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "参数配置控制器", tags = {"参数配置管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/config") | ||||
| public class SysConfigController extends BaseController { | ||||
|  | ||||
|     private final ISysConfigService configService; | ||||
|  | ||||
|     /** | ||||
|      * 获取参数配置列表 | ||||
|      */ | ||||
|     @ApiOperation("获取参数配置列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysConfig> list(SysConfig config) { | ||||
|         return configService.selectPageConfigList(config); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出参数配置列表") | ||||
|     @Log(title = "参数管理", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysConfig config, HttpServletResponse response) { | ||||
|         List<SysConfig> list = configService.selectConfigList(config); | ||||
|         ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据参数编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据参数编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:query')") | ||||
|     @GetMapping(value = "/{configId}") | ||||
|     public AjaxResult<SysConfig> getInfo(@PathVariable Long configId) { | ||||
|         return AjaxResult.success(configService.selectConfigById(configId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据参数键名查询参数值 | ||||
|      */ | ||||
|     @ApiOperation("根据参数键名查询参数值") | ||||
|     @GetMapping(value = "/configKey/{configKey}") | ||||
|     public AjaxResult<Void> getConfigKey(@PathVariable String configKey) { | ||||
|         return AjaxResult.success(configService.selectConfigByKey(configKey)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增参数配置 | ||||
|      */ | ||||
|     @ApiOperation("新增参数配置") | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:add')") | ||||
|     @Log(title = "参数管理", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     @RepeatSubmit | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysConfig config) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) { | ||||
|             return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); | ||||
|         } | ||||
|         return toAjax(configService.insertConfig(config)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改参数配置 | ||||
|      */ | ||||
|     @ApiOperation("修改参数配置") | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:edit')") | ||||
|     @Log(title = "参数管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysConfig config) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) { | ||||
|             return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); | ||||
|         } | ||||
|         return toAjax(configService.updateConfig(config)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除参数配置 | ||||
|      */ | ||||
|     @ApiOperation("删除参数配置") | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:remove')") | ||||
|     @Log(title = "参数管理", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{configIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] configIds) { | ||||
|         configService.deleteConfigByIds(configIds); | ||||
|         return success(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 刷新参数缓存 | ||||
|      */ | ||||
|     @ApiOperation("刷新参数缓存") | ||||
|     @PreAuthorize("@ss.hasPermi('system:config:remove')") | ||||
|     @Log(title = "参数管理", businessType = BusinessType.CLEAN) | ||||
|     @DeleteMapping("/refreshCache") | ||||
|     public AjaxResult<Void> refreshCache() { | ||||
|         configService.resetConfigCache(); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,146 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import cn.hutool.core.util.ArrayUtil; | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.TreeSelect; | ||||
| import com.ruoyi.common.core.domain.entity.SysDept; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.system.service.ISysDeptService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 部门信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "部门控制器", tags = {"部门管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/dept") | ||||
| public class SysDeptController extends BaseController { | ||||
|  | ||||
|     private final ISysDeptService deptService; | ||||
|  | ||||
|     /** | ||||
|      * 获取部门列表 | ||||
|      */ | ||||
|     @ApiOperation("获取部门列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dept:list')") | ||||
|     @GetMapping("/list") | ||||
|     public AjaxResult<List<SysDept>> list(SysDept dept) { | ||||
|         List<SysDept> depts = deptService.selectDeptList(dept); | ||||
|         return AjaxResult.success(depts); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询部门列表(排除节点) | ||||
|      */ | ||||
|     @ApiOperation("查询部门列表(排除节点)") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dept:list')") | ||||
|     @GetMapping("/list/exclude/{deptId}") | ||||
|     public AjaxResult<List<SysDept>> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { | ||||
|         List<SysDept> depts = deptService.selectDeptList(new SysDept()); | ||||
|         depts.removeIf(d -> d.getDeptId().equals(deptId) | ||||
|                 || ArrayUtil.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); | ||||
|         return AjaxResult.success(depts); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据部门编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据部门编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dept:query')") | ||||
|     @GetMapping(value = "/{deptId}") | ||||
|     public AjaxResult<SysDept> getInfo(@PathVariable Long deptId) { | ||||
|         deptService.checkDeptDataScope(deptId); | ||||
|         return AjaxResult.success(deptService.selectDeptById(deptId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取部门下拉树列表 | ||||
|      */ | ||||
|     @ApiOperation("获取部门下拉树列表") | ||||
|     @GetMapping("/treeselect") | ||||
|     public AjaxResult<List<TreeSelect>> treeselect(SysDept dept) { | ||||
|         List<SysDept> depts = deptService.selectDeptList(dept); | ||||
|         return AjaxResult.success(deptService.buildDeptTreeSelect(depts)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 加载对应角色部门列表树 | ||||
|      */ | ||||
|     @ApiOperation("加载对应角色部门列表树") | ||||
|     @GetMapping(value = "/roleDeptTreeselect/{roleId}") | ||||
|     public AjaxResult<Map<String, Object>> roleDeptTreeselect(@PathVariable("roleId") Long roleId) { | ||||
|         List<SysDept> depts = deptService.selectDeptList(new SysDept()); | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); | ||||
|         ajax.put("depts", deptService.buildDeptTreeSelect(depts)); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增部门 | ||||
|      */ | ||||
|     @ApiOperation("新增部门") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dept:add')") | ||||
|     @Log(title = "部门管理", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysDept dept) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) { | ||||
|             return AjaxResult.error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); | ||||
|         } | ||||
|         return toAjax(deptService.insertDept(dept)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改部门 | ||||
|      */ | ||||
|     @ApiOperation("修改部门") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dept:edit')") | ||||
|     @Log(title = "部门管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysDept dept) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) { | ||||
|             return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); | ||||
|         } else if (dept.getParentId().equals(dept.getDeptId())) { | ||||
|             return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); | ||||
|         } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) | ||||
|                 && deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0) { | ||||
|             return AjaxResult.error("该部门包含未停用的子部门!"); | ||||
|         } | ||||
|         return toAjax(deptService.updateDept(dept)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除部门 | ||||
|      */ | ||||
|     @ApiOperation("删除部门") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dept:remove')") | ||||
|     @Log(title = "部门管理", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{deptId}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long deptId) { | ||||
|         if (deptService.hasChildByDeptId(deptId)) { | ||||
|             return AjaxResult.error("存在下级部门,不允许删除"); | ||||
|         } | ||||
|         if (deptService.checkDeptExistUser(deptId)) { | ||||
|             return AjaxResult.error("部门存在用户,不允许删除"); | ||||
|         } | ||||
|         return toAjax(deptService.deleteDeptById(deptId)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,112 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.entity.SysDictData; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.service.ISysDictDataService; | ||||
| import com.ruoyi.system.service.ISysDictTypeService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 数据字典信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "数据字典信息控制器", tags = {"数据字典信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/dict/data") | ||||
| public class SysDictDataController extends BaseController { | ||||
|  | ||||
|     private final ISysDictDataService dictDataService; | ||||
|     private final ISysDictTypeService dictTypeService; | ||||
|  | ||||
|     @ApiOperation("查询字典数据列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysDictData> list(SysDictData dictData) { | ||||
|         return dictDataService.selectPageDictDataList(dictData); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出字典数据列表") | ||||
|     @Log(title = "字典数据", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysDictData dictData, HttpServletResponse response) { | ||||
|         List<SysDictData> list = dictDataService.selectDictDataList(dictData); | ||||
|         ExcelUtil.exportExcel(list, "字典数据", SysDictData.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询字典数据详细 | ||||
|      */ | ||||
|     @ApiOperation("查询字典数据详细") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:query')") | ||||
|     @GetMapping(value = "/{dictCode}") | ||||
|     public AjaxResult<SysDictData> getInfo(@PathVariable Long dictCode) { | ||||
|         return AjaxResult.success(dictDataService.selectDictDataById(dictCode)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据字典类型查询字典数据信息 | ||||
|      */ | ||||
|     @ApiOperation("根据字典类型查询字典数据信息") | ||||
|     @GetMapping(value = "/type/{dictType}") | ||||
|     public AjaxResult<List<SysDictData>> dictType(@PathVariable String dictType) { | ||||
|         List<SysDictData> data = dictTypeService.selectDictDataByType(dictType); | ||||
|         if (StringUtils.isNull(data)) { | ||||
|             data = new ArrayList<>(); | ||||
|         } | ||||
|         return AjaxResult.success(data); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增字典类型 | ||||
|      */ | ||||
|     @ApiOperation("新增字典类型") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:add')") | ||||
|     @Log(title = "字典数据", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysDictData dict) { | ||||
|         return toAjax(dictDataService.insertDictData(dict)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改保存字典类型 | ||||
|      */ | ||||
|     @ApiOperation("修改保存字典类型") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:edit')") | ||||
|     @Log(title = "字典数据", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysDictData dict) { | ||||
|         return toAjax(dictDataService.updateDictData(dict)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除字典类型 | ||||
|      */ | ||||
|     @ApiOperation("删除字典类型") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:remove')") | ||||
|     @Log(title = "字典类型", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{dictCodes}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] dictCodes) { | ||||
|         dictDataService.deleteDictDataByIds(dictCodes); | ||||
|         return success(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,124 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.entity.SysDictType; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.service.ISysDictTypeService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 数据字典信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "数据字典信息控制器", tags = {"数据字典信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/dict/type") | ||||
| public class SysDictTypeController extends BaseController { | ||||
|  | ||||
|     private final ISysDictTypeService dictTypeService; | ||||
|  | ||||
|     @ApiOperation("查询字典类型列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysDictType> list(SysDictType dictType) { | ||||
|         return dictTypeService.selectPageDictTypeList(dictType); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出字典类型列表") | ||||
|     @Log(title = "字典类型", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysDictType dictType, HttpServletResponse response) { | ||||
|         List<SysDictType> list = dictTypeService.selectDictTypeList(dictType); | ||||
|         ExcelUtil.exportExcel(list, "字典类型", SysDictType.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询字典类型详细 | ||||
|      */ | ||||
|     @ApiOperation("查询字典类型详细") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:query')") | ||||
|     @GetMapping(value = "/{dictId}") | ||||
|     public AjaxResult<SysDictType> getInfo(@PathVariable Long dictId) { | ||||
|         return AjaxResult.success(dictTypeService.selectDictTypeById(dictId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增字典类型 | ||||
|      */ | ||||
|     @ApiOperation("新增字典类型") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:add')") | ||||
|     @Log(title = "字典类型", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysDictType dict) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) { | ||||
|             return AjaxResult.error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); | ||||
|         } | ||||
|         return toAjax(dictTypeService.insertDictType(dict)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改字典类型 | ||||
|      */ | ||||
|     @ApiOperation("修改字典类型") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:edit')") | ||||
|     @Log(title = "字典类型", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysDictType dict) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) { | ||||
|             return AjaxResult.error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); | ||||
|         } | ||||
|         return toAjax(dictTypeService.updateDictType(dict)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除字典类型 | ||||
|      */ | ||||
|     @ApiOperation("删除字典类型") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:remove')") | ||||
|     @Log(title = "字典类型", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{dictIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] dictIds) { | ||||
|         dictTypeService.deleteDictTypeByIds(dictIds); | ||||
|         return success(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 刷新字典缓存 | ||||
|      */ | ||||
|     @ApiOperation("刷新字典缓存") | ||||
|     @PreAuthorize("@ss.hasPermi('system:dict:remove')") | ||||
|     @Log(title = "字典类型", businessType = BusinessType.CLEAN) | ||||
|     @DeleteMapping("/refreshCache") | ||||
|     public AjaxResult<Void> refreshCache() { | ||||
|         dictTypeService.resetDictCache(); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取字典选择框列表 | ||||
|      */ | ||||
|     @ApiOperation("获取字典选择框列表") | ||||
|     @GetMapping("/optionselect") | ||||
|     public AjaxResult<List<SysDictType>> optionselect() { | ||||
|         List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll(); | ||||
|         return AjaxResult.success(dictTypes); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.config.RuoYiConfig; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| /** | ||||
|  * 首页 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Api(value = "首页控制器", tags = {"首页管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| public class SysIndexController { | ||||
|  | ||||
|     /** | ||||
|      * 系统基础配置 | ||||
|      */ | ||||
|     private final RuoYiConfig ruoyiConfig; | ||||
|  | ||||
|     /** | ||||
|      * 访问首页,提示语 | ||||
|      */ | ||||
|     @ApiOperation("访问首页,提示语") | ||||
|     @GetMapping("/") | ||||
|     public String index() { | ||||
|         return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,92 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.constant.Constants; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.entity.SysMenu; | ||||
| import com.ruoyi.common.core.domain.entity.SysUser; | ||||
| import com.ruoyi.common.core.domain.model.LoginBody; | ||||
| import com.ruoyi.common.utils.SecurityUtils; | ||||
| import com.ruoyi.system.domain.vo.RouterVo; | ||||
| import com.ruoyi.system.service.ISysMenuService; | ||||
| import com.ruoyi.system.service.SysLoginService; | ||||
| import com.ruoyi.system.service.SysPermissionService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.PostMapping; | ||||
| import org.springframework.web.bind.annotation.RequestBody; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
|  | ||||
| /** | ||||
|  * 登录验证 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "数据字典信息控制器", tags = {"数据字典信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| public class SysLoginController { | ||||
|  | ||||
|     private final SysLoginService loginService; | ||||
|     private final ISysMenuService menuService; | ||||
|     private final SysPermissionService permissionService; | ||||
|  | ||||
|     /** | ||||
|      * 登录方法 | ||||
|      * | ||||
|      * @param loginBody 登录信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @ApiOperation("登录方法") | ||||
|     @PostMapping("/login") | ||||
|     public AjaxResult<Map<String, Object>> login(@RequestBody LoginBody loginBody) { | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         // 生成令牌 | ||||
|         String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), | ||||
|                 loginBody.getUuid()); | ||||
|         ajax.put(Constants.TOKEN, token); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取用户信息 | ||||
|      * | ||||
|      * @return 用户信息 | ||||
|      */ | ||||
|     @ApiOperation("获取用户信息") | ||||
|     @GetMapping("getInfo") | ||||
|     public AjaxResult<Map<String, Object>> getInfo() { | ||||
|         SysUser user = SecurityUtils.getLoginUser().getUser(); | ||||
|         // 角色集合 | ||||
|         Set<String> roles = permissionService.getRolePermission(user); | ||||
|         // 权限集合 | ||||
|         Set<String> permissions = permissionService.getMenuPermission(user); | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         ajax.put("user", user); | ||||
|         ajax.put("roles", roles); | ||||
|         ajax.put("permissions", permissions); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取路由信息 | ||||
|      * | ||||
|      * @return 路由信息 | ||||
|      */ | ||||
|     @ApiOperation("获取路由信息") | ||||
|     @GetMapping("getRouters") | ||||
|     public AjaxResult<List<RouterVo>> getRouters() { | ||||
|         Long userId = SecurityUtils.getUserId(); | ||||
|         List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId); | ||||
|         return AjaxResult.success(menuService.buildMenus(menus)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,132 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.TreeSelect; | ||||
| import com.ruoyi.common.core.domain.entity.SysMenu; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.system.service.ISysMenuService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 菜单信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "菜单信息控制器", tags = {"菜单信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/menu") | ||||
| public class SysMenuController extends BaseController { | ||||
|  | ||||
|     private final ISysMenuService menuService; | ||||
|  | ||||
|     /** | ||||
|      * 获取菜单列表 | ||||
|      */ | ||||
|     @ApiOperation("获取菜单列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:menu:list')") | ||||
|     @GetMapping("/list") | ||||
|     public AjaxResult<List<SysMenu>> list(SysMenu menu) { | ||||
|         List<SysMenu> menus = menuService.selectMenuList(menu, getUserId()); | ||||
|         return AjaxResult.success(menus); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据菜单编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据菜单编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:menu:query')") | ||||
|     @GetMapping(value = "/{menuId}") | ||||
|     public AjaxResult<SysMenu> getInfo(@PathVariable Long menuId) { | ||||
|         return AjaxResult.success(menuService.selectMenuById(menuId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取菜单下拉树列表 | ||||
|      */ | ||||
|     @ApiOperation("获取菜单下拉树列表") | ||||
|     @GetMapping("/treeselect") | ||||
|     public AjaxResult<List<TreeSelect>> treeselect(SysMenu menu) { | ||||
|         List<SysMenu> menus = menuService.selectMenuList(menu, getUserId()); | ||||
|         return AjaxResult.success(menuService.buildMenuTreeSelect(menus)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 加载对应角色菜单列表树 | ||||
|      */ | ||||
|     @ApiOperation("加载对应角色菜单列表树") | ||||
|     @GetMapping(value = "/roleMenuTreeselect/{roleId}") | ||||
|     public AjaxResult<Map<String, Object>> roleMenuTreeselect(@PathVariable("roleId") Long roleId) { | ||||
|         List<SysMenu> menus = menuService.selectMenuList(getUserId()); | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); | ||||
|         ajax.put("menus", menuService.buildMenuTreeSelect(menus)); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增菜单 | ||||
|      */ | ||||
|     @ApiOperation("新增菜单") | ||||
|     @PreAuthorize("@ss.hasPermi('system:menu:add')") | ||||
|     @Log(title = "菜单管理", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysMenu menu) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) { | ||||
|             return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); | ||||
|         } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { | ||||
|             return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); | ||||
|         } | ||||
|         return toAjax(menuService.insertMenu(menu)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改菜单 | ||||
|      */ | ||||
|     @ApiOperation("修改菜单") | ||||
|     @PreAuthorize("@ss.hasPermi('system:menu:edit')") | ||||
|     @Log(title = "菜单管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysMenu menu) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) { | ||||
|             return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); | ||||
|         } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { | ||||
|             return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); | ||||
|         } else if (menu.getMenuId().equals(menu.getParentId())) { | ||||
|             return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); | ||||
|         } | ||||
|         return toAjax(menuService.updateMenu(menu)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除菜单 | ||||
|      */ | ||||
|     @ApiOperation("删除菜单") | ||||
|     @PreAuthorize("@ss.hasPermi('system:menu:remove')") | ||||
|     @Log(title = "菜单管理", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{menuId}") | ||||
|     public AjaxResult<Void> remove(@PathVariable("menuId") Long menuId) { | ||||
|         if (menuService.hasChildByMenuId(menuId)) { | ||||
|             return AjaxResult.error("存在子菜单,不允许删除"); | ||||
|         } | ||||
|         if (menuService.checkMenuExistRole(menuId)) { | ||||
|             return AjaxResult.error("菜单已分配,不允许删除"); | ||||
|         } | ||||
|         return toAjax(menuService.deleteMenuById(menuId)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,84 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.system.domain.SysNotice; | ||||
| import com.ruoyi.system.service.ISysNoticeService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| /** | ||||
|  * 公告 信息操作处理 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "公告信息控制器", tags = {"公告信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/notice") | ||||
| public class SysNoticeController extends BaseController { | ||||
|  | ||||
|     private final ISysNoticeService noticeService; | ||||
|  | ||||
|     /** | ||||
|      * 获取通知公告列表 | ||||
|      */ | ||||
|     @ApiOperation("获取通知公告列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:notice:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysNotice> list(SysNotice notice) { | ||||
|         return noticeService.selectPageNoticeList(notice); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据通知公告编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据通知公告编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:notice:query')") | ||||
|     @GetMapping(value = "/{noticeId}") | ||||
|     public AjaxResult<SysNotice> getInfo(@PathVariable Long noticeId) { | ||||
|         return AjaxResult.success(noticeService.selectNoticeById(noticeId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增通知公告 | ||||
|      */ | ||||
|     @ApiOperation("新增通知公告") | ||||
|     @PreAuthorize("@ss.hasPermi('system:notice:add')") | ||||
|     @Log(title = "通知公告", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysNotice notice) { | ||||
|         return toAjax(noticeService.insertNotice(notice)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改通知公告 | ||||
|      */ | ||||
|     @ApiOperation("修改通知公告") | ||||
|     @PreAuthorize("@ss.hasPermi('system:notice:edit')") | ||||
|     @Log(title = "通知公告", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysNotice notice) { | ||||
|         return toAjax(noticeService.updateNotice(notice)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除通知公告 | ||||
|      */ | ||||
|     @ApiOperation("删除通知公告") | ||||
|     @PreAuthorize("@ss.hasPermi('system:notice:remove')") | ||||
|     @Log(title = "通知公告", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{noticeIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] noticeIds) { | ||||
|         return toAjax(noticeService.deleteNoticeByIds(noticeIds)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,110 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.annotation.RepeatSubmit; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.core.validate.AddGroup; | ||||
| import com.ruoyi.common.core.validate.EditGroup; | ||||
| import com.ruoyi.common.core.validate.QueryGroup; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.system.domain.bo.SysOssConfigBo; | ||||
| import com.ruoyi.system.domain.vo.SysOssConfigVo; | ||||
| import com.ruoyi.system.service.ISysOssConfigService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.validation.constraints.NotEmpty; | ||||
| import javax.validation.constraints.NotNull; | ||||
| import java.util.Arrays; | ||||
|  | ||||
| /** | ||||
|  * 对象存储配置Controller | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  * @author 孤舟烟雨 | ||||
|  * @date 2021-08-13 | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "对象存储配置控制器", tags = {"对象存储配置管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/oss/config") | ||||
| public class SysOssConfigController extends BaseController { | ||||
|  | ||||
|     private final ISysOssConfigService iSysOssConfigService; | ||||
|  | ||||
|     /** | ||||
|      * 查询对象存储配置列表 | ||||
|      */ | ||||
|     @ApiOperation("查询对象存储配置列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo) { | ||||
|         return iSysOssConfigService.queryPageList(bo); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取对象存储配置详细信息 | ||||
|      */ | ||||
|     @ApiOperation("获取对象存储配置详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:query')") | ||||
|     @GetMapping("/{ossConfigId}") | ||||
|     public AjaxResult<SysOssConfigVo> getInfo(@NotNull(message = "主键不能为空") | ||||
|                                               @PathVariable("ossConfigId") Integer ossConfigId) { | ||||
|         return AjaxResult.success(iSysOssConfigService.queryById(ossConfigId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增对象存储配置 | ||||
|      */ | ||||
|     @ApiOperation("新增对象存储配置") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:add')") | ||||
|     @Log(title = "对象存储配置", businessType = BusinessType.INSERT) | ||||
|     @RepeatSubmit() | ||||
|     @PostMapping() | ||||
|     public AjaxResult<Void> add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) { | ||||
|         return toAjax(iSysOssConfigService.insertByBo(bo) ? 1 : 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改对象存储配置 | ||||
|      */ | ||||
|     @ApiOperation("修改对象存储配置") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:edit')") | ||||
|     @Log(title = "对象存储配置", businessType = BusinessType.UPDATE) | ||||
|     @RepeatSubmit() | ||||
|     @PutMapping() | ||||
|     public AjaxResult<Void> edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) { | ||||
|         return toAjax(iSysOssConfigService.updateByBo(bo) ? 1 : 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除对象存储配置 | ||||
|      */ | ||||
|     @ApiOperation("删除对象存储配置") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:remove')") | ||||
|     @Log(title = "对象存储配置", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{ossConfigIds}") | ||||
|     public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空") | ||||
|                                    @PathVariable Long[] ossConfigIds) { | ||||
|         return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true) ? 1 : 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 状态修改 | ||||
|      */ | ||||
|     @ApiOperation("状态修改") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:edit')") | ||||
|     @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/changeStatus") | ||||
|     public AjaxResult<Void> changeStatus(@RequestBody SysOssConfigBo bo) { | ||||
|         return toAjax(iSysOssConfigService.updateOssConfigStatus(bo)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,143 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
|  | ||||
| import cn.hutool.core.convert.Convert; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import cn.hutool.http.HttpException; | ||||
| import cn.hutool.http.HttpUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.annotation.RepeatSubmit; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.core.validate.QueryGroup; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.exception.ServiceException; | ||||
| import com.ruoyi.common.utils.JsonUtils; | ||||
| import com.ruoyi.common.utils.file.FileUtils; | ||||
| import com.ruoyi.oss.constant.CloudConstant; | ||||
| import com.ruoyi.system.domain.SysConfig; | ||||
| import com.ruoyi.system.domain.SysOss; | ||||
| import com.ruoyi.system.domain.bo.SysOssBo; | ||||
| import com.ruoyi.system.domain.vo.SysOssVo; | ||||
| import com.ruoyi.system.service.ISysConfigService; | ||||
| import com.ruoyi.system.service.ISysOssService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiImplicitParam; | ||||
| import io.swagger.annotations.ApiImplicitParams; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.http.MediaType; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import javax.validation.constraints.NotEmpty; | ||||
| import java.io.IOException; | ||||
| import java.util.Arrays; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 文件上传 控制层 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "OSS对象存储控制器", tags = {"OSS对象存储管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/oss") | ||||
| public class SysOssController extends BaseController { | ||||
|  | ||||
|     private final ISysOssService iSysOssService; | ||||
|     private final ISysConfigService iSysConfigService; | ||||
|  | ||||
|     /** | ||||
|      * 查询OSS对象存储列表 | ||||
|      */ | ||||
|     @ApiOperation("查询OSS对象存储列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo) { | ||||
|         return iSysOssService.queryPageList(bo); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 上传OSS对象存储 | ||||
|      */ | ||||
|     @ApiOperation("上传OSS对象存储") | ||||
|     @ApiImplicitParams({ | ||||
|             @ApiImplicitParam(name = "file", value = "文件", dataType = "java.io.File", required = true), | ||||
|     }) | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:upload')") | ||||
|     @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) | ||||
|     @RepeatSubmit | ||||
|     @PostMapping("/upload") | ||||
|     public AjaxResult<Map<String, String>> upload(@RequestPart("file") MultipartFile file) { | ||||
|         if (ObjectUtil.isNull(file)) { | ||||
|             throw new ServiceException("上传文件不能为空"); | ||||
|         } | ||||
|         SysOss oss = iSysOssService.upload(file); | ||||
|         Map<String, String> map = new HashMap<>(2); | ||||
|         map.put("url", oss.getUrl()); | ||||
|         map.put("fileName", oss.getFileName()); | ||||
|         return AjaxResult.success(map); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("下载OSS对象存储") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:download')") | ||||
|     @GetMapping("/download/{ossId}") | ||||
|     public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { | ||||
|         SysOss sysOss = iSysOssService.getById(ossId); | ||||
|         if (ObjectUtil.isNull(sysOss)) { | ||||
|             throw new ServiceException("文件数据不存在!"); | ||||
|         } | ||||
|         response.reset(); | ||||
|         FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); | ||||
|         response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); | ||||
|         long data; | ||||
|         try { | ||||
|             data = HttpUtil.download(sysOss.getUrl(), response.getOutputStream(), false); | ||||
|         } catch (HttpException e) { | ||||
|             if (e.getMessage().contains("403")) { | ||||
|                 throw new ServiceException("无读取权限, 请在对应的OSS开启'公有读'权限!"); | ||||
|             } else { | ||||
|                 throw new ServiceException(e.getMessage()); | ||||
|             } | ||||
|         } | ||||
|         response.setContentLength(Convert.toInt(data)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除OSS对象存储 | ||||
|      */ | ||||
|     @ApiOperation("删除OSS对象存储") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:remove')") | ||||
|     @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{ossIds}") | ||||
|     public AjaxResult<Void> remove(@NotEmpty(message = "主键不能为空") | ||||
|                                    @PathVariable Long[] ossIds) { | ||||
|         return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true) ? 1 : 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 变更图片列表预览状态 | ||||
|      */ | ||||
|     @ApiOperation("变更图片列表预览状态") | ||||
|     @PreAuthorize("@ss.hasPermi('system:oss:edit')") | ||||
|     @Log(title = "OSS对象存储", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/changePreviewListResource") | ||||
|     public AjaxResult<Void> changePreviewListResource(@RequestBody String body) { | ||||
|         Map<String, Boolean> map = JsonUtils.parseMap(body); | ||||
|         SysConfig config = iSysConfigService.getOne(new LambdaQueryWrapper<SysConfig>() | ||||
|                 .eq(SysConfig::getConfigKey, CloudConstant.PEREVIEW_LIST_RESOURCE_KEY)); | ||||
|         config.setConfigValue(map.get("previewListResource").toString()); | ||||
|         return toAjax(iSysConfigService.updateConfig(config)); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,118 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.domain.SysPost; | ||||
| import com.ruoyi.system.service.ISysPostService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 岗位信息操作处理 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "岗位信息控制器", tags = {"岗位信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/post") | ||||
| public class SysPostController extends BaseController { | ||||
|  | ||||
|     private final ISysPostService postService; | ||||
|  | ||||
|     /** | ||||
|      * 获取岗位列表 | ||||
|      */ | ||||
|     @ApiOperation("获取岗位列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:post:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysPost> list(SysPost post) { | ||||
|         return postService.selectPagePostList(post); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出岗位列表") | ||||
|     @Log(title = "岗位管理", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:post:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysPost post, HttpServletResponse response) { | ||||
|         List<SysPost> list = postService.selectPostList(post); | ||||
|         ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据岗位编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据岗位编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:post:query')") | ||||
|     @GetMapping(value = "/{postId}") | ||||
|     public AjaxResult<SysPost> getInfo(@PathVariable Long postId) { | ||||
|         return AjaxResult.success(postService.selectPostById(postId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增岗位 | ||||
|      */ | ||||
|     @ApiOperation("新增岗位") | ||||
|     @PreAuthorize("@ss.hasPermi('system:post:add')") | ||||
|     @Log(title = "岗位管理", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysPost post) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) { | ||||
|             return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); | ||||
|         } else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) { | ||||
|             return AjaxResult.error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); | ||||
|         } | ||||
|         return toAjax(postService.insertPost(post)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改岗位 | ||||
|      */ | ||||
|     @ApiOperation("修改岗位") | ||||
|     @PreAuthorize("@ss.hasPermi('system:post:edit')") | ||||
|     @Log(title = "岗位管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysPost post) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) { | ||||
|             return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); | ||||
|         } else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) { | ||||
|             return AjaxResult.error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); | ||||
|         } | ||||
|         return toAjax(postService.updatePost(post)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除岗位 | ||||
|      */ | ||||
|     @ApiOperation("删除岗位") | ||||
|     @PreAuthorize("@ss.hasPermi('system:post:remove')") | ||||
|     @Log(title = "岗位管理", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{postIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] postIds) { | ||||
|         return toAjax(postService.deletePostByIds(postIds)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取岗位选择框列表 | ||||
|      */ | ||||
|     @ApiOperation("获取岗位选择框列表") | ||||
|     @GetMapping("/optionselect") | ||||
|     public AjaxResult<List<SysPost>> optionselect() { | ||||
|         List<SysPost> posts = postService.selectPostAll(); | ||||
|         return AjaxResult.success(posts); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,138 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.entity.SysUser; | ||||
| import com.ruoyi.common.core.domain.model.LoginUser; | ||||
| import com.ruoyi.common.core.service.TokenService; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.SecurityUtils; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.system.domain.SysOss; | ||||
| import com.ruoyi.system.service.ISysOssService; | ||||
| import com.ruoyi.system.service.ISysUserService; | ||||
| import io.swagger.annotations.*; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 个人信息 业务处理 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "个人信息控制器", tags = {"个人信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/user/profile") | ||||
| public class SysProfileController extends BaseController { | ||||
|  | ||||
|     private final ISysUserService userService; | ||||
|     private final TokenService tokenService; | ||||
|     private final ISysOssService iSysOssService; | ||||
|  | ||||
|     /** | ||||
|      * 个人信息 | ||||
|      */ | ||||
|     @ApiOperation("个人信息") | ||||
|     @GetMapping | ||||
|     public AjaxResult<Map<String, Object>> profile() { | ||||
|         LoginUser loginUser = getLoginUser(); | ||||
|         SysUser user = loginUser.getUser(); | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         ajax.put("user", user); | ||||
|         ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); | ||||
|         ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改用户 | ||||
|      */ | ||||
|     @ApiOperation("修改用户") | ||||
|     @Log(title = "个人信息", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> updateProfile(@RequestBody SysUser user) { | ||||
|         if (StringUtils.isNotEmpty(user.getPhonenumber()) | ||||
|                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { | ||||
|             return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); | ||||
|         } | ||||
|         if (StringUtils.isNotEmpty(user.getEmail()) | ||||
|                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { | ||||
|             return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); | ||||
|         } | ||||
|         LoginUser loginUser = getLoginUser(); | ||||
|         SysUser sysUser = loginUser.getUser(); | ||||
|         user.setUserId(sysUser.getUserId()); | ||||
|         user.setPassword(null); | ||||
|         if (userService.updateUserProfile(user) > 0) { | ||||
|             // 更新缓存用户信息 | ||||
|             sysUser.setNickName(user.getNickName()); | ||||
|             sysUser.setPhonenumber(user.getPhonenumber()); | ||||
|             sysUser.setEmail(user.getEmail()); | ||||
|             sysUser.setSex(user.getSex()); | ||||
|             tokenService.setLoginUser(loginUser); | ||||
|             return AjaxResult.success(); | ||||
|         } | ||||
|         return AjaxResult.error("修改个人信息异常,请联系管理员"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重置密码 | ||||
|      */ | ||||
|     @ApiOperation("重置密码") | ||||
|     @Log(title = "个人信息", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/updatePwd") | ||||
|     public AjaxResult<Void> updatePwd(String oldPassword, String newPassword) { | ||||
|         LoginUser loginUser = getLoginUser(); | ||||
|         String userName = loginUser.getUsername(); | ||||
|         String password = loginUser.getPassword(); | ||||
|         if (!SecurityUtils.matchesPassword(oldPassword, password)) { | ||||
|             return AjaxResult.error("修改密码失败,旧密码错误"); | ||||
|         } | ||||
|         if (SecurityUtils.matchesPassword(newPassword, password)) { | ||||
|             return AjaxResult.error("新密码不能与旧密码相同"); | ||||
|         } | ||||
|         if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) { | ||||
|             // 更新缓存用户密码 | ||||
|             loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); | ||||
|             tokenService.setLoginUser(loginUser); | ||||
|             return AjaxResult.success(); | ||||
|         } | ||||
|         return AjaxResult.error("修改密码异常,请联系管理员"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 头像上传 | ||||
|      */ | ||||
|     @ApiOperation("头像上传") | ||||
|     @ApiImplicitParams({ | ||||
|             @ApiImplicitParam(name = "file", value = "用户头像", dataType = "java.io.File", required = true), | ||||
|     }) | ||||
|     @Log(title = "用户头像", businessType = BusinessType.UPDATE) | ||||
|     @PostMapping("/avatar") | ||||
|     public AjaxResult<Map<String, Object>> avatar(@RequestPart("avatarfile") MultipartFile file) { | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         if (!file.isEmpty()) { | ||||
|             LoginUser loginUser = getLoginUser(); | ||||
|             SysOss oss = iSysOssService.upload(file); | ||||
|             String avatar = oss.getUrl(); | ||||
|             if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) { | ||||
|                 ajax.put("imgUrl", avatar); | ||||
|                 // 更新缓存用户头像 | ||||
|                 loginUser.getUser().setAvatar(avatar); | ||||
|                 tokenService.setLoginUser(loginUser); | ||||
|                 return AjaxResult.success(ajax); | ||||
|             } | ||||
|         } | ||||
|         return AjaxResult.error("上传图片异常,请联系管理员", ajax); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,41 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.model.RegisterBody; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.system.service.ISysConfigService; | ||||
| import com.ruoyi.system.service.SysRegisterService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.PostMapping; | ||||
| import org.springframework.web.bind.annotation.RequestBody; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| /** | ||||
|  * 注册验证 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "注册验证控制器", tags = {"注册验证管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| public class SysRegisterController extends BaseController { | ||||
|  | ||||
|     private final SysRegisterService registerService; | ||||
|     private final ISysConfigService configService; | ||||
|  | ||||
|     @ApiOperation("用户注册") | ||||
|     @PostMapping("/register") | ||||
|     public AjaxResult<Void> register(@RequestBody RegisterBody user) { | ||||
|         if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { | ||||
|             return error("当前系统没有开启注册功能!"); | ||||
|         } | ||||
|         String msg = registerService.register(user); | ||||
|         return StringUtils.isEmpty(msg) ? success() : error(msg); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,216 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.entity.SysRole; | ||||
| import com.ruoyi.common.core.domain.entity.SysUser; | ||||
| import com.ruoyi.common.core.domain.model.LoginUser; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.core.service.TokenService; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.domain.SysUserRole; | ||||
| import com.ruoyi.system.service.ISysRoleService; | ||||
| import com.ruoyi.system.service.ISysUserService; | ||||
| import com.ruoyi.system.service.SysPermissionService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 角色信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "角色信息控制器", tags = {"角色信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/role") | ||||
| public class SysRoleController extends BaseController { | ||||
|  | ||||
|     private final ISysRoleService roleService; | ||||
|     private final TokenService tokenService; | ||||
|     private final ISysUserService userService; | ||||
|     private final SysPermissionService permissionService; | ||||
|  | ||||
|     @ApiOperation("查询角色信息列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysRole> list(SysRole role) { | ||||
|         return roleService.selectPageRoleList(role); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出角色信息列表") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysRole role, HttpServletResponse response) { | ||||
|         List<SysRole> list = roleService.selectRoleList(role); | ||||
|         ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据角色编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据角色编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:query')") | ||||
|     @GetMapping(value = "/{roleId}") | ||||
|     public AjaxResult<SysRole> getInfo(@PathVariable Long roleId) { | ||||
|         roleService.checkRoleDataScope(roleId); | ||||
|         return AjaxResult.success(roleService.selectRoleById(roleId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增角色 | ||||
|      */ | ||||
|     @ApiOperation("新增角色") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:add')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysRole role) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) { | ||||
|             return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); | ||||
|         } else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) { | ||||
|             return AjaxResult.error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); | ||||
|         } | ||||
|         return toAjax(roleService.insertRole(role)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改保存角色 | ||||
|      */ | ||||
|     @ApiOperation("修改保存角色") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:edit')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysRole role) { | ||||
|         roleService.checkRoleAllowed(role); | ||||
|         if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) { | ||||
|             return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); | ||||
|         } else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) { | ||||
|             return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); | ||||
|         } | ||||
|  | ||||
|         if (roleService.updateRole(role) > 0) { | ||||
|             // 更新缓存用户权限 | ||||
|             LoginUser loginUser = getLoginUser(); | ||||
|             if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) { | ||||
|                 loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); | ||||
|                 loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); | ||||
|                 tokenService.setLoginUser(loginUser); | ||||
|             } | ||||
|             return AjaxResult.success(); | ||||
|         } | ||||
|         return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改保存数据权限 | ||||
|      */ | ||||
|     @ApiOperation("修改保存数据权限") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:edit')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/dataScope") | ||||
|     public AjaxResult<Void> dataScope(@RequestBody SysRole role) { | ||||
|         roleService.checkRoleAllowed(role); | ||||
|         return toAjax(roleService.authDataScope(role)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 状态修改 | ||||
|      */ | ||||
|     @ApiOperation("状态修改") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:edit')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/changeStatus") | ||||
|     public AjaxResult<Void> changeStatus(@RequestBody SysRole role) { | ||||
|         roleService.checkRoleAllowed(role); | ||||
|         return toAjax(roleService.updateRoleStatus(role)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除角色 | ||||
|      */ | ||||
|     @ApiOperation("删除角色") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:remove')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{roleIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] roleIds) { | ||||
|         return toAjax(roleService.deleteRoleByIds(roleIds)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取角色选择框列表 | ||||
|      */ | ||||
|     @ApiOperation("获取角色选择框列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:query')") | ||||
|     @GetMapping("/optionselect") | ||||
|     public AjaxResult<List<SysRole>> optionselect() { | ||||
|         return AjaxResult.success(roleService.selectRoleAll()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询已分配用户角色列表 | ||||
|      */ | ||||
|     @ApiOperation("查询已分配用户角色列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:list')") | ||||
|     @GetMapping("/authUser/allocatedList") | ||||
|     public TableDataInfo<SysUser> allocatedList(SysUser user) { | ||||
|         return userService.selectAllocatedList(user); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询未分配用户角色列表 | ||||
|      */ | ||||
|     @ApiOperation("查询未分配用户角色列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:list')") | ||||
|     @GetMapping("/authUser/unallocatedList") | ||||
|     public TableDataInfo<SysUser> unallocatedList(SysUser user) { | ||||
|         return userService.selectUnallocatedList(user); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 取消授权用户 | ||||
|      */ | ||||
|     @ApiOperation("取消授权用户") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:edit')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.GRANT) | ||||
|     @PutMapping("/authUser/cancel") | ||||
|     public AjaxResult<Void> cancelAuthUser(@RequestBody SysUserRole userRole) { | ||||
|         return toAjax(roleService.deleteAuthUser(userRole)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 批量取消授权用户 | ||||
|      */ | ||||
|     @ApiOperation("批量取消授权用户") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:edit')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.GRANT) | ||||
|     @PutMapping("/authUser/cancelAll") | ||||
|     public AjaxResult<Void> cancelAuthUserAll(Long roleId, Long[] userIds) { | ||||
|         return toAjax(roleService.deleteAuthUsers(roleId, userIds)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 批量选择用户授权 | ||||
|      */ | ||||
|     @ApiOperation("批量选择用户授权") | ||||
|     @PreAuthorize("@ss.hasPermi('system:role:edit')") | ||||
|     @Log(title = "角色管理", businessType = BusinessType.GRANT) | ||||
|     @PutMapping("/authUser/selectAll") | ||||
|     public AjaxResult<Void> selectAuthUserAll(Long roleId, Long[] userIds) { | ||||
|         return toAjax(roleService.insertAuthUsers(roleId, userIds)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,231 @@ | ||||
| package com.ruoyi.web.controller.system; | ||||
|  | ||||
| import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.hutool.core.util.ArrayUtil; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.UserConstants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.domain.entity.SysDept; | ||||
| import com.ruoyi.common.core.domain.entity.SysRole; | ||||
| import com.ruoyi.common.core.domain.entity.SysUser; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.SecurityUtils; | ||||
| import com.ruoyi.common.utils.StringUtils; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.system.domain.vo.SysUserExportVo; | ||||
| import com.ruoyi.system.domain.vo.SysUserImportVo; | ||||
| import com.ruoyi.system.service.ISysPostService; | ||||
| import com.ruoyi.system.service.ISysRoleService; | ||||
| import com.ruoyi.system.service.ISysUserService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiImplicitParam; | ||||
| import io.swagger.annotations.ApiImplicitParams; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
|  | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * 用户信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Validated | ||||
| @Api(value = "用户信息控制器", tags = {"用户信息管理"}) | ||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||
| @RestController | ||||
| @RequestMapping("/system/user") | ||||
| public class SysUserController extends BaseController { | ||||
|  | ||||
|     private final ISysUserService userService; | ||||
|     private final ISysRoleService roleService; | ||||
|     private final ISysPostService postService; | ||||
|  | ||||
|     /** | ||||
|      * 获取用户列表 | ||||
|      */ | ||||
|     @ApiOperation("获取用户列表") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo<SysUser> list(SysUser user) { | ||||
|         return userService.selectPageUserList(user); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导出用户列表") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.EXPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:export')") | ||||
|     @GetMapping("/export") | ||||
|     public void export(SysUser user, HttpServletResponse response) { | ||||
|         List<SysUser> list = userService.selectUserList(user); | ||||
|         List<SysUserExportVo> listVo = BeanUtil.copyToList(list, SysUserExportVo.class); | ||||
|         for (int i = 0; i < list.size(); i++) { | ||||
|             SysDept dept = list.get(i).getDept(); | ||||
|             SysUserExportVo vo = listVo.get(i); | ||||
|             if (ObjectUtil.isNotEmpty(dept)) { | ||||
|                 vo.setDeptName(dept.getDeptName()); | ||||
|                 vo.setLeader(dept.getLeader()); | ||||
|             } | ||||
|         } | ||||
|         ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("导入用户列表") | ||||
|     @ApiImplicitParams({ | ||||
|             @ApiImplicitParam(name = "file", value = "导入文件", dataType = "java.io.File", required = true), | ||||
|     }) | ||||
|     @Log(title = "用户管理", businessType = BusinessType.IMPORT) | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:import')") | ||||
|     @PostMapping("/importData") | ||||
|     public AjaxResult<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { | ||||
|         List<SysUserImportVo> userListVo = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class); | ||||
|         List<SysUser> userList = BeanUtil.copyToList(userListVo, SysUser.class); | ||||
|         String operName = getUsername(); | ||||
|         String message = userService.importUser(userList, updateSupport, operName); | ||||
|         return AjaxResult.success(message); | ||||
|     } | ||||
|  | ||||
|     @ApiOperation("下载导入模板") | ||||
|     @GetMapping("/importTemplate") | ||||
|     public void importTemplate(HttpServletResponse response) { | ||||
|         ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据用户编号获取详细信息 | ||||
|      */ | ||||
|     @ApiOperation("根据用户编号获取详细信息") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:query')") | ||||
|     @GetMapping(value = {"/", "/{userId}"}) | ||||
|     public AjaxResult<Map<String, Object>> getInfo(@PathVariable(value = "userId", required = false) Long userId) { | ||||
|         userService.checkUserDataScope(userId); | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         List<SysRole> roles = roleService.selectRoleAll(); | ||||
|         ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | ||||
|         ajax.put("posts", postService.selectPostAll()); | ||||
|         if (StringUtils.isNotNull(userId)) { | ||||
|             ajax.put("user", userService.selectUserById(userId)); | ||||
|             ajax.put("postIds", postService.selectPostListByUserId(userId)); | ||||
|             ajax.put("roleIds", roleService.selectRoleListByUserId(userId)); | ||||
|         } | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增用户 | ||||
|      */ | ||||
|     @ApiOperation("新增用户") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:add')") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult<Void> add(@Validated @RequestBody SysUser user) { | ||||
|         if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) { | ||||
|             return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); | ||||
|         } else if (StringUtils.isNotEmpty(user.getPhonenumber()) | ||||
|                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { | ||||
|             return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); | ||||
|         } else if (StringUtils.isNotEmpty(user.getEmail()) | ||||
|                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { | ||||
|             return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); | ||||
|         } | ||||
|         user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); | ||||
|         return toAjax(userService.insertUser(user)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改用户 | ||||
|      */ | ||||
|     @ApiOperation("修改用户") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:edit')") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult<Void> edit(@Validated @RequestBody SysUser user) { | ||||
|         userService.checkUserAllowed(user); | ||||
|         if (StringUtils.isNotEmpty(user.getPhonenumber()) | ||||
|                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { | ||||
|             return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); | ||||
|         } else if (StringUtils.isNotEmpty(user.getEmail()) | ||||
|                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { | ||||
|             return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); | ||||
|         } | ||||
|         return toAjax(userService.updateUser(user)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除用户 | ||||
|      */ | ||||
|     @ApiOperation("删除用户") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:remove')") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{userIds}") | ||||
|     public AjaxResult<Void> remove(@PathVariable Long[] userIds) { | ||||
|         if (ArrayUtil.contains(userIds, getUserId())) { | ||||
|             return error("当前用户不能删除"); | ||||
|         } | ||||
|         return toAjax(userService.deleteUserByIds(userIds)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重置密码 | ||||
|      */ | ||||
|     @ApiOperation("重置密码") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:resetPwd')") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/resetPwd") | ||||
|     public AjaxResult<Void> resetPwd(@RequestBody SysUser user) { | ||||
|         userService.checkUserAllowed(user); | ||||
|         user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); | ||||
|         return toAjax(userService.resetPwd(user)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 状态修改 | ||||
|      */ | ||||
|     @ApiOperation("状态修改") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:edit')") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/changeStatus") | ||||
|     public AjaxResult<Void> changeStatus(@RequestBody SysUser user) { | ||||
|         userService.checkUserAllowed(user); | ||||
|         return toAjax(userService.updateUserStatus(user)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据用户编号获取授权角色 | ||||
|      */ | ||||
|     @ApiOperation("根据用户编号获取授权角色") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:query')") | ||||
|     @GetMapping("/authRole/{userId}") | ||||
|     public AjaxResult<Map<String, Object>> authRole(@PathVariable("userId") Long userId) { | ||||
|         SysUser user = userService.selectUserById(userId); | ||||
|         List<SysRole> roles = roleService.selectRolesByUserId(userId); | ||||
|         Map<String, Object> ajax = new HashMap<>(); | ||||
|         ajax.put("user", user); | ||||
|         ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | ||||
|         return AjaxResult.success(ajax); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 用户授权角色 | ||||
|      */ | ||||
|     @ApiOperation("用户授权角色") | ||||
|     @PreAuthorize("@ss.hasPermi('system:user:edit')") | ||||
|     @Log(title = "用户管理", businessType = BusinessType.GRANT) | ||||
|     @PutMapping("/authRole") | ||||
|     public AjaxResult<Void> insertAuthRole(Long userId, Long[] roleIds) { | ||||
|         userService.insertUserAuth(userId, roleIds); | ||||
|         return success(); | ||||
|     } | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| package org.dromara; | ||||
|  | ||||
| import org.springframework.boot.SpringApplication; | ||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
| import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; | ||||
|  | ||||
| /** | ||||
|  * 启动程序 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
|  | ||||
| @SpringBootApplication | ||||
| public class DromaraApplication { | ||||
|  | ||||
|     public static void main(String[] args) { | ||||
|         SpringApplication application = new SpringApplication(DromaraApplication.class); | ||||
|         application.setApplicationStartup(new BufferingApplicationStartup(2048)); | ||||
|         application.run(args); | ||||
|         System.out.println("(♥◠‿◠)ノ゙  RuoYi-Vue-Plus启动成功   ლ(´ڡ`ლ)゙"); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,239 +0,0 @@ | ||||
| package org.dromara.web.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaIgnore; | ||||
| import cn.dev33.satoken.exception.NotLoginException; | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.hutool.core.codec.Base64; | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import jakarta.servlet.http.HttpServletRequest; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import me.zhyd.oauth.model.AuthResponse; | ||||
| import me.zhyd.oauth.model.AuthUser; | ||||
| import me.zhyd.oauth.request.AuthRequest; | ||||
| import me.zhyd.oauth.utils.AuthStateUtils; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.core.domain.model.LoginBody; | ||||
| import org.dromara.common.core.domain.model.RegisterBody; | ||||
| import org.dromara.common.core.domain.model.SocialLoginBody; | ||||
| import org.dromara.common.core.utils.*; | ||||
| import org.dromara.common.encrypt.annotation.ApiEncrypt; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.social.config.properties.SocialLoginConfigProperties; | ||||
| import org.dromara.common.social.config.properties.SocialProperties; | ||||
| import org.dromara.common.social.utils.SocialUtils; | ||||
| import org.dromara.common.sse.dto.SseMessageDto; | ||||
| import org.dromara.common.sse.utils.SseMessageUtils; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.system.domain.bo.SysTenantBo; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.system.domain.vo.SysTenantVo; | ||||
| import org.dromara.system.service.ISysClientService; | ||||
| import org.dromara.system.service.ISysConfigService; | ||||
| import org.dromara.system.service.ISysSocialService; | ||||
| import org.dromara.system.service.ISysTenantService; | ||||
| import org.dromara.web.domain.vo.LoginTenantVo; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
| import org.dromara.web.domain.vo.TenantListVo; | ||||
| import org.dromara.web.service.IAuthStrategy; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.dromara.web.service.SysRegisterService; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.net.URL; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ScheduledExecutorService; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|  * 认证 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Slf4j | ||||
| @SaIgnore | ||||
| @RequiredArgsConstructor | ||||
| @RestController | ||||
| @RequestMapping("/auth") | ||||
| public class AuthController { | ||||
|  | ||||
|     private final SocialProperties socialProperties; | ||||
|     private final SysLoginService loginService; | ||||
|     private final SysRegisterService registerService; | ||||
|     private final ISysConfigService configService; | ||||
|     private final ISysTenantService tenantService; | ||||
|     private final ISysSocialService socialUserService; | ||||
|     private final ISysClientService clientService; | ||||
|     private final ScheduledExecutorService scheduledExecutorService; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 登录方法 | ||||
|      * | ||||
|      * @param body 登录信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @ApiEncrypt | ||||
|     @PostMapping("/login") | ||||
|     public R<LoginVo> login(@RequestBody String body) { | ||||
|         LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class); | ||||
|         ValidatorUtils.validate(loginBody); | ||||
|         // 授权类型和客户端id | ||||
|         String clientId = loginBody.getClientId(); | ||||
|         String grantType = loginBody.getGrantType(); | ||||
|         SysClientVo client = clientService.queryByClientId(clientId); | ||||
|         // 查询不到 client 或 client 内不包含 grantType | ||||
|         if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { | ||||
|             log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); | ||||
|             return R.fail(MessageUtils.message("auth.grant.type.error")); | ||||
|         } else if (!SystemConstants.NORMAL.equals(client.getStatus())) { | ||||
|             return R.fail(MessageUtils.message("auth.grant.type.blocked")); | ||||
|         } | ||||
|         // 校验租户 | ||||
|         loginService.checkTenant(loginBody.getTenantId()); | ||||
|         // 登录 | ||||
|         LoginVo loginVo = IAuthStrategy.login(body, client, grantType); | ||||
|  | ||||
|         Long userId = LoginHelper.getUserId(); | ||||
|         scheduledExecutorService.schedule(() -> { | ||||
|             SseMessageDto dto = new SseMessageDto(); | ||||
|             dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统"); | ||||
|             dto.setUserIds(List.of(userId)); | ||||
|             SseMessageUtils.publishMessage(dto); | ||||
|         }, 5, TimeUnit.SECONDS); | ||||
|         return R.ok(loginVo); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取跳转URL | ||||
|      * | ||||
|      * @param source 登录来源 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @GetMapping("/binding/{source}") | ||||
|     public R<String> authBinding(@PathVariable("source") String source, | ||||
|                                  @RequestParam String tenantId, @RequestParam String domain) { | ||||
|         SocialLoginConfigProperties obj = socialProperties.getType().get(source); | ||||
|         if (ObjectUtil.isNull(obj)) { | ||||
|             return R.fail(source + "平台账号暂不支持"); | ||||
|         } | ||||
|         AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties); | ||||
|         Map<String, String> map = new HashMap<>(); | ||||
|         map.put("tenantId", tenantId); | ||||
|         map.put("domain", domain); | ||||
|         map.put("state", AuthStateUtils.createState()); | ||||
|         String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8)); | ||||
|         return R.ok("操作成功", authorizeUrl); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 前端回调绑定授权(需要token) | ||||
|      * | ||||
|      * @param loginBody 请求体 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @PostMapping("/social/callback") | ||||
|     public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) { | ||||
|         // 校验token | ||||
|         StpUtil.checkLogin(); | ||||
|         // 获取第三方登录信息 | ||||
|         AuthResponse<AuthUser> response = SocialUtils.loginAuth( | ||||
|                 loginBody.getSource(), loginBody.getSocialCode(), | ||||
|                 loginBody.getSocialState(), socialProperties); | ||||
|         AuthUser authUserData = response.getData(); | ||||
|         // 判断授权响应是否成功 | ||||
|         if (!response.ok()) { | ||||
|             return R.fail(response.getMsg()); | ||||
|         } | ||||
|         loginService.socialRegister(authUserData); | ||||
|         return R.ok(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 取消授权(需要token) | ||||
|      * | ||||
|      * @param socialId socialId | ||||
|      */ | ||||
|     @DeleteMapping(value = "/unlock/{socialId}") | ||||
|     public R<Void> unlockSocial(@PathVariable Long socialId) { | ||||
|         // 校验token | ||||
|         StpUtil.checkLogin(); | ||||
|         Boolean rows = socialUserService.deleteWithValidById(socialId); | ||||
|         return rows ? R.ok() : R.fail("取消授权失败"); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 退出登录 | ||||
|      */ | ||||
|     @PostMapping("/logout") | ||||
|     public R<Void> logout() { | ||||
|         loginService.logout(); | ||||
|         return R.ok("退出成功"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 用户注册 | ||||
|      */ | ||||
|     @ApiEncrypt | ||||
|     @PostMapping("/register") | ||||
|     public R<Void> register(@Validated @RequestBody RegisterBody user) { | ||||
|         if (!configService.selectRegisterEnabled(user.getTenantId())) { | ||||
|             return R.fail("当前系统没有开启注册功能!"); | ||||
|         } | ||||
|         registerService.register(user); | ||||
|         return R.ok(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 登录页面租户下拉框 | ||||
|      * | ||||
|      * @return 租户列表 | ||||
|      */ | ||||
|     @GetMapping("/tenant/list") | ||||
|     public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception { | ||||
|         // 返回对象 | ||||
|         LoginTenantVo result = new LoginTenantVo(); | ||||
|         boolean enable = TenantHelper.isEnable(); | ||||
|         result.setTenantEnabled(enable); | ||||
|         // 如果未开启租户这直接返回 | ||||
|         if (!enable) { | ||||
|             return R.ok(result); | ||||
|         } | ||||
|  | ||||
|         List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo()); | ||||
|         List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class); | ||||
|         try { | ||||
|             // 如果只超管返回所有租户 | ||||
|             if (LoginHelper.isSuperAdmin()) { | ||||
|                 result.setVoList(voList); | ||||
|                 return R.ok(result); | ||||
|             } | ||||
|         } catch (NotLoginException ignored) { | ||||
|         } | ||||
|  | ||||
|         // 获取域名 | ||||
|         String host; | ||||
|         String referer = request.getHeader("referer"); | ||||
|         if (StringUtils.isNotBlank(referer)) { | ||||
|             // 这里从referer中取值是为了本地使用hosts添加虚拟域名,方便本地环境调试 | ||||
|             host = referer.split("//")[1].split("/")[0]; | ||||
|         } else { | ||||
|             host = new URL(request.getRequestURL().toString()).getHost(); | ||||
|         } | ||||
|         // 根据域名进行筛选 | ||||
|         List<TenantListVo> list = StreamUtils.filter(voList, vo -> | ||||
|             StringUtils.equalsIgnoreCase(vo.getDomain(), host)); | ||||
|         result.setVoList(CollUtil.isNotEmpty(list) ? list : voList); | ||||
|         return R.ok(result); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,154 +0,0 @@ | ||||
| package org.dromara.web.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaIgnore; | ||||
| import cn.hutool.captcha.AbstractCaptcha; | ||||
| import cn.hutool.captcha.generator.CodeGenerator; | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| import cn.hutool.core.util.RandomUtil; | ||||
| import jakarta.validation.constraints.NotBlank; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.constant.GlobalConstants; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.core.utils.reflect.ReflectUtils; | ||||
| import org.dromara.common.mail.config.properties.MailProperties; | ||||
| import org.dromara.common.mail.utils.MailUtils; | ||||
| import org.dromara.common.ratelimiter.annotation.RateLimiter; | ||||
| import org.dromara.common.ratelimiter.enums.LimitType; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.web.config.properties.CaptchaProperties; | ||||
| import org.dromara.common.web.enums.CaptchaType; | ||||
| import org.dromara.sms4j.api.SmsBlend; | ||||
| import org.dromara.sms4j.api.entity.SmsResponse; | ||||
| import org.dromara.sms4j.core.factory.SmsFactory; | ||||
| import org.dromara.web.domain.vo.CaptchaVo; | ||||
| import org.springframework.expression.Expression; | ||||
| import org.springframework.expression.ExpressionParser; | ||||
| import org.springframework.expression.spel.standard.SpelExpressionParser; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import java.time.Duration; | ||||
| import java.util.LinkedHashMap; | ||||
|  | ||||
| /** | ||||
|  * 验证码操作处理 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @SaIgnore | ||||
| @Slf4j | ||||
| @Validated | ||||
| @RequiredArgsConstructor | ||||
| @RestController | ||||
| public class CaptchaController { | ||||
|  | ||||
|     private final CaptchaProperties captchaProperties; | ||||
|     private final MailProperties mailProperties; | ||||
|  | ||||
|     /** | ||||
|      * 短信验证码 | ||||
|      * | ||||
|      * @param phonenumber 用户手机号 | ||||
|      */ | ||||
|     @RateLimiter(key = "#phonenumber", time = 60, count = 1) | ||||
|     @GetMapping("/resource/sms/code") | ||||
|     public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { | ||||
|         String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; | ||||
|         String code = RandomUtil.randomNumbers(4); | ||||
|         RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); | ||||
|         // 验证码模板id 自行处理 (查数据库或写死均可) | ||||
|         String templateId = ""; | ||||
|         LinkedHashMap<String, String> map = new LinkedHashMap<>(1); | ||||
|         map.put("code", code); | ||||
|         SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); | ||||
|         SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map); | ||||
|         if (!smsResponse.isSuccess()) { | ||||
|             log.error("验证码短信发送异常 => {}", smsResponse); | ||||
|             return R.fail(smsResponse.getData().toString()); | ||||
|         } | ||||
|         return R.ok(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 邮箱验证码 | ||||
|      * | ||||
|      * @param email 邮箱 | ||||
|      */ | ||||
|     @GetMapping("/resource/email/code") | ||||
|     public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { | ||||
|         if (!mailProperties.getEnabled()) { | ||||
|             return R.fail("当前系统没有开启邮箱功能!"); | ||||
|         } | ||||
|         SpringUtils.getAopProxy(this).emailCodeImpl(email); | ||||
|         return R.ok(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 邮箱验证码 | ||||
|      * 独立方法避免验证码关闭之后仍然走限流 | ||||
|      */ | ||||
|     @RateLimiter(key = "#email", time = 60, count = 1) | ||||
|     public void emailCodeImpl(String email) { | ||||
|         String key = GlobalConstants.CAPTCHA_CODE_KEY + email; | ||||
|         String code = RandomUtil.randomNumbers(4); | ||||
|         RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); | ||||
|         try { | ||||
|             MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); | ||||
|         } catch (Exception e) { | ||||
|             log.error("验证码短信发送异常 => {}", e.getMessage()); | ||||
|             throw new ServiceException(e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 生成验证码 | ||||
|      */ | ||||
|     @GetMapping("/auth/code") | ||||
|     public R<CaptchaVo> getCode() { | ||||
|         boolean captchaEnabled = captchaProperties.getEnable(); | ||||
|         if (!captchaEnabled) { | ||||
|             CaptchaVo captchaVo = new CaptchaVo(); | ||||
|             captchaVo.setCaptchaEnabled(false); | ||||
|             return R.ok(captchaVo); | ||||
|         } | ||||
|         return R.ok(SpringUtils.getAopProxy(this).getCodeImpl()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 生成验证码 | ||||
|      * 独立方法避免验证码关闭之后仍然走限流 | ||||
|      */ | ||||
|     @RateLimiter(time = 60, count = 10, limitType = LimitType.IP) | ||||
|     public CaptchaVo getCodeImpl() { | ||||
|         // 保存验证码信息 | ||||
|         String uuid = IdUtil.simpleUUID(); | ||||
|         String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; | ||||
|         // 生成验证码 | ||||
|         CaptchaType captchaType = captchaProperties.getType(); | ||||
|         boolean isMath = CaptchaType.MATH == captchaType; | ||||
|         Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); | ||||
|         CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); | ||||
|         AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); | ||||
|         captcha.setGenerator(codeGenerator); | ||||
|         captcha.createCode(); | ||||
|         // 如果是数学验证码,使用SpEL表达式处理验证码结果 | ||||
|         String code = captcha.getCode(); | ||||
|         if (isMath) { | ||||
|             ExpressionParser parser = new SpelExpressionParser(); | ||||
|             Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); | ||||
|             code = exp.getValue(String.class); | ||||
|         } | ||||
|         RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); | ||||
|         CaptchaVo captchaVo = new CaptchaVo(); | ||||
|         captchaVo.setUuid(uuid); | ||||
|         captchaVo.setImg(captcha.getImageBase64()); | ||||
|         return captchaVo; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,28 +0,0 @@ | ||||
| package org.dromara.web.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaIgnore; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| /** | ||||
|  * 首页 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @SaIgnore | ||||
| @RequiredArgsConstructor | ||||
| @RestController | ||||
| public class IndexController { | ||||
|  | ||||
|     /** | ||||
|      * 访问首页,提示语 | ||||
|      */ | ||||
|     @GetMapping("/") | ||||
|     public String index() { | ||||
|         return StringUtils.format("欢迎使用{}后台管理框架,请通过前端地址访问。", SpringUtils.getApplicationName()); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| package org.dromara.web.domain.vo; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| /** | ||||
|  * 验证码信息 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Data | ||||
| public class CaptchaVo { | ||||
|  | ||||
|     /** | ||||
|      * 是否开启验证码 | ||||
|      */ | ||||
|     private Boolean captchaEnabled = true; | ||||
|  | ||||
|     private String uuid; | ||||
|  | ||||
|     /** | ||||
|      * 验证码图片 | ||||
|      */ | ||||
|     private String img; | ||||
|  | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| package org.dromara.web.domain.vo; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 登录租户对象 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Data | ||||
| public class LoginTenantVo { | ||||
|  | ||||
|     /** | ||||
|      * 租户开关 | ||||
|      */ | ||||
|     private Boolean tenantEnabled; | ||||
|  | ||||
|     /** | ||||
|      * 租户对象列表 | ||||
|      */ | ||||
|     private List<TenantListVo> voList; | ||||
|  | ||||
| } | ||||
| @@ -1,54 +0,0 @@ | ||||
| package org.dromara.web.domain.vo; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||||
| import lombok.Data; | ||||
|  | ||||
| /** | ||||
|  * 登录验证信息 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Data | ||||
| public class LoginVo { | ||||
|  | ||||
|     /** | ||||
|      * 授权令牌 | ||||
|      */ | ||||
|     @JsonProperty("access_token") | ||||
|     private String accessToken; | ||||
|  | ||||
|     /** | ||||
|      * 刷新令牌 | ||||
|      */ | ||||
|     @JsonProperty("refresh_token") | ||||
|     private String refreshToken; | ||||
|  | ||||
|     /** | ||||
|      * 授权令牌 access_token 的有效期 | ||||
|      */ | ||||
|     @JsonProperty("expire_in") | ||||
|     private Long expireIn; | ||||
|  | ||||
|     /** | ||||
|      * 刷新令牌 refresh_token 的有效期 | ||||
|      */ | ||||
|     @JsonProperty("refresh_expire_in") | ||||
|     private Long refreshExpireIn; | ||||
|  | ||||
|     /** | ||||
|      * 应用id | ||||
|      */ | ||||
|     @JsonProperty("client_id") | ||||
|     private String clientId; | ||||
|  | ||||
|     /** | ||||
|      * 令牌权限 | ||||
|      */ | ||||
|     private String scope; | ||||
|  | ||||
|     /** | ||||
|      * 用户 openid | ||||
|      */ | ||||
|     private String openid; | ||||
|  | ||||
| } | ||||
| @@ -1,31 +0,0 @@ | ||||
| package org.dromara.web.domain.vo; | ||||
|  | ||||
| import org.dromara.system.domain.vo.SysTenantVo; | ||||
| import io.github.linpeilie.annotations.AutoMapper; | ||||
| import lombok.Data; | ||||
|  | ||||
| /** | ||||
|  * 租户列表 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Data | ||||
| @AutoMapper(target = SysTenantVo.class) | ||||
| public class TenantListVo { | ||||
|  | ||||
|     /** | ||||
|      * 租户编号 | ||||
|      */ | ||||
|     private String tenantId; | ||||
|  | ||||
|     /** | ||||
|      * 企业名称 | ||||
|      */ | ||||
|     private String companyName; | ||||
|  | ||||
|     /** | ||||
|      * 域名 | ||||
|      */ | ||||
|     private String domain; | ||||
|  | ||||
| } | ||||
| @@ -1,163 +0,0 @@ | ||||
| package org.dromara.web.listener; | ||||
|  | ||||
| import cn.dev33.satoken.listener.SaTokenListener; | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.dev33.satoken.stp.parameter.SaLoginParameter; | ||||
| import cn.hutool.core.convert.Convert; | ||||
| import cn.hutool.http.useragent.UserAgent; | ||||
| import cn.hutool.http.useragent.UserAgentUtil; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.common.core.constant.CacheConstants; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.domain.dto.UserOnlineDTO; | ||||
| import org.dromara.common.core.utils.MessageUtils; | ||||
| import org.dromara.common.core.utils.ServletUtils; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.common.core.utils.ip.AddressUtils; | ||||
| import org.dromara.common.log.event.LogininforEvent; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import java.time.Duration; | ||||
|  | ||||
| /** | ||||
|  * 用户行为 侦听器的实现 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| @Component | ||||
| @Slf4j | ||||
| public class UserActionListener implements SaTokenListener { | ||||
|  | ||||
|     private final SysLoginService loginService; | ||||
|  | ||||
|     /** | ||||
|      * 每次登录时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) { | ||||
|         UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); | ||||
|         String ip = ServletUtils.getClientIP(); | ||||
|         UserOnlineDTO dto = new UserOnlineDTO(); | ||||
|         dto.setIpaddr(ip); | ||||
|         dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); | ||||
|         dto.setBrowser(userAgent.getBrowser().getName()); | ||||
|         dto.setOs(userAgent.getOs().getName()); | ||||
|         dto.setLoginTime(System.currentTimeMillis()); | ||||
|         dto.setTokenId(tokenValue); | ||||
|         String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY); | ||||
|         String tenantId = (String) loginParameter.getExtra(LoginHelper.TENANT_KEY); | ||||
|         dto.setUserName(username); | ||||
|         dto.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY)); | ||||
|         dto.setDeviceType(loginParameter.getDeviceType()); | ||||
|         dto.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY)); | ||||
|         TenantHelper.dynamic(tenantId, () -> { | ||||
|             if(loginParameter.getTimeout() == -1) { | ||||
|                 RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); | ||||
|             } else { | ||||
|                 RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(loginParameter.getTimeout())); | ||||
|             } | ||||
|         }); | ||||
|         // 记录登录日志 | ||||
|         LogininforEvent logininforEvent = new LogininforEvent(); | ||||
|         logininforEvent.setTenantId(tenantId); | ||||
|         logininforEvent.setUsername(username); | ||||
|         logininforEvent.setStatus(Constants.LOGIN_SUCCESS); | ||||
|         logininforEvent.setMessage(MessageUtils.message("user.login.success")); | ||||
|         logininforEvent.setRequest(ServletUtils.getRequest()); | ||||
|         SpringUtils.context().publishEvent(logininforEvent); | ||||
|         // 更新登录信息 | ||||
|         loginService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip); | ||||
|         log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次注销时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doLogout(String loginType, Object loginId, String tokenValue) { | ||||
|         String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); | ||||
|         TenantHelper.dynamic(tenantId, () -> { | ||||
|             RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); | ||||
|         }); | ||||
|         log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次被踢下线时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doKickout(String loginType, Object loginId, String tokenValue) { | ||||
|         String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); | ||||
|         TenantHelper.dynamic(tenantId, () -> { | ||||
|             RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); | ||||
|         }); | ||||
|         log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次被顶下线时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doReplaced(String loginType, Object loginId, String tokenValue) { | ||||
|         String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); | ||||
|         TenantHelper.dynamic(tenantId, () -> { | ||||
|             RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); | ||||
|         }); | ||||
|         log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次被封禁时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次被解封时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doUntieDisable(String loginType, Object loginId, String service) { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次打开二级认证时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次创建Session时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doCloseSafe(String loginType, String tokenValue, String service) { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次创建Session时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doCreateSession(String id) { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次注销Session时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doLogoutSession(String id) { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 每次Token续期时触发 | ||||
|      */ | ||||
|     @Override | ||||
|     public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { | ||||
|     } | ||||
| } | ||||
| @@ -1,46 +0,0 @@ | ||||
| package org.dromara.web.service; | ||||
|  | ||||
|  | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.system.domain.SysClient; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
|  | ||||
| /** | ||||
|  * 授权策略 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| public interface IAuthStrategy { | ||||
|  | ||||
|     String BASE_NAME = "AuthStrategy"; | ||||
|  | ||||
|     /** | ||||
|      * 登录 | ||||
|      * | ||||
|      * @param body      登录对象 | ||||
|      * @param client    授权管理视图对象 | ||||
|      * @param grantType 授权类型 | ||||
|      * @return 登录验证信息 | ||||
|      */ | ||||
|     static LoginVo login(String body, SysClientVo client, String grantType) { | ||||
|         // 授权类型和客户端id | ||||
|         String beanName = grantType + BASE_NAME; | ||||
|         if (!SpringUtils.containsBean(beanName)) { | ||||
|             throw new ServiceException("授权类型不正确!"); | ||||
|         } | ||||
|         IAuthStrategy instance = SpringUtils.getBean(beanName); | ||||
|         return instance.login(body, client); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 登录 | ||||
|      * | ||||
|      * @param body   登录对象 | ||||
|      * @param client 授权管理视图对象 | ||||
|      * @return 登录验证信息 | ||||
|      */ | ||||
|     LoginVo login(String body, SysClientVo client); | ||||
|  | ||||
| } | ||||
| @@ -1,251 +0,0 @@ | ||||
| package org.dromara.web.service; | ||||
|  | ||||
| import cn.dev33.satoken.exception.NotLoginException; | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.lang.Opt; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import com.baomidou.lock.annotation.Lock4j; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import me.zhyd.oauth.model.AuthUser; | ||||
| import org.dromara.common.core.constant.CacheConstants; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.constant.TenantConstants; | ||||
| import org.dromara.common.core.domain.dto.PostDTO; | ||||
| import org.dromara.common.core.domain.dto.RoleDTO; | ||||
| import org.dromara.common.core.domain.model.LoginUser; | ||||
| import org.dromara.common.core.enums.LoginType; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.exception.user.UserException; | ||||
| import org.dromara.common.core.utils.*; | ||||
| import org.dromara.common.log.event.LogininforEvent; | ||||
| import org.dromara.common.mybatis.helper.DataPermissionHelper; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.tenant.exception.TenantException; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.system.domain.SysUser; | ||||
| import org.dromara.system.domain.bo.SysSocialBo; | ||||
| import org.dromara.system.domain.vo.*; | ||||
| import org.dromara.system.mapper.SysUserMapper; | ||||
| import org.dromara.system.service.*; | ||||
| import org.springframework.beans.factory.annotation.Value; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.time.Duration; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.function.Supplier; | ||||
|  | ||||
| /** | ||||
|  * 登录校验方法 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| @Slf4j | ||||
| @Service | ||||
| public class SysLoginService { | ||||
|  | ||||
|     @Value("${user.password.maxRetryCount}") | ||||
|     private Integer maxRetryCount; | ||||
|  | ||||
|     @Value("${user.password.lockTime}") | ||||
|     private Integer lockTime; | ||||
|  | ||||
|     private final ISysTenantService tenantService; | ||||
|     private final ISysPermissionService permissionService; | ||||
|     private final ISysSocialService sysSocialService; | ||||
|     private final ISysRoleService roleService; | ||||
|     private final ISysDeptService deptService; | ||||
|     private final ISysPostService postService; | ||||
|     private final SysUserMapper userMapper; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 绑定第三方用户 | ||||
|      * | ||||
|      * @param authUserData 授权响应实体 | ||||
|      */ | ||||
|     @Lock4j | ||||
|     public void socialRegister(AuthUser authUserData) { | ||||
|         String authId = authUserData.getSource() + authUserData.getUuid(); | ||||
|         // 第三方用户信息 | ||||
|         SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); | ||||
|         BeanUtil.copyProperties(authUserData.getToken(), bo); | ||||
|         Long userId = LoginHelper.getUserId(); | ||||
|         bo.setUserId(userId); | ||||
|         bo.setAuthId(authId); | ||||
|         bo.setOpenId(authUserData.getUuid()); | ||||
|         bo.setUserName(authUserData.getUsername()); | ||||
|         bo.setNickName(authUserData.getNickname()); | ||||
|         List<SysSocialVo> checkList = sysSocialService.selectByAuthId(authId); | ||||
|         if (CollUtil.isNotEmpty(checkList)) { | ||||
|             throw new ServiceException("此三方账号已经被绑定!"); | ||||
|         } | ||||
|         // 查询是否已经绑定用户 | ||||
|         SysSocialBo params = new SysSocialBo(); | ||||
|         params.setUserId(userId); | ||||
|         params.setSource(bo.getSource()); | ||||
|         List<SysSocialVo> list = sysSocialService.queryList(params); | ||||
|         if (CollUtil.isEmpty(list)) { | ||||
|             // 没有绑定用户, 新增用户信息 | ||||
|             sysSocialService.insertByBo(bo); | ||||
|         } else { | ||||
|             // 更新用户信息 | ||||
|             bo.setId(list.get(0).getId()); | ||||
|             sysSocialService.updateByBo(bo); | ||||
|             // 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断 | ||||
|             // throw new ServiceException("此平台账号已经被绑定!"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 退出登录 | ||||
|      */ | ||||
|     public void logout() { | ||||
|         try { | ||||
|             LoginUser loginUser = LoginHelper.getLoginUser(); | ||||
|             if (ObjectUtil.isNull(loginUser)) { | ||||
|                 return; | ||||
|             } | ||||
|             if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { | ||||
|                 // 超级管理员 登出清除动态租户 | ||||
|                 TenantHelper.clearDynamic(); | ||||
|             } | ||||
|             recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); | ||||
|         } catch (NotLoginException ignored) { | ||||
|         } finally { | ||||
|             try { | ||||
|                 StpUtil.logout(); | ||||
|             } catch (NotLoginException ignored) { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 记录登录信息 | ||||
|      * | ||||
|      * @param tenantId 租户ID | ||||
|      * @param username 用户名 | ||||
|      * @param status   状态 | ||||
|      * @param message  消息内容 | ||||
|      */ | ||||
|     public void recordLogininfor(String tenantId, String username, String status, String message) { | ||||
|         LogininforEvent logininforEvent = new LogininforEvent(); | ||||
|         logininforEvent.setTenantId(tenantId); | ||||
|         logininforEvent.setUsername(username); | ||||
|         logininforEvent.setStatus(status); | ||||
|         logininforEvent.setMessage(message); | ||||
|         logininforEvent.setRequest(ServletUtils.getRequest()); | ||||
|         SpringUtils.context().publishEvent(logininforEvent); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建登录用户 | ||||
|      */ | ||||
|     public LoginUser buildLoginUser(SysUserVo user) { | ||||
|         LoginUser loginUser = new LoginUser(); | ||||
|         Long userId = user.getUserId(); | ||||
|         loginUser.setTenantId(user.getTenantId()); | ||||
|         loginUser.setUserId(userId); | ||||
|         loginUser.setDeptId(user.getDeptId()); | ||||
|         loginUser.setUsername(user.getUserName()); | ||||
|         loginUser.setNickname(user.getNickName()); | ||||
|         loginUser.setUserType(user.getUserType()); | ||||
|         loginUser.setMenuPermission(permissionService.getMenuPermission(userId)); | ||||
|         loginUser.setRolePermission(permissionService.getRolePermission(userId)); | ||||
|         if (ObjectUtil.isNotNull(user.getDeptId())) { | ||||
|             Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById); | ||||
|             loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); | ||||
|             loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); | ||||
|         } | ||||
|         List<SysRoleVo> roles = roleService.selectRolesByUserId(userId); | ||||
|         List<SysPostVo> posts = postService.selectPostsByUserId(userId); | ||||
|         loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); | ||||
|         loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class)); | ||||
|         return loginUser; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 记录登录信息 | ||||
|      * | ||||
|      * @param userId 用户ID | ||||
|      */ | ||||
|     public void recordLoginInfo(Long userId, String ip) { | ||||
|         SysUser sysUser = new SysUser(); | ||||
|         sysUser.setUserId(userId); | ||||
|         sysUser.setLoginIp(ip); | ||||
|         sysUser.setLoginDate(DateUtils.getNowDate()); | ||||
|         sysUser.setUpdateBy(userId); | ||||
|         DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 登录校验 | ||||
|      */ | ||||
|     public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { | ||||
|         String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; | ||||
|         String loginFail = Constants.LOGIN_FAIL; | ||||
|  | ||||
|         // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) | ||||
|         int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); | ||||
|         // 锁定时间内登录 则踢出 | ||||
|         if (errorNumber >= maxRetryCount) { | ||||
|             recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); | ||||
|             throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); | ||||
|         } | ||||
|  | ||||
|         if (supplier.get()) { | ||||
|             // 错误次数递增 | ||||
|             errorNumber++; | ||||
|             RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); | ||||
|             // 达到规定错误次数 则锁定登录 | ||||
|             if (errorNumber >= maxRetryCount) { | ||||
|                 recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); | ||||
|                 throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); | ||||
|             } else { | ||||
|                 // 未达到规定错误次数 | ||||
|                 recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); | ||||
|                 throw new UserException(loginType.getRetryLimitCount(), errorNumber); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 登录成功 清空错误次数 | ||||
|         RedisUtils.deleteObject(errorKey); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验租户 | ||||
|      * | ||||
|      * @param tenantId 租户ID | ||||
|      */ | ||||
|     public void checkTenant(String tenantId) { | ||||
|         if (!TenantHelper.isEnable()) { | ||||
|             return; | ||||
|         } | ||||
|         if (StringUtils.isBlank(tenantId)) { | ||||
|             throw new TenantException("tenant.number.not.blank"); | ||||
|         } | ||||
|         if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { | ||||
|             return; | ||||
|         } | ||||
|         SysTenantVo tenant = tenantService.queryByTenantId(tenantId); | ||||
|         if (ObjectUtil.isNull(tenant)) { | ||||
|             log.info("登录租户:{} 不存在.", tenantId); | ||||
|             throw new TenantException("tenant.not.exists"); | ||||
|         } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) { | ||||
|             log.info("登录租户:{} 已被停用.", tenantId); | ||||
|             throw new TenantException("tenant.blocked"); | ||||
|         } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) | ||||
|             && new Date().after(tenant.getExpireTime())) { | ||||
|             log.info("登录租户:{} 已超过有效期.", tenantId); | ||||
|             throw new TenantException("tenant.expired"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,115 +0,0 @@ | ||||
| package org.dromara.web.service; | ||||
|  | ||||
| import cn.hutool.crypto.digest.BCrypt; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.constant.GlobalConstants; | ||||
| import org.dromara.common.core.domain.model.RegisterBody; | ||||
| import org.dromara.common.core.enums.UserType; | ||||
| import org.dromara.common.core.exception.user.CaptchaException; | ||||
| import org.dromara.common.core.exception.user.CaptchaExpireException; | ||||
| import org.dromara.common.core.exception.user.UserException; | ||||
| import org.dromara.common.core.utils.MessageUtils; | ||||
| import org.dromara.common.core.utils.ServletUtils; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.log.event.LogininforEvent; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.common.web.config.properties.CaptchaProperties; | ||||
| import org.dromara.system.domain.SysUser; | ||||
| import org.dromara.system.domain.bo.SysUserBo; | ||||
| import org.dromara.system.mapper.SysUserMapper; | ||||
| import org.dromara.system.service.ISysUserService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| /** | ||||
|  * 注册校验方法 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| @Service | ||||
| public class SysRegisterService { | ||||
|  | ||||
|     private final ISysUserService userService; | ||||
|     private final SysUserMapper userMapper; | ||||
|     private final CaptchaProperties captchaProperties; | ||||
|  | ||||
|     /** | ||||
|      * 注册 | ||||
|      */ | ||||
|     public void register(RegisterBody registerBody) { | ||||
|         String tenantId = registerBody.getTenantId(); | ||||
|         String username = registerBody.getUsername(); | ||||
|         String password = registerBody.getPassword(); | ||||
|         // 校验用户类型是否存在 | ||||
|         String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); | ||||
|  | ||||
|         boolean captchaEnabled = captchaProperties.getEnable(); | ||||
|         // 验证码开关 | ||||
|         if (captchaEnabled) { | ||||
|             validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); | ||||
|         } | ||||
|         SysUserBo sysUser = new SysUserBo(); | ||||
|         sysUser.setUserName(username); | ||||
|         sysUser.setNickName(username); | ||||
|         sysUser.setPassword(BCrypt.hashpw(password)); | ||||
|         sysUser.setUserType(userType); | ||||
|  | ||||
|         boolean exist = TenantHelper.dynamic(tenantId, () -> { | ||||
|             return userMapper.exists(new LambdaQueryWrapper<SysUser>() | ||||
|                 .eq(SysUser::getUserName, sysUser.getUserName())); | ||||
|         }); | ||||
|         if (exist) { | ||||
|             throw new UserException("user.register.save.error", username); | ||||
|         } | ||||
|         boolean regFlag = userService.registerUser(sysUser, tenantId); | ||||
|         if (!regFlag) { | ||||
|             throw new UserException("user.register.error"); | ||||
|         } | ||||
|         recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验验证码 | ||||
|      * | ||||
|      * @param username 用户名 | ||||
|      * @param code     验证码 | ||||
|      * @param uuid     唯一标识 | ||||
|      */ | ||||
|     public void validateCaptcha(String tenantId, String username, String code, String uuid) { | ||||
|         String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); | ||||
|         String captcha = RedisUtils.getCacheObject(verifyKey); | ||||
|         RedisUtils.deleteObject(verifyKey); | ||||
|         if (captcha == null) { | ||||
|             recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); | ||||
|             throw new CaptchaExpireException(); | ||||
|         } | ||||
|         if (!code.equalsIgnoreCase(captcha)) { | ||||
|             recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); | ||||
|             throw new CaptchaException(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 记录登录信息 | ||||
|      * | ||||
|      * @param tenantId 租户ID | ||||
|      * @param username 用户名 | ||||
|      * @param status   状态 | ||||
|      * @param message  消息内容 | ||||
|      * @return | ||||
|      */ | ||||
|     private void recordLogininfor(String tenantId, String username, String status, String message) { | ||||
|         LogininforEvent logininforEvent = new LogininforEvent(); | ||||
|         logininforEvent.setTenantId(tenantId); | ||||
|         logininforEvent.setUsername(username); | ||||
|         logininforEvent.setStatus(status); | ||||
|         logininforEvent.setMessage(message); | ||||
|         logininforEvent.setRequest(ServletUtils.getRequest()); | ||||
|         SpringUtils.context().publishEvent(logininforEvent); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,102 +0,0 @@ | ||||
| package org.dromara.web.service.impl; | ||||
|  | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.dev33.satoken.stp.parameter.SaLoginParameter; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.constant.GlobalConstants; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.domain.model.EmailLoginBody; | ||||
| import org.dromara.common.core.domain.model.LoginUser; | ||||
| import org.dromara.common.core.enums.LoginType; | ||||
| import org.dromara.common.core.exception.user.CaptchaExpireException; | ||||
| import org.dromara.common.core.exception.user.UserException; | ||||
| import org.dromara.common.core.utils.MessageUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.core.utils.ValidatorUtils; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.system.domain.SysUser; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.mapper.SysUserMapper; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
| import org.dromara.web.service.IAuthStrategy; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| /** | ||||
|  * 邮件认证策略 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Slf4j | ||||
| @Service("email" + IAuthStrategy.BASE_NAME) | ||||
| @RequiredArgsConstructor | ||||
| public class EmailAuthStrategy implements IAuthStrategy { | ||||
|  | ||||
|     private final SysLoginService loginService; | ||||
|     private final SysUserMapper userMapper; | ||||
|  | ||||
|     @Override | ||||
|     public LoginVo login(String body, SysClientVo client) { | ||||
|         EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); | ||||
|         ValidatorUtils.validate(loginBody); | ||||
|         String tenantId = loginBody.getTenantId(); | ||||
|         String email = loginBody.getEmail(); | ||||
|         String emailCode = loginBody.getEmailCode(); | ||||
|         LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { | ||||
|             SysUserVo user = loadUserByEmail(email); | ||||
|             loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); | ||||
|             // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 | ||||
|             return loginService.buildLoginUser(user); | ||||
|         }); | ||||
|         loginUser.setClientKey(client.getClientKey()); | ||||
|         loginUser.setDeviceType(client.getDeviceType()); | ||||
|         SaLoginParameter model = new SaLoginParameter(); | ||||
|         model.setDeviceType(client.getDeviceType()); | ||||
|         // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 | ||||
|         // 例如: 后台用户30分钟过期 app用户1天过期 | ||||
|         model.setTimeout(client.getTimeout()); | ||||
|         model.setActiveTimeout(client.getActiveTimeout()); | ||||
|         model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); | ||||
|         // 生成token | ||||
|         LoginHelper.login(loginUser, model); | ||||
|  | ||||
|         LoginVo loginVo = new LoginVo(); | ||||
|         loginVo.setAccessToken(StpUtil.getTokenValue()); | ||||
|         loginVo.setExpireIn(StpUtil.getTokenTimeout()); | ||||
|         loginVo.setClientId(client.getClientId()); | ||||
|         return loginVo; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验邮箱验证码 | ||||
|      */ | ||||
|     private boolean validateEmailCode(String tenantId, String email, String emailCode) { | ||||
|         String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); | ||||
|         if (StringUtils.isBlank(code)) { | ||||
|             loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); | ||||
|             throw new CaptchaExpireException(); | ||||
|         } | ||||
|         return code.equals(emailCode); | ||||
|     } | ||||
|  | ||||
|     private SysUserVo loadUserByEmail(String email) { | ||||
|         SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email)); | ||||
|         if (ObjectUtil.isNull(user)) { | ||||
|             log.info("登录用户:{} 不存在.", email); | ||||
|             throw new UserException("user.not.exists", email); | ||||
|         } else if (SystemConstants.DISABLE.equals(user.getStatus())) { | ||||
|             log.info("登录用户:{} 已被停用.", email); | ||||
|             throw new UserException("user.blocked", email); | ||||
|         } | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,123 +0,0 @@ | ||||
| package org.dromara.web.service.impl; | ||||
|  | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.dev33.satoken.stp.parameter.SaLoginParameter; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import cn.hutool.crypto.digest.BCrypt; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.constant.GlobalConstants; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.domain.model.LoginUser; | ||||
| import org.dromara.common.core.domain.model.PasswordLoginBody; | ||||
| import org.dromara.common.core.enums.LoginType; | ||||
| import org.dromara.common.core.exception.user.CaptchaException; | ||||
| import org.dromara.common.core.exception.user.CaptchaExpireException; | ||||
| import org.dromara.common.core.exception.user.UserException; | ||||
| import org.dromara.common.core.utils.MessageUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.core.utils.ValidatorUtils; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.common.web.config.properties.CaptchaProperties; | ||||
| import org.dromara.system.domain.SysUser; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.mapper.SysUserMapper; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
| import org.dromara.web.service.IAuthStrategy; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| /** | ||||
|  * 密码认证策略 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Slf4j | ||||
| @Service("password" + IAuthStrategy.BASE_NAME) | ||||
| @RequiredArgsConstructor | ||||
| public class PasswordAuthStrategy implements IAuthStrategy { | ||||
|  | ||||
|     private final CaptchaProperties captchaProperties; | ||||
|     private final SysLoginService loginService; | ||||
|     private final SysUserMapper userMapper; | ||||
|  | ||||
|     @Override | ||||
|     public LoginVo login(String body, SysClientVo client) { | ||||
|         PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); | ||||
|         ValidatorUtils.validate(loginBody); | ||||
|         String tenantId = loginBody.getTenantId(); | ||||
|         String username = loginBody.getUsername(); | ||||
|         String password = loginBody.getPassword(); | ||||
|         String code = loginBody.getCode(); | ||||
|         String uuid = loginBody.getUuid(); | ||||
|  | ||||
|         boolean captchaEnabled = captchaProperties.getEnable(); | ||||
|         // 验证码开关 | ||||
|         if (captchaEnabled) { | ||||
|             validateCaptcha(tenantId, username, code, uuid); | ||||
|         } | ||||
|         LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { | ||||
|             SysUserVo user = loadUserByUsername(username); | ||||
|             loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); | ||||
|             // 此处可根据登录用户的数据不同 自行创建 loginUser | ||||
|             return loginService.buildLoginUser(user); | ||||
|         }); | ||||
|         loginUser.setClientKey(client.getClientKey()); | ||||
|         loginUser.setDeviceType(client.getDeviceType()); | ||||
|         SaLoginParameter model = new SaLoginParameter(); | ||||
|         model.setDeviceType(client.getDeviceType()); | ||||
|         // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 | ||||
|         // 例如: 后台用户30分钟过期 app用户1天过期 | ||||
|         model.setTimeout(client.getTimeout()); | ||||
|         model.setActiveTimeout(client.getActiveTimeout()); | ||||
|         model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); | ||||
|         // 生成token | ||||
|         LoginHelper.login(loginUser, model); | ||||
|  | ||||
|         LoginVo loginVo = new LoginVo(); | ||||
|         loginVo.setAccessToken(StpUtil.getTokenValue()); | ||||
|         loginVo.setExpireIn(StpUtil.getTokenTimeout()); | ||||
|         loginVo.setClientId(client.getClientId()); | ||||
|         return loginVo; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验验证码 | ||||
|      * | ||||
|      * @param username 用户名 | ||||
|      * @param code     验证码 | ||||
|      * @param uuid     唯一标识 | ||||
|      */ | ||||
|     private void validateCaptcha(String tenantId, String username, String code, String uuid) { | ||||
|         String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); | ||||
|         String captcha = RedisUtils.getCacheObject(verifyKey); | ||||
|         RedisUtils.deleteObject(verifyKey); | ||||
|         if (captcha == null) { | ||||
|             loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); | ||||
|             throw new CaptchaExpireException(); | ||||
|         } | ||||
|         if (!code.equalsIgnoreCase(captcha)) { | ||||
|             loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); | ||||
|             throw new CaptchaException(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private SysUserVo loadUserByUsername(String username) { | ||||
|         SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username)); | ||||
|         if (ObjectUtil.isNull(user)) { | ||||
|             log.info("登录用户:{} 不存在.", username); | ||||
|             throw new UserException("user.not.exists", username); | ||||
|         } else if (SystemConstants.DISABLE.equals(user.getStatus())) { | ||||
|             log.info("登录用户:{} 已被停用.", username); | ||||
|             throw new UserException("user.blocked", username); | ||||
|         } | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,102 +0,0 @@ | ||||
| package org.dromara.web.service.impl; | ||||
|  | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.dev33.satoken.stp.parameter.SaLoginParameter; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.common.core.constant.Constants; | ||||
| import org.dromara.common.core.constant.GlobalConstants; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.domain.model.LoginUser; | ||||
| import org.dromara.common.core.domain.model.SmsLoginBody; | ||||
| import org.dromara.common.core.enums.LoginType; | ||||
| import org.dromara.common.core.exception.user.CaptchaExpireException; | ||||
| import org.dromara.common.core.exception.user.UserException; | ||||
| import org.dromara.common.core.utils.MessageUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.core.utils.ValidatorUtils; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.system.domain.SysUser; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.mapper.SysUserMapper; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
| import org.dromara.web.service.IAuthStrategy; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| /** | ||||
|  * 短信认证策略 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Slf4j | ||||
| @Service("sms" + IAuthStrategy.BASE_NAME) | ||||
| @RequiredArgsConstructor | ||||
| public class SmsAuthStrategy implements IAuthStrategy { | ||||
|  | ||||
|     private final SysLoginService loginService; | ||||
|     private final SysUserMapper userMapper; | ||||
|  | ||||
|     @Override | ||||
|     public LoginVo login(String body, SysClientVo client) { | ||||
|         SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); | ||||
|         ValidatorUtils.validate(loginBody); | ||||
|         String tenantId = loginBody.getTenantId(); | ||||
|         String phonenumber = loginBody.getPhonenumber(); | ||||
|         String smsCode = loginBody.getSmsCode(); | ||||
|         LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { | ||||
|             SysUserVo user = loadUserByPhonenumber(phonenumber); | ||||
|             loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); | ||||
|             // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 | ||||
|             return loginService.buildLoginUser(user); | ||||
|         }); | ||||
|         loginUser.setClientKey(client.getClientKey()); | ||||
|         loginUser.setDeviceType(client.getDeviceType()); | ||||
|         SaLoginParameter model = new SaLoginParameter(); | ||||
|         model.setDeviceType(client.getDeviceType()); | ||||
|         // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 | ||||
|         // 例如: 后台用户30分钟过期 app用户1天过期 | ||||
|         model.setTimeout(client.getTimeout()); | ||||
|         model.setActiveTimeout(client.getActiveTimeout()); | ||||
|         model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); | ||||
|         // 生成token | ||||
|         LoginHelper.login(loginUser, model); | ||||
|  | ||||
|         LoginVo loginVo = new LoginVo(); | ||||
|         loginVo.setAccessToken(StpUtil.getTokenValue()); | ||||
|         loginVo.setExpireIn(StpUtil.getTokenTimeout()); | ||||
|         loginVo.setClientId(client.getClientId()); | ||||
|         return loginVo; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验短信验证码 | ||||
|      */ | ||||
|     private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { | ||||
|         String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); | ||||
|         if (StringUtils.isBlank(code)) { | ||||
|             loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); | ||||
|             throw new CaptchaExpireException(); | ||||
|         } | ||||
|         return code.equals(smsCode); | ||||
|     } | ||||
|  | ||||
|     private SysUserVo loadUserByPhonenumber(String phonenumber) { | ||||
|         SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber)); | ||||
|         if (ObjectUtil.isNull(user)) { | ||||
|             log.info("登录用户:{} 不存在.", phonenumber); | ||||
|             throw new UserException("user.not.exists", phonenumber); | ||||
|         } else if (SystemConstants.DISABLE.equals(user.getStatus())) { | ||||
|             log.info("登录用户:{} 已被停用.", phonenumber); | ||||
|             throw new UserException("user.blocked", phonenumber); | ||||
|         } | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,131 +0,0 @@ | ||||
| package org.dromara.web.service.impl; | ||||
|  | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.dev33.satoken.stp.parameter.SaLoginParameter; | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.map.MapUtil; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import cn.hutool.http.HttpUtil; | ||||
| import cn.hutool.http.Method; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import me.zhyd.oauth.model.AuthResponse; | ||||
| import me.zhyd.oauth.model.AuthUser; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.domain.model.LoginUser; | ||||
| import org.dromara.common.core.domain.model.SocialLoginBody; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.exception.user.UserException; | ||||
| import org.dromara.common.core.utils.StreamUtils; | ||||
| import org.dromara.common.core.utils.ValidatorUtils; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.common.social.config.properties.SocialProperties; | ||||
| import org.dromara.common.social.utils.SocialUtils; | ||||
| import org.dromara.common.tenant.helper.TenantHelper; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.system.domain.vo.SysSocialVo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.mapper.SysUserMapper; | ||||
| import org.dromara.system.service.ISysSocialService; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
| import org.dromara.web.service.IAuthStrategy; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
|  | ||||
| /** | ||||
|  * 第三方授权策略 | ||||
|  * | ||||
|  * @author thiszhc is 三三 | ||||
|  */ | ||||
| @Slf4j | ||||
| @Service("social" + IAuthStrategy.BASE_NAME) | ||||
| @RequiredArgsConstructor | ||||
| public class SocialAuthStrategy implements IAuthStrategy { | ||||
|  | ||||
|     private final SocialProperties socialProperties; | ||||
|     private final ISysSocialService sysSocialService; | ||||
|     private final SysUserMapper userMapper; | ||||
|     private final SysLoginService loginService; | ||||
|  | ||||
|     /** | ||||
|      * 登录-第三方授权登录 | ||||
|      * | ||||
|      * @param body     登录信息 | ||||
|      * @param client   客户端信息 | ||||
|      */ | ||||
|     @Override | ||||
|     public LoginVo login(String body, SysClientVo client) { | ||||
|         SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); | ||||
|         ValidatorUtils.validate(loginBody); | ||||
|         AuthResponse<AuthUser> response = SocialUtils.loginAuth( | ||||
|                 loginBody.getSource(), loginBody.getSocialCode(), | ||||
|                 loginBody.getSocialState(), socialProperties); | ||||
|         if (!response.ok()) { | ||||
|             throw new ServiceException(response.getMsg()); | ||||
|         } | ||||
|         AuthUser authUserData = response.getData(); | ||||
|         if ("GITEE".equals(authUserData.getSource())) { | ||||
|             // 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖 | ||||
|             HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus") | ||||
|                     .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) | ||||
|                     .executeAsync(); | ||||
|             HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus") | ||||
|                     .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) | ||||
|                     .executeAsync(); | ||||
|         } | ||||
|  | ||||
|         List<SysSocialVo> list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid()); | ||||
|         if (CollUtil.isEmpty(list)) { | ||||
|             throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); | ||||
|         } | ||||
|         SysSocialVo social; | ||||
|         if (TenantHelper.isEnable()) { | ||||
|             Optional<SysSocialVo> opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId())); | ||||
|             if (opt.isEmpty()) { | ||||
|                 throw new ServiceException("对不起,你没有权限登录当前租户!"); | ||||
|             } | ||||
|             social = opt.get(); | ||||
|         } else { | ||||
|             social = list.get(0); | ||||
|         } | ||||
|         LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> { | ||||
|             SysUserVo user = loadUser(social.getUserId()); | ||||
|             // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 | ||||
|             return loginService.buildLoginUser(user); | ||||
|         }); | ||||
|         loginUser.setClientKey(client.getClientKey()); | ||||
|         loginUser.setDeviceType(client.getDeviceType()); | ||||
|         SaLoginParameter model = new SaLoginParameter(); | ||||
|         model.setDeviceType(client.getDeviceType()); | ||||
|         // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 | ||||
|         // 例如: 后台用户30分钟过期 app用户1天过期 | ||||
|         model.setTimeout(client.getTimeout()); | ||||
|         model.setActiveTimeout(client.getActiveTimeout()); | ||||
|         model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); | ||||
|         // 生成token | ||||
|         LoginHelper.login(loginUser, model); | ||||
|  | ||||
|         LoginVo loginVo = new LoginVo(); | ||||
|         loginVo.setAccessToken(StpUtil.getTokenValue()); | ||||
|         loginVo.setExpireIn(StpUtil.getTokenTimeout()); | ||||
|         loginVo.setClientId(client.getClientId()); | ||||
|         return loginVo; | ||||
|     } | ||||
|  | ||||
|     private SysUserVo loadUser(Long userId) { | ||||
|         SysUserVo user = userMapper.selectVoById(userId); | ||||
|         if (ObjectUtil.isNull(user)) { | ||||
|             log.info("登录用户:{} 不存在.", ""); | ||||
|             throw new UserException("user.not.exists", ""); | ||||
|         } else if (SystemConstants.DISABLE.equals(user.getStatus())) { | ||||
|             log.info("登录用户:{} 已被停用.", ""); | ||||
|             throw new UserException("user.blocked", ""); | ||||
|         } | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,111 +0,0 @@ | ||||
| package org.dromara.web.service.impl; | ||||
|  | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import cn.dev33.satoken.stp.parameter.SaLoginParameter; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import me.zhyd.oauth.config.AuthConfig; | ||||
| import me.zhyd.oauth.model.AuthCallback; | ||||
| import me.zhyd.oauth.model.AuthResponse; | ||||
| import me.zhyd.oauth.model.AuthToken; | ||||
| import me.zhyd.oauth.model.AuthUser; | ||||
| import me.zhyd.oauth.request.AuthRequest; | ||||
| import me.zhyd.oauth.request.AuthWechatMiniProgramRequest; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| import org.dromara.common.core.domain.model.XcxLoginBody; | ||||
| import org.dromara.common.core.domain.model.XcxLoginUser; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.ValidatorUtils; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.system.domain.vo.SysClientVo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.web.domain.vo.LoginVo; | ||||
| import org.dromara.web.service.IAuthStrategy; | ||||
| import org.dromara.web.service.SysLoginService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| /** | ||||
|  * 小程序认证策略 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Slf4j | ||||
| @Service("xcx" + IAuthStrategy.BASE_NAME) | ||||
| @RequiredArgsConstructor | ||||
| public class XcxAuthStrategy implements IAuthStrategy { | ||||
|  | ||||
|     private final SysLoginService loginService; | ||||
|  | ||||
|     @Override | ||||
|     public LoginVo login(String body, SysClientVo client) { | ||||
|         XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); | ||||
|         ValidatorUtils.validate(loginBody); | ||||
|         // xcxCode 为 小程序调用 wx.login 授权后获取 | ||||
|         String xcxCode = loginBody.getXcxCode(); | ||||
|         // 多个小程序识别使用 | ||||
|         String appid = loginBody.getAppid(); | ||||
|  | ||||
|         // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid | ||||
|         AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder() | ||||
|             .clientId(appid).clientSecret("自行填写密钥 可根据不同appid填入不同密钥") | ||||
|             .ignoreCheckRedirectUri(true).ignoreCheckState(true).build()); | ||||
|         AuthCallback authCallback = new AuthCallback(); | ||||
|         authCallback.setCode(xcxCode); | ||||
|         AuthResponse<AuthUser> resp = authRequest.login(authCallback); | ||||
|         String openid, unionId; | ||||
|         if (resp.ok()) { | ||||
|             AuthToken token = resp.getData().getToken(); | ||||
|             openid = token.getOpenId(); | ||||
|             // 微信小程序只有关联到微信开放平台下之后才能获取到 unionId,因此unionId不一定能返回。 | ||||
|             unionId = token.getUnionId(); | ||||
|         } else { | ||||
|             throw new ServiceException(resp.getMsg()); | ||||
|         } | ||||
|         // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 | ||||
|         SysUserVo user = loadUserByOpenid(openid); | ||||
|         // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 | ||||
|         XcxLoginUser loginUser = new XcxLoginUser(); | ||||
|         loginUser.setTenantId(user.getTenantId()); | ||||
|         loginUser.setUserId(user.getUserId()); | ||||
|         loginUser.setUsername(user.getUserName()); | ||||
|         loginUser.setNickname(user.getNickName()); | ||||
|         loginUser.setUserType(user.getUserType()); | ||||
|         loginUser.setClientKey(client.getClientKey()); | ||||
|         loginUser.setDeviceType(client.getDeviceType()); | ||||
|         loginUser.setOpenid(openid); | ||||
|  | ||||
|         SaLoginParameter model = new SaLoginParameter(); | ||||
|         model.setDeviceType(client.getDeviceType()); | ||||
|         // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 | ||||
|         // 例如: 后台用户30分钟过期 app用户1天过期 | ||||
|         model.setTimeout(client.getTimeout()); | ||||
|         model.setActiveTimeout(client.getActiveTimeout()); | ||||
|         model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); | ||||
|         // 生成token | ||||
|         LoginHelper.login(loginUser, model); | ||||
|  | ||||
|         LoginVo loginVo = new LoginVo(); | ||||
|         loginVo.setAccessToken(StpUtil.getTokenValue()); | ||||
|         loginVo.setExpireIn(StpUtil.getTokenTimeout()); | ||||
|         loginVo.setClientId(client.getClientId()); | ||||
|         loginVo.setOpenid(openid); | ||||
|         return loginVo; | ||||
|     } | ||||
|  | ||||
|     private SysUserVo loadUserByOpenid(String openid) { | ||||
|         // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 | ||||
|         // todo 自行实现 userService.selectUserByOpenid(openid); | ||||
|         SysUserVo user = new SysUserVo(); | ||||
|         if (ObjectUtil.isNull(user)) { | ||||
|             log.info("登录用户:{} 不存在.", openid); | ||||
|             // todo 用户不存在 业务逻辑自行实现 | ||||
|         } else if (SystemConstants.DISABLE.equals(user.getStatus())) { | ||||
|             log.info("登录用户:{} 已被停用.", openid); | ||||
|             // todo 用户已被停用 业务逻辑自行实现 | ||||
|         } | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,101 +1,116 @@ | ||||
| --- # 监控中心配置 | ||||
| spring.boot.admin.client: | ||||
|   # 增加客户端开关 | ||||
|   enabled: true | ||||
|   url: http://localhost:9090/admin | ||||
|   instance: | ||||
|     service-host-type: IP | ||||
|     metadata: | ||||
|       username: ${spring.boot.admin.client.username} | ||||
|       userpassword: ${spring.boot.admin.client.password} | ||||
|   username: @monitor.username@ | ||||
|   password: @monitor.password@ | ||||
| --- # 监控配置 | ||||
| spring: | ||||
|   boot: | ||||
|     admin: | ||||
|       # Spring Boot Admin Client 客户端的相关配置 | ||||
|       client: | ||||
|         # 增加客户端开关 | ||||
|         enabled: true | ||||
|         # 设置 Spring Boot Admin Server 地址 | ||||
|         url: http://localhost:9090/admin | ||||
|         instance: | ||||
|           prefer-ip: true # 注册实例时,优先使用 IP | ||||
|         username: ruoyi | ||||
|         password: 123456 | ||||
|  | ||||
| --- # snail-job 配置 | ||||
| snail-job: | ||||
|   enabled: true | ||||
|   # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 | ||||
|   group: "ruoyi_group" | ||||
|   # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表 | ||||
|   token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" | ||||
|   server: | ||||
|     host: 127.0.0.1 | ||||
|     port: 17888 | ||||
|   # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 | ||||
|   namespace: ${spring.profiles.active} | ||||
|   # 随主应用端口漂移 | ||||
|   port: 2${server.port} | ||||
|   # 客户端ip指定 | ||||
|   host: | ||||
|   # RPC类型: netty, grpc | ||||
|   rpc-type: grpc | ||||
| --- # xxl-job 配置 | ||||
| xxl: | ||||
|   job: | ||||
|     # 执行器开关 | ||||
|     enabled: true | ||||
|     # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 | ||||
|     admin-addresses: http://localhost:9100/xxl-job-admin | ||||
|     # 执行器通讯TOKEN:非空时启用 | ||||
|     access-token: xxl-job | ||||
|     # 执行器配置 | ||||
|     executor: | ||||
|       # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册 | ||||
|       appname: xxl-job-executor | ||||
|       # 执行器端口号 执行器从9101开始往后写 | ||||
|       port: 9101 | ||||
|       # 执行器注册:默认IP:PORT | ||||
|       address: | ||||
|       # 执行器IP:默认自动获取IP | ||||
|       ip: | ||||
|       # 执行器运行日志文件存储磁盘路径 | ||||
|       logpath: ./logs/xxl-job | ||||
|       # 执行器日志文件保存天数:大于3生效 | ||||
|       logretentiondays: 30 | ||||
|  | ||||
| --- # 数据源配置 | ||||
| spring: | ||||
|   datasource: | ||||
|     type: com.zaxxer.hikari.HikariDataSource | ||||
|     type: com.alibaba.druid.pool.DruidDataSource | ||||
|     # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content | ||||
|     dynamic: | ||||
|       # 性能分析插件(有性能损耗 不建议生产环境使用) | ||||
|       p6spy: true | ||||
|       # 设置默认的数据源或者数据源组,默认值即为 master | ||||
|       primary: master | ||||
|       # 严格模式 匹配不到数据源则报错 | ||||
|       strict: true | ||||
|       datasource: | ||||
|         # 主库数据源 | ||||
|         master: | ||||
|           type: ${spring.datasource.type} | ||||
|           driverClassName: com.mysql.cj.jdbc.Driver | ||||
|           # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 | ||||
|           # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) | ||||
|           url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true | ||||
|           url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true | ||||
|           username: root | ||||
|           password: root | ||||
| #        # 从库数据源 | ||||
| #        slave: | ||||
| #          lazy: true | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: com.mysql.cj.jdbc.Driver | ||||
| #          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true | ||||
| #          username: | ||||
| #          password: | ||||
| #        oracle: | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: oracle.jdbc.OracleDriver | ||||
| #          url: jdbc:oracle:thin:@//localhost:1521/XE | ||||
| #          username: ROOT | ||||
| #          password: root | ||||
| #        postgres: | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: org.postgresql.Driver | ||||
| #          url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true | ||||
| #          username: root | ||||
| #          password: root | ||||
| #        sqlserver: | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver | ||||
| #          url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true | ||||
| #          username: SA | ||||
| #          password: root | ||||
|       hikari: | ||||
|         # 最大连接池数量 | ||||
|         maxPoolSize: 20 | ||||
|         # 最小空闲线程数量 | ||||
|         # 从库数据源 | ||||
|         slave: | ||||
|           lazy: true | ||||
|           driverClassName: com.mysql.cj.jdbc.Driver | ||||
|           url: | ||||
|           username: | ||||
|           password: | ||||
|       druid: | ||||
|         # 初始连接数 | ||||
|         initialSize: 5 | ||||
|         # 最小连接池数量 | ||||
|         minIdle: 10 | ||||
|         # 最大连接池数量 | ||||
|         maxActive: 20 | ||||
|         # 配置获取连接等待超时的时间 | ||||
|         connectionTimeout: 30000 | ||||
|         # 校验超时时间 | ||||
|         validationTimeout: 5000 | ||||
|         # 空闲连接存活最大时间,默认10分钟 | ||||
|         idleTimeout: 600000 | ||||
|         # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 | ||||
|         maxLifetime: 1800000 | ||||
|         # 多久检查一次连接的活性 | ||||
|         keepaliveTime: 30000 | ||||
|         maxWait: 60000 | ||||
|         # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | ||||
|         timeBetweenEvictionRunsMillis: 60000 | ||||
|         # 配置一个连接在池中最小生存的时间,单位是毫秒 | ||||
|         minEvictableIdleTimeMillis: 300000 | ||||
|         # 配置一个连接在池中最大生存的时间,单位是毫秒 | ||||
|         maxEvictableIdleTimeMillis: 900000 | ||||
|         # 配置检测连接是否有效 | ||||
|         validationQuery: SELECT 1 FROM DUAL | ||||
|         testWhileIdle: true | ||||
|         testOnBorrow: false | ||||
|         testOnReturn: false | ||||
|         # 注意这个值和druid原生不一致,默认启动了stat | ||||
|         filters: stat | ||||
|  | ||||
| --- # druid 配置 | ||||
| spring: | ||||
|   datasource: | ||||
|     druid: | ||||
|       webStatFilter: | ||||
|         enabled: true | ||||
|       statViewServlet: | ||||
|         enabled: true | ||||
|         # 设置白名单,不填则允许所有访问 | ||||
|         allow: | ||||
|         url-pattern: /druid/* | ||||
|         # 控制台管理用户名和密码 | ||||
|         login-username: ruoyi | ||||
|         login-password: 123456 | ||||
|       filter: | ||||
|         stat: | ||||
|           enabled: true | ||||
|           # 慢SQL记录 | ||||
|           log-slow-sql: true | ||||
|           slow-sql-millis: 1000 | ||||
|           merge-sql: true | ||||
|         wall: | ||||
|           config: | ||||
|             multi-statement-allow: true | ||||
|  | ||||
| --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) | ||||
| spring.data: | ||||
| spring: | ||||
|   redis: | ||||
|     # 地址 | ||||
|     host: localhost | ||||
| @@ -103,163 +118,41 @@ spring.data: | ||||
|     port: 6379 | ||||
|     # 数据库索引 | ||||
|     database: 0 | ||||
|     # redis 密码必须配置 | ||||
|     password: ruoyi123 | ||||
|     # 密码 | ||||
|     password: | ||||
|     # 连接超时时间 | ||||
|     timeout: 10s | ||||
|     # 是否开启ssl | ||||
|     ssl.enabled: false | ||||
|     ssl: false | ||||
|  | ||||
| # redisson 配置 | ||||
| redisson: | ||||
|   # redis key前缀 | ||||
|   keyPrefix: | ||||
|   # 线程池数量 | ||||
|   threads: 4 | ||||
|   threads: 16 | ||||
|   # Netty线程池数量 | ||||
|   nettyThreads: 8 | ||||
|   nettyThreads: 32 | ||||
|   # 传输模式 | ||||
|   transportMode: "NIO" | ||||
|   # 单节点配置 | ||||
|   singleServerConfig: | ||||
|     # 客户端名称 不能用中文 | ||||
|     clientName: RuoYi-Vue-Plus | ||||
|     # 客户端名称 | ||||
|     clientName: ${ruoyi.name} | ||||
|     # 最小空闲连接数 | ||||
|     connectionMinimumIdleSize: 8 | ||||
|     connectionMinimumIdleSize: 32 | ||||
|     # 连接池大小 | ||||
|     connectionPoolSize: 32 | ||||
|     connectionPoolSize: 64 | ||||
|     # 连接空闲超时,单位:毫秒 | ||||
|     idleConnectionTimeout: 10000 | ||||
|     # 命令等待超时,单位:毫秒 | ||||
|     timeout: 3000 | ||||
|     # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 | ||||
|     retryAttempts: 3 | ||||
|     # 命令重试发送时间间隔,单位:毫秒 | ||||
|     retryInterval: 1500 | ||||
|     # 发布和订阅连接的最小空闲连接数 | ||||
|     subscriptionConnectionMinimumIdleSize: 1 | ||||
|     # 发布和订阅连接池大小 | ||||
|     subscriptionConnectionPoolSize: 50 | ||||
|  | ||||
| --- # mail 邮件发送 | ||||
| mail: | ||||
|   enabled: false | ||||
|   host: smtp.163.com | ||||
|   port: 465 | ||||
|   # 是否需要用户名密码验证 | ||||
|   auth: true | ||||
|   # 发送方,遵循RFC-822标准 | ||||
|   from: xxx@163.com | ||||
|   # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) | ||||
|   user: xxx@163.com | ||||
|   # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) | ||||
|   pass: xxxxxxxxxx | ||||
|   # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 | ||||
|   starttlsEnable: true | ||||
|   # 使用SSL安全连接 | ||||
|   sslEnable: true | ||||
|   # SMTP超时时长,单位毫秒,缺省值不超时 | ||||
|   timeout: 0 | ||||
|   # Socket连接超时值,单位毫秒,缺省值不超时 | ||||
|   connectionTimeout: 0 | ||||
|  | ||||
| --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 | ||||
| # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 | ||||
| sms: | ||||
|   # 配置源类型用于标定配置来源(interface,yaml) | ||||
|   config-type: yaml | ||||
|   # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 | ||||
|   restricted: true | ||||
|   # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 | ||||
|   minute-max: 1 | ||||
|   # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 | ||||
|   account-max: 30 | ||||
|   # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 | ||||
|   blends: | ||||
|     # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 | ||||
|     # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 | ||||
|     config1: | ||||
|       # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 | ||||
|       supplier: alibaba | ||||
|       # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 | ||||
|       access-key-id: 您的accessKey | ||||
|       # 称为accessSecret有些称之为apiSecret | ||||
|       access-key-secret: 您的accessKeySecret | ||||
|       signature: 您的短信签名 | ||||
|       sdk-app-id: 您的sdkAppId | ||||
|     config2: | ||||
|       # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 | ||||
|       supplier: tencent | ||||
|       access-key-id: 您的accessKey | ||||
|       access-key-secret: 您的accessKeySecret | ||||
|       signature: 您的短信签名 | ||||
|       sdk-app-id: 您的sdkAppId | ||||
|  | ||||
|  | ||||
| --- # 三方授权 | ||||
| justauth: | ||||
|   # 前端外网访问地址 | ||||
|   address: http://localhost:80 | ||||
|   type: | ||||
|     maxkey: | ||||
|       # maxkey 服务器地址 | ||||
|       # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 | ||||
|       server-url: http://sso.maxkey.top | ||||
|       client-id: 876892492581044224 | ||||
|       client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=maxkey | ||||
|     topiam: | ||||
|       # topiam 服务器地址 | ||||
|       server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol | ||||
|       client-id: 449c4*********937************759 | ||||
|       client-secret: ac7***********1e0************28d | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=topiam | ||||
|       scopes: [openid, email, phone, profile] | ||||
|     qq: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=qq | ||||
|       union-id: false | ||||
|     weibo: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=weibo | ||||
|     gitee: | ||||
|       client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 | ||||
|       client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=gitee | ||||
|     dingtalk: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=dingtalk | ||||
|     baidu: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=baidu | ||||
|     csdn: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=csdn | ||||
|     coding: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=coding | ||||
|       coding-group-name: xx | ||||
|     oschina: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=oschina | ||||
|     alipay_wallet: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet | ||||
|       alipay-public-key: MIIB**************DAQAB | ||||
|     wechat_open: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=wechat_open | ||||
|     wechat_mp: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=wechat_mp | ||||
|     wechat_enterprise: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise | ||||
|       agent-id: 1000002 | ||||
|     gitlab: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=gitlab | ||||
|     # 单个连接最大订阅数量 | ||||
|     subscriptionsPerConnection: 5 | ||||
|     # DNS监测时间间隔,单位:毫秒 | ||||
|     dnsMonitoringInterval: 5000 | ||||
|   | ||||
| @@ -1,130 +1,141 @@ | ||||
| --- # 临时文件存储位置 避免临时文件被系统清理报错 | ||||
| spring.servlet.multipart.location: /ruoyi/server/temp | ||||
| --- # 监控配置 | ||||
| spring: | ||||
|   boot: | ||||
|     admin: | ||||
|       # Spring Boot Admin Client 客户端的相关配置 | ||||
|       client: | ||||
|         # 增加客户端开关 | ||||
|         enabled: true | ||||
|         # 设置 Spring Boot Admin Server 地址 | ||||
|         url: http://172.30.0.90:9090/admin | ||||
|         instance: | ||||
|           prefer-ip: true # 注册实例时,优先使用 IP | ||||
|         username: ruoyi | ||||
|         password: 123456 | ||||
|  | ||||
| --- # 监控中心配置 | ||||
| spring.boot.admin.client: | ||||
|   # 增加客户端开关 | ||||
|   enabled: true | ||||
|   url: http://localhost:9090/admin | ||||
|   instance: | ||||
|     service-host-type: IP | ||||
|     metadata: | ||||
|       username: ${spring.boot.admin.client.username} | ||||
|       userpassword: ${spring.boot.admin.client.password} | ||||
|   username: @monitor.username@ | ||||
|   password: @monitor.password@ | ||||
|  | ||||
| --- # snail-job 配置 | ||||
| snail-job: | ||||
|   enabled: true | ||||
|   # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 | ||||
|   group: "ruoyi_group" | ||||
|   # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表 | ||||
|   token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" | ||||
|   server: | ||||
|     host: 127.0.0.1 | ||||
|     port: 17888 | ||||
|   # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 | ||||
|   namespace: ${spring.profiles.active} | ||||
|   # 随主应用端口漂移 | ||||
|   port: 2${server.port} | ||||
|   # 客户端ip指定 | ||||
|   host: | ||||
|   # RPC类型: netty, grpc | ||||
|   rpc-type: grpc | ||||
| --- # xxl-job 配置 | ||||
| xxl: | ||||
|   job: | ||||
|     # 执行器开关 | ||||
|     enabled: true | ||||
|     # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 | ||||
|     admin-addresses: http://172.30.0.92:9100/xxl-job-admin | ||||
|     # 执行器通讯TOKEN:非空时启用 | ||||
|     access-token: xxl-job | ||||
|     # 执行器配置 | ||||
|     executor: | ||||
|       # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册 | ||||
|       appname: xxl-job-executor | ||||
|       # 执行器端口号 执行器从9101开始往后写 | ||||
|       port: 9101 | ||||
|       # 执行器注册:默认IP:PORT | ||||
|       address: | ||||
|       # 执行器IP:默认自动获取IP | ||||
|       ip: | ||||
|       # 执行器运行日志文件存储磁盘路径 | ||||
|       logpath: ./logs/xxl-job | ||||
|       # 执行器日志文件保存天数:大于3生效 | ||||
|       logretentiondays: 30 | ||||
|  | ||||
| --- # 数据源配置 | ||||
| spring: | ||||
|   datasource: | ||||
|     type: com.zaxxer.hikari.HikariDataSource | ||||
|     type: com.alibaba.druid.pool.DruidDataSource | ||||
|     # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content | ||||
|     dynamic: | ||||
|       # 性能分析插件(有性能损耗 不建议生产环境使用) | ||||
|       p6spy: false | ||||
|       # 设置默认的数据源或者数据源组,默认值即为 master | ||||
|       primary: master | ||||
|       # 严格模式 匹配不到数据源则报错 | ||||
|       strict: true | ||||
|       datasource: | ||||
|         # 主库数据源 | ||||
|         master: | ||||
|           type: ${spring.datasource.type} | ||||
|           driverClassName: com.mysql.cj.jdbc.Driver | ||||
|           # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 | ||||
|           # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) | ||||
|           url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true | ||||
|           url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true | ||||
|           username: root | ||||
|           password: root | ||||
| #        # 从库数据源 | ||||
| #        slave: | ||||
| #          lazy: true | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: com.mysql.cj.jdbc.Driver | ||||
| #          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true | ||||
| #          username: | ||||
| #          password: | ||||
| #        oracle: | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: oracle.jdbc.OracleDriver | ||||
| #          url: jdbc:oracle:thin:@//localhost:1521/XE | ||||
| #          username: ROOT | ||||
| #          password: root | ||||
| #        postgres: | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: org.postgresql.Driver | ||||
| #          url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true | ||||
| #          username: root | ||||
| #          password: root | ||||
| #        sqlserver: | ||||
| #          type: ${spring.datasource.type} | ||||
| #          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver | ||||
| #          url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true | ||||
| #          username: SA | ||||
| #          password: root | ||||
|       hikari: | ||||
|         # 最大连接池数量 | ||||
|         maxPoolSize: 20 | ||||
|         # 最小空闲线程数量 | ||||
|         # 从库数据源 | ||||
|         slave: | ||||
|           lazy: true | ||||
|           driverClassName: com.mysql.cj.jdbc.Driver | ||||
|           url: | ||||
|           username: | ||||
|           password: | ||||
|       druid: | ||||
|         # 初始连接数 | ||||
|         initialSize: 5 | ||||
|         # 最小连接池数量 | ||||
|         minIdle: 10 | ||||
|         # 最大连接池数量 | ||||
|         maxActive: 20 | ||||
|         # 配置获取连接等待超时的时间 | ||||
|         connectionTimeout: 30000 | ||||
|         # 校验超时时间 | ||||
|         validationTimeout: 5000 | ||||
|         # 空闲连接存活最大时间,默认10分钟 | ||||
|         idleTimeout: 600000 | ||||
|         # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 | ||||
|         maxLifetime: 1800000 | ||||
|         # 多久检查一次连接的活性 | ||||
|         keepaliveTime: 30000 | ||||
|         maxWait: 60000 | ||||
|         # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | ||||
|         timeBetweenEvictionRunsMillis: 60000 | ||||
|         # 配置一个连接在池中最小生存的时间,单位是毫秒 | ||||
|         minEvictableIdleTimeMillis: 300000 | ||||
|         # 配置一个连接在池中最大生存的时间,单位是毫秒 | ||||
|         maxEvictableIdleTimeMillis: 900000 | ||||
|         # 配置检测连接是否有效 | ||||
|         validationQuery: SELECT 1 FROM DUAL | ||||
|         testWhileIdle: true | ||||
|         testOnBorrow: false | ||||
|         testOnReturn: false | ||||
|         # 注意这个值和druid原生不一致,默认启动了stat | ||||
|         filters: stat | ||||
|  | ||||
| --- # druid 配置 | ||||
| spring: | ||||
|   datasource: | ||||
|     druid: | ||||
|       webStatFilter: | ||||
|         enabled: true | ||||
|       statViewServlet: | ||||
|         enabled: true | ||||
|         # 设置白名单,不填则允许所有访问 | ||||
|         allow: | ||||
|         url-pattern: /druid/* | ||||
|         # 控制台管理用户名和密码 | ||||
|         login-username: ruoyi | ||||
|         login-password: 123456 | ||||
|       filter: | ||||
|         stat: | ||||
|           enabled: true | ||||
|           # 慢SQL记录 | ||||
|           log-slow-sql: true | ||||
|           slow-sql-millis: 1000 | ||||
|           merge-sql: true | ||||
|         wall: | ||||
|           config: | ||||
|             multi-statement-allow: true | ||||
|  | ||||
| --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) | ||||
| spring.data: | ||||
| spring: | ||||
|   redis: | ||||
|     # 地址 | ||||
|     host: localhost | ||||
|     host: 172.30.0.48 | ||||
|     # 端口,默认为6379 | ||||
|     port: 6379 | ||||
|     # 数据库索引 | ||||
|     database: 0 | ||||
|     # redis 密码必须配置 | ||||
|     password: ruoyi123 | ||||
|     # 密码 | ||||
|     password: | ||||
|     # 连接超时时间 | ||||
|     timeout: 10s | ||||
|     # 是否开启ssl | ||||
|     ssl.enabled: false | ||||
|     ssl: false | ||||
|  | ||||
| # redisson 配置 | ||||
| redisson: | ||||
|   # redis key前缀 | ||||
|   keyPrefix: | ||||
|   # 线程池数量 | ||||
|   threads: 16 | ||||
|   # Netty线程池数量 | ||||
|   nettyThreads: 32 | ||||
|   # 传输模式 | ||||
|   transportMode: "NIO" | ||||
|   # 单节点配置 | ||||
|   singleServerConfig: | ||||
|     # 客户端名称 不能用中文 | ||||
|     clientName: RuoYi-Vue-Plus | ||||
|     # 客户端名称 | ||||
|     clientName: ${ruoyi.name} | ||||
|     # 最小空闲连接数 | ||||
|     connectionMinimumIdleSize: 32 | ||||
|     # 连接池大小 | ||||
| @@ -133,135 +144,15 @@ redisson: | ||||
|     idleConnectionTimeout: 10000 | ||||
|     # 命令等待超时,单位:毫秒 | ||||
|     timeout: 3000 | ||||
|     # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 | ||||
|     retryAttempts: 3 | ||||
|     # 命令重试发送时间间隔,单位:毫秒 | ||||
|     retryInterval: 1500 | ||||
|     # 发布和订阅连接的最小空闲连接数 | ||||
|     subscriptionConnectionMinimumIdleSize: 1 | ||||
|     # 发布和订阅连接池大小 | ||||
|     subscriptionConnectionPoolSize: 50 | ||||
|  | ||||
| --- # mail 邮件发送 | ||||
| mail: | ||||
|   enabled: false | ||||
|   host: smtp.163.com | ||||
|   port: 465 | ||||
|   # 是否需要用户名密码验证 | ||||
|   auth: true | ||||
|   # 发送方,遵循RFC-822标准 | ||||
|   from: xxx@163.com | ||||
|   # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) | ||||
|   user: xxx@163.com | ||||
|   # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) | ||||
|   pass: xxxxxxxxxx | ||||
|   # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 | ||||
|   starttlsEnable: true | ||||
|   # 使用SSL安全连接 | ||||
|   sslEnable: true | ||||
|   # SMTP超时时长,单位毫秒,缺省值不超时 | ||||
|   timeout: 0 | ||||
|   # Socket连接超时值,单位毫秒,缺省值不超时 | ||||
|   connectionTimeout: 0 | ||||
|  | ||||
| --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 | ||||
| # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 | ||||
| sms: | ||||
|   # 配置源类型用于标定配置来源(interface,yaml) | ||||
|   config-type: yaml | ||||
|   # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 | ||||
|   restricted: true | ||||
|   # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 | ||||
|   minute-max: 1 | ||||
|   # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 | ||||
|   account-max: 30 | ||||
|   # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 | ||||
|   blends: | ||||
|     # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 | ||||
|     # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 | ||||
|     config1: | ||||
|       # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 | ||||
|       supplier: alibaba | ||||
|       # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 | ||||
|       access-key-id: 您的accessKey | ||||
|       # 称为accessSecret有些称之为apiSecret | ||||
|       access-key-secret: 您的accessKeySecret | ||||
|       signature: 您的短信签名 | ||||
|       sdk-app-id: 您的sdkAppId | ||||
|     config2: | ||||
|       # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 | ||||
|       supplier: tencent | ||||
|       access-key-id: 您的accessKey | ||||
|       access-key-secret: 您的accessKeySecret | ||||
|       signature: 您的短信签名 | ||||
|       sdk-app-id: 您的sdkAppId | ||||
|  | ||||
| --- # 三方授权 | ||||
| justauth: | ||||
|   # 前端外网访问地址 | ||||
|   address: http://localhost:80 | ||||
|   type: | ||||
|     maxkey: | ||||
|       # maxkey 服务器地址 | ||||
|       # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 | ||||
|       server-url: http://sso.maxkey.top | ||||
|       client-id: 876892492581044224 | ||||
|       client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=maxkey | ||||
|     topiam: | ||||
|       # topiam 服务器地址 | ||||
|       server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol | ||||
|       client-id: 449c4*********937************759 | ||||
|       client-secret: ac7***********1e0************28d | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=topiam | ||||
|       scopes: [ openid, email, phone, profile ] | ||||
|     qq: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=qq | ||||
|       union-id: false | ||||
|     weibo: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=weibo | ||||
|     gitee: | ||||
|       client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 | ||||
|       client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=gitee | ||||
|     dingtalk: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=dingtalk | ||||
|     baidu: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=baidu | ||||
|     csdn: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=csdn | ||||
|     coding: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=coding | ||||
|       coding-group-name: xx | ||||
|     oschina: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=oschina | ||||
|     alipay_wallet: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet | ||||
|       alipay-public-key: MIIB**************DAQAB | ||||
|     wechat_open: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=wechat_open | ||||
|     wechat_mp: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=wechat_mp | ||||
|     wechat_enterprise: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise | ||||
|       agent-id: 1000002 | ||||
|     gitlab: | ||||
|       client-id: 10**********6 | ||||
|       client-secret: 1f7d08**********5b7**********29e | ||||
|       redirect-uri: ${justauth.address}/social-callback?source=gitlab | ||||
|     # 单个连接最大订阅数量 | ||||
|     subscriptionsPerConnection: 5 | ||||
|     # DNS监测时间间隔,单位:毫秒 | ||||
|     dnsMonitoringInterval: 5000 | ||||
|   | ||||
| @@ -1,3 +1,27 @@ | ||||
| # 项目相关配置 | ||||
| ruoyi: | ||||
|   # 名称 | ||||
|   name: RuoYi-Vue-Plus | ||||
|   # 版本 | ||||
|   version: ${ruoyi-vue-plus.version} | ||||
|   # 版权年份 | ||||
|   copyrightYear: 2021 | ||||
|   # 实例演示开关 | ||||
|   demoEnabled: true | ||||
|   # 获取ip地址开关 | ||||
|   addressEnabled: true | ||||
|  | ||||
| captcha: | ||||
|   # 页面 <参数设置> 可开启关闭 验证码校验 | ||||
|   # 验证码类型 math 数组计算 char 字符验证 | ||||
|   type: MATH | ||||
|   # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 | ||||
|   category: CIRCLE | ||||
|   # 数字验证码位数 | ||||
|   numberLength: 1 | ||||
|   # 字符验证码长度 | ||||
|   charLength: 4 | ||||
|  | ||||
| # 开发环境配置 | ||||
| server: | ||||
|   # 服务器的HTTP端口,默认为8080 | ||||
| @@ -20,43 +44,21 @@ server: | ||||
|       # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 | ||||
|       worker: 256 | ||||
|  | ||||
| captcha: | ||||
|   enable: true | ||||
|   # 页面 <参数设置> 可开启关闭 验证码校验 | ||||
|   # 验证码类型 math 数组计算 char 字符验证 | ||||
|   type: MATH | ||||
|   # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 | ||||
|   category: CIRCLE | ||||
|   # 数字验证码位数 | ||||
|   numberLength: 1 | ||||
|   # 字符验证码长度 | ||||
|   charLength: 4 | ||||
|  | ||||
| # 日志配置 | ||||
| logging: | ||||
|   level: | ||||
|     org.dromara: @logging.level@ | ||||
|     com.ruoyi: @logging.level@ | ||||
|     org.springframework: warn | ||||
|     org.mybatis.spring.mapper: error | ||||
|     org.apache.fury: warn | ||||
|   config: classpath:logback-plus.xml | ||||
|   config: classpath:logback.xml | ||||
|  | ||||
| # 用户配置 | ||||
| user: | ||||
|   password: | ||||
|     # 密码最大错误次数 | ||||
|     maxRetryCount: 5 | ||||
|     # 密码锁定时间(默认10分钟) | ||||
|     lockTime: 10 | ||||
| # tlog 全局访问性能拦截 | ||||
| tlog: | ||||
|   enable-invoke-time-print: true | ||||
|  | ||||
| # Spring配置 | ||||
| spring: | ||||
|   application: | ||||
|     name: RuoYi-Vue-Plus | ||||
|   threads: | ||||
|     # 开启虚拟线程 仅jdk21可用 | ||||
|     virtual: | ||||
|       enabled: false | ||||
|     name: ${ruoyi.name} | ||||
|   # 资源信息 | ||||
|   messages: | ||||
|     # 国际化资源文件路径 | ||||
| @@ -70,11 +72,15 @@ spring: | ||||
|       max-file-size: 10MB | ||||
|       # 设置总上传的文件大小 | ||||
|       max-request-size: 20MB | ||||
|   mvc: | ||||
|     # 设置静态资源路径 防止所有请求都去查静态资源 | ||||
|     static-path-pattern: /static/** | ||||
|     format: | ||||
|       date-time: yyyy-MM-dd HH:mm:ss | ||||
|   # 服务模块 | ||||
|   devtools: | ||||
|     restart: | ||||
|       # 热部署开关 | ||||
|       enabled: true | ||||
|   # 与vue整合部署使用 | ||||
|   thymeleaf: | ||||
|     # 将系统模板放置到最前面 否则会与 springboot-admin 页面冲突 | ||||
|     template-resolver-order: 1 | ||||
|   jackson: | ||||
|     # 日期格式化 | ||||
|     date-format: yyyy-MM-dd HH:mm:ss | ||||
| @@ -87,192 +93,234 @@ spring: | ||||
|       # 允许对象忽略json中不存在的属性 | ||||
|       fail_on_unknown_properties: false | ||||
|  | ||||
| # Sa-Token配置 | ||||
| sa-token: | ||||
|   # token名称 (同时也是cookie名称) | ||||
|   token-name: Authorization | ||||
|   # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) | ||||
|   is-concurrent: true | ||||
|   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) | ||||
|   is-share: false | ||||
|   # jwt秘钥 | ||||
|   jwt-secret-key: abcdefghijklmnopqrstuvwxyz | ||||
| # token配置 | ||||
| token: | ||||
|   # 令牌自定义标识 | ||||
|   header: Authorization | ||||
|   # 令牌密钥 | ||||
|   secret: abcdefghijklmnopqrstuvwxyz | ||||
|   # 令牌有效期(默认30分钟) | ||||
|   expireTime: 30 | ||||
|  | ||||
| # security配置 | ||||
| security: | ||||
|   # 排除路径 | ||||
|   excludes: | ||||
|     - /*.html | ||||
|     - /**/*.html | ||||
|     - /**/*.css | ||||
|     - /**/*.js | ||||
|     - /favicon.ico | ||||
|     - /error | ||||
|   # 登出路径 | ||||
|   logout-url: /logout | ||||
|   # 匿名路径 | ||||
|   anonymous: | ||||
|     - /login | ||||
|     - /register | ||||
|     - /captchaImage | ||||
|     # swagger 文档配置 | ||||
|     - /doc.html | ||||
|     - /swagger-resources/** | ||||
|     - /webjars/** | ||||
|     - /*/api-docs | ||||
|     - /*/api-docs/** | ||||
|     - /warm-flow-ui/token-name | ||||
|     # druid 监控配置 | ||||
|     - /druid/** | ||||
|     # actuator 监控配置 | ||||
|     - /actuator | ||||
|     - /actuator/** | ||||
|   # 用户放行 | ||||
|   permit-all: | ||||
|  | ||||
| # 多租户配置 | ||||
| tenant: | ||||
|   # 是否开启 | ||||
|   enable: true | ||||
|   # 排除表 | ||||
|   excludes: | ||||
|     - sys_menu | ||||
|     - sys_tenant | ||||
|     - sys_tenant_package | ||||
|     - sys_role_dept | ||||
|     - sys_role_menu | ||||
|     - sys_user_post | ||||
|     - sys_user_role | ||||
|     - sys_client | ||||
|     - sys_oss_config | ||||
| # 重复提交 | ||||
| repeat-submit: | ||||
|   # 全局间隔时间(毫秒) | ||||
|   interval: 5000 | ||||
|  | ||||
| # MyBatisPlus配置 | ||||
| # https://baomidou.com/config/ | ||||
| mybatis-plus: | ||||
|   # 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效 | ||||
|   enableLogicDelete: true | ||||
|   # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper | ||||
|   mapperPackage: org.dromara.**.mapper | ||||
|   # 不支持多包, 如有需要可在注解配置 或 提升扫包等级 | ||||
|   # 例如 com.**.**.mapper | ||||
|   mapperPackage: com.ruoyi.**.mapper | ||||
|   # 对应的 XML 文件位置 | ||||
|   mapperLocations: classpath*:mapper/**/*Mapper.xml | ||||
|   # 实体扫描,多个package用逗号或者分号分隔 | ||||
|   typeAliasesPackage: org.dromara.**.domain | ||||
|   typeAliasesPackage: com.ruoyi.**.domain | ||||
|   # 启动时是否检查 MyBatis XML 文件的存在,默认不检查 | ||||
|   checkConfigLocation: false | ||||
|   # 通过该属性可指定 MyBatis 的执行器,MyBatis 的执行器总共有三种: | ||||
|   # SIMPLE:每个语句创建新的预处理器 REUSE:会复用预处理器 BATCH:批量执行所有的更新 | ||||
|   executorType: SIMPLE | ||||
|   configuration: | ||||
|     # 自动驼峰命名规则(camel case)映射 | ||||
|     mapUnderscoreToCamelCase: true | ||||
|     # 当设置为 true 的时候,懒加载的对象可能被任何懒属性全部加载,否则,每个属性都按需加载。需要和 lazyLoadingEnabled 一起使用。 | ||||
|     aggressiveLazyLoading: true | ||||
|     # MyBatis 自动映射策略 | ||||
|     # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 | ||||
|     autoMappingBehavior: PARTIAL | ||||
|     # MyBatis 自动映射时未知列或未知属性处理策 | ||||
|     # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 | ||||
|     autoMappingUnknownColumnBehavior: NONE | ||||
|     # Mybatis一级缓存,默认为 SESSION | ||||
|     # SESSION session级别缓存 STATEMENT 关闭一级缓存 | ||||
|     localCacheScope: SESSION | ||||
|     # 开启Mybatis二级缓存,默认为 true | ||||
|     cacheEnabled: false | ||||
|     # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl | ||||
|     # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl | ||||
|     # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl | ||||
|     logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl | ||||
|   global-config: | ||||
|     # 是否打印 Logo banner | ||||
|     banner: true | ||||
|     # 是否初始化 SqlRunner | ||||
|     enableSqlRunner: false | ||||
|     dbConfig: | ||||
|       # 主键类型 | ||||
|       # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID | ||||
|       # 如需改为自增 需要将数据库表全部设置为自增 | ||||
|       idType: ASSIGN_ID | ||||
|       idType: AUTO | ||||
|       # 表名是否使用驼峰转下划线命名,只对表名生效 | ||||
|       tableUnderline: true | ||||
|       # 大写命名,对表名和字段名均生效 | ||||
|       capitalMode: false | ||||
|       # 逻辑已删除值 | ||||
|       logicDeleteValue: 2 | ||||
|       # 逻辑未删除值 | ||||
|       logicNotDeleteValue: 0 | ||||
|       # 字段验证策略之 insert,在 insert 的时候的字段验证策略 | ||||
|       # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL | ||||
|       insertStrategy: NOT_NULL | ||||
|       # 字段验证策略之 update,在 update 的时候的字段验证策略 | ||||
|       updateStrategy: NOT_NULL | ||||
|       # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件 | ||||
|       where-strategy: NOT_NULL | ||||
|  | ||||
| # 数据加密 | ||||
| mybatis-encryptor: | ||||
|   # 是否开启加密 | ||||
|   enable: false | ||||
|   # 默认加密算法 | ||||
|   algorithm: BASE64 | ||||
|   # 编码方式 BASE64/HEX。默认BASE64 | ||||
|   encode: BASE64 | ||||
|   # 安全秘钥 对称算法的秘钥 如:AES,SM4 | ||||
|   password: | ||||
|   # 公私钥 非对称算法的公私钥 如:SM2,RSA | ||||
|   publicKey: | ||||
|   privateKey: | ||||
|  | ||||
| # api接口加密 | ||||
| api-decrypt: | ||||
|   # 是否开启全局接口加密 | ||||
| # Swagger配置 | ||||
| swagger: | ||||
|   # 是否开启swagger | ||||
|   enabled: true | ||||
|   # AES 加密头标识 | ||||
|   headerFlag: encrypt-key | ||||
|   # 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 | ||||
|   # 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= | ||||
|   publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== | ||||
|   # 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 | ||||
|   # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== | ||||
|   privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= | ||||
|  | ||||
| springdoc: | ||||
|   api-docs: | ||||
|     # 是否开启接口文档 | ||||
|     enabled: true | ||||
|   info: | ||||
|     # 标题 | ||||
|     title: '标题:RuoYi-Vue-Plus多租户管理系统_接口文档' | ||||
|     # 描述 | ||||
|     description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' | ||||
|     # 版本 | ||||
|     version: '版本号: ${ruoyi.version}' | ||||
|     # 作者信息 | ||||
|     contact: | ||||
|       name: Lion Li | ||||
|       email: crazylionli@163.com | ||||
|       url: https://gitee.com/dromara/RuoYi-Vue-Plus | ||||
|   components: | ||||
|     # 鉴权方式配置 | ||||
|     security-schemes: | ||||
|       apiKey: | ||||
|         type: APIKEY | ||||
|         in: HEADER | ||||
|         name: ${sa-token.token-name} | ||||
|   #这里定义了两个分组,可定义多个,也可以不定义 | ||||
|   group-configs: | ||||
|     - group: 1.演示模块 | ||||
|       packages-to-scan: org.dromara.demo | ||||
|     - group: 2.通用模块 | ||||
|       packages-to-scan: org.dromara.web | ||||
|     - group: 3.系统模块 | ||||
|       packages-to-scan: org.dromara.system | ||||
|     - group: 4.代码生成模块 | ||||
|       packages-to-scan: org.dromara.generator | ||||
|     - group: 5.工作流模块 | ||||
|       packages-to-scan: org.dromara.workflow | ||||
|   # 请求前缀 | ||||
|   pathMapping: /dev-api | ||||
|   # 标题 | ||||
|   title: '标题:${ruoyi.name}后台管理系统_接口文档' | ||||
|   # 描述 | ||||
|   description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' | ||||
|   # 版本 | ||||
|   version: '版本号: ${ruoyi-vue-plus.version}' | ||||
|   # 作者信息 | ||||
|   contact: | ||||
|     name: Lion Li | ||||
|     email: crazylionli@163.com | ||||
|     url: https://gitee.com/JavaLionLi/RuoYi-Vue-Plus | ||||
|   groups: | ||||
|     - name: 1.演示案例 | ||||
|       basePackage: com.ruoyi.demo | ||||
|     - name: 2.系统模块 | ||||
|       basePackage: com.ruoyi.web | ||||
|     - name: 3.代码生成模块 | ||||
|       basePackage: com.ruoyi.generator | ||||
|  | ||||
| # 防止XSS攻击 | ||||
| xss: | ||||
|   # 过滤开关 | ||||
|   enabled: true | ||||
|   # 排除链接(多个用逗号分隔) | ||||
|   excludeUrls: | ||||
|     - /system/notice | ||||
|   excludes: /system/notice | ||||
|   # 匹配链接 | ||||
|   urlPatterns: /system/*,/monitor/*,/tool/* | ||||
|  | ||||
| # 全局线程池相关配置 | ||||
| # 如使用JDK21请直接使用虚拟线程 不要开启此配置 | ||||
| thread-pool: | ||||
|   # 是否开启线程池 | ||||
|   enabled: false | ||||
|   # 核心线程池大小 | ||||
|   corePoolSize: 8 | ||||
|   # 最大可创建的线程数 | ||||
|   maxPoolSize: 16 | ||||
|   # 队列最大长度 | ||||
|   queueCapacity: 128 | ||||
|   # 线程池维护线程所允许的空闲时间 | ||||
|   keepAliveSeconds: 300 | ||||
|   # 线程池对拒绝任务(无线程可用)的处理策略 | ||||
|   # CALLER_RUNS_POLICY 调用方执行 | ||||
|   # DISCARD_OLDEST_POLICY 放弃最旧的 | ||||
|   # DISCARD_POLICY 丢弃 | ||||
|   # ABORT_POLICY 中止 | ||||
|   rejectedExecutionHandler: CALLER_RUNS_POLICY | ||||
|  | ||||
| # feign 相关配置 | ||||
| feign: | ||||
|   # 不支持多包, 如有需要可在注解配置 或 提升扫包等级 | ||||
|   # 例如 com.**.**.feign | ||||
|   package: com.ruoyi.**.feign | ||||
|   # 开启压缩 | ||||
|   compression: | ||||
|     request: | ||||
|       enabled: true | ||||
|     response: | ||||
|       enabled: true | ||||
|   okhttp: | ||||
|     enabled: true | ||||
|   circuitbreaker: | ||||
|     enabled: true | ||||
|  | ||||
| --- # redisson 缓存配置 | ||||
| redisson: | ||||
|   cacheGroup: | ||||
|     # 用例: @Cacheable(cacheNames="groupId", key="#XXX") 方可使用缓存组配置 | ||||
|     - groupId: redissonCacheMap | ||||
|       # 组过期时间(脚本监控) | ||||
|       ttl: 60000 | ||||
|       # 组最大空闲时间(脚本监控) | ||||
|       maxIdleTime: 60000 | ||||
|       # 组最大长度 | ||||
|       maxSize: 0 | ||||
|     - groupId: testCache | ||||
|       ttl: 1000 | ||||
|       maxIdleTime: 500 | ||||
|  | ||||
| --- # 分布式锁 lock4j 全局配置 | ||||
| lock4j: | ||||
|   # 获取分布式锁超时时间,默认为 3000 毫秒 | ||||
|   acquire-timeout: 3000 | ||||
|   # 分布式锁的超时时间,默认为 30 秒 | ||||
|   # 分布式锁的超时时间,默认为 30 毫秒 | ||||
|   expire: 30000 | ||||
|  | ||||
| --- # Actuator 监控端点的配置项 | ||||
| management: | ||||
|   endpoints: | ||||
|     web: | ||||
|       # Actuator 提供的 API 接口的根目录。默认为 /actuator | ||||
|       base-path: /actuator | ||||
|       exposure: | ||||
|         include: '*' | ||||
|         # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 | ||||
|         # 生产环境不建议放开所有 根据项目需求放开即可 | ||||
|         include: @endpoints.include@ | ||||
|   endpoint: | ||||
|     health: | ||||
|       show-details: ALWAYS | ||||
|     logfile: | ||||
|       external-file: ./logs/sys-console.log | ||||
|  | ||||
| --- # 默认/推荐使用sse推送 | ||||
| sse: | ||||
|   enabled: true | ||||
|   path: /resource/sse | ||||
|  | ||||
| --- # websocket | ||||
| websocket: | ||||
|   # 如果关闭 需要和前端开关一起关闭 | ||||
|   enabled: false | ||||
|   # 路径 | ||||
|   path: /resource/websocket | ||||
|   # 设置访问源地址 | ||||
|   allowedOrigins: '*' | ||||
|  | ||||
| --- # warm-flow工作流配置 | ||||
| warm-flow: | ||||
|   # 是否开启工作流,默认true | ||||
|   enabled: true | ||||
|   # 是否开启设计器ui | ||||
|   ui: true | ||||
|   # 默认Authorization,如果有多个token,用逗号分隔 | ||||
|   token-name: ${sa-token.token-name},clientid | ||||
|   # 流程状态对应的三元色 | ||||
|   chart-status-color: | ||||
|     ## 未办理 | ||||
|     - 62,62,62 | ||||
|     ## 待办理 | ||||
|     - 255,205,23 | ||||
|     ## 已办理 | ||||
|     - 157,255,0 | ||||
| --- # 定时任务配置 | ||||
| spring: | ||||
|   quartz: | ||||
|     scheduler-name: RuoyiScheduler | ||||
|     startup-delay: 1s | ||||
|     overwrite-existing-jobs: true | ||||
|     auto-startup: true | ||||
|     job-store-type: jdbc | ||||
|     properties: | ||||
|       org: | ||||
|         quartz: | ||||
|           # Scheduler 相关配置 | ||||
|           scheduler: | ||||
|             instanceName: RuoyiScheduler | ||||
|             instanceId: AUTO | ||||
|           # 线程池相关配置 | ||||
|           threadPool: | ||||
|             class: org.quartz.simpl.SimpleThreadPool | ||||
|             threadCount: 20 | ||||
|             threadPriority: 5 | ||||
|           # JobStore 集群配置 | ||||
|           jobStore: | ||||
|             class: org.quartz.impl.jdbcjobstore.JobStoreTX | ||||
|             isClustered: true | ||||
|             clusterCheckinInterval: 15000 | ||||
|             txIsolationLevelSerializable: true | ||||
|             misfireThreshold: 60000 | ||||
|             tablePrefix: QRTZ_ | ||||
|             # sqlserver 启用 | ||||
|             # selectWithLockSQL: SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ? | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| Application Version: ${revision} | ||||
| Application Version: ${ruoyi-vue-plus.version} | ||||
| Spring Boot Version: ${spring-boot.version} | ||||
| __________            _____.___.__         ____   ____                     __________.__ | ||||
| \______   \__ __  ____\__  |   |__|        \   \ /   /_ __   ____          \______   \  |  __ __  ______ | ||||
|   | ||||
| @@ -2,36 +2,24 @@ | ||||
| not.null=* 必须填写 | ||||
| user.jcaptcha.error=验证码错误 | ||||
| user.jcaptcha.expire=验证码已失效 | ||||
| user.not.exists=对不起, 您的账号:{0} 不存在. | ||||
| user.not.exists=用户不存在/密码错误 | ||||
| user.password.not.match=用户不存在/密码错误 | ||||
| user.password.retry.limit.count=密码输入错误{0}次 | ||||
| user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 | ||||
| user.password.delete=对不起,您的账号:{0} 已被删除 | ||||
| user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 | ||||
| user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 | ||||
| user.password.delete=对不起,您的账号已被删除 | ||||
| user.blocked=用户已封禁,请联系管理员 | ||||
| role.blocked=角色已封禁,请联系管理员 | ||||
| user.logout.success=退出成功 | ||||
| length.not.valid=长度必须在{min}到{max}个字符之间 | ||||
| user.username.not.blank=用户名不能为空 | ||||
| user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 | ||||
| user.username.length.valid=账户长度必须在{min}到{max}个字符之间 | ||||
| user.password.not.blank=用户密码不能为空 | ||||
| user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 | ||||
| user.password.not.valid=* 5-50个字符 | ||||
| user.email.not.valid=邮箱格式错误 | ||||
| user.email.not.blank=邮箱不能为空 | ||||
| user.phonenumber.not.blank=用户手机号不能为空 | ||||
| user.mobile.phone.number.not.valid=手机号格式错误 | ||||
| user.login.success=登录成功 | ||||
| user.register.success=注册成功 | ||||
| user.register.save.error=保存用户 {0} 失败,注册账号已存在 | ||||
| user.register.error=注册失败,请联系系统管理人员 | ||||
| user.notfound=请重新登录 | ||||
| user.forcelogout=管理员强制退出,请重新登录 | ||||
| user.unknown.error=未知错误,请重新登录 | ||||
| auth.grant.type.error=认证权限类型错误 | ||||
| auth.grant.type.blocked=认证权限类型已禁用 | ||||
| auth.grant.type.not.blank=认证权限类型不能为空 | ||||
| auth.clientid.not.blank=认证客户端id不能为空 | ||||
| ##文件上传消息 | ||||
| upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB! | ||||
| upload.filename.exceed.length=上传的文件名最长{0}个字符 | ||||
| @@ -42,20 +30,3 @@ no.update.permission=您没有修改数据的权限,请联系管理员添加 | ||||
| no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] | ||||
| no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] | ||||
| no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] | ||||
| repeat.submit.message=不允许重复提交,请稍候再试 | ||||
| rate.limiter.message=访问过于频繁,请稍候再试 | ||||
| sms.code.not.blank=短信验证码不能为空 | ||||
| sms.code.retry.limit.count=短信验证码输入错误{0}次 | ||||
| sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 | ||||
| email.code.not.blank=邮箱验证码不能为空 | ||||
| email.code.retry.limit.count=邮箱验证码输入错误{0}次 | ||||
| email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 | ||||
| xcx.code.not.blank=小程序[code]不能为空 | ||||
| social.source.not.blank=第三方登录平台[source]不能为空 | ||||
| social.code.not.blank=第三方登录平台[code]不能为空 | ||||
| social.state.not.blank=第三方登录平台[state]不能为空 | ||||
| ##租户 | ||||
| tenant.number.not.blank=租户编号不能为空 | ||||
| tenant.not.exists=对不起, 您的租户不存在,请联系管理员 | ||||
| tenant.blocked=对不起,您的租户已禁用,请联系管理员 | ||||
| tenant.expired=对不起,您的租户已过期,请联系管理员 | ||||
|   | ||||
| @@ -2,36 +2,24 @@ | ||||
| not.null=* Required fill in | ||||
| user.jcaptcha.error=Captcha error | ||||
| user.jcaptcha.expire=Captcha invalid | ||||
| user.not.exists=Sorry, your account: {0} does not exist | ||||
| user.not.exists=User does not exist/Password error | ||||
| user.password.not.match=User does not exist/Password error | ||||
| user.password.retry.limit.count=Password input error {0} times | ||||
| user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes | ||||
| user.password.delete=Sorry, your account:{0} has been deleted | ||||
| user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator | ||||
| user.password.retry.limit.exceed=Password input error {0} times, account locked for 10 minutes | ||||
| user.password.delete=Sorry, your account has been deleted | ||||
| user.blocked=User disabled,please contact administrators | ||||
| role.blocked=Role disabled,please contact administrators | ||||
| user.logout.success=Exit successful | ||||
| length.not.valid=The length must be between {min} and {max} characters | ||||
| user.username.not.blank=Username cannot be blank | ||||
| user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number | ||||
| user.username.length.valid=Account length must be between {min} and {max} characters | ||||
| user.password.not.blank=Password cannot be empty | ||||
| user.password.length.valid=Password length must be between {min} and {max} characters | ||||
| user.password.not.valid=* 5-50 characters | ||||
| user.email.not.valid=Mailbox format error | ||||
| user.email.not.blank=Mailbox cannot be blank | ||||
| user.phonenumber.not.blank=Phone number cannot be blank | ||||
| user.mobile.phone.number.not.valid=Phone number format error | ||||
| user.login.success=Login successful | ||||
| user.register.success=Register successful | ||||
| user.register.save.error=Failed to save user {0}, The registered account already exists | ||||
| user.register.error=Register failed, please contact system administrator | ||||
| user.notfound=Please login again | ||||
| user.forcelogout=The administrator is forced to exit,please login again | ||||
| user.unknown.error=Unknown error, please login again | ||||
| auth.grant.type.error=Auth grant type error | ||||
| auth.grant.type.blocked=Auth grant type disabled | ||||
| auth.grant.type.not.blank=Auth grant type cannot be blank | ||||
| auth.clientid.not.blank=Auth clientid cannot be blank | ||||
| ##文件上传消息 | ||||
| upload.exceed.maxSize=The uploaded file size exceeds the limit file size!<br/>the maximum allowed file size is:{0}MB! | ||||
| upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters | ||||
| @@ -42,20 +30,3 @@ no.update.permission=You do not have permission to modify data,please contact | ||||
| no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] | ||||
| no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] | ||||
| no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] | ||||
| repeat.submit.message=Repeat submit is not allowed, please try again later | ||||
| rate.limiter.message=Visit too frequently, please try again later | ||||
| sms.code.not.blank=Sms code cannot be blank | ||||
| sms.code.retry.limit.count=Sms code input error {0} times | ||||
| sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes | ||||
| email.code.not.blank=Email code cannot be blank | ||||
| email.code.retry.limit.count=Email code input error {0} times | ||||
| email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes | ||||
| xcx.code.not.blank=Mini program [code] cannot be blank | ||||
| social.source.not.blank=Social login platform [source] cannot be blank | ||||
| social.code.not.blank=Social login platform [code] cannot be blank | ||||
| social.state.not.blank=Social login platform [state] cannot be blank | ||||
| ##租户 | ||||
| tenant.number.not.blank=Tenant number cannot be blank | ||||
| tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator | ||||
| tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator | ||||
| tenant.expired=Sorry, your tenant has expired. Please contact the administrator. | ||||
|   | ||||
| @@ -2,36 +2,24 @@ | ||||
| not.null=* 必须填写 | ||||
| user.jcaptcha.error=验证码错误 | ||||
| user.jcaptcha.expire=验证码已失效 | ||||
| user.not.exists=对不起, 您的账号:{0} 不存在. | ||||
| user.not.exists=用户不存在/密码错误 | ||||
| user.password.not.match=用户不存在/密码错误 | ||||
| user.password.retry.limit.count=密码输入错误{0}次 | ||||
| user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 | ||||
| user.password.delete=对不起,您的账号:{0} 已被删除 | ||||
| user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 | ||||
| user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 | ||||
| user.password.delete=对不起,您的账号已被删除 | ||||
| user.blocked=用户已封禁,请联系管理员 | ||||
| role.blocked=角色已封禁,请联系管理员 | ||||
| user.logout.success=退出成功 | ||||
| length.not.valid=长度必须在{min}到{max}个字符之间 | ||||
| user.username.not.blank=用户名不能为空 | ||||
| user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 | ||||
| user.username.length.valid=账户长度必须在{min}到{max}个字符之间 | ||||
| user.password.not.blank=用户密码不能为空 | ||||
| user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 | ||||
| user.password.not.valid=* 5-50个字符 | ||||
| user.email.not.valid=邮箱格式错误 | ||||
| user.email.not.blank=邮箱不能为空 | ||||
| user.phonenumber.not.blank=用户手机号不能为空 | ||||
| user.mobile.phone.number.not.valid=手机号格式错误 | ||||
| user.login.success=登录成功 | ||||
| user.register.success=注册成功 | ||||
| user.register.save.error=保存用户 {0} 失败,注册账号已存在 | ||||
| user.register.error=注册失败,请联系系统管理人员 | ||||
| user.notfound=请重新登录 | ||||
| user.forcelogout=管理员强制退出,请重新登录 | ||||
| user.unknown.error=未知错误,请重新登录 | ||||
| auth.grant.type.error=认证权限类型错误 | ||||
| auth.grant.type.blocked=认证权限类型已禁用 | ||||
| auth.grant.type.not.blank=认证权限类型不能为空 | ||||
| auth.clientid.not.blank=认证客户端id不能为空 | ||||
| ##文件上传消息 | ||||
| upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB! | ||||
| upload.filename.exceed.length=上传的文件名最长{0}个字符 | ||||
| @@ -42,20 +30,3 @@ no.update.permission=您没有修改数据的权限,请联系管理员添加 | ||||
| no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] | ||||
| no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] | ||||
| no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] | ||||
| repeat.submit.message=不允许重复提交,请稍候再试 | ||||
| rate.limiter.message=访问过于频繁,请稍候再试 | ||||
| sms.code.not.blank=短信验证码不能为空 | ||||
| sms.code.retry.limit.count=短信验证码输入错误{0}次 | ||||
| sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 | ||||
| email.code.not.blank=邮箱验证码不能为空 | ||||
| email.code.retry.limit.count=邮箱验证码输入错误{0}次 | ||||
| email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 | ||||
| xcx.code.not.blank=小程序[code]不能为空 | ||||
| social.source.not.blank=第三方登录平台[source]不能为空 | ||||
| social.code.not.blank=第三方登录平台[code]不能为空 | ||||
| social.state.not.blank=第三方登录平台[state]不能为空 | ||||
| ##租户 | ||||
| tenant.number.not.blank=租户编号不能为空 | ||||
| tenant.not.exists=对不起, 您的租户不存在,请联系管理员 | ||||
| tenant.blocked=对不起,您的租户已禁用,请联系管理员 | ||||
| tenant.expired=对不起,您的租户已过期,请联系管理员 | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,129 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <configuration> | ||||
|     <property name="log.path" value="./logs"/> | ||||
|     <property name="console.log.pattern" | ||||
|               value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/> | ||||
|     <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/> | ||||
|  | ||||
|     <!-- 控制台输出 --> | ||||
|     <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> | ||||
|         <encoder> | ||||
|             <pattern>${console.log.pattern}</pattern> | ||||
|             <charset>utf-8</charset> | ||||
|         </encoder> | ||||
|     </appender> | ||||
|  | ||||
|     <!-- 控制台输出 --> | ||||
|     <appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
|         <file>${log.path}/sys-console.log</file> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 日志文件名格式 --> | ||||
|             <fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
|             <!-- 日志最大 1天 --> | ||||
|             <maxHistory>1</maxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder> | ||||
|             <pattern>${log.pattern}</pattern> | ||||
|             <charset>utf-8</charset> | ||||
|         </encoder> | ||||
|         <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | ||||
|             <!-- 过滤的级别 --> | ||||
|             <level>INFO</level> | ||||
|         </filter> | ||||
|     </appender> | ||||
|  | ||||
|     <!-- 系统日志输出 --> | ||||
|     <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
|         <file>${log.path}/sys-info.log</file> | ||||
|         <!-- 循环政策:基于时间创建日志文件 --> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 日志文件名格式 --> | ||||
|             <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
|             <!-- 日志最大的历史 60天 --> | ||||
|             <maxHistory>60</maxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder> | ||||
|             <pattern>${log.pattern}</pattern> | ||||
|         </encoder> | ||||
|         <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||||
|             <!-- 过滤的级别 --> | ||||
|             <level>INFO</level> | ||||
|             <!-- 匹配时的操作:接收(记录) --> | ||||
|             <onMatch>ACCEPT</onMatch> | ||||
|             <!-- 不匹配时的操作:拒绝(不记录) --> | ||||
|             <onMismatch>DENY</onMismatch> | ||||
|         </filter> | ||||
|     </appender> | ||||
|  | ||||
|     <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
|         <file>${log.path}/sys-error.log</file> | ||||
|         <!-- 循环政策:基于时间创建日志文件 --> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 日志文件名格式 --> | ||||
|             <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
|             <!-- 日志最大的历史 60天 --> | ||||
|             <maxHistory>60</maxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder> | ||||
|             <pattern>${log.pattern}</pattern> | ||||
|         </encoder> | ||||
|         <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||||
|             <!-- 过滤的级别 --> | ||||
|             <level>ERROR</level> | ||||
|             <!-- 匹配时的操作:接收(记录) --> | ||||
|             <onMatch>ACCEPT</onMatch> | ||||
|             <!-- 不匹配时的操作:拒绝(不记录) --> | ||||
|             <onMismatch>DENY</onMismatch> | ||||
|         </filter> | ||||
|     </appender> | ||||
|  | ||||
|     <!-- info异步输出 --> | ||||
|     <appender name="async_info" class="ch.qos.logback.classic.AsyncAppender"> | ||||
|         <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> | ||||
|         <discardingThreshold>0</discardingThreshold> | ||||
|         <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> | ||||
|         <queueSize>512</queueSize> | ||||
|         <!-- 添加附加的appender,最多只能添加一个 --> | ||||
|         <appender-ref ref="file_info"/> | ||||
|     </appender> | ||||
|  | ||||
|     <!-- error异步输出 --> | ||||
|     <appender name="async_error" class="ch.qos.logback.classic.AsyncAppender"> | ||||
|         <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> | ||||
|         <discardingThreshold>0</discardingThreshold> | ||||
|         <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> | ||||
|         <queueSize>512</queueSize> | ||||
|         <!-- 添加附加的appender,最多只能添加一个 --> | ||||
|         <appender-ref ref="file_error"/> | ||||
|     </appender> | ||||
|  | ||||
|     <!-- 整合 skywalking 控制台输出 tid --> | ||||
| <!--    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">--> | ||||
| <!--        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">--> | ||||
| <!--            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">--> | ||||
| <!--                <pattern>[%tid] ${console.log.pattern}</pattern>--> | ||||
| <!--            </layout>--> | ||||
| <!--            <charset>utf-8</charset>--> | ||||
| <!--        </encoder>--> | ||||
| <!--    </appender>--> | ||||
|  | ||||
|     <!-- 整合 skywalking 推送采集日志 --> | ||||
| <!--    <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">--> | ||||
| <!--        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">--> | ||||
| <!--            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">--> | ||||
| <!--                <pattern>[%tid] ${console.log.pattern}</pattern>--> | ||||
| <!--            </layout>--> | ||||
| <!--            <charset>utf-8</charset>--> | ||||
| <!--        </encoder>--> | ||||
| <!--    </appender>--> | ||||
|  | ||||
|     <!--系统操作日志--> | ||||
|     <root level="info"> | ||||
|         <appender-ref ref="console" /> | ||||
|         <appender-ref ref="async_info" /> | ||||
|         <appender-ref ref="async_error" /> | ||||
|         <appender-ref ref="file_console" /> | ||||
| <!--        <appender-ref ref="sky_log"/>--> | ||||
|     </root> | ||||
|  | ||||
| </configuration> | ||||
							
								
								
									
										114
									
								
								ruoyi-admin/src/main/resources/logback.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								ruoyi-admin/src/main/resources/logback.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <configuration> | ||||
|     <property name="log.path" value="./logs"/> | ||||
|     <property name="console.log.pattern" | ||||
|               value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/> | ||||
|     <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/> | ||||
|  | ||||
| 	<!-- 控制台输出 --> | ||||
| 	<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> | ||||
|         <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"> | ||||
| 			<pattern>${console.log.pattern}</pattern> | ||||
|             <charset>utf-8</charset> | ||||
| 		</encoder> | ||||
| 	</appender> | ||||
|  | ||||
|     <!-- 控制台输出 --> | ||||
|     <appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
|         <file>${log.path}/sys-console.log</file> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 日志文件名格式 --> | ||||
|             <fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
|             <!-- 日志最大 1天 --> | ||||
|             <maxHistory>1</maxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"> | ||||
|             <pattern>${log.pattern}</pattern> | ||||
|             <charset>utf-8</charset> | ||||
|         </encoder> | ||||
|         <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | ||||
|             <!-- 过滤的级别 --> | ||||
|             <level>INFO</level> | ||||
|         </filter> | ||||
|     </appender> | ||||
| 	 | ||||
| 	<!-- 系统日志输出 --> | ||||
| 	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
| 	    <file>${log.path}/sys-info.log</file> | ||||
|         <!-- 循环政策:基于时间创建日志文件 --> | ||||
| 		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 日志文件名格式 --> | ||||
| 			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
| 			<!-- 日志最大的历史 60天 --> | ||||
| 			<maxHistory>60</maxHistory> | ||||
| 		</rollingPolicy> | ||||
|         <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"> | ||||
| 			<pattern>${log.pattern}</pattern> | ||||
| 		</encoder> | ||||
| 		<filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||||
|             <!-- 过滤的级别 --> | ||||
|             <level>INFO</level> | ||||
|             <!-- 匹配时的操作:接收(记录) --> | ||||
|             <onMatch>ACCEPT</onMatch> | ||||
|             <!-- 不匹配时的操作:拒绝(不记录) --> | ||||
|             <onMismatch>DENY</onMismatch> | ||||
|         </filter> | ||||
| 	</appender> | ||||
| 	 | ||||
| 	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
| 	    <file>${log.path}/sys-error.log</file> | ||||
|         <!-- 循环政策:基于时间创建日志文件 --> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 日志文件名格式 --> | ||||
|             <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
| 			<!-- 日志最大的历史 60天 --> | ||||
| 			<maxHistory>60</maxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"> | ||||
|             <pattern>${log.pattern}</pattern> | ||||
|         </encoder> | ||||
|         <filter class="ch.qos.logback.classic.filter.LevelFilter"> | ||||
|             <!-- 过滤的级别 --> | ||||
|             <level>ERROR</level> | ||||
| 			<!-- 匹配时的操作:接收(记录) --> | ||||
|             <onMatch>ACCEPT</onMatch> | ||||
| 			<!-- 不匹配时的操作:拒绝(不记录) --> | ||||
|             <onMismatch>DENY</onMismatch> | ||||
|         </filter> | ||||
|     </appender> | ||||
| 	 | ||||
| 	<!-- 用户访问日志输出  --> | ||||
|     <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
| 		<file>${log.path}/sys-user.log</file> | ||||
|         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | ||||
|             <!-- 按天回滚 daily --> | ||||
|             <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern> | ||||
|             <!-- 日志最大的历史 60天 --> | ||||
|             <maxHistory>60</maxHistory> | ||||
|         </rollingPolicy> | ||||
|         <encoder class="com.yomahub.tlog.core.enhance.logback.AspectLogbackEncoder"> | ||||
|             <pattern>${log.pattern}</pattern> | ||||
|         </encoder> | ||||
|     </appender> | ||||
| 	 | ||||
| 	<!-- 系统模块日志级别控制  --> | ||||
| 	<logger name="com.ruoyi" level="info" /> | ||||
| 	<!-- Spring日志级别控制  --> | ||||
| 	<logger name="org.springframework" level="warn" /> | ||||
|  | ||||
| 	<root level="info"> | ||||
| 		<appender-ref ref="console" /> | ||||
| 	</root> | ||||
| 	 | ||||
| 	<!--系统操作日志--> | ||||
|     <root level="info"> | ||||
|         <appender-ref ref="file_info" /> | ||||
|         <appender-ref ref="file_error" /> | ||||
|         <appender-ref ref="file_console" /> | ||||
|     </root> | ||||
| 	 | ||||
| 	<!--系统用户操作日志--> | ||||
|     <logger name="sys-user" level="info"> | ||||
|         <appender-ref ref="sys-user"/> | ||||
|     </logger> | ||||
| </configuration>  | ||||
| @@ -6,15 +6,21 @@ logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger | ||||
| appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger | ||||
| # 使用日志系统记录 sql | ||||
| #appender=com.p6spy.engine.spy.appender.Slf4JLogger | ||||
| # 设置 p6spy driver 代理 | ||||
| #deregisterdrivers=true | ||||
| # 取消JDBC URL前缀 | ||||
| useprefix=true | ||||
| # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. | ||||
| excludecategories=info,debug,result,commit,resultset | ||||
| # 日期格式 | ||||
| dateformat=yyyy-MM-dd HH:mm:ss | ||||
| # SQL语句打印时间格式 | ||||
| databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss | ||||
| # 实际驱动可多个 | ||||
| #driverlist=org.h2.Driver | ||||
| # 是否开启慢SQL记录 | ||||
| outagedetection=true | ||||
| # 慢SQL记录标准 2 秒 | ||||
| outagedetectioninterval=2 | ||||
| # 是否过滤 Log | ||||
| filter=true | ||||
| # 过滤 Log 时所排除的 sql 关键字,以逗号分隔 | ||||
| exclude= | ||||
| # 过滤 Log 时所排除的表名列表,以逗号分隔 | ||||
| exclude=QRTZ_ | ||||
| @@ -1,45 +0,0 @@ | ||||
| package org.dromara.test; | ||||
|  | ||||
| import org.junit.jupiter.api.Assertions; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.api.Test; | ||||
|  | ||||
| /** | ||||
|  * 断言单元测试案例 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @DisplayName("断言单元测试案例") | ||||
| public class AssertUnitTest { | ||||
|  | ||||
|     @DisplayName("测试 assertEquals 方法") | ||||
|     @Test | ||||
|     public void testAssertEquals() { | ||||
|         Assertions.assertEquals("666", new String("666")); | ||||
|         Assertions.assertNotEquals("666", new String("666")); | ||||
|     } | ||||
|  | ||||
|     @DisplayName("测试 assertSame 方法") | ||||
|     @Test | ||||
|     public void testAssertSame() { | ||||
|         Object obj = new Object(); | ||||
|         Object obj1 = obj; | ||||
|         Assertions.assertSame(obj, obj1); | ||||
|         Assertions.assertNotSame(obj, obj1); | ||||
|     } | ||||
|  | ||||
|     @DisplayName("测试 assertTrue 方法") | ||||
|     @Test | ||||
|     public void testAssertTrue() { | ||||
|         Assertions.assertTrue(true); | ||||
|         Assertions.assertFalse(true); | ||||
|     } | ||||
|  | ||||
|     @DisplayName("测试 assertNull 方法") | ||||
|     @Test | ||||
|     public void testAssertNull() { | ||||
|         Assertions.assertNull(null); | ||||
|         Assertions.assertNotNull(null); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| package org.dromara.test; | ||||
|  | ||||
| import org.dromara.common.web.config.properties.CaptchaProperties; | ||||
| import org.junit.jupiter.api.*; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.boot.test.context.SpringBootTest; | ||||
|  | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|  * 单元测试案例 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件 | ||||
| @DisplayName("单元测试案例") | ||||
| public class DemoUnitTest { | ||||
|  | ||||
|     @Autowired | ||||
|     private CaptchaProperties captchaProperties; | ||||
|  | ||||
|     @DisplayName("测试 @SpringBootTest @Test @DisplayName 注解") | ||||
|     @Test | ||||
|     public void testTest() { | ||||
|         System.out.println(captchaProperties); | ||||
|     } | ||||
|  | ||||
|     @Disabled | ||||
|     @DisplayName("测试 @Disabled 注解") | ||||
|     @Test | ||||
|     public void testDisabled() { | ||||
|         System.out.println(captchaProperties); | ||||
|     } | ||||
|  | ||||
|     @Timeout(value = 2L, unit = TimeUnit.SECONDS) | ||||
|     @DisplayName("测试 @Timeout 注解") | ||||
|     @Test | ||||
|     public void testTimeout() throws InterruptedException { | ||||
|         Thread.sleep(3000); | ||||
|         System.out.println(captchaProperties); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @DisplayName("测试 @RepeatedTest 注解") | ||||
|     @RepeatedTest(3) | ||||
|     public void testRepeatedTest() { | ||||
|         System.out.println(666); | ||||
|     } | ||||
|  | ||||
|     @BeforeAll | ||||
|     public static void testBeforeAll() { | ||||
|         System.out.println("@BeforeAll =================="); | ||||
|     } | ||||
|  | ||||
|     @BeforeEach | ||||
|     public void testBeforeEach() { | ||||
|         System.out.println("@BeforeEach =================="); | ||||
|     } | ||||
|  | ||||
|     @AfterEach | ||||
|     public void testAfterEach() { | ||||
|         System.out.println("@AfterEach =================="); | ||||
|     } | ||||
|  | ||||
|     @AfterAll | ||||
|     public static void testAfterAll() { | ||||
|         System.out.println("@AfterAll =================="); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| package org.dromara.test; | ||||
|  | ||||
| import org.dromara.common.core.enums.UserType; | ||||
| import org.junit.jupiter.api.AfterEach; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.params.ParameterizedTest; | ||||
| import org.junit.jupiter.params.provider.EnumSource; | ||||
| import org.junit.jupiter.params.provider.MethodSource; | ||||
| import org.junit.jupiter.params.provider.NullSource; | ||||
| import org.junit.jupiter.params.provider.ValueSource; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.stream.Stream; | ||||
|  | ||||
| /** | ||||
|  * 带参数单元测试案例 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @DisplayName("带参数单元测试案例") | ||||
| public class ParamUnitTest { | ||||
|  | ||||
|     @DisplayName("测试 @ValueSource 注解") | ||||
|     @ParameterizedTest | ||||
|     @ValueSource(strings = {"t1", "t2", "t3"}) | ||||
|     public void testValueSource(String str) { | ||||
|         System.out.println(str); | ||||
|     } | ||||
|  | ||||
|     @DisplayName("测试 @NullSource 注解") | ||||
|     @ParameterizedTest | ||||
|     @NullSource | ||||
|     public void testNullSource(String str) { | ||||
|         System.out.println(str); | ||||
|     } | ||||
|  | ||||
|     @DisplayName("测试 @EnumSource 注解") | ||||
|     @ParameterizedTest | ||||
|     @EnumSource(UserType.class) | ||||
|     public void testEnumSource(UserType type) { | ||||
|         System.out.println(type.getUserType()); | ||||
|     } | ||||
|  | ||||
|     @DisplayName("测试 @MethodSource 注解") | ||||
|     @ParameterizedTest | ||||
|     @MethodSource("getParam") | ||||
|     public void testMethodSource(String str) { | ||||
|         System.out.println(str); | ||||
|     } | ||||
|  | ||||
|     public static Stream<String> getParam() { | ||||
|         List<String> list = new ArrayList<>(); | ||||
|         list.add("t1"); | ||||
|         list.add("t2"); | ||||
|         list.add("t3"); | ||||
|         return list.stream(); | ||||
|     } | ||||
|  | ||||
|     @BeforeEach | ||||
|     public void testBeforeEach() { | ||||
|         System.out.println("@BeforeEach =================="); | ||||
|     } | ||||
|  | ||||
|     @AfterEach | ||||
|     public void testAfterEach() { | ||||
|         System.out.println("@AfterEach =================="); | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,54 +0,0 @@ | ||||
| package org.dromara.test; | ||||
|  | ||||
| import org.junit.jupiter.api.*; | ||||
| import org.springframework.boot.test.context.SpringBootTest; | ||||
|  | ||||
| /** | ||||
|  * 标签单元测试案例 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @SpringBootTest | ||||
| @DisplayName("标签单元测试案例") | ||||
| public class TagUnitTest { | ||||
|  | ||||
|     @Tag("dev") | ||||
|     @DisplayName("测试 @Tag dev") | ||||
|     @Test | ||||
|     public void testTagDev() { | ||||
|         System.out.println("dev"); | ||||
|     } | ||||
|  | ||||
|     @Tag("prod") | ||||
|     @DisplayName("测试 @Tag prod") | ||||
|     @Test | ||||
|     public void testTagProd() { | ||||
|         System.out.println("prod"); | ||||
|     } | ||||
|  | ||||
|     @Tag("local") | ||||
|     @DisplayName("测试 @Tag local") | ||||
|     @Test | ||||
|     public void testTagLocal() { | ||||
|         System.out.println("local"); | ||||
|     } | ||||
|  | ||||
|     @Tag("exclude") | ||||
|     @DisplayName("测试 @Tag exclude") | ||||
|     @Test | ||||
|     public void testTagExclude() { | ||||
|         System.out.println("exclude"); | ||||
|     } | ||||
|  | ||||
|     @BeforeEach | ||||
|     public void testBeforeEach() { | ||||
|         System.out.println("@BeforeEach =================="); | ||||
|     } | ||||
|  | ||||
|     @AfterEach | ||||
|     public void testAfterEach() { | ||||
|         System.out.println("@AfterEach =================="); | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1 +0,0 @@ | ||||
| 3f2ee348-0303-40ca-bf03-03f48d2d2141 | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,4 +0,0 @@ | ||||
| 3 | ||||
| SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1 | ||||
| SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1 | ||||
| SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r | ||||
| @@ -1,4 +0,0 @@ | ||||
| 3 | ||||
| SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1 | ||||
| SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1 | ||||
| SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r | ||||
| @@ -4,43 +4,181 @@ | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <parent> | ||||
|         <artifactId>ruoyi-vue-plus</artifactId> | ||||
|         <groupId>org.dromara</groupId> | ||||
|         <version>${revision}</version> | ||||
|         <groupId>com.ruoyi</groupId> | ||||
|         <version>3.3.0</version> | ||||
|     </parent> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <modules> | ||||
|         <module>ruoyi-common-bom</module> | ||||
|         <module>ruoyi-common-social</module> | ||||
|         <module>ruoyi-common-core</module> | ||||
|         <module>ruoyi-common-doc</module> | ||||
|         <module>ruoyi-common-excel</module> | ||||
|         <module>ruoyi-common-idempotent</module> | ||||
|         <module>ruoyi-common-job</module> | ||||
|         <module>ruoyi-common-log</module> | ||||
|         <module>ruoyi-common-mail</module> | ||||
|         <module>ruoyi-common-mybatis</module> | ||||
|         <module>ruoyi-common-oss</module> | ||||
|         <module>ruoyi-common-ratelimiter</module> | ||||
|         <module>ruoyi-common-redis</module> | ||||
|         <module>ruoyi-common-satoken</module> | ||||
|         <module>ruoyi-common-security</module> | ||||
|         <module>ruoyi-common-sms</module> | ||||
|         <module>ruoyi-common-web</module> | ||||
|         <module>ruoyi-common-translation</module> | ||||
|         <module>ruoyi-common-sensitive</module> | ||||
|         <module>ruoyi-common-json</module> | ||||
|         <module>ruoyi-common-encrypt</module> | ||||
|         <module>ruoyi-common-tenant</module> | ||||
|         <module>ruoyi-common-websocket</module> | ||||
|         <module>ruoyi-common-sse</module> | ||||
|     </modules> | ||||
|  | ||||
|     <artifactId>ruoyi-common</artifactId> | ||||
|     <packaging>pom</packaging> | ||||
|  | ||||
|     <description> | ||||
|         common 通用模块 | ||||
|         common通用工具 | ||||
|     </description> | ||||
|  | ||||
|     <dependencies> | ||||
|  | ||||
|         <!-- Spring框架基本的核心工具 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework</groupId> | ||||
|             <artifactId>spring-context-support</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- SpringWeb模块 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework</groupId> | ||||
|             <artifactId>spring-web</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- spring security 安全认证 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-security</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 自定义验证注解 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-validation</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--常用工具类 --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.commons</groupId> | ||||
|             <artifactId>commons-lang3</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- JSON工具类 --> | ||||
|         <dependency> | ||||
|             <groupId>com.fasterxml.jackson.core</groupId> | ||||
|             <artifactId>jackson-databind</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- excel工具 --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.poi</groupId> | ||||
|             <artifactId>poi-ooxml</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.alibaba</groupId> | ||||
|             <artifactId>easyexcel</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- yml解析器 --> | ||||
|         <dependency> | ||||
|             <groupId>org.yaml</groupId> | ||||
|             <artifactId>snakeyaml</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Token生成与解析--> | ||||
|         <dependency> | ||||
|             <groupId>io.jsonwebtoken</groupId> | ||||
|             <artifactId>jjwt</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- jdk11 缺失依赖 jaxb--> | ||||
|         <dependency> | ||||
|             <groupId>com.sun.xml.bind</groupId> | ||||
|             <artifactId>jaxb-impl</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- redis 缓存操作 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-data-redis</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- pool 对象池 --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.commons</groupId> | ||||
|             <artifactId>commons-pool2</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- servlet包 --> | ||||
|         <dependency> | ||||
|             <groupId>javax.servlet</groupId> | ||||
|             <artifactId>javax.servlet-api</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.baomidou</groupId> | ||||
|             <artifactId>mybatis-plus-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.baomidou</groupId> | ||||
|             <artifactId>mybatis-plus-extension</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>cn.hutool</groupId> | ||||
|             <artifactId>hutool-all</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.projectlombok</groupId> | ||||
|             <artifactId>lombok</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- @deprecated 由于使用人数较少 决定与 3.4.0 版本移除 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.cloud</groupId> | ||||
|             <artifactId>spring-cloud-starter-openfeign</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- @deprecated 由于使用人数较少 决定与 3.4.0 版本移除 --> | ||||
|         <dependency> | ||||
|             <groupId>io.github.openfeign</groupId> | ||||
|             <artifactId>feign-okhttp</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>de.codecentric</groupId> | ||||
|             <artifactId>spring-boot-admin-starter-client</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.github.xiaoymin</groupId> | ||||
|             <artifactId>knife4j-spring-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>io.swagger</groupId> | ||||
|             <artifactId>swagger-annotations</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-actuator</artifactId> | ||||
|         </dependency> | ||||
|         <!--  自动生成YML配置关联JSON文件  --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-configuration-processor</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--redisson--> | ||||
|         <dependency> | ||||
|             <groupId>org.redisson</groupId> | ||||
|             <artifactId>redisson-spring-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.baomidou</groupId> | ||||
|             <artifactId>lock4j-redisson-spring-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.yomahub</groupId> | ||||
|             <artifactId>tlog-spring-boot-configuration</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.yomahub</groupId> | ||||
|             <artifactId>tlog-webroot</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>com.yomahub</groupId> | ||||
|             <artifactId>tlog-feign</artifactId> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|  | ||||
| </project> | ||||
|   | ||||
| @@ -1,185 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||
|          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <groupId>org.dromara</groupId> | ||||
|     <artifactId>ruoyi-common-bom</artifactId> | ||||
|     <version>${revision}</version> | ||||
|     <packaging>pom</packaging> | ||||
|  | ||||
|     <description> | ||||
|         ruoyi-common-bom common依赖项 | ||||
|     </description> | ||||
|  | ||||
|     <properties> | ||||
|         <revision>5.3.1</revision> | ||||
|     </properties> | ||||
|  | ||||
|     <dependencyManagement> | ||||
|         <dependencies> | ||||
|             <!-- 核心模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-core</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 接口模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-doc</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- excel --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-excel</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 幂等 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-idempotent</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 调度模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-job</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 日志记录 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-log</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 邮件服务 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-mail</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 数据库服务 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-mybatis</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- OSS --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-oss</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 限流 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-ratelimiter</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 缓存服务 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-redis</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- satoken --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-satoken</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 安全模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-security</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 短信模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-sms</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-social</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- web服务 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-web</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 翻译模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-translation</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 脱敏模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-sensitive</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 序列化模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-json</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 数据库加解密模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-encrypt</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 租户模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-tenant</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- WebSocket模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-websocket</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- SSE模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>org.dromara</groupId> | ||||
|                 <artifactId>ruoyi-common-sse</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|         </dependencies> | ||||
|     </dependencyManagement> | ||||
|  | ||||
| </project> | ||||
| @@ -1,99 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||
|          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <parent> | ||||
|         <groupId>org.dromara</groupId> | ||||
|         <artifactId>ruoyi-common</artifactId> | ||||
|         <version>${revision}</version> | ||||
|     </parent> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <artifactId>ruoyi-common-core</artifactId> | ||||
|  | ||||
|     <description> | ||||
|         ruoyi-common-core 核心模块 | ||||
|     </description> | ||||
|  | ||||
|     <dependencies> | ||||
|         <!-- Spring框架基本的核心工具 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework</groupId> | ||||
|             <artifactId>spring-context-support</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- SpringWeb模块 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework</groupId> | ||||
|             <artifactId>spring-web</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 自定义验证注解 --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-validation</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-aop</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--常用工具类 --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.commons</groupId> | ||||
|             <artifactId>commons-lang3</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- servlet包 --> | ||||
|         <dependency> | ||||
|             <groupId>jakarta.servlet</groupId> | ||||
|             <artifactId>jakarta.servlet-api</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>cn.hutool</groupId> | ||||
|             <artifactId>hutool-core</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>cn.hutool</groupId> | ||||
|             <artifactId>hutool-http</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>cn.hutool</groupId> | ||||
|             <artifactId>hutool-extra</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.projectlombok</groupId> | ||||
|             <artifactId>lombok</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!--  自动生成YML配置关联JSON文件  --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-configuration-processor</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-properties-migrator</artifactId> | ||||
|             <scope>runtime</scope> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>io.github.linpeilie</groupId> | ||||
|             <artifactId>mapstruct-plus-spring-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- 离线IP地址定位库 --> | ||||
|         <dependency> | ||||
|             <groupId>org.lionsoul</groupId> | ||||
|             <artifactId>ip2region</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|     </dependencies> | ||||
|  | ||||
| </project> | ||||
| @@ -1,17 +0,0 @@ | ||||
| package org.dromara.common.core.config; | ||||
|  | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
| import org.springframework.context.annotation.EnableAspectJAutoProxy; | ||||
| import org.springframework.scheduling.annotation.EnableAsync; | ||||
|  | ||||
| /** | ||||
|  * 程序注解配置 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @AutoConfiguration | ||||
| @EnableAspectJAutoProxy | ||||
| @EnableAsync(proxyTargetClass = true) | ||||
| public class ApplicationConfig { | ||||
|  | ||||
| } | ||||
| @@ -1,87 +0,0 @@ | ||||
| package org.dromara.common.core.config; | ||||
|  | ||||
| import jakarta.annotation.PreDestroy; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.apache.commons.lang3.concurrent.BasicThreadFactory; | ||||
| import org.dromara.common.core.config.properties.ThreadPoolProperties; | ||||
| import org.dromara.common.core.utils.SpringUtils; | ||||
| import org.dromara.common.core.utils.Threads; | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.core.task.VirtualThreadTaskExecutor; | ||||
| import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||||
|  | ||||
| import java.util.concurrent.ScheduledExecutorService; | ||||
| import java.util.concurrent.ScheduledThreadPoolExecutor; | ||||
| import java.util.concurrent.ThreadPoolExecutor; | ||||
|  | ||||
| /** | ||||
|  * 线程池配置 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  **/ | ||||
| @Slf4j | ||||
| @AutoConfiguration | ||||
| @EnableConfigurationProperties(ThreadPoolProperties.class) | ||||
| public class ThreadPoolConfig { | ||||
|  | ||||
|     /** | ||||
|      * 核心线程数 = cpu 核心数 + 1 | ||||
|      */ | ||||
|     private final int core = Runtime.getRuntime().availableProcessors() + 1; | ||||
|  | ||||
|     private ScheduledExecutorService scheduledExecutorService; | ||||
|  | ||||
|     @Bean(name = "threadPoolTaskExecutor") | ||||
|     @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") | ||||
|     public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) { | ||||
|         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||||
|         executor.setCorePoolSize(core); | ||||
|         executor.setMaxPoolSize(core * 2); | ||||
|         executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); | ||||
|         executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); | ||||
|         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); | ||||
|         return executor; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行周期性或定时任务 | ||||
|      */ | ||||
|     @Bean(name = "scheduledExecutorService") | ||||
|     protected ScheduledExecutorService scheduledExecutorService() { | ||||
|         // daemon 必须为 true | ||||
|         BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder().daemon(true); | ||||
|         if (SpringUtils.isVirtual()) { | ||||
|             builder.namingPattern("virtual-schedule-pool-%d").wrappedFactory(new VirtualThreadTaskExecutor().getVirtualThreadFactory()); | ||||
|         } else { | ||||
|             builder.namingPattern("schedule-pool-%d"); | ||||
|         } | ||||
|         ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core, | ||||
|             builder.build(), | ||||
|             new ThreadPoolExecutor.CallerRunsPolicy()) { | ||||
|             @Override | ||||
|             protected void afterExecute(Runnable r, Throwable t) { | ||||
|                 super.afterExecute(r, t); | ||||
|                 Threads.printException(r, t); | ||||
|             } | ||||
|         }; | ||||
|         this.scheduledExecutorService = scheduledThreadPoolExecutor; | ||||
|         return scheduledThreadPoolExecutor; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 销毁事件 | ||||
|      */ | ||||
|     @PreDestroy | ||||
|     public void destroy() { | ||||
|         try { | ||||
|             log.info("====关闭后台任务任务线程池===="); | ||||
|             Threads.shutdownAndAwaitTermination(scheduledExecutorService); | ||||
|         } catch (Exception e) { | ||||
|             log.error(e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| package org.dromara.common.core.config; | ||||
|  | ||||
| import jakarta.validation.Validator; | ||||
| import org.hibernate.validator.HibernateValidator; | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
| import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; | ||||
| import org.springframework.context.MessageSource; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; | ||||
|  | ||||
| import java.util.Properties; | ||||
|  | ||||
| /** | ||||
|  * 校验框架配置类 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @AutoConfiguration(before = ValidationAutoConfiguration.class) | ||||
| public class ValidatorConfig { | ||||
|  | ||||
|     /** | ||||
|      * 配置校验框架 快速失败模式 | ||||
|      */ | ||||
|     @Bean | ||||
|     public Validator validator(MessageSource messageSource) { | ||||
|         try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { | ||||
|             // 国际化 | ||||
|             factoryBean.setValidationMessageSource(messageSource); | ||||
|             // 设置使用 HibernateValidator 校验器 | ||||
|             factoryBean.setProviderClass(HibernateValidator.class); | ||||
|             Properties properties = new Properties(); | ||||
|             // 设置快速失败模式(fail-fast),即校验过程中一旦遇到失败,立即停止并返回错误 | ||||
|             properties.setProperty("hibernate.validator.fail_fast", "true"); | ||||
|             factoryBean.setValidationProperties(properties); | ||||
|             // 加载配置 | ||||
|             factoryBean.afterPropertiesSet(); | ||||
|             return factoryBean.getValidator(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,30 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 缓存的key 常量 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| public interface CacheConstants { | ||||
|  | ||||
|     /** | ||||
|      * 在线用户 redis key | ||||
|      */ | ||||
|     String ONLINE_TOKEN_KEY = "online_tokens:"; | ||||
|  | ||||
|     /** | ||||
|      * 参数管理 cache key | ||||
|      */ | ||||
|     String SYS_CONFIG_KEY = "sys_config:"; | ||||
|  | ||||
|     /** | ||||
|      * 字典管理 cache key | ||||
|      */ | ||||
|     String SYS_DICT_KEY = "sys_dict:"; | ||||
|  | ||||
|     /** | ||||
|      * 登录账户密码错误次数 redis key | ||||
|      */ | ||||
|     String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; | ||||
|  | ||||
| } | ||||
| @@ -1,89 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 缓存组名称常量 | ||||
|  * <p> | ||||
|  * key 格式为 cacheNames#ttl#maxIdleTime#maxSize#local | ||||
|  * <p> | ||||
|  * ttl 过期时间 如果设置为0则不过期 默认为0 | ||||
|  * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 | ||||
|  * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 | ||||
|  * local 默认开启本地缓存为1 关闭本地缓存为0 | ||||
|  * <p> | ||||
|  * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500、test#1h#0#500#0 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| public interface CacheNames { | ||||
|  | ||||
|     /** | ||||
|      * 演示案例 | ||||
|      */ | ||||
|     String DEMO_CACHE = "demo:cache#60s#10m#20"; | ||||
|  | ||||
|     /** | ||||
|      * 系统配置 | ||||
|      */ | ||||
|     String SYS_CONFIG = "sys_config"; | ||||
|  | ||||
|     /** | ||||
|      * 数据字典 | ||||
|      */ | ||||
|     String SYS_DICT = "sys_dict"; | ||||
|  | ||||
|     /** | ||||
|      * 数据字典类型 | ||||
|      */ | ||||
|     String SYS_DICT_TYPE = "sys_dict_type"; | ||||
|  | ||||
|     /** | ||||
|      * 租户 | ||||
|      */ | ||||
|     String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; | ||||
|  | ||||
|     /** | ||||
|      * 客户端 | ||||
|      */ | ||||
|     String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d"; | ||||
|  | ||||
|     /** | ||||
|      * 用户账户 | ||||
|      */ | ||||
|     String SYS_USER_NAME = "sys_user_name#30d"; | ||||
|  | ||||
|     /** | ||||
|      * 用户名称 | ||||
|      */ | ||||
|     String SYS_NICKNAME = "sys_nickname#30d"; | ||||
|  | ||||
|     /** | ||||
|      * 部门 | ||||
|      */ | ||||
|     String SYS_DEPT = "sys_dept#30d"; | ||||
|  | ||||
|     /** | ||||
|      * OSS内容 | ||||
|      */ | ||||
|     String SYS_OSS = "sys_oss#30d"; | ||||
|  | ||||
|     /** | ||||
|      * 角色自定义权限 | ||||
|      */ | ||||
|     String SYS_ROLE_CUSTOM = "sys_role_custom#30d"; | ||||
|  | ||||
|     /** | ||||
|      * 部门及以下权限 | ||||
|      */ | ||||
|     String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d"; | ||||
|  | ||||
|     /** | ||||
|      * OSS配置 | ||||
|      */ | ||||
|     String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config"; | ||||
|  | ||||
|     /** | ||||
|      * 在线用户 | ||||
|      */ | ||||
|     String ONLINE_TOKEN = "online_tokens"; | ||||
|  | ||||
| } | ||||
| @@ -1,76 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 通用常量信息 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public interface Constants { | ||||
|  | ||||
|     /** | ||||
|      * UTF-8 字符集 | ||||
|      */ | ||||
|     String UTF8 = "UTF-8"; | ||||
|  | ||||
|     /** | ||||
|      * GBK 字符集 | ||||
|      */ | ||||
|     String GBK = "GBK"; | ||||
|  | ||||
|     /** | ||||
|      * www主域 | ||||
|      */ | ||||
|     String WWW = "www."; | ||||
|  | ||||
|     /** | ||||
|      * http请求 | ||||
|      */ | ||||
|     String HTTP = "http://"; | ||||
|  | ||||
|     /** | ||||
|      * https请求 | ||||
|      */ | ||||
|     String HTTPS = "https://"; | ||||
|  | ||||
|     /** | ||||
|      * 通用成功标识 | ||||
|      */ | ||||
|     String SUCCESS = "0"; | ||||
|  | ||||
|     /** | ||||
|      * 通用失败标识 | ||||
|      */ | ||||
|     String FAIL = "1"; | ||||
|  | ||||
|     /** | ||||
|      * 登录成功 | ||||
|      */ | ||||
|     String LOGIN_SUCCESS = "Success"; | ||||
|  | ||||
|     /** | ||||
|      * 注销 | ||||
|      */ | ||||
|     String LOGOUT = "Logout"; | ||||
|  | ||||
|     /** | ||||
|      * 注册 | ||||
|      */ | ||||
|     String REGISTER = "Register"; | ||||
|  | ||||
|     /** | ||||
|      * 登录失败 | ||||
|      */ | ||||
|     String LOGIN_FAIL = "Error"; | ||||
|  | ||||
|     /** | ||||
|      * 验证码有效期(分钟) | ||||
|      */ | ||||
|     Integer CAPTCHA_EXPIRATION = 2; | ||||
|  | ||||
|     /** | ||||
|      * 顶级父级id | ||||
|      */ | ||||
|     Long TOP_PARENT_ID = 0L; | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -1,34 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 全局的key常量 (业务无关的key) | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| public interface GlobalConstants { | ||||
|  | ||||
|     /** | ||||
|      * 全局 redis key (业务无关的key) | ||||
|      */ | ||||
|     String GLOBAL_REDIS_KEY = "global:"; | ||||
|  | ||||
|     /** | ||||
|      * 验证码 redis key | ||||
|      */ | ||||
|     String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; | ||||
|  | ||||
|     /** | ||||
|      * 防重提交 redis key | ||||
|      */ | ||||
|     String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; | ||||
|  | ||||
|     /** | ||||
|      * 限流 redis key | ||||
|      */ | ||||
|     String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; | ||||
|  | ||||
|     /** | ||||
|      * 三方认证 redis key | ||||
|      */ | ||||
|     String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; | ||||
| } | ||||
| @@ -1,93 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 返回状态码 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| public interface HttpStatus { | ||||
|     /** | ||||
|      * 操作成功 | ||||
|      */ | ||||
|     int SUCCESS = 200; | ||||
|  | ||||
|     /** | ||||
|      * 对象创建成功 | ||||
|      */ | ||||
|     int CREATED = 201; | ||||
|  | ||||
|     /** | ||||
|      * 请求已经被接受 | ||||
|      */ | ||||
|     int ACCEPTED = 202; | ||||
|  | ||||
|     /** | ||||
|      * 操作已经执行成功,但是没有返回数据 | ||||
|      */ | ||||
|     int NO_CONTENT = 204; | ||||
|  | ||||
|     /** | ||||
|      * 资源已被移除 | ||||
|      */ | ||||
|     int MOVED_PERM = 301; | ||||
|  | ||||
|     /** | ||||
|      * 重定向 | ||||
|      */ | ||||
|     int SEE_OTHER = 303; | ||||
|  | ||||
|     /** | ||||
|      * 资源没有被修改 | ||||
|      */ | ||||
|     int NOT_MODIFIED = 304; | ||||
|  | ||||
|     /** | ||||
|      * 参数列表错误(缺少,格式不匹配) | ||||
|      */ | ||||
|     int BAD_REQUEST = 400; | ||||
|  | ||||
|     /** | ||||
|      * 未授权 | ||||
|      */ | ||||
|     int UNAUTHORIZED = 401; | ||||
|  | ||||
|     /** | ||||
|      * 访问受限,授权过期 | ||||
|      */ | ||||
|     int FORBIDDEN = 403; | ||||
|  | ||||
|     /** | ||||
|      * 资源,服务未找到 | ||||
|      */ | ||||
|     int NOT_FOUND = 404; | ||||
|  | ||||
|     /** | ||||
|      * 不允许的http方法 | ||||
|      */ | ||||
|     int BAD_METHOD = 405; | ||||
|  | ||||
|     /** | ||||
|      * 资源冲突,或者资源被锁 | ||||
|      */ | ||||
|     int CONFLICT = 409; | ||||
|  | ||||
|     /** | ||||
|      * 不支持的数据,媒体类型 | ||||
|      */ | ||||
|     int UNSUPPORTED_TYPE = 415; | ||||
|  | ||||
|     /** | ||||
|      * 系统内部错误 | ||||
|      */ | ||||
|     int ERROR = 500; | ||||
|  | ||||
|     /** | ||||
|      * 接口未实现 | ||||
|      */ | ||||
|     int NOT_IMPLEMENTED = 501; | ||||
|  | ||||
|     /** | ||||
|      * 系统警告消息 | ||||
|      */ | ||||
|     int WARN = 601; | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| import cn.hutool.core.lang.RegexPool; | ||||
|  | ||||
| /** | ||||
|  * 常用正则表达式字符串 | ||||
|  * <p> | ||||
|  * 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/ | ||||
|  * | ||||
|  * @author Feng | ||||
|  */ | ||||
| public interface RegexConstants extends RegexPool { | ||||
|  | ||||
|     /** | ||||
|      * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) | ||||
|      */ | ||||
|     String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$"; | ||||
|  | ||||
|     /** | ||||
|      * 权限标识必须符合以下格式: | ||||
|      * 1. 标准格式:xxx:yyy:zzz | ||||
|      * - 第一部分(xxx):只能包含字母、数字和下划线(_),不能使用 `*` | ||||
|      * - 第二部分(yyy):可以包含字母、数字、下划线(_)和 `*` | ||||
|      * - 第三部分(zzz):可以包含字母、数字、下划线(_)和 `*` | ||||
|      * 2. 允许空字符串(""),表示没有权限标识 | ||||
|      */ | ||||
|     String PERMISSION_STRING = "^$|^[a-zA-Z0-9_]+:[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]+$"; | ||||
|  | ||||
|     /** | ||||
|      * 身份证号码(后6位) | ||||
|      */ | ||||
|     String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; | ||||
|  | ||||
|     /** | ||||
|      * QQ号码 | ||||
|      */ | ||||
|     String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$"; | ||||
|  | ||||
|     /** | ||||
|      * 邮政编码 | ||||
|      */ | ||||
|     String POSTAL_CODE = "^[1-9]\\d{5}$"; | ||||
|  | ||||
|     /** | ||||
|      * 注册账号 | ||||
|      */ | ||||
|     String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$"; | ||||
|  | ||||
|     /** | ||||
|      * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 | ||||
|      */ | ||||
|     String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; | ||||
|  | ||||
|     /** | ||||
|      * 通用状态(0表示正常,1表示停用) | ||||
|      */ | ||||
|     String STATUS = "^[01]$"; | ||||
|  | ||||
| } | ||||
| @@ -1,80 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 系统常量信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| public interface SystemConstants { | ||||
|  | ||||
|     /** | ||||
|      * 正常状态 | ||||
|      */ | ||||
|     String NORMAL = "0"; | ||||
|  | ||||
|     /** | ||||
|      * 异常状态 | ||||
|      */ | ||||
|     String DISABLE = "1"; | ||||
|  | ||||
|     /** | ||||
|      * 是否为系统默认(是) | ||||
|      */ | ||||
|     String YES = "Y"; | ||||
|  | ||||
|     /** | ||||
|      * 是否为系统默认(否) | ||||
|      */ | ||||
|     String NO = "N"; | ||||
|  | ||||
|     /** | ||||
|      * 是否菜单外链(是) | ||||
|      */ | ||||
|     String YES_FRAME = "0"; | ||||
|  | ||||
|     /** | ||||
|      * 是否菜单外链(否) | ||||
|      */ | ||||
|     String NO_FRAME = "1"; | ||||
|  | ||||
|     /** | ||||
|      * 菜单类型(目录) | ||||
|      */ | ||||
|     String TYPE_DIR = "M"; | ||||
|  | ||||
|     /** | ||||
|      * 菜单类型(菜单) | ||||
|      */ | ||||
|     String TYPE_MENU = "C"; | ||||
|  | ||||
|     /** | ||||
|      * 菜单类型(按钮) | ||||
|      */ | ||||
|     String TYPE_BUTTON = "F"; | ||||
|  | ||||
|     /** | ||||
|      * Layout组件标识 | ||||
|      */ | ||||
|     String LAYOUT = "Layout"; | ||||
|  | ||||
|     /** | ||||
|      * ParentView组件标识 | ||||
|      */ | ||||
|     String PARENT_VIEW = "ParentView"; | ||||
|  | ||||
|     /** | ||||
|      * InnerLink组件标识 | ||||
|      */ | ||||
|     String INNER_LINK = "InnerLink"; | ||||
|  | ||||
|     /** | ||||
|      * 超级管理员ID | ||||
|      */ | ||||
|     Long SUPER_ADMIN_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 根部门祖级列表 | ||||
|      */ | ||||
|     String ROOT_DEPT_ANCESTORS = "0"; | ||||
|  | ||||
| } | ||||
| @@ -1,35 +0,0 @@ | ||||
| package org.dromara.common.core.constant; | ||||
|  | ||||
| /** | ||||
|  * 租户常量信息 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| public interface TenantConstants { | ||||
|  | ||||
|     /** | ||||
|      * 超级管理员ID | ||||
|      */ | ||||
|     Long SUPER_ADMIN_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 超级管理员角色 roleKey | ||||
|      */ | ||||
|     String SUPER_ADMIN_ROLE_KEY = "superadmin"; | ||||
|  | ||||
|     /** | ||||
|      * 租户管理员角色 roleKey | ||||
|      */ | ||||
|     String TENANT_ADMIN_ROLE_KEY = "admin"; | ||||
|  | ||||
|     /** | ||||
|      * 租户管理员角色名称 | ||||
|      */ | ||||
|     String TENANT_ADMIN_ROLE_NAME = "管理员"; | ||||
|  | ||||
|     /** | ||||
|      * 默认租户ID | ||||
|      */ | ||||
|     String DEFAULT_TENANT_ID = "000000"; | ||||
|  | ||||
| } | ||||
| @@ -1,110 +0,0 @@ | ||||
| package org.dromara.common.core.domain; | ||||
|  | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 响应信息主体 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class R<T> implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 成功 | ||||
|      */ | ||||
|     public static final int SUCCESS = 200; | ||||
|  | ||||
|     /** | ||||
|      * 失败 | ||||
|      */ | ||||
|     public static final int FAIL = 500; | ||||
|  | ||||
|     private int code; | ||||
|  | ||||
|     private String msg; | ||||
|  | ||||
|     private T data; | ||||
|  | ||||
|     public static <T> R<T> ok() { | ||||
|         return restResult(null, SUCCESS, "操作成功"); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> ok(T data) { | ||||
|         return restResult(data, SUCCESS, "操作成功"); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> ok(String msg) { | ||||
|         return restResult(null, SUCCESS, msg); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> ok(String msg, T data) { | ||||
|         return restResult(data, SUCCESS, msg); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> fail() { | ||||
|         return restResult(null, FAIL, "操作失败"); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> fail(String msg) { | ||||
|         return restResult(null, FAIL, msg); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> fail(T data) { | ||||
|         return restResult(data, FAIL, "操作失败"); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> fail(String msg, T data) { | ||||
|         return restResult(data, FAIL, msg); | ||||
|     } | ||||
|  | ||||
|     public static <T> R<T> fail(int code, String msg) { | ||||
|         return restResult(null, code, msg); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回警告消息 | ||||
|      * | ||||
|      * @param msg 返回内容 | ||||
|      * @return 警告消息 | ||||
|      */ | ||||
|     public static <T> R<T> warn(String msg) { | ||||
|         return restResult(null, HttpStatus.WARN, msg); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回警告消息 | ||||
|      * | ||||
|      * @param msg 返回内容 | ||||
|      * @param data 数据对象 | ||||
|      * @return 警告消息 | ||||
|      */ | ||||
|     public static <T> R<T> warn(String msg, T data) { | ||||
|         return restResult(data, HttpStatus.WARN, msg); | ||||
|     } | ||||
|  | ||||
|     private static <T> R<T> restResult(T data, int code, String msg) { | ||||
|         R<T> r = new R<>(); | ||||
|         r.setCode(code); | ||||
|         r.setData(data); | ||||
|         r.setMsg(msg); | ||||
|         return r; | ||||
|     } | ||||
|  | ||||
|     public static <T> Boolean isError(R<T> ret) { | ||||
|         return !isSuccess(ret); | ||||
|     } | ||||
|  | ||||
|     public static <T> Boolean isSuccess(R<T> ret) { | ||||
|         return R.SUCCESS == ret.getCode(); | ||||
|     } | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 办理任务请求对象 | ||||
|  * | ||||
|  * @author may | ||||
|  */ | ||||
| @Data | ||||
| public class CompleteTaskDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 任务id | ||||
|      */ | ||||
|     private Long taskId; | ||||
|  | ||||
|     /** | ||||
|      * 附件id | ||||
|      */ | ||||
|     private String fileId; | ||||
|  | ||||
|     /** | ||||
|      * 抄送人员 | ||||
|      */ | ||||
|     private List<FlowCopyDTO> flowCopyList; | ||||
|  | ||||
|     /** | ||||
|      * 消息类型 | ||||
|      */ | ||||
|     private List<String> messageType; | ||||
|  | ||||
|     /** | ||||
|      * 办理意见 | ||||
|      */ | ||||
|     private String message; | ||||
|  | ||||
|     /** | ||||
|      * 消息通知 | ||||
|      */ | ||||
|     private String notice; | ||||
|  | ||||
|     /** | ||||
|      * 流程变量 | ||||
|      */ | ||||
|     private Map<String, Object> variables; | ||||
|  | ||||
|     /** | ||||
|      * 扩展变量(此处为逗号分隔的ossId) | ||||
|      */ | ||||
|     private String ext; | ||||
|  | ||||
|     public Map<String, Object> getVariables() { | ||||
|         if (variables == null) { | ||||
|             return new HashMap<>(16); | ||||
|         } | ||||
|         variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); | ||||
|         return variables; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 部门 | ||||
|  * | ||||
|  * @author AprilWind | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class DeptDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 部门ID | ||||
|      */ | ||||
|     private Long deptId; | ||||
|  | ||||
|     /** | ||||
|      * 父部门ID | ||||
|      */ | ||||
|     private Long parentId; | ||||
|  | ||||
|     /** | ||||
|      * 部门名称 | ||||
|      */ | ||||
|     private String deptName; | ||||
|  | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 字典数据DTO | ||||
|  * | ||||
|  * @author AprilWind | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class DictDataDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 字典标签 | ||||
|      */ | ||||
|     private String dictLabel; | ||||
|  | ||||
|     /** | ||||
|      * 字典键值 | ||||
|      */ | ||||
|     private String dictValue; | ||||
|  | ||||
|     /** | ||||
|      * 是否默认(Y是 N否) | ||||
|      */ | ||||
|     private String isDefault; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
|  | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 字典类型DTO | ||||
|  * | ||||
|  * @author AprilWind | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class DictTypeDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 字典主键 | ||||
|      */ | ||||
|     private Long dictId; | ||||
|  | ||||
|     /** | ||||
|      * 字典名称 | ||||
|      */ | ||||
|     private String dictName; | ||||
|  | ||||
|     /** | ||||
|      * 字典类型 | ||||
|      */ | ||||
|     private String dictType; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
|  | ||||
| } | ||||
| @@ -1,30 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 抄送 | ||||
|  * | ||||
|  * @author may | ||||
|  */ | ||||
| @Data | ||||
| public class FlowCopyDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 用户id | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 用户名称 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
| } | ||||
| @@ -1,46 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * OSS对象 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class OssDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 对象存储主键 | ||||
|      */ | ||||
|     private Long ossId; | ||||
|  | ||||
|     /** | ||||
|      * 文件名 | ||||
|      */ | ||||
|     private String fileName; | ||||
|  | ||||
|     /** | ||||
|      * 原名 | ||||
|      */ | ||||
|     private String originalName; | ||||
|  | ||||
|     /** | ||||
|      * 文件后缀名 | ||||
|      */ | ||||
|     private String fileSuffix; | ||||
|  | ||||
|     /** | ||||
|      * URL地址 | ||||
|      */ | ||||
|     private String url; | ||||
|  | ||||
| } | ||||
| @@ -1,46 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 岗位 | ||||
|  * | ||||
|  * @author AprilWind | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class PostDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 岗位ID | ||||
|      */ | ||||
|     private Long postId; | ||||
|  | ||||
|     /** | ||||
|      * 部门id | ||||
|      */ | ||||
|     private Long deptId; | ||||
|  | ||||
|     /** | ||||
|      * 岗位编码 | ||||
|      */ | ||||
|     private String postCode; | ||||
|  | ||||
|     /** | ||||
|      * 岗位名称 | ||||
|      */ | ||||
|     private String postName; | ||||
|  | ||||
|     /** | ||||
|      * 岗位类别编码 | ||||
|      */ | ||||
|     private String postCategory; | ||||
|  | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 角色 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
|  | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class RoleDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 角色ID | ||||
|      */ | ||||
|     private Long roleId; | ||||
|  | ||||
|     /** | ||||
|      * 角色名称 | ||||
|      */ | ||||
|     private String roleName; | ||||
|  | ||||
|     /** | ||||
|      * 角色权限 | ||||
|      */ | ||||
|     private String roleKey; | ||||
|  | ||||
|     /** | ||||
|      * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限 6:部门及以下或本人数据权限) | ||||
|      */ | ||||
|     private String dataScope; | ||||
|  | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 启动流程对象 | ||||
|  * | ||||
|  * @author may | ||||
|  */ | ||||
| @Data | ||||
| public class StartProcessDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 业务唯一值id | ||||
|      */ | ||||
|     private String businessId; | ||||
|  | ||||
|     /** | ||||
|      * 流程定义编码 | ||||
|      */ | ||||
|     private String flowCode; | ||||
|  | ||||
|     /** | ||||
|      * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} | ||||
|      */ | ||||
|     private Map<String, Object> variables; | ||||
|  | ||||
|     public Map<String, Object> getVariables() { | ||||
|         if (variables == null) { | ||||
|             return new HashMap<>(16); | ||||
|         } | ||||
|         variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); | ||||
|         return variables; | ||||
|     } | ||||
| } | ||||
| @@ -1,30 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 启动流程返回对象 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Data | ||||
| public class StartProcessReturnDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 流程实例id | ||||
|      */ | ||||
|     private Long processInstanceId; | ||||
|  | ||||
|     /** | ||||
|      * 任务id | ||||
|      */ | ||||
|     private Long taskId; | ||||
|  | ||||
| } | ||||
| @@ -1,101 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.function.Function; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * 任务受让人 | ||||
|  * | ||||
|  * @author AprilWind | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class TaskAssigneeDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 总大小 | ||||
|      */ | ||||
|     private Long total = 0L; | ||||
|  | ||||
|     /** | ||||
|      * | ||||
|      */ | ||||
|     private List<TaskHandler> list; | ||||
|  | ||||
|     public TaskAssigneeDTO(Long total, List<TaskHandler> list) { | ||||
|         this.total = total; | ||||
|         this.list = list; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将源列表转换为 TaskHandler 列表 | ||||
|      * | ||||
|      * @param <T>              通用类型 | ||||
|      * @param sourceList       待转换的源列表 | ||||
|      * @param storageId        提取 storageId 的函数 | ||||
|      * @param handlerCode      提取 handlerCode 的函数 | ||||
|      * @param handlerName      提取 handlerName 的函数 | ||||
|      * @param groupName        提取 groupName 的函数 | ||||
|      * @param createTimeMapper 提取 createTime 的函数 | ||||
|      * @return 转换后的 TaskHandler 列表 | ||||
|      */ | ||||
|     public static <T> List<TaskHandler> convertToHandlerList( | ||||
|         List<T> sourceList, | ||||
|         Function<T, Long> storageId, | ||||
|         Function<T, String> handlerCode, | ||||
|         Function<T, String> handlerName, | ||||
|         Function<T, Long> groupName, | ||||
|         Function<T, Date> createTimeMapper) { | ||||
|         return sourceList.stream() | ||||
|             .map(item -> new TaskHandler( | ||||
|                 String.valueOf(storageId.apply(item)), | ||||
|                 handlerCode.apply(item), | ||||
|                 handlerName.apply(item), | ||||
|                 groupName != null ? String.valueOf(groupName.apply(item)) : null, | ||||
|                 createTimeMapper.apply(item) | ||||
|             )).collect(Collectors.toList()); | ||||
|     } | ||||
|  | ||||
|     @Data | ||||
|     @NoArgsConstructor | ||||
|     @AllArgsConstructor | ||||
|     public static class TaskHandler { | ||||
|  | ||||
|         /** | ||||
|          * 主键 | ||||
|          */ | ||||
|         private String storageId; | ||||
|  | ||||
|         /** | ||||
|          * 权限编码 | ||||
|          */ | ||||
|         private String handlerCode; | ||||
|  | ||||
|         /** | ||||
|          * 权限名称 | ||||
|          */ | ||||
|         private String handlerName; | ||||
|  | ||||
|         /** | ||||
|          * 权限分组 | ||||
|          */ | ||||
|         private String groupName; | ||||
|  | ||||
|         /** | ||||
|          * 创建时间 | ||||
|          */ | ||||
|         private Date createTime; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,73 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 用户 | ||||
|  * | ||||
|  * @author Michelle.Chung | ||||
|  */ | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class UserDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 用户ID | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 部门ID | ||||
|      */ | ||||
|     private Long deptId; | ||||
|  | ||||
|     /** | ||||
|      * 用户账号 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 用户昵称 | ||||
|      */ | ||||
|     private String nickName; | ||||
|  | ||||
|     /** | ||||
|      * 用户类型(sys_user系统用户) | ||||
|      */ | ||||
|     private String userType; | ||||
|  | ||||
|     /** | ||||
|      * 用户邮箱 | ||||
|      */ | ||||
|     private String email; | ||||
|  | ||||
|     /** | ||||
|      * 手机号码 | ||||
|      */ | ||||
|     private String phonenumber; | ||||
|  | ||||
|     /** | ||||
|      * 用户性别(0男 1女 2未知) | ||||
|      */ | ||||
|     private String sex; | ||||
|  | ||||
|     /** | ||||
|      * 帐号状态(0正常 1停用) | ||||
|      */ | ||||
|     private String status; | ||||
|  | ||||
|     /** | ||||
|      * 创建时间 | ||||
|      */ | ||||
|     private Date createTime; | ||||
|  | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| package org.dromara.common.core.domain.dto; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 当前在线会话 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
|  | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| public class UserOnlineDTO implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 会话编号 | ||||
|      */ | ||||
|     private String tokenId; | ||||
|  | ||||
|     /** | ||||
|      * 部门名称 | ||||
|      */ | ||||
|     private String deptName; | ||||
|  | ||||
|     /** | ||||
|      * 用户名称 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 客户端 | ||||
|      */ | ||||
|     private String clientKey; | ||||
|  | ||||
|     /** | ||||
|      * 设备类型 | ||||
|      */ | ||||
|     private String deviceType; | ||||
|  | ||||
|     /** | ||||
|      * 登录IP地址 | ||||
|      */ | ||||
|     private String ipaddr; | ||||
|  | ||||
|     /** | ||||
|      * 登录地址 | ||||
|      */ | ||||
|     private String loginLocation; | ||||
|  | ||||
|     /** | ||||
|      * 浏览器类型 | ||||
|      */ | ||||
|     private String browser; | ||||
|  | ||||
|     /** | ||||
|      * 操作系统 | ||||
|      */ | ||||
|     private String os; | ||||
|  | ||||
|     /** | ||||
|      * 登录时间 | ||||
|      */ | ||||
|     private Long loginTime; | ||||
|  | ||||
| } | ||||
| @@ -1,54 +0,0 @@ | ||||
| package org.dromara.common.core.domain.event; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 流程创建任务监听 | ||||
|  * | ||||
|  * @author may | ||||
|  */ | ||||
| @Data | ||||
| public class ProcessCreateTaskEvent implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 租户ID | ||||
|      */ | ||||
|     private String tenantId; | ||||
|  | ||||
|     /** | ||||
|      * 流程定义编码 | ||||
|      */ | ||||
|     private String flowCode; | ||||
|  | ||||
|     /** | ||||
|      * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) | ||||
|      */ | ||||
|     private Integer nodeType; | ||||
|  | ||||
|     /** | ||||
|      * 流程节点编码 | ||||
|      */ | ||||
|     private String nodeCode; | ||||
|  | ||||
|     /** | ||||
|      * 流程节点名称 | ||||
|      */ | ||||
|     private String nodeName; | ||||
|  | ||||
|     /** | ||||
|      * 任务id | ||||
|      */ | ||||
|     private Long taskId; | ||||
|  | ||||
|     /** | ||||
|      * 业务id | ||||
|      */ | ||||
|     private String businessId; | ||||
|  | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user