mirror of
				https://github.com/dromara/RuoYi-Vue-Plus.git
				synced 2025-11-04 08:13:44 +08:00 
			
		
		
		
	Compare commits
	
		
			19 Commits
		
	
	
		
			7e7d857ba5
			...
			v3.5.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d98acffe4e | ||
| 
						 | 
					4d92ef22c3 | ||
| 
						 | 
					255b5f2f07 | ||
| 
						 | 
					c6fe27b040 | ||
| 
						 | 
					3e2ddb3b25 | ||
| 
						 | 
					ebc6617a8e | ||
| 
						 | 
					65eb873f9a | ||
| 
						 | 
					36fd16562e | ||
| 
						 | 
					f99e24bf82 | ||
| 
						 | 
					9aa8438ced | ||
| 
						 | 
					a2c8b0d13e | ||
| 
						 | 
					2c6e1f0db7 | ||
| 
						 | 
					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.4.0" />
 | 
			
		||||
        <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.4.0" />
 | 
			
		||||
        <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.4.0" />
 | 
			
		||||
        <option name="buildOnly" value="true" />
 | 
			
		||||
        <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
 | 
			
		||||
      </settings>
 | 
			
		||||
    </deployment>
 | 
			
		||||
    <method v="2" />
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
							
								
								
									
										296
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										296
									
								
								README.md
									
									
									
									
									
								
							@@ -1,187 +1,153 @@
 | 
			
		||||
<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://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/系统演示?sort_id=4836388)
 | 
			
		||||
 | 
			
		||||
> 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system)
 | 
			
		||||
 | 
			
		||||
> 官方前端项目地址: [gitee](https://gitee.com/JavaLionLi/plus-ui) - [github](https://github.com/JavaLionLi/plus-ui) - [gitcode](https://gitcode.com/dromara/plus-ui)<br>
 | 
			
		||||
> 成员前端项目地址: 基于vben5 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)<br>
 | 
			
		||||
> 成员前端项目地址: 基于soybean [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)<br>
 | 
			
		||||
> 成员项目地址: 删除多租户与工作流 [RuoYi-Vue-Plus-Single](https://gitee.com/ColorDreams/RuoYi-Vue-Plus-Single)<br>
 | 
			
		||||
 | 
			
		||||
> 文档地址: [plus-doc](https://plus-doc.dromara.org) 文档在华为云上如果打不开大概率是DNS问题 可以尝试切换网络等方式(或者科学上网)
 | 
			
		||||
 | 
			
		||||
## 赞助商
 | 
			
		||||
 | 
			
		||||
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/) | 高可读性 扩展性(推荐使用) |
 | 
			
		||||
| 单体分支 | RuoYi-Vue-Plus-fast | [fast分支地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) | 单体应用结构 |
 | 
			
		||||
| Vue3分支 | RuoYi-Vue-Plus-UI | [UI地址](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus-UI) | 由于组件还未完善 仅供学习 |
 | 
			
		||||
| 原框架 | RuoYi-Vue | [RuoYi-Vue官网](http://ruoyi.vip/) | 定期同步需要的功能 |
 | 
			
		||||
| 前端开发框架 | Vue、Element UI | [Element UI官网](https://element.eleme.cn/#/zh-CN) | |
 | 
			
		||||
| 后端开发框架 | SpringBoot | [SpringBoot官网](https://spring.io/projects/spring-boot/#learn) | |
 | 
			
		||||
| 容器框架 | Undertow | [Undertow官网](https://undertow.io/) | 基于 XNIO 的高性能容器 |
 | 
			
		||||
| 权限认证框架 | Spring Security、Jwt | [SpringSecurity官网](https://spring.io/projects/spring-security#learn) | 支持多终端认证系统 |
 | 
			
		||||
| 权限认证框架 | Sa-Token、Jwt | [Sa-Token官网](https://sa-token.dev33.cn/) | 强解耦、强扩展 |
 | 
			
		||||
| 关系数据库 | 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 高效可靠 |
 | 
			
		||||
| 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) | 注解锁、工具锁 多种多样 |
 | 
			
		||||
| 分布式幂等 | Redisson | [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)
 | 
			
		||||
 | 
			
		||||
## 软件架构图
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||

 | 
			
		||||
## 贡献代码
 | 
			
		||||
 | 
			
		||||
## 如何参与贡献
 | 
			
		||||
欢迎各路英雄豪杰 `PR` 代码 请提交到 `dev` 开发分支 统一测试发版
 | 
			
		||||
 | 
			
		||||
[参与贡献的方式 https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution)
 | 
			
		||||
框架定位为 `通用后台管理系统(分布式集群强化)` 原则上不接受业务 `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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										522
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										522
									
								
								pom.xml
									
									
									
									
									
								
							@@ -2,101 +2,58 @@
 | 
			
		||||
<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.5.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.4.0</revision>
 | 
			
		||||
        <spring-boot.version>3.4.6</spring-boot.version>
 | 
			
		||||
        <ruoyi-vue-plus.version>3.5.0</ruoyi-vue-plus.version>
 | 
			
		||||
        <spring-boot.version>2.5.8</spring-boot.version>
 | 
			
		||||
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
			
		||||
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 | 
			
		||||
        <java.version>17</java.version>
 | 
			
		||||
        <mybatis.version>3.5.16</mybatis.version>
 | 
			
		||||
        <springdoc.version>2.8.8</springdoc.version>
 | 
			
		||||
        <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
 | 
			
		||||
        <fastexcel.version>1.2.0</fastexcel.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>
 | 
			
		||||
        <cglib.version>3.3.0</cglib.version>
 | 
			
		||||
        <velocity.version>2.3</velocity.version>
 | 
			
		||||
        <satoken.version>1.42.0</satoken.version>
 | 
			
		||||
        <mybatis-plus.version>3.5.12</mybatis-plus.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.7</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.5.0</snailjob.version>
 | 
			
		||||
        <mapstruct-plus.version>1.4.8</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.18</hutool.version>
 | 
			
		||||
        <okhttp.version>4.9.2</okhttp.version>
 | 
			
		||||
        <spring-boot-admin.version>2.5.5</spring-boot-admin.version>
 | 
			
		||||
        <redisson.version>3.16.7</redisson.version>
 | 
			
		||||
        <lock4j.version>2.2.1</lock4j.version>
 | 
			
		||||
        <dynamic-ds.version>3.5.0</dynamic-ds.version>
 | 
			
		||||
        <tlog.version>1.3.6</tlog.version>
 | 
			
		||||
        <xxl-job.version>2.3.0</xxl-job.version>
 | 
			
		||||
 | 
			
		||||
        <!-- jdk11 缺失依赖 jaxb-->
 | 
			
		||||
        <jaxb.version>3.0.1</jaxb.version>
 | 
			
		||||
 | 
			
		||||
        <!-- OSS 配置 -->
 | 
			
		||||
        <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.7.3</warm-flow.version>
 | 
			
		||||
        <qiniu.version>7.9.0</qiniu.version>
 | 
			
		||||
        <aliyun.oss.version>3.13.1</aliyun.oss.version>
 | 
			
		||||
        <qcloud.cos.version>5.6.58</qcloud.cos.version>
 | 
			
		||||
        <minio.version>8.3.4</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,65 +67,58 @@
 | 
			
		||||
                <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>
 | 
			
		||||
                <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>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>cn.idev.excel</groupId>
 | 
			
		||||
                <artifactId>fastexcel</artifactId>
 | 
			
		||||
                <version>${fastexcel.version}</version>
 | 
			
		||||
                <groupId>cglib</groupId>
 | 
			
		||||
                <artifactId>cglib</artifactId>
 | 
			
		||||
                <version>${cglib.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <!-- velocity代码生成使用模板 -->
 | 
			
		||||
@@ -178,61 +128,30 @@
 | 
			
		||||
                <version>${velocity.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
 | 
			
		||||
            <!-- jdk11 缺失依赖 jaxb-->
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>cn.dev33</groupId>
 | 
			
		||||
                <artifactId>sa-token-spring-boot3-starter</artifactId>
 | 
			
		||||
                <version>${satoken.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <!-- Sa-Token 整合 jwt -->
 | 
			
		||||
            <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 +159,40 @@
 | 
			
		||||
                <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-core</artifactId>
 | 
			
		||||
                <version>${hutool.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>software.amazon.awssdk</groupId>
 | 
			
		||||
                <artifactId>s3-transfer-manager</artifactId>
 | 
			
		||||
                <version>${aws.sdk.version}</version>
 | 
			
		||||
                <groupId>cn.hutool</groupId>
 | 
			
		||||
                <artifactId>hutool-http</artifactId>
 | 
			
		||||
                <version>${hutool.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>software.amazon.awssdk</groupId>
 | 
			
		||||
                <artifactId>netty-nio-client</artifactId>
 | 
			
		||||
                <version>${aws.sdk.version}</version>
 | 
			
		||||
                <groupId>cn.hutool</groupId>
 | 
			
		||||
                <artifactId>hutool-captcha</artifactId>
 | 
			
		||||
                <version>${hutool.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <!--短信sms4j-->
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.dromara.sms4j</groupId>
 | 
			
		||||
                <artifactId>sms4j-spring-boot-starter</artifactId>
 | 
			
		||||
                <version>${sms4j.version}</version>
 | 
			
		||||
                <groupId>cn.hutool</groupId>
 | 
			
		||||
                <artifactId>hutool-extra</artifactId>
 | 
			
		||||
                <version>${hutool.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>cn.hutool</groupId>
 | 
			
		||||
                <artifactId>hutool-jwt</artifactId>
 | 
			
		||||
                <version>${hutool.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.squareup.okhttp3</groupId>
 | 
			
		||||
                <artifactId>okhttp</artifactId>
 | 
			
		||||
                <version>${okhttp.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
@@ -282,80 +212,78 @@
 | 
			
		||||
                <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-web-spring-boot-starter</artifactId>
 | 
			
		||||
                <version>${tlog.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.alibaba</groupId>
 | 
			
		||||
                <artifactId>fastjson</artifactId>
 | 
			
		||||
                <version>${fastjson.version}</version>
 | 
			
		||||
                <groupId>com.yomahub</groupId>
 | 
			
		||||
                <artifactId>tlog-xxljob-spring-boot-starter</artifactId>
 | 
			
		||||
                <version>${tlog.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <!-- 定时任务 -->
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.dromara</groupId>
 | 
			
		||||
                <artifactId>ruoyi-system</artifactId>
 | 
			
		||||
                <version>${revision}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.dromara</groupId>
 | 
			
		||||
                <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 +291,14 @@
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
        <module>ruoyi-admin</module>
 | 
			
		||||
        <module>ruoyi-framework</module>
 | 
			
		||||
        <module>ruoyi-system</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 +307,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 +328,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 +339,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 +350,40 @@
 | 
			
		||||
        </pluginRepository>
 | 
			
		||||
    </pluginRepositories>
 | 
			
		||||
 | 
			
		||||
    <profiles>
 | 
			
		||||
        <profile>
 | 
			
		||||
            <id>local</id>
 | 
			
		||||
            <properties>
 | 
			
		||||
                <!-- 环境标识,需要与配置文件的名称相对应 -->
 | 
			
		||||
                <profiles.active>local</profiles.active>
 | 
			
		||||
                <logging.level>debug</logging.level>
 | 
			
		||||
                <knife4j.production>false</knife4j.production>
 | 
			
		||||
                <endpoints.include>'*'</endpoints.include>
 | 
			
		||||
            </properties>
 | 
			
		||||
        </profile>
 | 
			
		||||
        <profile>
 | 
			
		||||
            <id>dev</id>
 | 
			
		||||
            <properties>
 | 
			
		||||
                <!-- 环境标识,需要与配置文件的名称相对应 -->
 | 
			
		||||
                <profiles.active>dev</profiles.active>
 | 
			
		||||
                <logging.level>debug</logging.level>
 | 
			
		||||
                <knife4j.production>false</knife4j.production>
 | 
			
		||||
                <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>
 | 
			
		||||
                <knife4j.production>true</knife4j.production>
 | 
			
		||||
                <endpoints.include>health, info, logfile</endpoints.include>
 | 
			
		||||
            </properties>
 | 
			
		||||
        </profile>
 | 
			
		||||
    </profiles>
 | 
			
		||||
 | 
			
		||||
</project>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,15 @@
 | 
			
		||||
# 贝尔实验室 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
 | 
			
		||||
RUN mkdir -p /ruoyi/server/temp
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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.5.0</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
@@ -17,105 +17,52 @@
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
 | 
			
		||||
        <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 +72,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 +83,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>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package org.dromara;
 | 
			
		||||
package com.ruoyi;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
@@ -7,14 +7,15 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
 | 
			
		||||
/**
 | 
			
		||||
 * 启动程序
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 * @author ruoyi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
public class DromaraApplication {
 | 
			
		||||
public class RuoYiApplication {
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        SpringApplication application = new SpringApplication(DromaraApplication.class);
 | 
			
		||||
        System.setProperty("spring.devtools.restart.enabled", "false");
 | 
			
		||||
        SpringApplication application = new SpringApplication(RuoYiApplication.class);
 | 
			
		||||
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
 | 
			
		||||
        application.run(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,69 @@
 | 
			
		||||
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.domain.PageQuery;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return logininforService.selectPageLogininforList(logininfor, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出系统访问记录列表")
 | 
			
		||||
    @Log(title = "登录日志", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
 | 
			
		||||
    @PostMapping("/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,69 @@
 | 
			
		||||
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.domain.PageQuery;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return operLogService.selectPageOperLogList(operLog, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出操作日志记录列表")
 | 
			
		||||
    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
 | 
			
		||||
    @PostMapping("/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,79 @@
 | 
			
		||||
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.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)) {
 | 
			
		||||
                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 TableDataInfo.build(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.constant.UserConstants;
 | 
			
		||||
import com.ruoyi.common.core.controller.BaseController;
 | 
			
		||||
import com.ruoyi.common.core.domain.AjaxResult;
 | 
			
		||||
import com.ruoyi.common.core.domain.PageQuery;
 | 
			
		||||
import com.ruoyi.common.core.page.TableDataInfo;
 | 
			
		||||
import com.ruoyi.common.enums.BusinessType;
 | 
			
		||||
import com.ruoyi.common.utils.poi.ExcelUtil;
 | 
			
		||||
import com.ruoyi.system.domain.SysConfig;
 | 
			
		||||
import com.ruoyi.system.service.ISysConfigService;
 | 
			
		||||
import io.swagger.annotations.Api;
 | 
			
		||||
import io.swagger.annotations.ApiOperation;
 | 
			
		||||
import io.swagger.annotations.ApiParam;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return configService.selectPageConfigList(config, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出参数配置列表")
 | 
			
		||||
    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:config:export')")
 | 
			
		||||
    @PostMapping("/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(@ApiParam("参数ID") @PathVariable Long configId) {
 | 
			
		||||
        return AjaxResult.success(configService.selectConfigById(configId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据参数键名查询参数值
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("根据参数键名查询参数值")
 | 
			
		||||
    @GetMapping(value = "/configKey/{configKey}")
 | 
			
		||||
    public AjaxResult<Void> getConfigKey(@ApiParam("参数Key") @PathVariable String configKey) {
 | 
			
		||||
        return AjaxResult.success(configService.selectConfigByKey(configKey));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 新增参数配置
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("新增参数配置")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:config:add')")
 | 
			
		||||
    @Log(title = "参数管理", businessType = BusinessType.INSERT)
 | 
			
		||||
    @PostMapping
 | 
			
		||||
    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(@ApiParam("参数ID串") @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,147 @@
 | 
			
		||||
package com.ruoyi.web.controller.system;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.tree.Tree;
 | 
			
		||||
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.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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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(@ApiParam("部门ID") @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(@ApiParam("部门ID") @PathVariable Long deptId) {
 | 
			
		||||
        deptService.checkDeptDataScope(deptId);
 | 
			
		||||
        return AjaxResult.success(deptService.selectDeptById(deptId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取部门下拉树列表
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("获取部门下拉树列表")
 | 
			
		||||
    @GetMapping("/treeselect")
 | 
			
		||||
    public AjaxResult<List<Tree<Long>>> 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(@ApiParam("角色ID") @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(@ApiParam("部门ID串") @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,114 @@
 | 
			
		||||
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.PageQuery;
 | 
			
		||||
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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return dictDataService.selectPageDictDataList(dictData, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出字典数据列表")
 | 
			
		||||
    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:dict:export')")
 | 
			
		||||
    @PostMapping("/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(@ApiParam("字典code") @PathVariable Long dictCode) {
 | 
			
		||||
        return AjaxResult.success(dictDataService.selectDictDataById(dictCode));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据字典类型查询字典数据信息
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("根据字典类型查询字典数据信息")
 | 
			
		||||
    @GetMapping(value = "/type/{dictType}")
 | 
			
		||||
    public AjaxResult<List<SysDictData>> dictType(@ApiParam("字典类型") @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(@ApiParam("字典code串") @PathVariable Long[] dictCodes) {
 | 
			
		||||
        dictDataService.deleteDictDataByIds(dictCodes);
 | 
			
		||||
        return success();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,126 @@
 | 
			
		||||
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.PageQuery;
 | 
			
		||||
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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return dictTypeService.selectPageDictTypeList(dictType, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出字典类型列表")
 | 
			
		||||
    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:dict:export')")
 | 
			
		||||
    @PostMapping("/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(@ApiParam("字典ID") @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(@ApiParam("字典ID串") @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,94 @@
 | 
			
		||||
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.ISysUserService;
 | 
			
		||||
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 ISysUserService userService;
 | 
			
		||||
    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 = userService.selectUserById(SecurityUtils.getUserId());
 | 
			
		||||
        // 角色集合
 | 
			
		||||
        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,133 @@
 | 
			
		||||
package com.ruoyi.web.controller.system;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.tree.Tree;
 | 
			
		||||
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.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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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(@ApiParam("菜单ID") @PathVariable Long menuId) {
 | 
			
		||||
        return AjaxResult.success(menuService.selectMenuById(menuId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取菜单下拉树列表
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("获取菜单下拉树列表")
 | 
			
		||||
    @GetMapping("/treeselect")
 | 
			
		||||
    public AjaxResult<List<Tree<Long>>> 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(@ApiParam("角色ID") @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(@ApiParam("菜单ID") @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,86 @@
 | 
			
		||||
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.PageQuery;
 | 
			
		||||
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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return noticeService.selectPageNoticeList(notice, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据通知公告编号获取详细信息
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("根据通知公告编号获取详细信息")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:notice:query')")
 | 
			
		||||
    @GetMapping(value = "/{noticeId}")
 | 
			
		||||
    public AjaxResult<SysNotice> getInfo(@ApiParam("公告ID") @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(@ApiParam("公告ID串") @PathVariable Long[] noticeIds) {
 | 
			
		||||
        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,114 @@
 | 
			
		||||
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.domain.PageQuery;
 | 
			
		||||
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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return iSysOssConfigService.queryPageList(bo, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取对象存储配置详细信息
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("获取对象存储配置详细信息")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:oss:query')")
 | 
			
		||||
    @GetMapping("/{ossConfigId}")
 | 
			
		||||
    public AjaxResult<SysOssConfigVo> getInfo(@ApiParam("OSS配置ID")
 | 
			
		||||
                                              @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(@ApiParam("OSS配置ID串")
 | 
			
		||||
                                   @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.domain.PageQuery;
 | 
			
		||||
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.OssConstant;
 | 
			
		||||
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.*;
 | 
			
		||||
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.File;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return iSysOssService.queryPageList(bo, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 上传OSS对象存储
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("上传OSS对象存储")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
        @ApiImplicitParam(name = "file", value = "文件", dataTypeClass = File.class, 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(@ApiParam("OSS对象ID") @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(@ApiParam("OSS对象ID串")
 | 
			
		||||
                                   @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, OssConstant.PEREVIEW_LIST_RESOURCE_KEY));
 | 
			
		||||
        config.setConfigValue(map.get("previewListResource").toString());
 | 
			
		||||
        return toAjax(iSysConfigService.updateConfig(config));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,120 @@
 | 
			
		||||
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.PageQuery;
 | 
			
		||||
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 io.swagger.annotations.ApiParam;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return postService.selectPagePostList(post, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出岗位列表")
 | 
			
		||||
    @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:post:export')")
 | 
			
		||||
    @PostMapping("/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(@ApiParam("岗位ID") @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(@ApiParam("岗位ID串") @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,135 @@
 | 
			
		||||
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.Api;
 | 
			
		||||
import io.swagger.annotations.ApiImplicitParam;
 | 
			
		||||
import io.swagger.annotations.ApiImplicitParams;
 | 
			
		||||
import io.swagger.annotations.ApiOperation;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
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 = userService.selectUserById(loginUser.getUserId());
 | 
			
		||||
        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 = userService.selectUserById(loginUser.getUserId());
 | 
			
		||||
        user.setUserId(sysUser.getUserId());
 | 
			
		||||
        user.setUserName(null);
 | 
			
		||||
        user.setPassword(null);
 | 
			
		||||
        if (userService.updateUserProfile(user) > 0) {
 | 
			
		||||
            return AjaxResult.success();
 | 
			
		||||
        }
 | 
			
		||||
        return AjaxResult.error("修改个人信息异常,请联系管理员");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 重置密码
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("重置密码")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
        @ApiImplicitParam(name = "oldPassword", value = "旧密码", paramType = "query", dataTypeClass = String.class),
 | 
			
		||||
        @ApiImplicitParam(name = "newPassword", value = "新密码", paramType = "query", dataTypeClass = String.class)
 | 
			
		||||
    })
 | 
			
		||||
    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
 | 
			
		||||
    @PutMapping("/updatePwd")
 | 
			
		||||
    public AjaxResult<Void> updatePwd(String oldPassword, String newPassword) {
 | 
			
		||||
        SysUser user = userService.selectUserById(SecurityUtils.getUserId());
 | 
			
		||||
        String userName = user.getUserName();
 | 
			
		||||
        String password = user.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) {
 | 
			
		||||
            return AjaxResult.success();
 | 
			
		||||
        }
 | 
			
		||||
        return AjaxResult.error("修改密码异常,请联系管理员");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 头像上传
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("头像上传")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
        @ApiImplicitParam(name = "avatarfile", value = "用户头像", dataTypeClass = File.class, 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);
 | 
			
		||||
                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,224 @@
 | 
			
		||||
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.PageQuery;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysRole;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysUser;
 | 
			
		||||
import com.ruoyi.common.core.domain.model.LoginUser;
 | 
			
		||||
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.*;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return roleService.selectPageRoleList(role, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出角色信息列表")
 | 
			
		||||
    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:role:export')")
 | 
			
		||||
    @PostMapping("/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(@ApiParam("角色ID") @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();
 | 
			
		||||
            SysUser sysUser = userService.selectUserById(loginUser.getUserId());
 | 
			
		||||
            if (StringUtils.isNotNull(sysUser) && !sysUser.isAdmin()) {
 | 
			
		||||
                loginUser.setMenuPermissions(permissionService.getMenuPermission(sysUser));
 | 
			
		||||
                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(@ApiParam("岗位ID串") @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, PageQuery pageQuery) {
 | 
			
		||||
        return userService.selectAllocatedList(user, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询未分配用户角色列表
 | 
			
		||||
     */
 | 
			
		||||
    @ApiOperation("查询未分配用户角色列表")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:role:list')")
 | 
			
		||||
    @GetMapping("/authUser/unallocatedList")
 | 
			
		||||
    public TableDataInfo<SysUser> unallocatedList(SysUser user, PageQuery pageQuery) {
 | 
			
		||||
        return userService.selectUnallocatedList(user, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 取消授权用户
 | 
			
		||||
     */
 | 
			
		||||
    @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("批量取消授权用户")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
        @ApiImplicitParam(name = "roleId", value = "角色ID", paramType = "query", dataTypeClass = String.class),
 | 
			
		||||
        @ApiImplicitParam(name = "userIds", value = "用户ID串", paramType = "query", dataTypeClass = String.class)
 | 
			
		||||
    })
 | 
			
		||||
    @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("批量选择用户授权")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
        @ApiImplicitParam(name = "roleId", value = "角色ID", paramType = "query", dataTypeClass = String.class),
 | 
			
		||||
        @ApiImplicitParam(name = "userIds", value = "用户ID串", paramType = "query", dataTypeClass = String.class)
 | 
			
		||||
    })
 | 
			
		||||
    @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,232 @@
 | 
			
		||||
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.PageQuery;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysDept;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysRole;
 | 
			
		||||
import com.ruoyi.common.core.domain.entity.SysUser;
 | 
			
		||||
import com.ruoyi.common.core.page.TableDataInfo;
 | 
			
		||||
import com.ruoyi.common.enums.BusinessType;
 | 
			
		||||
import com.ruoyi.common.excel.ExcelResult;
 | 
			
		||||
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.listener.SysUserImportListener;
 | 
			
		||||
import com.ruoyi.system.service.ISysPostService;
 | 
			
		||||
import com.ruoyi.system.service.ISysRoleService;
 | 
			
		||||
import com.ruoyi.system.service.ISysUserService;
 | 
			
		||||
import io.swagger.annotations.*;
 | 
			
		||||
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, PageQuery pageQuery) {
 | 
			
		||||
        return userService.selectPageUserList(user, pageQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("导出用户列表")
 | 
			
		||||
    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermi('system:user:export')")
 | 
			
		||||
    @PostMapping("/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 {
 | 
			
		||||
        ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
 | 
			
		||||
        return AjaxResult.success(result.getAnalysis());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ApiOperation("下载导入模板")
 | 
			
		||||
    @PostMapping("/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(@ApiParam("用户ID") @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(@ApiParam("角色ID串") @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(@ApiParam("用户ID") @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("用户授权角色")
 | 
			
		||||
    @ApiImplicitParams({
 | 
			
		||||
        @ApiImplicitParam(name = "userId", value = "用户Id", paramType = "query", dataTypeClass = String.class),
 | 
			
		||||
        @ApiImplicitParam(name = "roleIds", value = "角色ID串", paramType = "query", dataTypeClass = String.class)
 | 
			
		||||
    })
 | 
			
		||||
    @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,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,118 @@
 | 
			
		||||
--- # 监控中心配置
 | 
			
		||||
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&rewriteBatchedStatements=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,170 +120,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
 | 
			
		||||
    gitea:
 | 
			
		||||
      # 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
 | 
			
		||||
      # gitea 服务器地址
 | 
			
		||||
      server-url: https://demo.gitea.com
 | 
			
		||||
      client-id: 10**********6
 | 
			
		||||
      client-secret: 1f7d08**********5b7**********29e
 | 
			
		||||
      redirect-uri: ${justauth.address}/social-callback?source=gitea
 | 
			
		||||
    # 单个连接最大订阅数量
 | 
			
		||||
    subscriptionsPerConnection: 5
 | 
			
		||||
    # DNS监测时间间隔,单位:毫秒
 | 
			
		||||
    dnsMonitoringInterval: 5000
 | 
			
		||||
 
 | 
			
		||||
@@ -1,130 +1,150 @@
 | 
			
		||||
--- # 临时文件存储位置 避免临时文件被系统清理报错
 | 
			
		||||
spring.servlet.multipart.location: /ruoyi/server/temp
 | 
			
		||||
--- # 配置临时路径存储
 | 
			
		||||
spring:
 | 
			
		||||
  servlet:
 | 
			
		||||
    multipart:
 | 
			
		||||
      # 临时文件存储位置 避免临时文件被系统清理报错
 | 
			
		||||
      location: /ruoyi/server/temp
 | 
			
		||||
 | 
			
		||||
--- # 监控中心配置
 | 
			
		||||
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://172.30.0.90: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://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&rewriteBatchedStatements=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,142 +153,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
 | 
			
		||||
    gitea:
 | 
			
		||||
      # 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
 | 
			
		||||
      # gitea 服务器地址
 | 
			
		||||
      server-url: https://demo.gitea.com
 | 
			
		||||
      client-id: 10**********6
 | 
			
		||||
      client-secret: 1f7d08**********5b7**********29e
 | 
			
		||||
      redirect-uri: ${justauth.address}/social-callback?source=gitea
 | 
			
		||||
    # 单个连接最大订阅数量
 | 
			
		||||
    subscriptionsPerConnection: 5
 | 
			
		||||
    # DNS监测时间间隔,单位:毫秒
 | 
			
		||||
    dnsMonitoringInterval: 5000
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,29 @@
 | 
			
		||||
# 项目相关配置
 | 
			
		||||
ruoyi:
 | 
			
		||||
  # 名称
 | 
			
		||||
  name: RuoYi-Vue-Plus
 | 
			
		||||
  # 版本
 | 
			
		||||
  version: ${ruoyi-vue-plus.version}
 | 
			
		||||
  # 版权年份
 | 
			
		||||
  copyrightYear: 2021
 | 
			
		||||
  # 实例演示开关
 | 
			
		||||
  demoEnabled: true
 | 
			
		||||
  # 获取ip地址开关
 | 
			
		||||
  addressEnabled: true
 | 
			
		||||
  # 缓存懒加载
 | 
			
		||||
  cacheLazy: false
 | 
			
		||||
 | 
			
		||||
captcha:
 | 
			
		||||
  # 页面 <参数设置> 可开启关闭 验证码校验
 | 
			
		||||
  # 验证码类型 math 数组计算 char 字符验证
 | 
			
		||||
  type: MATH
 | 
			
		||||
  # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
 | 
			
		||||
  category: CIRCLE
 | 
			
		||||
  # 数字验证码位数
 | 
			
		||||
  numberLength: 1
 | 
			
		||||
  # 字符验证码长度
 | 
			
		||||
  charLength: 4
 | 
			
		||||
 | 
			
		||||
# 开发环境配置
 | 
			
		||||
server:
 | 
			
		||||
  # 服务器的HTTP端口,默认为8080
 | 
			
		||||
@@ -20,43 +46,17 @@ 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
 | 
			
		||||
 | 
			
		||||
# 用户配置
 | 
			
		||||
user:
 | 
			
		||||
  password:
 | 
			
		||||
    # 密码最大错误次数
 | 
			
		||||
    maxRetryCount: 5
 | 
			
		||||
    # 密码锁定时间(默认10分钟)
 | 
			
		||||
    lockTime: 10
 | 
			
		||||
  config: classpath:logback.xml
 | 
			
		||||
 | 
			
		||||
# Spring配置
 | 
			
		||||
spring:
 | 
			
		||||
  application:
 | 
			
		||||
    name: RuoYi-Vue-Plus
 | 
			
		||||
  threads:
 | 
			
		||||
    # 开启虚拟线程 仅jdk21可用
 | 
			
		||||
    virtual:
 | 
			
		||||
      enabled: false
 | 
			
		||||
    name: ${ruoyi.name}
 | 
			
		||||
  # 资源信息
 | 
			
		||||
  messages:
 | 
			
		||||
    # 国际化资源文件路径
 | 
			
		||||
@@ -70,11 +70,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 +91,203 @@ 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/config
 | 
			
		||||
    # druid 监控配置
 | 
			
		||||
    - /druid/**
 | 
			
		||||
  # 用户放行
 | 
			
		||||
  permit-all:
 | 
			
		||||
    # actuator 监控配置
 | 
			
		||||
    - /actuator
 | 
			
		||||
    - /actuator/**
 | 
			
		||||
 | 
			
		||||
# 多租户配置
 | 
			
		||||
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=
 | 
			
		||||
  # 请求前缀
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
knife4j:
 | 
			
		||||
  # 是否开启Knife4j增强模式
 | 
			
		||||
  enable: true
 | 
			
		||||
  # 是否开启生产环境保护策略
 | 
			
		||||
  production: @knife4j.production@
 | 
			
		||||
  # 前端Ui的个性化配置属性
 | 
			
		||||
  setting:
 | 
			
		||||
    # 默认语言
 | 
			
		||||
    language: zh-CN
 | 
			
		||||
    # 是否显示Footer
 | 
			
		||||
    enableFooter: false
 | 
			
		||||
    # 是否开启动态参数调试功能
 | 
			
		||||
    enableDynamicParameter: true
 | 
			
		||||
    # 是否在每个Debug调试栏后显示刷新变量按钮
 | 
			
		||||
    enableReloadCacheParameter: true
 | 
			
		||||
 | 
			
		||||
# 防止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
 | 
			
		||||
 | 
			
		||||
--- # 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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
Application Version: ${revision}
 | 
			
		||||
Application Version: ${ruoyi-vue-plus.version}
 | 
			
		||||
Spring Boot Version: ${spring-boot.version}
 | 
			
		||||
__________            _____.___.__         ____   ____                     __________.__
 | 
			
		||||
\______   \__ __  ____\__  |   |__|        \   \ /   /_ __   ____          \______   \  |  __ __  ______
 | 
			
		||||
 
 | 
			
		||||
@@ -5,33 +5,21 @@ user.jcaptcha.expire=验证码已失效
 | 
			
		||||
user.not.exists=对不起, 您的账号:{0} 不存在.
 | 
			
		||||
user.password.not.match=用户不存在/密码错误
 | 
			
		||||
user.password.retry.limit.count=密码输入错误{0}次
 | 
			
		||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
 | 
			
		||||
user.password.retry.limit.exceed=密码错误次数过多,帐户锁定{0}分钟
 | 
			
		||||
user.password.delete=对不起,您的账号:{0} 已被删除
 | 
			
		||||
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
 | 
			
		||||
role.blocked=角色已封禁,请联系管理员
 | 
			
		||||
user.logout.success=退出成功
 | 
			
		||||
length.not.valid=长度必须在{min}到{max}个字符之间
 | 
			
		||||
user.username.not.blank=用户名不能为空
 | 
			
		||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
 | 
			
		||||
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
 | 
			
		||||
user.password.not.blank=用户密码不能为空
 | 
			
		||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
 | 
			
		||||
user.password.not.valid=* 5-50个字符
 | 
			
		||||
user.email.not.valid=邮箱格式错误
 | 
			
		||||
user.email.not.blank=邮箱不能为空
 | 
			
		||||
user.phonenumber.not.blank=用户手机号不能为空
 | 
			
		||||
user.mobile.phone.number.not.valid=手机号格式错误
 | 
			
		||||
user.login.success=登录成功
 | 
			
		||||
user.register.success=注册成功
 | 
			
		||||
user.register.save.error=保存用户 {0} 失败,注册账号已存在
 | 
			
		||||
user.register.error=注册失败,请联系系统管理人员
 | 
			
		||||
user.notfound=请重新登录
 | 
			
		||||
user.forcelogout=管理员强制退出,请重新登录
 | 
			
		||||
user.unknown.error=未知错误,请重新登录
 | 
			
		||||
auth.grant.type.error=认证权限类型错误
 | 
			
		||||
auth.grant.type.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=对不起,您的租户已过期,请联系管理员
 | 
			
		||||
 
 | 
			
		||||
@@ -5,33 +5,21 @@ user.jcaptcha.expire=Captcha invalid
 | 
			
		||||
user.not.exists=Sorry, your account: {0} does not exist
 | 
			
		||||
user.password.not.match=User does not exist/Password error
 | 
			
		||||
user.password.retry.limit.count=Password input error {0} times
 | 
			
		||||
user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
 | 
			
		||||
user.password.retry.limit.exceed=Too many password errors, account locked for {0} minutes
 | 
			
		||||
user.password.delete=Sorry, your account:{0} has been deleted
 | 
			
		||||
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
 | 
			
		||||
role.blocked=Role disabled,please contact administrators
 | 
			
		||||
user.logout.success=Exit successful
 | 
			
		||||
length.not.valid=The length must be between {min} and {max} characters
 | 
			
		||||
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.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,33 +5,21 @@ user.jcaptcha.expire=验证码已失效
 | 
			
		||||
user.not.exists=对不起, 您的账号:{0} 不存在.
 | 
			
		||||
user.password.not.match=用户不存在/密码错误
 | 
			
		||||
user.password.retry.limit.count=密码输入错误{0}次
 | 
			
		||||
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
 | 
			
		||||
user.password.retry.limit.exceed=密码错误次数过多,帐户锁定{0}分钟
 | 
			
		||||
user.password.delete=对不起,您的账号:{0} 已被删除
 | 
			
		||||
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
 | 
			
		||||
role.blocked=角色已封禁,请联系管理员
 | 
			
		||||
user.logout.success=退出成功
 | 
			
		||||
length.not.valid=长度必须在{min}到{max}个字符之间
 | 
			
		||||
user.username.not.blank=用户名不能为空
 | 
			
		||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
 | 
			
		||||
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
 | 
			
		||||
user.password.not.blank=用户密码不能为空
 | 
			
		||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
 | 
			
		||||
user.password.not.valid=* 5-50个字符
 | 
			
		||||
user.email.not.valid=邮箱格式错误
 | 
			
		||||
user.email.not.blank=邮箱不能为空
 | 
			
		||||
user.phonenumber.not.blank=用户手机号不能为空
 | 
			
		||||
user.mobile.phone.number.not.valid=手机号格式错误
 | 
			
		||||
user.login.success=登录成功
 | 
			
		||||
user.register.success=注册成功
 | 
			
		||||
user.register.save.error=保存用户 {0} 失败,注册账号已存在
 | 
			
		||||
user.register.error=注册失败,请联系系统管理人员
 | 
			
		||||
user.notfound=请重新登录
 | 
			
		||||
user.forcelogout=管理员强制退出,请重新登录
 | 
			
		||||
user.unknown.error=未知错误,请重新登录
 | 
			
		||||
auth.grant.type.error=认证权限类型错误
 | 
			
		||||
auth.grant.type.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>
 | 
			
		||||
							
								
								
									
										96
									
								
								ruoyi-admin/src/main/resources/logback.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								ruoyi-admin/src/main/resources/logback.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
<?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>
 | 
			
		||||
 | 
			
		||||
	<!-- 系统模块日志级别控制  -->
 | 
			
		||||
	<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>
 | 
			
		||||
 | 
			
		||||
</configuration>
 | 
			
		||||
@@ -6,15 +6,19 @@ 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=
 | 
			
		||||
@@ -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 ==================");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -4,43 +4,161 @@
 | 
			
		||||
         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.5.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>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>cglib</groupId>
 | 
			
		||||
            <artifactId>cglib</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- yml解析器 -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.yaml</groupId>
 | 
			
		||||
            <artifactId>snakeyaml</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- jdk11 缺失依赖 jaxb-->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.sun.xml.bind</groupId>
 | 
			
		||||
            <artifactId>jaxb-impl</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>
 | 
			
		||||
 | 
			
		||||
        <!-- dynamic-datasource 多数据源-->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.baomidou</groupId>
 | 
			
		||||
            <artifactId>dynamic-datasource-spring-boot-starter</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-captcha</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>cn.hutool</groupId>
 | 
			
		||||
            <artifactId>hutool-jwt</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>cn.hutool</groupId>
 | 
			
		||||
            <artifactId>hutool-extra</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.projectlombok</groupId>
 | 
			
		||||
            <artifactId>lombok</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.github.xiaoymin</groupId>
 | 
			
		||||
            <artifactId>knife4j-spring-boot-starter</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>io.swagger</groupId>
 | 
			
		||||
            <artifactId>swagger-annotations</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>
 | 
			
		||||
 | 
			
		||||
    </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.4.0</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,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,34 +0,0 @@
 | 
			
		||||
package org.dromara.common.core.domain.event;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 删除流程监听
 | 
			
		||||
 *
 | 
			
		||||
 * @author AprilWind
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class ProcessDeleteEvent implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 租户ID
 | 
			
		||||
     */
 | 
			
		||||
    private String tenantId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 流程定义编码
 | 
			
		||||
     */
 | 
			
		||||
    private String flowCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 业务id
 | 
			
		||||
     */
 | 
			
		||||
    private String businessId;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,65 +0,0 @@
 | 
			
		||||
package org.dromara.common.core.domain.event;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 总体流程监听
 | 
			
		||||
 *
 | 
			
		||||
 * @author may
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class ProcessEvent implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 租户ID
 | 
			
		||||
     */
 | 
			
		||||
    private String tenantId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 流程定义编码
 | 
			
		||||
     */
 | 
			
		||||
    private String flowCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 业务id
 | 
			
		||||
     */
 | 
			
		||||
    private String businessId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)
 | 
			
		||||
     */
 | 
			
		||||
    private Integer nodeType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 流程节点编码
 | 
			
		||||
     */
 | 
			
		||||
    private String nodeCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 流程节点名称
 | 
			
		||||
     */
 | 
			
		||||
    private String nodeName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 流程状态
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 办理参数
 | 
			
		||||
     */
 | 
			
		||||
    private Map<String, Object> params;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 当为true时为申请人节点办理
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean submit;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,59 +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 ProcessTaskEvent 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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 流程状态
 | 
			
		||||
     */
 | 
			
		||||
    private String status;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package org.dromara.common.core.domain.model;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.Email;
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 邮件登录对象
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
public class EmailLoginBody extends LoginBody {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 邮箱
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "{user.email.not.blank}")
 | 
			
		||||
    @Email(message = "{user.email.not.valid}")
 | 
			
		||||
    private String email;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 邮箱code
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "{email.code.not.blank}")
 | 
			
		||||
    private String emailCode;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
package org.dromara.common.core.domain.model;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户登录对象
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class LoginBody implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 客户端id
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "{auth.clientid.not.blank}")
 | 
			
		||||
    private String clientId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权类型
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "{auth.grant.type.not.blank}")
 | 
			
		||||
    private String grantType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 租户ID
 | 
			
		||||
     */
 | 
			
		||||
    private String tenantId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证码
 | 
			
		||||
     */
 | 
			
		||||
    private String code;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 唯一标识
 | 
			
		||||
     */
 | 
			
		||||
    private String uuid;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,148 +0,0 @@
 | 
			
		||||
package org.dromara.common.core.domain.model;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.dromara.common.core.domain.dto.PostDTO;
 | 
			
		||||
import org.dromara.common.core.domain.dto.RoleDTO;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 登录用户身份权限
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
public class LoginUser implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 租户ID
 | 
			
		||||
     */
 | 
			
		||||
    private String tenantId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long deptId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门类别编码
 | 
			
		||||
     */
 | 
			
		||||
    private String deptCategory;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 部门名
 | 
			
		||||
     */
 | 
			
		||||
    private String deptName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户唯一标识
 | 
			
		||||
     */
 | 
			
		||||
    private String token;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户类型
 | 
			
		||||
     */
 | 
			
		||||
    private String userType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登录时间
 | 
			
		||||
     */
 | 
			
		||||
    private Long loginTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 过期时间
 | 
			
		||||
     */
 | 
			
		||||
    private Long expireTime;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登录IP地址
 | 
			
		||||
     */
 | 
			
		||||
    private String ipaddr;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登录地点
 | 
			
		||||
     */
 | 
			
		||||
    private String loginLocation;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 浏览器类型
 | 
			
		||||
     */
 | 
			
		||||
    private String browser;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 操作系统
 | 
			
		||||
     */
 | 
			
		||||
    private String os;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 菜单权限
 | 
			
		||||
     */
 | 
			
		||||
    private Set<String> menuPermission;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 角色权限
 | 
			
		||||
     */
 | 
			
		||||
    private Set<String> rolePermission;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户名
 | 
			
		||||
     */
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户昵称
 | 
			
		||||
     */
 | 
			
		||||
    private String nickname;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 角色对象
 | 
			
		||||
     */
 | 
			
		||||
    private List<RoleDTO> roles;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 岗位对象
 | 
			
		||||
     */
 | 
			
		||||
    private List<PostDTO> posts;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 数据权限 当前角色ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long roleId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 客户端
 | 
			
		||||
     */
 | 
			
		||||
    private String clientKey;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设备类型
 | 
			
		||||
     */
 | 
			
		||||
    private String deviceType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取登录id
 | 
			
		||||
     */
 | 
			
		||||
    public String getLoginId() {
 | 
			
		||||
        if (userType == null) {
 | 
			
		||||
            throw new IllegalArgumentException("用户类型不能为空");
 | 
			
		||||
        }
 | 
			
		||||
        if (userId == null) {
 | 
			
		||||
            throw new IllegalArgumentException("用户ID不能为空");
 | 
			
		||||
        }
 | 
			
		||||
        return userType + ":" + userId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package org.dromara.common.core.domain.model;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotBlank;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import org.hibernate.validator.constraints.Length;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 密码登录对象
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
public class PasswordLoginBody extends LoginBody {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户名
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "{user.username.not.blank}")
 | 
			
		||||
    @Length(min = 2, max = 30, message = "{user.username.length.valid}")
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户密码
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "{user.password.not.blank}")
 | 
			
		||||
    @Length(min = 5, max = 30, message = "{user.password.length.valid}")
 | 
			
		||||
    private String password;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user