commit
a9dc752360
775 changed files with 74573 additions and 0 deletions
@ -0,0 +1,18 @@ |
|||||
|
# http://editorconfig.org |
||||
|
root = true |
||||
|
|
||||
|
# 空格替代Tab缩进在各种编辑工具下效果一致 |
||||
|
[*] |
||||
|
indent_style = space |
||||
|
indent_size = 4 |
||||
|
charset = utf-8 |
||||
|
end_of_line = lf |
||||
|
trim_trailing_whitespace = true |
||||
|
insert_final_newline = true |
||||
|
|
||||
|
[*.{json,yml,yaml}] |
||||
|
indent_size = 2 |
||||
|
|
||||
|
[*.md] |
||||
|
insert_final_newline = false |
||||
|
trim_trailing_whitespace = false |
@ -0,0 +1,49 @@ |
|||||
|
### 使用版本(未按照模板填写直接删除) |
||||
|
|
||||
|
- jdk版本(带上尾号): 例如 1.8.0_202 |
||||
|
- 框架版本(项目启动时输出的版本号): 例如 4.4.0 |
||||
|
- 其他依赖版本(你觉得有必要的): |
||||
|
|
||||
|
### 问题前提 |
||||
|
|
||||
|
> 功能不好用 不会用 是否已经看过项目文档 |
||||
|
> 项目运行报错 是否已经拿着报错信息去百度 常见报错百度百度足以 |
||||
|
> 是否搜索过其他issue 一些已经解决的问题 会在issue内留下解决方法 |
||||
|
> 无法线上解决或者与框架无关的问题的欢迎加VIP群跟作者一对一谈 |
||||
|
|
||||
|
### 异常模块 |
||||
|
|
||||
|
> 此报错都涉及到那些系统模块 |
||||
|
|
||||
|
例如 ruoyi-system ruoyi-auth 等等 |
||||
|
|
||||
|
### 问题描述 |
||||
|
|
||||
|
> 越详细越容易直击问题所在 |
||||
|
|
||||
|
已知: XXX功能不好用 或 XXX数据不正常 等等 |
||||
|
|
||||
|
### 希望结果 |
||||
|
|
||||
|
> 想知道你觉得怎么样是正常或者合理的 |
||||
|
|
||||
|
希望功能可以有XXX结果 或者 XXX现象 |
||||
|
|
||||
|
### 重现步骤 |
||||
|
|
||||
|
> 作者并不知道这个问题是如何出现的 |
||||
|
|
||||
|
- 1 |
||||
|
- 2 |
||||
|
- 3 |
||||
|
|
||||
|
### 相关代码与报错信息(请勿发混乱格式) |
||||
|
|
||||
|
> 代码可按照如下形式提供或者截图均可 越详细越好 |
||||
|
> 大多数问题都是 代码编写错误问题 逻辑问题 或者用法错误等问题 |
||||
|
|
||||
|
```java |
||||
|
public class XXX { |
||||
|
|
||||
|
} |
||||
|
``` |
@ -0,0 +1,50 @@ |
|||||
|
name: Bug 反馈 |
||||
|
description: 当你使用过程中发现了一个 Bug,导致应用崩溃或抛出异常,或者有一个组件存在问题,或者某些地方看起来不对劲,请在这里反馈。 |
||||
|
title: "[Bug]: " |
||||
|
labels: ["bug"] |
||||
|
body: |
||||
|
- type: textarea |
||||
|
id: version |
||||
|
attributes: |
||||
|
label: 版本 |
||||
|
description: 你当前正在使用我们软件的哪个版本(pom文件内的版本号)? |
||||
|
value: | |
||||
|
jdk版本(带上尾号): 例如 17.0.8 |
||||
|
框架版本(项目启动时输出的版本号): 例如 5.1.1 |
||||
|
其他依赖版本(你觉得有必要的): |
||||
|
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: | |
||||
|
[在这里上传图片] |
||||
|
|
@ -0,0 +1,5 @@ |
|||||
|
blank_issues_enabled: false |
||||
|
contact_links: |
||||
|
- name: RuoYi-Vue-Plus 文档中心 |
||||
|
url: https://plus-doc.dromara.org |
||||
|
about: 提供 RuoYi-Vue-Plus 搭建使用指南、平台基本开发使用方式、介绍、基础知识和常见问题解答 |
@ -0,0 +1,43 @@ |
|||||
|
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 |
@ -0,0 +1,7 @@ |
|||||
|
### 更改目的 解决了什么问题(请提交到dev分支) |
||||
|
|
||||
|
|
||||
|
### 改动逻辑 这么写的思路(让作者更好的理解你的意图) |
||||
|
|
||||
|
|
||||
|
### 测试 都做了哪些测试(未经过测试不采纳) |
@ -0,0 +1,48 @@ |
|||||
|
###################################################################### |
||||
|
# Build Tools |
||||
|
|
||||
|
.gradle |
||||
|
/build/ |
||||
|
!gradle/wrapper/gradle-wrapper.jar |
||||
|
|
||||
|
target/ |
||||
|
!.mvn/wrapper/maven-wrapper.jar |
||||
|
|
||||
|
###################################################################### |
||||
|
# IDE |
||||
|
|
||||
|
### STS ### |
||||
|
.apt_generated |
||||
|
.classpath |
||||
|
.factorypath |
||||
|
.project |
||||
|
.settings |
||||
|
.springBeans |
||||
|
|
||||
|
### IntelliJ IDEA ### |
||||
|
.idea |
||||
|
*.iws |
||||
|
*.iml |
||||
|
*.ipr |
||||
|
|
||||
|
### JRebel ### |
||||
|
rebel.xml |
||||
|
|
||||
|
### NetBeans ### |
||||
|
nbproject/private/ |
||||
|
build/* |
||||
|
nbbuild/ |
||||
|
nbdist/ |
||||
|
.nb-gradle/ |
||||
|
|
||||
|
###################################################################### |
||||
|
# Others |
||||
|
*.log |
||||
|
*.xml.versionsBackup |
||||
|
*.swp |
||||
|
|
||||
|
!*/build/*.java |
||||
|
!*/build/*.html |
||||
|
!*/build/*.xml |
||||
|
|
||||
|
.flattened-pom.xml |
@ -0,0 +1,12 @@ |
|||||
|
<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.2.0" /> |
||||
|
<option name="buildOnly" value="true" /> |
||||
|
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" /> |
||||
|
</settings> |
||||
|
</deployment> |
||||
|
<method v="2" /> |
||||
|
</configuration> |
||||
|
</component> |
@ -0,0 +1,12 @@ |
|||||
|
<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.2.0" /> |
||||
|
<option name="buildOnly" value="true" /> |
||||
|
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" /> |
||||
|
</settings> |
||||
|
</deployment> |
||||
|
<method v="2" /> |
||||
|
</configuration> |
||||
|
</component> |
@ -0,0 +1,12 @@ |
|||||
|
<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.2.0" /> |
||||
|
<option name="buildOnly" value="true" /> |
||||
|
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" /> |
||||
|
</settings> |
||||
|
</deployment> |
||||
|
<method v="2" /> |
||||
|
</configuration> |
||||
|
</component> |
@ -0,0 +1,20 @@ |
|||||
|
The MIT License (MIT) |
||||
|
|
||||
|
Copyright (c) 2019 RuoYi-Vue-Plus |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
|
this software and associated documentation files (the "Software"), to deal in |
||||
|
the Software without restriction, including without limitation the rights to |
||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
||||
|
the Software, and to permit persons to whom the Software is furnished to do so, |
||||
|
subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,180 @@ |
|||||
|
<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://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) |
||||
|
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) |
||||
|
<br> |
||||
|
[](https://gitee.com/dromara/RuoYi-Vue-Plus) |
||||
|
[]() |
||||
|
[]() |
||||
|
[]() |
||||
|
|
||||
|
> RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) |
||||
|
|
||||
|
> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可<br> |
||||
|
活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 |
||||
|
|
||||
|
> 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system) |
||||
|
|
||||
|
> 前端项目地址: [plus-ui](https://gitee.com/JavaLionLi/plus-ui) |
||||
|
|
||||
|
> 文档地址: [plus-doc](https://plus-doc.dromara.org) |
||||
|
|
||||
|
## 赞助商 |
||||
|
|
||||
|
MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey <br> |
||||
|
CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br> |
||||
|
数舵科技 软件定制开发APP小程序等 - http://www.shuduokeji.com/ <br> |
||||
|
引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc <br> |
||||
|
[如何成为赞助商 加群联系作者详谈](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鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | |
||||
|
| 序列化 | 采用 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框架 | 采用 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、内存、磁盘监控 | |
||||
|
| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | |
||||
|
| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | |
||||
|
| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | |
||||
|
|
||||
|
## 参考文档 |
||||
|
|
||||
|
使用框架前请仔细阅读文档重点注意事项 |
||||
|
<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://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution) |
||||
|
|
||||
|
## 捐献作者 |
||||
|
作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭 |
||||
|
<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" /> |
||||
|
|
||||
|
## 演示图例 |
||||
|
|
||||
|
| | | |
||||
|
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|  |  | |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,513 @@ |
|||||
|
<?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-vue-plus</artifactId> |
||||
|
<version>${revision}</version> |
||||
|
|
||||
|
<name>RuoYi-Vue-Plus</name> |
||||
|
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url> |
||||
|
<description>RuoYi-Vue-Plus多租户管理系统</description> |
||||
|
|
||||
|
<properties> |
||||
|
<revision>5.2.0</revision> |
||||
|
<spring-boot.version>3.2.6</spring-boot.version> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
||||
|
<java.version>17</java.version> |
||||
|
<mybatis.version>3.5.16</mybatis.version> |
||||
|
<springdoc.version>2.5.0</springdoc.version> |
||||
|
<therapi-javadoc.version>0.15.0</therapi-javadoc.version> |
||||
|
<poi.version>5.2.3</poi.version> |
||||
|
<easyexcel.version>3.3.4</easyexcel.version> |
||||
|
<velocity.version>2.3</velocity.version> |
||||
|
<satoken.version>1.38.0</satoken.version> |
||||
|
<mybatis-plus.version>3.5.7</mybatis-plus.version> |
||||
|
<p6spy.version>3.9.1</p6spy.version> |
||||
|
<hutool.version>5.8.27</hutool.version> |
||||
|
<okhttp.version>4.10.0</okhttp.version> |
||||
|
<spring-boot-admin.version>3.2.3</spring-boot-admin.version> |
||||
|
<redisson.version>3.31.0</redisson.version> |
||||
|
<lock4j.version>2.2.7</lock4j.version> |
||||
|
<dynamic-ds.version>4.3.1</dynamic-ds.version> |
||||
|
<alibaba-ttl.version>2.14.4</alibaba-ttl.version> |
||||
|
<snailjob.version>1.0.1</snailjob.version> |
||||
|
<mapstruct-plus.version>1.3.6</mapstruct-plus.version> |
||||
|
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version> |
||||
|
<lombok.version>1.18.32</lombok.version> |
||||
|
<bouncycastle.version>1.76</bouncycastle.version> |
||||
|
<justauth.version>1.16.6</justauth.version> |
||||
|
<!-- 离线IP地址定位库 --> |
||||
|
<ip2region.version>2.7.0</ip2region.version> |
||||
|
|
||||
|
<!-- OSS 配置 --> |
||||
|
<aws.sdk.version>2.25.15</aws.sdk.version> |
||||
|
<aws.crt.version>0.29.13</aws.crt.version> |
||||
|
<!-- SMS 配置 --> |
||||
|
<sms4j.version>3.2.1</sms4j.version> |
||||
|
<!-- 限制框架中的fastjson版本 --> |
||||
|
<fastjson.version>1.2.83</fastjson.version> |
||||
|
<!--工作流配置--> |
||||
|
<flowable.version>7.0.0</flowable.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.verison>3.11.0</maven-compiler-plugin.verison> |
||||
|
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version> |
||||
|
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version> |
||||
|
</properties> |
||||
|
|
||||
|
<profiles> |
||||
|
<profile> |
||||
|
<id>local</id> |
||||
|
<properties> |
||||
|
<!-- 环境标识,需要与配置文件的名称相对应 --> |
||||
|
<profiles.active>local</profiles.active> |
||||
|
<logging.level>info</logging.level> |
||||
|
</properties> |
||||
|
</profile> |
||||
|
<profile> |
||||
|
<id>dev</id> |
||||
|
<properties> |
||||
|
<!-- 环境标识,需要与配置文件的名称相对应 --> |
||||
|
<profiles.active>dev</profiles.active> |
||||
|
<logging.level>info</logging.level> |
||||
|
</properties> |
||||
|
<activation> |
||||
|
<!-- 默认环境 --> |
||||
|
<activeByDefault>true</activeByDefault> |
||||
|
</activation> |
||||
|
</profile> |
||||
|
<profile> |
||||
|
<id>prod</id> |
||||
|
<properties> |
||||
|
<profiles.active>prod</profiles.active> |
||||
|
<logging.level>warn</logging.level> |
||||
|
</properties> |
||||
|
</profile> |
||||
|
</profiles> |
||||
|
|
||||
|
<!-- 依赖声明 --> |
||||
|
<dependencyManagement> |
||||
|
<dependencies> |
||||
|
|
||||
|
<!-- SpringBoot的依赖配置--> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-dependencies</artifactId> |
||||
|
<version>${spring-boot.version}</version> |
||||
|
<type>pom</type> |
||||
|
<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> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.flowable</groupId> |
||||
|
<artifactId>flowable-bom</artifactId> |
||||
|
<version>${flowable.version}</version> |
||||
|
<type>pom</type> |
||||
|
<scope>import</scope> |
||||
|
</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> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springdoc</groupId> |
||||
|
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId> |
||||
|
<version>${springdoc.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.github.therapi</groupId> |
||||
|
<artifactId>therapi-runtime-javadoc</artifactId> |
||||
|
<version>${therapi-javadoc.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
<version>${lombok.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.apache.poi</groupId> |
||||
|
<artifactId>poi</artifactId> |
||||
|
<version>${poi.version}</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.poi</groupId> |
||||
|
<artifactId>poi-ooxml</artifactId> |
||||
|
<version>${poi.version}</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>easyexcel</artifactId> |
||||
|
<version>${easyexcel.version}</version> |
||||
|
<exclusions> |
||||
|
<exclusion> |
||||
|
<groupId>org.apache.poi</groupId> |
||||
|
<artifactId>poi-ooxml-schemas</artifactId> |
||||
|
</exclusion> |
||||
|
</exclusions> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- velocity代码生成使用模板 --> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.velocity</groupId> |
||||
|
<artifactId>velocity-engine-core</artifactId> |
||||
|
<version>${velocity.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ --> |
||||
|
<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> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- dynamic-datasource 多数据源--> |
||||
|
<dependency> |
||||
|
<groupId>com.baomidou</groupId> |
||||
|
<artifactId>dynamic-datasource-spring-boot3-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> |
||||
|
<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> |
||||
|
<artifactId>p6spy</artifactId> |
||||
|
<version>${p6spy.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.squareup.okhttp3</groupId> |
||||
|
<artifactId>okhttp</artifactId> |
||||
|
<version>${okhttp.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- AWS SDK for Java 2.x --> |
||||
|
<dependency> |
||||
|
<groupId>software.amazon.awssdk</groupId> |
||||
|
<artifactId>s3</artifactId> |
||||
|
<version>${aws.sdk.version}</version> |
||||
|
</dependency> |
||||
|
<!-- 使用AWS基于 CRT 的 S3 客户端 --> |
||||
|
<dependency> |
||||
|
<groupId>software.amazon.awssdk.crt</groupId> |
||||
|
<artifactId>aws-crt</artifactId> |
||||
|
<version>${aws.crt.version}</version> |
||||
|
</dependency> |
||||
|
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 --> |
||||
|
<dependency> |
||||
|
<groupId>software.amazon.awssdk</groupId> |
||||
|
<artifactId>s3-transfer-manager</artifactId> |
||||
|
<version>${aws.sdk.version}</version> |
||||
|
</dependency> |
||||
|
<!--短信sms4j--> |
||||
|
<dependency> |
||||
|
<groupId>org.dromara.sms4j</groupId> |
||||
|
<artifactId>sms4j-spring-boot-starter</artifactId> |
||||
|
<version>${sms4j.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>de.codecentric</groupId> |
||||
|
<artifactId>spring-boot-admin-starter-server</artifactId> |
||||
|
<version>${spring-boot-admin.version}</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>de.codecentric</groupId> |
||||
|
<artifactId>spring-boot-admin-starter-client</artifactId> |
||||
|
<version>${spring-boot-admin.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!--redisson--> |
||||
|
<dependency> |
||||
|
<groupId>org.redisson</groupId> |
||||
|
<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 --> |
||||
|
<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>com.alibaba</groupId> |
||||
|
<artifactId>transmittable-thread-local</artifactId> |
||||
|
<version>${alibaba-ttl.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- 加密包引入 --> |
||||
|
<dependency> |
||||
|
<groupId>org.bouncycastle</groupId> |
||||
|
<artifactId>bcprov-jdk15to18</artifactId> |
||||
|
<version>${bouncycastle.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> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>fastjson</artifactId> |
||||
|
<version>${fastjson.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-system</artifactId> |
||||
|
<version>${revision}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-job</artifactId> |
||||
|
<version>${revision}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-generator</artifactId> |
||||
|
<version>${revision}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-demo</artifactId> |
||||
|
<version>${revision}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- 工作流模块 --> |
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-workflow</artifactId> |
||||
|
<version>${revision}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
</dependencies> |
||||
|
</dependencyManagement> |
||||
|
|
||||
|
<modules> |
||||
|
<module>ruoyi-admin</module> |
||||
|
<module>ruoyi-common</module> |
||||
|
<module>ruoyi-extend</module> |
||||
|
<module>ruoyi-modules</module> |
||||
|
</modules> |
||||
|
<packaging>pom</packaging> |
||||
|
|
||||
|
<build> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||
|
<version>${maven-compiler-plugin.verison}</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> |
||||
|
<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> |
||||
|
</resources> |
||||
|
</build> |
||||
|
|
||||
|
<repositories> |
||||
|
<repository> |
||||
|
<id>public</id> |
||||
|
<name>huawei nexus</name> |
||||
|
<url>https://mirrors.huaweicloud.com/repository/maven/</url> |
||||
|
<releases> |
||||
|
<enabled>true</enabled> |
||||
|
</releases> |
||||
|
</repository> |
||||
|
</repositories> |
||||
|
|
||||
|
<pluginRepositories> |
||||
|
<pluginRepository> |
||||
|
<id>public</id> |
||||
|
<name>huawei nexus</name> |
||||
|
<url>https://mirrors.huaweicloud.com/repository/maven/</url> |
||||
|
<releases> |
||||
|
<enabled>true</enabled> |
||||
|
</releases> |
||||
|
<snapshots> |
||||
|
<enabled>false</enabled> |
||||
|
</snapshots> |
||||
|
</pluginRepository> |
||||
|
</pluginRepositories> |
||||
|
|
||||
|
</project> |
||||
|
|
||||
|
|
@ -0,0 +1,24 @@ |
|||||
|
#FROM findepi/graalvm:java17-native |
||||
|
FROM openjdk:17.0.2-oraclelinux8 |
||||
|
|
||||
|
MAINTAINER Lion Li |
||||
|
|
||||
|
RUN mkdir -p /ruoyi/server/logs \ |
||||
|
/ruoyi/server/temp \ |
||||
|
/ruoyi/skywalking/agent |
||||
|
|
||||
|
WORKDIR /ruoyi/server |
||||
|
|
||||
|
ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" |
||||
|
|
||||
|
EXPOSE ${SERVER_PORT} |
||||
|
|
||||
|
ADD ./target/ruoyi-admin.jar ./app.jar |
||||
|
|
||||
|
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ |
||||
|
# 应用名称 如果想区分集群节点监控 改成不同的名称即可 |
||||
|
#-Dskywalking.agent.service_name=ruoyi-server \ |
||||
|
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ |
||||
|
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ |
||||
|
-jar app.jar |
||||
|
|
@ -0,0 +1,146 @@ |
|||||
|
<?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> |
||||
|
<artifactId>ruoyi-vue-plus</artifactId> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<version>${revision}</version> |
||||
|
</parent> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<packaging>jar</packaging> |
||||
|
<artifactId>ruoyi-admin</artifactId> |
||||
|
|
||||
|
<description> |
||||
|
web服务入口 |
||||
|
</description> |
||||
|
|
||||
|
<dependencies> |
||||
|
|
||||
|
<!-- Mysql驱动包 --> |
||||
|
<dependency> |
||||
|
<groupId>com.mysql</groupId> |
||||
|
<artifactId>mysql-connector-j</artifactId> |
||||
|
</dependency> |
||||
|
<!-- Oracle --> |
||||
|
<dependency> |
||||
|
<groupId>com.oracle.database.jdbc</groupId> |
||||
|
<artifactId>ojdbc8</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> |
||||
|
</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> |
||||
|
<artifactId>ruoyi-system</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-job</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- 代码生成--> |
||||
|
<dependency> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<artifactId>ruoyi-generator</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- demo模块 --> |
||||
|
<dependency> |
||||
|
<groupId>org.dromara</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> |
||||
|
<finalName>${project.artifactId}</finalName> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
|
<version>${spring-boot.version}</version> |
||||
|
<executions> |
||||
|
<execution> |
||||
|
<goals> |
||||
|
<goal>repackage</goal> |
||||
|
</goals> |
||||
|
</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> |
||||
|
<configuration> |
||||
|
<failOnMissingWebXml>false</failOnMissingWebXml> |
||||
|
<warName>${project.artifactId}</warName> |
||||
|
</configuration> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
</build> |
||||
|
|
||||
|
</project> |
@ -0,0 +1,23 @@ |
|||||
|
package org.dromara; |
||||
|
|
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; |
||||
|
|
||||
|
/** |
||||
|
* 启动程序 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
|
||||
|
@SpringBootApplication |
||||
|
public class DromaraApplication { |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
SpringApplication application = new SpringApplication(DromaraApplication.class); |
||||
|
application.setApplicationStartup(new BufferingApplicationStartup(2048)); |
||||
|
application.run(args); |
||||
|
System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙"); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara; |
||||
|
|
||||
|
import org.springframework.boot.builder.SpringApplicationBuilder; |
||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||
|
|
||||
|
/** |
||||
|
* web容器中进行部署 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public class DromaraServletInitializer extends SpringBootServletInitializer { |
||||
|
|
||||
|
@Override |
||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { |
||||
|
return application.sources(DromaraApplication.class); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,218 @@ |
|||||
|
package org.dromara.web.controller; |
||||
|
|
||||
|
import cn.dev33.satoken.annotation.SaIgnore; |
||||
|
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.UserConstants; |
||||
|
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.tenant.helper.TenantHelper; |
||||
|
import org.dromara.common.websocket.dto.WebSocketMessageDto; |
||||
|
import org.dromara.common.websocket.utils.WebSocketUtils; |
||||
|
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 (!UserConstants.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(() -> { |
||||
|
WebSocketMessageDto dto = new WebSocketMessageDto(); |
||||
|
dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统"); |
||||
|
dto.setSessionKeys(List.of(userId)); |
||||
|
WebSocketUtils.publishMessage(dto); |
||||
|
}, 3, TimeUnit.SECONDS); |
||||
|
return R.ok(loginVo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 第三方登录请求 |
||||
|
* |
||||
|
* @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); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 第三方登录回调业务处理 绑定授权 |
||||
|
* |
||||
|
* @param loginBody 请求体 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
@PostMapping("/social/callback") |
||||
|
public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) { |
||||
|
// 获取第三方登录信息
|
||||
|
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(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 取消授权 |
||||
|
* |
||||
|
* @param socialId socialId |
||||
|
*/ |
||||
|
@DeleteMapping(value = "/unlock/{socialId}") |
||||
|
public R<Void> unlockSocial(@PathVariable Long socialId) { |
||||
|
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 { |
||||
|
List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo()); |
||||
|
List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class); |
||||
|
// 获取域名
|
||||
|
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.equals(vo.getDomain(), host)); |
||||
|
// 返回对象
|
||||
|
LoginTenantVo vo = new LoginTenantVo(); |
||||
|
vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList); |
||||
|
vo.setTenantEnabled(TenantHelper.isEnable()); |
||||
|
return R.ok(vo); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,136 @@ |
|||||
|
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.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 邮箱 |
||||
|
*/ |
||||
|
@RateLimiter(key = "#email", time = 60, count = 1) |
||||
|
@GetMapping("/resource/email/code") |
||||
|
public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { |
||||
|
if (!mailProperties.getEnabled()) { |
||||
|
return R.fail("当前系统没有开启邮箱功能!"); |
||||
|
} |
||||
|
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()); |
||||
|
return R.fail(e.getMessage()); |
||||
|
} |
||||
|
return R.ok(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成验证码 |
||||
|
*/ |
||||
|
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP) |
||||
|
@GetMapping("/auth/code") |
||||
|
public R<CaptchaVo> getCode() { |
||||
|
CaptchaVo captchaVo = new CaptchaVo(); |
||||
|
boolean captchaEnabled = captchaProperties.getEnable(); |
||||
|
if (!captchaEnabled) { |
||||
|
captchaVo.setCaptchaEnabled(false); |
||||
|
return R.ok(captchaVo); |
||||
|
} |
||||
|
// 保存验证码信息
|
||||
|
String uuid = IdUtil.simpleUUID(); |
||||
|
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; |
||||
|
// 生成验证码
|
||||
|
CaptchaType captchaType = captchaProperties.getType(); |
||||
|
boolean isMath = CaptchaType.MATH == captchaType; |
||||
|
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); |
||||
|
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); |
||||
|
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); |
||||
|
captcha.setGenerator(codeGenerator); |
||||
|
captcha.createCode(); |
||||
|
// 如果是数学验证码,使用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.setUuid(uuid); |
||||
|
captchaVo.setImg(captcha.getImageBase64()); |
||||
|
return R.ok(captchaVo); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
package org.dromara.web.controller; |
||||
|
|
||||
|
import cn.dev33.satoken.annotation.SaIgnore; |
||||
|
import org.dromara.common.core.config.RuoYiConfig; |
||||
|
import org.dromara.common.core.utils.StringUtils; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
/** |
||||
|
* 首页 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@SaIgnore |
||||
|
@RequiredArgsConstructor |
||||
|
@RestController |
||||
|
public class IndexController { |
||||
|
|
||||
|
/** |
||||
|
* 系统基础配置 |
||||
|
*/ |
||||
|
private final RuoYiConfig ruoyiConfig; |
||||
|
|
||||
|
/** |
||||
|
* 访问首页,提示语 |
||||
|
*/ |
||||
|
@GetMapping("/") |
||||
|
public String index() { |
||||
|
return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,154 @@ |
|||||
|
package org.dromara.web.listener; |
||||
|
|
||||
|
import cn.dev33.satoken.config.SaTokenConfig; |
||||
|
import cn.dev33.satoken.listener.SaTokenListener; |
||||
|
import cn.dev33.satoken.stp.SaLoginModel; |
||||
|
import cn.hutool.http.useragent.UserAgent; |
||||
|
import cn.hutool.http.useragent.UserAgentUtil; |
||||
|
import 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 SaTokenConfig tokenConfig; |
||||
|
private final SysLoginService loginService; |
||||
|
|
||||
|
/** |
||||
|
* 每次登录时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { |
||||
|
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) loginModel.getExtra(LoginHelper.USER_NAME_KEY); |
||||
|
String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY); |
||||
|
dto.setUserName(username); |
||||
|
dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY)); |
||||
|
dto.setDeviceType(loginModel.getDevice()); |
||||
|
dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY)); |
||||
|
TenantHelper.dynamic(tenantId, () -> { |
||||
|
if(tokenConfig.getTimeout() == -1) { |
||||
|
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); |
||||
|
} else { |
||||
|
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); |
||||
|
} |
||||
|
}); |
||||
|
// 记录登录日志
|
||||
|
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) loginModel.getExtra(LoginHelper.USER_KEY), ip); |
||||
|
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次注销时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doLogout(String loginType, Object loginId, String tokenValue) { |
||||
|
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); |
||||
|
log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次被踢下线时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doKickout(String loginType, Object loginId, String tokenValue) { |
||||
|
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); |
||||
|
log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次被顶下线时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doReplaced(String loginType, Object loginId, String tokenValue) { |
||||
|
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); |
||||
|
log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次被封禁时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次被解封时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doUntieDisable(String loginType, Object loginId, String service) { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次打开二级认证时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次创建Session时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doCloseSafe(String loginType, String tokenValue, String service) { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次创建Session时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doCreateSession(String id) { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次注销Session时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doLogoutSession(String id) { |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 每次Token续期时触发 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { |
||||
|
} |
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
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); |
||||
|
|
||||
|
} |
@ -0,0 +1,248 @@ |
|||||
|
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.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.Constants; |
||||
|
import org.dromara.common.core.constant.GlobalConstants; |
||||
|
import org.dromara.common.core.constant.TenantConstants; |
||||
|
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.enums.TenantStatus; |
||||
|
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 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(); |
||||
|
loginUser.setTenantId(user.getTenantId()); |
||||
|
loginUser.setUserId(user.getUserId()); |
||||
|
loginUser.setDeptId(user.getDeptId()); |
||||
|
loginUser.setUsername(user.getUserName()); |
||||
|
loginUser.setNickname(user.getNickName()); |
||||
|
loginUser.setUserType(user.getUserType()); |
||||
|
loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); |
||||
|
loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); |
||||
|
TenantHelper.dynamic(user.getTenantId(), () -> { |
||||
|
SysDeptVo dept = null; |
||||
|
if (ObjectUtil.isNotNull(user.getDeptId())) { |
||||
|
dept = deptService.selectDeptById(user.getDeptId()); |
||||
|
} |
||||
|
loginUser.setDeptName(ObjectUtil.isNull(dept) ? "" : dept.getDeptName()); |
||||
|
loginUser.setDeptCategory(ObjectUtil.isNull(dept) ? "" : dept.getDeptCategory()); |
||||
|
List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId()); |
||||
|
loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.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 = GlobalConstants.PWD_ERR_CNT_KEY + username; |
||||
|
String loginFail = Constants.LOGIN_FAIL; |
||||
|
|
||||
|
// 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip)
|
||||
|
int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); |
||||
|
// 锁定时间内登录 则踢出
|
||||
|
if (errorNumber >= maxRetryCount) { |
||||
|
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
||||
|
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
||||
|
} |
||||
|
|
||||
|
if (supplier.get()) { |
||||
|
// 错误次数递增
|
||||
|
errorNumber++; |
||||
|
RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); |
||||
|
// 达到规定错误次数 则锁定登录
|
||||
|
if (errorNumber >= maxRetryCount) { |
||||
|
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
||||
|
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
||||
|
} else { |
||||
|
// 未达到规定错误次数
|
||||
|
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); |
||||
|
throw new UserException(loginType.getRetryLimitCount(), errorNumber); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 登录成功 清空错误次数
|
||||
|
RedisUtils.deleteObject(errorKey); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校验租户 |
||||
|
* |
||||
|
* @param tenantId 租户ID |
||||
|
*/ |
||||
|
public void checkTenant(String tenantId) { |
||||
|
if (!TenantHelper.isEnable()) { |
||||
|
return; |
||||
|
} |
||||
|
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { |
||||
|
return; |
||||
|
} |
||||
|
if (StringUtils.isBlank(tenantId)) { |
||||
|
throw new TenantException("tenant.number.not.blank"); |
||||
|
} |
||||
|
SysTenantVo tenant = tenantService.queryByTenantId(tenantId); |
||||
|
if (ObjectUtil.isNull(tenant)) { |
||||
|
log.info("登录租户:{} 不存在.", tenantId); |
||||
|
throw new TenantException("tenant.not.exists"); |
||||
|
} else if (TenantStatus.DISABLE.getCode().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"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,115 @@ |
|||||
|
package org.dromara.web.service; |
||||
|
|
||||
|
import cn.dev33.satoken.secure.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.REGISTER, MessageUtils.message("user.jcaptcha.expire")); |
||||
|
throw new CaptchaExpireException(); |
||||
|
} |
||||
|
if (!code.equalsIgnoreCase(captcha)) { |
||||
|
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error")); |
||||
|
throw new CaptchaException(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 记录登录信息 |
||||
|
* |
||||
|
* @param tenantId 租户ID |
||||
|
* @param username 用户名 |
||||
|
* @param status 状态 |
||||
|
* @param message 消息内容 |
||||
|
* @return |
||||
|
*/ |
||||
|
private void recordLogininfor(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); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,106 @@ |
|||||
|
package org.dromara.web.service.impl; |
||||
|
|
||||
|
import cn.dev33.satoken.stp.SaLoginModel; |
||||
|
import cn.dev33.satoken.stp.StpUtil; |
||||
|
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.domain.model.EmailLoginBody; |
||||
|
import org.dromara.common.core.domain.model.LoginUser; |
||||
|
import org.dromara.common.core.enums.LoginType; |
||||
|
import org.dromara.common.core.enums.UserStatus; |
||||
|
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.SysClient; |
||||
|
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(); |
||||
|
|
||||
|
// 通过邮箱查找用户
|
||||
|
SysUserVo user = loadUserByEmail(tenantId, email); |
||||
|
|
||||
|
loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); |
||||
|
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
|
||||
|
LoginUser loginUser = loginService.buildLoginUser(user); |
||||
|
loginUser.setClientKey(client.getClientKey()); |
||||
|
loginUser.setDeviceType(client.getDeviceType()); |
||||
|
SaLoginModel model = new SaLoginModel(); |
||||
|
model.setDevice(client.getDeviceType()); |
||||
|
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
||||
|
// 例如: 后台用户30分钟过期 app用户1天过期
|
||||
|
model.setTimeout(client.getTimeout()); |
||||
|
model.setActiveTimeout(client.getActiveTimeout()); |
||||
|
model.setExtra(LoginHelper.CLIENT_KEY, 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 tenantId, String email) { |
||||
|
return TenantHelper.dynamic(tenantId, () -> { |
||||
|
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 (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
||||
|
log.info("登录用户:{} 已被停用.", email); |
||||
|
throw new UserException("user.blocked", email); |
||||
|
} |
||||
|
return user; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
package org.dromara.web.service.impl; |
||||
|
|
||||
|
import cn.dev33.satoken.secure.BCrypt; |
||||
|
import cn.dev33.satoken.stp.SaLoginModel; |
||||
|
import cn.dev33.satoken.stp.StpUtil; |
||||
|
import cn.hutool.core.util.ObjectUtil; |
||||
|
import com.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.domain.model.LoginUser; |
||||
|
import org.dromara.common.core.domain.model.PasswordLoginBody; |
||||
|
import org.dromara.common.core.enums.LoginType; |
||||
|
import org.dromara.common.core.enums.UserStatus; |
||||
|
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.SysClient; |
||||
|
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); |
||||
|
} |
||||
|
|
||||
|
SysUserVo user = loadUserByUsername(tenantId, username); |
||||
|
loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); |
||||
|
// 此处可根据登录用户的数据不同 自行创建 loginUser
|
||||
|
LoginUser loginUser = loginService.buildLoginUser(user); |
||||
|
loginUser.setClientKey(client.getClientKey()); |
||||
|
loginUser.setDeviceType(client.getDeviceType()); |
||||
|
SaLoginModel model = new SaLoginModel(); |
||||
|
model.setDevice(client.getDeviceType()); |
||||
|
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
||||
|
// 例如: 后台用户30分钟过期 app用户1天过期
|
||||
|
model.setTimeout(client.getTimeout()); |
||||
|
model.setActiveTimeout(client.getActiveTimeout()); |
||||
|
model.setExtra(LoginHelper.CLIENT_KEY, 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.defaultString(uuid, ""); |
||||
|
String captcha = RedisUtils.getCacheObject(verifyKey); |
||||
|
RedisUtils.deleteObject(verifyKey); |
||||
|
if (captcha == null) { |
||||
|
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
||||
|
throw new CaptchaExpireException(); |
||||
|
} |
||||
|
if (!code.equalsIgnoreCase(captcha)) { |
||||
|
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); |
||||
|
throw new CaptchaException(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private SysUserVo loadUserByUsername(String tenantId, String username) { |
||||
|
return TenantHelper.dynamic(tenantId, () -> { |
||||
|
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 (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
||||
|
log.info("登录用户:{} 已被停用.", username); |
||||
|
throw new UserException("user.blocked", username); |
||||
|
} |
||||
|
return user; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,106 @@ |
|||||
|
package org.dromara.web.service.impl; |
||||
|
|
||||
|
import cn.dev33.satoken.stp.SaLoginModel; |
||||
|
import cn.dev33.satoken.stp.StpUtil; |
||||
|
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.domain.model.LoginUser; |
||||
|
import org.dromara.common.core.domain.model.SmsLoginBody; |
||||
|
import org.dromara.common.core.enums.LoginType; |
||||
|
import org.dromara.common.core.enums.UserStatus; |
||||
|
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.SysClient; |
||||
|
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(); |
||||
|
|
||||
|
// 通过手机号查找用户
|
||||
|
SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber); |
||||
|
|
||||
|
loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); |
||||
|
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
|
||||
|
LoginUser loginUser = loginService.buildLoginUser(user); |
||||
|
loginUser.setClientKey(client.getClientKey()); |
||||
|
loginUser.setDeviceType(client.getDeviceType()); |
||||
|
SaLoginModel model = new SaLoginModel(); |
||||
|
model.setDevice(client.getDeviceType()); |
||||
|
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
||||
|
// 例如: 后台用户30分钟过期 app用户1天过期
|
||||
|
model.setTimeout(client.getTimeout()); |
||||
|
model.setActiveTimeout(client.getActiveTimeout()); |
||||
|
model.setExtra(LoginHelper.CLIENT_KEY, 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 tenantId, String phonenumber) { |
||||
|
return TenantHelper.dynamic(tenantId, () -> { |
||||
|
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 (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
||||
|
log.info("登录用户:{} 已被停用.", phonenumber); |
||||
|
throw new UserException("user.blocked", phonenumber); |
||||
|
} |
||||
|
return user; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,132 @@ |
|||||
|
package org.dromara.web.service.impl; |
||||
|
|
||||
|
import cn.dev33.satoken.stp.SaLoginModel; |
||||
|
import cn.dev33.satoken.stp.StpUtil; |
||||
|
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.domain.model.LoginUser; |
||||
|
import org.dromara.common.core.domain.model.SocialLoginBody; |
||||
|
import org.dromara.common.core.enums.UserStatus; |
||||
|
import org.dromara.common.core.exception.ServiceException; |
||||
|
import org.dromara.common.core.exception.user.UserException; |
||||
|
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 = list.stream().filter(x -> x.getTenantId().equals(loginBody.getTenantId())).findAny(); |
||||
|
if (opt.isEmpty()) { |
||||
|
throw new ServiceException("对不起,你没有权限登录当前租户!"); |
||||
|
} |
||||
|
social = opt.get(); |
||||
|
} else { |
||||
|
social = list.get(0); |
||||
|
} |
||||
|
// 查找用户
|
||||
|
SysUserVo user = loadUser(social.getTenantId(), social.getUserId()); |
||||
|
|
||||
|
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
|
||||
|
LoginUser loginUser = loginService.buildLoginUser(user); |
||||
|
loginUser.setClientKey(client.getClientKey()); |
||||
|
loginUser.setDeviceType(client.getDeviceType()); |
||||
|
SaLoginModel model = new SaLoginModel(); |
||||
|
model.setDevice(client.getDeviceType()); |
||||
|
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
||||
|
// 例如: 后台用户30分钟过期 app用户1天过期
|
||||
|
model.setTimeout(client.getTimeout()); |
||||
|
model.setActiveTimeout(client.getActiveTimeout()); |
||||
|
model.setExtra(LoginHelper.CLIENT_KEY, 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(String tenantId, Long userId) { |
||||
|
return TenantHelper.dynamic(tenantId, () -> { |
||||
|
SysUserVo user = userMapper.selectVoById(userId); |
||||
|
if (ObjectUtil.isNull(user)) { |
||||
|
log.info("登录用户:{} 不存在.", ""); |
||||
|
throw new UserException("user.not.exists", ""); |
||||
|
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
||||
|
log.info("登录用户:{} 已被停用.", ""); |
||||
|
throw new UserException("user.blocked", ""); |
||||
|
} |
||||
|
return user; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,92 @@ |
|||||
|
package org.dromara.web.service.impl; |
||||
|
|
||||
|
import cn.dev33.satoken.stp.SaLoginModel; |
||||
|
import cn.dev33.satoken.stp.StpUtil; |
||||
|
import cn.hutool.core.util.ObjectUtil; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.dromara.common.core.domain.model.XcxLoginBody; |
||||
|
import org.dromara.common.core.domain.model.XcxLoginUser; |
||||
|
import org.dromara.common.core.enums.UserStatus; |
||||
|
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.SysClient; |
||||
|
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(); |
||||
|
|
||||
|
// todo 以下自行实现
|
||||
|
// 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
|
||||
|
String openid = ""; |
||||
|
// 框架登录不限制从什么表查询 只要最终构建出 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); |
||||
|
|
||||
|
SaLoginModel model = new SaLoginModel(); |
||||
|
model.setDevice(client.getDeviceType()); |
||||
|
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
||||
|
// 例如: 后台用户30分钟过期 app用户1天过期
|
||||
|
model.setTimeout(client.getTimeout()); |
||||
|
model.setActiveTimeout(client.getActiveTimeout()); |
||||
|
model.setExtra(LoginHelper.CLIENT_KEY, 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 (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
||||
|
log.info("登录用户:{} 已被停用.", openid); |
||||
|
// todo 用户已被停用 业务逻辑自行实现
|
||||
|
} |
||||
|
return user; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,258 @@ |
|||||
|
--- # 监控中心配置 |
||||
|
spring.boot.admin.client: |
||||
|
# 增加客户端开关 |
||||
|
enabled: true |
||||
|
url: http://localhost:9090/admin |
||||
|
instance: |
||||
|
service-host-type: IP |
||||
|
username: ruoyi |
||||
|
password: 123456 |
||||
|
|
||||
|
--- # snail-job 配置 |
||||
|
snail-job: |
||||
|
enabled: false |
||||
|
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 |
||||
|
group: "ruoyi_group" |
||||
|
# SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表 |
||||
|
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" |
||||
|
server: |
||||
|
host: 127.0.0.1 |
||||
|
port: 1788 |
||||
|
# 详见 script/sql/snail_job.sql `sj_namespace` 表 |
||||
|
namespace: ${spring.profiles.active} |
||||
|
# 随主应用端口飘逸 |
||||
|
port: 2${server.port} |
||||
|
|
||||
|
--- # 数据源配置 |
||||
|
spring: |
||||
|
datasource: |
||||
|
type: com.zaxxer.hikari.HikariDataSource |
||||
|
# 动态数据源文档 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/zaojia?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=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 |
||||
|
# 最小空闲线程数量 |
||||
|
minIdle: 10 |
||||
|
# 配置获取连接等待超时的时间 |
||||
|
connectionTimeout: 30000 |
||||
|
# 校验超时时间 |
||||
|
validationTimeout: 5000 |
||||
|
# 空闲连接存活最大时间,默认10分钟 |
||||
|
idleTimeout: 600000 |
||||
|
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 |
||||
|
maxLifetime: 1800000 |
||||
|
# 多久检查一次连接的活性 |
||||
|
keepaliveTime: 30000 |
||||
|
|
||||
|
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) |
||||
|
spring.data: |
||||
|
redis: |
||||
|
# 地址 |
||||
|
host: localhost |
||||
|
# 端口,默认为6379 |
||||
|
port: 6379 |
||||
|
# 数据库索引 |
||||
|
database: 0 |
||||
|
# 密码(如没有密码请注释掉) |
||||
|
# password: |
||||
|
# 连接超时时间 |
||||
|
timeout: 10s |
||||
|
# 是否开启ssl |
||||
|
ssl.enabled: false |
||||
|
|
||||
|
# redisson 配置 |
||||
|
redisson: |
||||
|
# redis key前缀 |
||||
|
keyPrefix: |
||||
|
# 线程池数量 |
||||
|
threads: 4 |
||||
|
# Netty线程池数量 |
||||
|
nettyThreads: 8 |
||||
|
# 单节点配置 |
||||
|
singleServerConfig: |
||||
|
# 客户端名称 |
||||
|
clientName: ${ruoyi.name} |
||||
|
# 最小空闲连接数 |
||||
|
connectionMinimumIdleSize: 8 |
||||
|
# 连接池大小 |
||||
|
connectionPoolSize: 32 |
||||
|
# 连接空闲超时,单位:毫秒 |
||||
|
idleConnectionTimeout: 10000 |
||||
|
# 命令等待超时,单位:毫秒 |
||||
|
timeout: 3000 |
||||
|
# 发布和订阅连接池大小 |
||||
|
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 |
@ -0,0 +1,260 @@ |
|||||
|
--- # 临时文件存储位置 避免临时文件被系统清理报错 |
||||
|
spring.servlet.multipart.location: /ruoyi/server/temp |
||||
|
|
||||
|
--- # 监控中心配置 |
||||
|
spring.boot.admin.client: |
||||
|
# 增加客户端开关 |
||||
|
enabled: true |
||||
|
url: http://localhost:9090/admin |
||||
|
instance: |
||||
|
service-host-type: IP |
||||
|
username: ruoyi |
||||
|
password: 123456 |
||||
|
|
||||
|
--- # snail-job 配置 |
||||
|
snail-job: |
||||
|
enabled: false |
||||
|
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 |
||||
|
group: "ruoyi_group" |
||||
|
# SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表 |
||||
|
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" |
||||
|
server: |
||||
|
host: 127.0.0.1 |
||||
|
port: 1788 |
||||
|
# 详见 script/sql/snail_job.sql `sj_namespace` 表 |
||||
|
namespace: ${spring.profiles.active} |
||||
|
# 随主应用端口飘逸 |
||||
|
port: 2${server.port} |
||||
|
|
||||
|
--- # 数据源配置 |
||||
|
spring: |
||||
|
datasource: |
||||
|
type: com.zaxxer.hikari.HikariDataSource |
||||
|
# 动态数据源文档 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 |
||||
|
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 |
||||
|
# 最小空闲线程数量 |
||||
|
minIdle: 10 |
||||
|
# 配置获取连接等待超时的时间 |
||||
|
connectionTimeout: 30000 |
||||
|
# 校验超时时间 |
||||
|
validationTimeout: 5000 |
||||
|
# 空闲连接存活最大时间,默认10分钟 |
||||
|
idleTimeout: 600000 |
||||
|
# 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 |
||||
|
maxLifetime: 1800000 |
||||
|
# 多久检查一次连接的活性 |
||||
|
keepaliveTime: 30000 |
||||
|
|
||||
|
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) |
||||
|
spring.data: |
||||
|
redis: |
||||
|
# 地址 |
||||
|
host: localhost |
||||
|
# 端口,默认为6379 |
||||
|
port: 6379 |
||||
|
# 数据库索引 |
||||
|
database: 0 |
||||
|
# 密码(如没有密码请注释掉) |
||||
|
# password: |
||||
|
# 连接超时时间 |
||||
|
timeout: 10s |
||||
|
# 是否开启ssl |
||||
|
ssl.enabled: false |
||||
|
|
||||
|
# redisson 配置 |
||||
|
redisson: |
||||
|
# redis key前缀 |
||||
|
keyPrefix: |
||||
|
# 线程池数量 |
||||
|
threads: 16 |
||||
|
# Netty线程池数量 |
||||
|
nettyThreads: 32 |
||||
|
# 单节点配置 |
||||
|
singleServerConfig: |
||||
|
# 客户端名称 |
||||
|
clientName: ${ruoyi.name} |
||||
|
# 最小空闲连接数 |
||||
|
connectionMinimumIdleSize: 32 |
||||
|
# 连接池大小 |
||||
|
connectionPoolSize: 64 |
||||
|
# 连接空闲超时,单位:毫秒 |
||||
|
idleConnectionTimeout: 10000 |
||||
|
# 命令等待超时,单位:毫秒 |
||||
|
timeout: 3000 |
||||
|
# 发布和订阅连接池大小 |
||||
|
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 |
@ -0,0 +1,287 @@ |
|||||
|
# 项目相关配置 |
||||
|
ruoyi: |
||||
|
# 名称 |
||||
|
name: RuoYi-Vue-Plus |
||||
|
# 版本 |
||||
|
version: ${revision} |
||||
|
# 版权年份 |
||||
|
copyrightYear: 2024 |
||||
|
|
||||
|
captcha: |
||||
|
enable: true |
||||
|
# 页面 <参数设置> 可开启关闭 验证码校验 |
||||
|
# 验证码类型 math 数组计算 char 字符验证 |
||||
|
type: MATH |
||||
|
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 |
||||
|
category: CIRCLE |
||||
|
# 数字验证码位数 |
||||
|
numberLength: 1 |
||||
|
# 字符验证码长度 |
||||
|
charLength: 4 |
||||
|
|
||||
|
# 开发环境配置 |
||||
|
server: |
||||
|
# 服务器的HTTP端口,默认为8080 |
||||
|
port: 8080 |
||||
|
servlet: |
||||
|
# 应用的访问路径 |
||||
|
context-path: / |
||||
|
# undertow 配置 |
||||
|
undertow: |
||||
|
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 |
||||
|
max-http-post-size: -1 |
||||
|
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 |
||||
|
# 每块buffer的空间大小,越小的空间被利用越充分 |
||||
|
buffer-size: 512 |
||||
|
# 是否分配的直接内存 |
||||
|
direct-buffers: true |
||||
|
threads: |
||||
|
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 |
||||
|
io: 8 |
||||
|
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 |
||||
|
worker: 256 |
||||
|
|
||||
|
# 日志配置 |
||||
|
logging: |
||||
|
level: |
||||
|
org.dromara: @logging.level@ |
||||
|
org.springframework: warn |
||||
|
org.mybatis.spring.mapper: error |
||||
|
config: classpath:logback-plus.xml |
||||
|
|
||||
|
# 用户配置 |
||||
|
user: |
||||
|
password: |
||||
|
# 密码最大错误次数 |
||||
|
maxRetryCount: 5 |
||||
|
# 密码锁定时间(默认10分钟) |
||||
|
lockTime: 10 |
||||
|
|
||||
|
# Spring配置 |
||||
|
spring: |
||||
|
application: |
||||
|
name: ${ruoyi.name} |
||||
|
threads: |
||||
|
# 开启虚拟线程 仅jdk21可用 |
||||
|
virtual: |
||||
|
enabled: false |
||||
|
# 资源信息 |
||||
|
messages: |
||||
|
# 国际化资源文件路径 |
||||
|
basename: i18n/messages |
||||
|
profiles: |
||||
|
active: @profiles.active@ |
||||
|
# 文件上传 |
||||
|
servlet: |
||||
|
multipart: |
||||
|
# 单个文件大小 |
||||
|
max-file-size: 10MB |
||||
|
# 设置总上传的文件大小 |
||||
|
max-request-size: 20MB |
||||
|
mvc: |
||||
|
# 设置静态资源路径 防止所有请求都去查静态资源 |
||||
|
static-path-pattern: /static/** |
||||
|
format: |
||||
|
date-time: yyyy-MM-dd HH:mm:ss |
||||
|
jackson: |
||||
|
# 日期格式化 |
||||
|
date-format: yyyy-MM-dd HH:mm:ss |
||||
|
serialization: |
||||
|
# 格式化输出 |
||||
|
indent_output: false |
||||
|
# 忽略无法转换的对象 |
||||
|
fail_on_empty_beans: false |
||||
|
deserialization: |
||||
|
# 允许对象忽略json中不存在的属性 |
||||
|
fail_on_unknown_properties: false |
||||
|
|
||||
|
# 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 |
||||
|
|
||||
|
# security配置 |
||||
|
security: |
||||
|
# 排除路径 |
||||
|
excludes: |
||||
|
# 静态资源 |
||||
|
- /*.html |
||||
|
- /**/*.html |
||||
|
- /**/*.css |
||||
|
- /**/*.js |
||||
|
# 公共路径 |
||||
|
- /favicon.ico |
||||
|
- /error |
||||
|
# swagger 文档配置 |
||||
|
- /*/api-docs |
||||
|
- /*/api-docs/** |
||||
|
# 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 |
||||
|
|
||||
|
# MyBatisPlus配置 |
||||
|
# https://baomidou.com/config/ |
||||
|
mybatis-plus: |
||||
|
# 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper |
||||
|
mapperPackage: org.dromara.**.mapper |
||||
|
# 对应的 XML 文件位置 |
||||
|
mapperLocations: classpath*:mapper/**/*Mapper.xml |
||||
|
# 实体扫描,多个package用逗号或者分号分隔 |
||||
|
typeAliasesPackage: org.dromara.**.domain |
||||
|
global-config: |
||||
|
dbConfig: |
||||
|
# 主键类型 |
||||
|
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID |
||||
|
# 如需改为自增 需要将数据库表全部设置为自增 |
||||
|
idType: ASSIGN_ID |
||||
|
|
||||
|
# 数据加密 |
||||
|
mybatis-encryptor: |
||||
|
# 是否开启加密 |
||||
|
enable: false |
||||
|
# 默认加密算法 |
||||
|
algorithm: BASE64 |
||||
|
# 编码方式 BASE64/HEX。默认BASE64 |
||||
|
encode: BASE64 |
||||
|
# 安全秘钥 对称算法的秘钥 如:AES,SM4 |
||||
|
password: |
||||
|
# 公私钥 非对称算法的公私钥 如:SM2,RSA |
||||
|
publicKey: |
||||
|
privateKey: |
||||
|
|
||||
|
# api接口加密 |
||||
|
api-decrypt: |
||||
|
# 是否开启全局接口加密 |
||||
|
enabled: true |
||||
|
# AES 加密头标识 |
||||
|
headerFlag: encrypt-key |
||||
|
# 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 |
||||
|
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= |
||||
|
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== |
||||
|
# 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 |
||||
|
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== |
||||
|
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= |
||||
|
|
||||
|
springdoc: |
||||
|
api-docs: |
||||
|
# 是否开启接口文档 |
||||
|
enabled: true |
||||
|
# swagger-ui: |
||||
|
# # 持久化认证数据 |
||||
|
# persistAuthorization: true |
||||
|
info: |
||||
|
# 标题 |
||||
|
title: '标题:${ruoyi.name}多租户管理系统_接口文档' |
||||
|
# 描述 |
||||
|
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 |
||||
|
|
||||
|
# 防止XSS攻击 |
||||
|
xss: |
||||
|
# 过滤开关 |
||||
|
enabled: true |
||||
|
# 排除链接(多个用逗号分隔) |
||||
|
excludes: /system/notice |
||||
|
# 匹配链接 |
||||
|
urlPatterns: /system/*,/monitor/*,/tool/* |
||||
|
|
||||
|
# 全局线程池相关配置 |
||||
|
# 如使用JDK21请直接使用虚拟线程 不要开启此配置 |
||||
|
thread-pool: |
||||
|
# 是否开启线程池 |
||||
|
enabled: false |
||||
|
# 队列最大长度 |
||||
|
queueCapacity: 128 |
||||
|
# 线程池维护线程所允许的空闲时间 |
||||
|
keepAliveSeconds: 300 |
||||
|
|
||||
|
--- # 分布式锁 lock4j 全局配置 |
||||
|
lock4j: |
||||
|
# 获取分布式锁超时时间,默认为 3000 毫秒 |
||||
|
acquire-timeout: 3000 |
||||
|
# 分布式锁的超时时间,默认为 30 秒 |
||||
|
expire: 30000 |
||||
|
|
||||
|
--- # Actuator 监控端点的配置项 |
||||
|
management: |
||||
|
endpoints: |
||||
|
web: |
||||
|
exposure: |
||||
|
include: '*' |
||||
|
endpoint: |
||||
|
health: |
||||
|
show-details: ALWAYS |
||||
|
logfile: |
||||
|
external-file: ./logs/sys-console.log |
||||
|
|
||||
|
--- # websocket |
||||
|
websocket: |
||||
|
# 如果关闭 需要和前端开关一起关闭 |
||||
|
enabled: true |
||||
|
# 路径 |
||||
|
path: /resource/websocket |
||||
|
# 设置访问源地址 |
||||
|
allowedOrigins: '*' |
||||
|
|
||||
|
--- #flowable配置 |
||||
|
flowable: |
||||
|
async-executor-activate: false #关闭定时任务JOB |
||||
|
# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。 |
||||
|
database-schema-update: true |
||||
|
activity-font-name: 宋体 |
||||
|
label-font-name: 宋体 |
||||
|
annotation-font-name: 宋体 |
||||
|
# 关闭各个模块生成表,目前只使用工作流基础表 |
||||
|
idm: |
||||
|
enabled: false |
||||
|
cmmn: |
||||
|
enabled: false |
||||
|
dmn: |
||||
|
enabled: false |
||||
|
app: |
||||
|
enabled: false |
@ -0,0 +1,8 @@ |
|||||
|
Application Version: ${revision} |
||||
|
Spring Boot Version: ${spring-boot.version} |
||||
|
__________ _____.___.__ ____ ____ __________.__ |
||||
|
\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______ |
||||
|
| _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/ |
||||
|
| | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \ |
||||
|
|____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ > |
||||
|
\/ \/ \/ \/ |
@ -0,0 +1,61 @@ |
|||||
|
#错误消息 |
||||
|
not.null=* 必须填写 |
||||
|
user.jcaptcha.error=验证码错误 |
||||
|
user.jcaptcha.expire=验证码已失效 |
||||
|
user.not.exists=对不起, 您的账号:{0} 不存在. |
||||
|
user.password.not.match=用户不存在/密码错误 |
||||
|
user.password.retry.limit.count=密码输入错误{0}次 |
||||
|
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 |
||||
|
user.password.delete=对不起,您的账号:{0} 已被删除 |
||||
|
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 |
||||
|
role.blocked=角色已封禁,请联系管理员 |
||||
|
user.logout.success=退出成功 |
||||
|
length.not.valid=长度必须在{min}到{max}个字符之间 |
||||
|
user.username.not.blank=用户名不能为空 |
||||
|
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 |
||||
|
user.username.length.valid=账户长度必须在{min}到{max}个字符之间 |
||||
|
user.password.not.blank=用户密码不能为空 |
||||
|
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 |
||||
|
user.password.not.valid=* 5-50个字符 |
||||
|
user.email.not.valid=邮箱格式错误 |
||||
|
user.email.not.blank=邮箱不能为空 |
||||
|
user.phonenumber.not.blank=用户手机号不能为空 |
||||
|
user.mobile.phone.number.not.valid=手机号格式错误 |
||||
|
user.login.success=登录成功 |
||||
|
user.register.success=注册成功 |
||||
|
user.register.save.error=保存用户 {0} 失败,注册账号已存在 |
||||
|
user.register.error=注册失败,请联系系统管理人员 |
||||
|
user.notfound=请重新登录 |
||||
|
user.forcelogout=管理员强制退出,请重新登录 |
||||
|
user.unknown.error=未知错误,请重新登录 |
||||
|
auth.grant.type.error=认证权限类型错误 |
||||
|
auth.grant.type.blocked=认证权限类型已禁用 |
||||
|
auth.grant.type.not.blank=认证权限类型不能为空 |
||||
|
auth.clientid.not.blank=认证客户端id不能为空 |
||||
|
##文件上传消息 |
||||
|
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB! |
||||
|
upload.filename.exceed.length=上传的文件名最长{0}个字符 |
||||
|
##权限 |
||||
|
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] |
||||
|
repeat.submit.message=不允许重复提交,请稍候再试 |
||||
|
rate.limiter.message=访问过于频繁,请稍候再试 |
||||
|
sms.code.not.blank=短信验证码不能为空 |
||||
|
sms.code.retry.limit.count=短信验证码输入错误{0}次 |
||||
|
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 |
||||
|
email.code.not.blank=邮箱验证码不能为空 |
||||
|
email.code.retry.limit.count=邮箱验证码输入错误{0}次 |
||||
|
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 |
||||
|
xcx.code.not.blank=小程序[code]不能为空 |
||||
|
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=对不起,您的租户已过期,请联系管理员 |
@ -0,0 +1,61 @@ |
|||||
|
#错误消息 |
||||
|
not.null=* Required fill in |
||||
|
user.jcaptcha.error=Captcha error |
||||
|
user.jcaptcha.expire=Captcha invalid |
||||
|
user.not.exists=Sorry, your account: {0} does not exist |
||||
|
user.password.not.match=User does not exist/Password error |
||||
|
user.password.retry.limit.count=Password input error {0} times |
||||
|
user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes |
||||
|
user.password.delete=Sorry, your account:{0} has been deleted |
||||
|
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator |
||||
|
role.blocked=Role disabled,please contact administrators |
||||
|
user.logout.success=Exit successful |
||||
|
length.not.valid=The length must be between {min} and {max} characters |
||||
|
user.username.not.blank=Username cannot be blank |
||||
|
user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number |
||||
|
user.username.length.valid=Account length must be between {min} and {max} characters |
||||
|
user.password.not.blank=Password cannot be empty |
||||
|
user.password.length.valid=Password length must be between {min} and {max} characters |
||||
|
user.password.not.valid=* 5-50 characters |
||||
|
user.email.not.valid=Mailbox format error |
||||
|
user.email.not.blank=Mailbox cannot be blank |
||||
|
user.phonenumber.not.blank=Phone number cannot be blank |
||||
|
user.mobile.phone.number.not.valid=Phone number format error |
||||
|
user.login.success=Login successful |
||||
|
user.register.success=Register successful |
||||
|
user.register.save.error=Failed to save user {0}, The registered account already exists |
||||
|
user.register.error=Register failed, please contact system administrator |
||||
|
user.notfound=Please login again |
||||
|
user.forcelogout=The administrator is forced to exit,please login again |
||||
|
user.unknown.error=Unknown error, please login again |
||||
|
auth.grant.type.error=Auth grant type error |
||||
|
auth.grant.type.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 |
||||
|
##权限 |
||||
|
no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] |
||||
|
no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] |
||||
|
no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] |
||||
|
no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] |
||||
|
no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] |
||||
|
no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] |
||||
|
repeat.submit.message=Repeat submit is not allowed, please try again later |
||||
|
rate.limiter.message=Visit too frequently, please try again later |
||||
|
sms.code.not.blank=Sms code cannot be blank |
||||
|
sms.code.retry.limit.count=Sms code input error {0} times |
||||
|
sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes |
||||
|
email.code.not.blank=Email code cannot be blank |
||||
|
email.code.retry.limit.count=Email code input error {0} times |
||||
|
email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes |
||||
|
xcx.code.not.blank=Mini program [code] cannot be blank |
||||
|
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. |
@ -0,0 +1,61 @@ |
|||||
|
#错误消息 |
||||
|
not.null=* 必须填写 |
||||
|
user.jcaptcha.error=验证码错误 |
||||
|
user.jcaptcha.expire=验证码已失效 |
||||
|
user.not.exists=对不起, 您的账号:{0} 不存在. |
||||
|
user.password.not.match=用户不存在/密码错误 |
||||
|
user.password.retry.limit.count=密码输入错误{0}次 |
||||
|
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 |
||||
|
user.password.delete=对不起,您的账号:{0} 已被删除 |
||||
|
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 |
||||
|
role.blocked=角色已封禁,请联系管理员 |
||||
|
user.logout.success=退出成功 |
||||
|
length.not.valid=长度必须在{min}到{max}个字符之间 |
||||
|
user.username.not.blank=用户名不能为空 |
||||
|
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 |
||||
|
user.username.length.valid=账户长度必须在{min}到{max}个字符之间 |
||||
|
user.password.not.blank=用户密码不能为空 |
||||
|
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 |
||||
|
user.password.not.valid=* 5-50个字符 |
||||
|
user.email.not.valid=邮箱格式错误 |
||||
|
user.email.not.blank=邮箱不能为空 |
||||
|
user.phonenumber.not.blank=用户手机号不能为空 |
||||
|
user.mobile.phone.number.not.valid=手机号格式错误 |
||||
|
user.login.success=登录成功 |
||||
|
user.register.success=注册成功 |
||||
|
user.register.save.error=保存用户 {0} 失败,注册账号已存在 |
||||
|
user.register.error=注册失败,请联系系统管理人员 |
||||
|
user.notfound=请重新登录 |
||||
|
user.forcelogout=管理员强制退出,请重新登录 |
||||
|
user.unknown.error=未知错误,请重新登录 |
||||
|
auth.grant.type.error=认证权限类型错误 |
||||
|
auth.grant.type.blocked=认证权限类型已禁用 |
||||
|
auth.grant.type.not.blank=认证权限类型不能为空 |
||||
|
auth.clientid.not.blank=认证客户端id不能为空 |
||||
|
##文件上传消息 |
||||
|
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB! |
||||
|
upload.filename.exceed.length=上传的文件名最长{0}个字符 |
||||
|
##权限 |
||||
|
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] |
||||
|
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] |
||||
|
repeat.submit.message=不允许重复提交,请稍候再试 |
||||
|
rate.limiter.message=访问过于频繁,请稍候再试 |
||||
|
sms.code.not.blank=短信验证码不能为空 |
||||
|
sms.code.retry.limit.count=短信验证码输入错误{0}次 |
||||
|
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 |
||||
|
email.code.not.blank=邮箱验证码不能为空 |
||||
|
email.code.retry.limit.count=邮箱验证码输入错误{0}次 |
||||
|
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 |
||||
|
xcx.code.not.blank=小程序[code]不能为空 |
||||
|
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.
@ -0,0 +1,129 @@ |
|||||
|
<?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> |
||||
|
<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> |
@ -0,0 +1,45 @@ |
|||||
|
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); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
package org.dromara.test; |
||||
|
|
||||
|
import org.dromara.common.core.config.RuoYiConfig; |
||||
|
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 RuoYiConfig ruoYiConfig; |
||||
|
|
||||
|
@DisplayName("测试 @SpringBootTest @Test @DisplayName 注解") |
||||
|
@Test |
||||
|
public void testTest() { |
||||
|
System.out.println(ruoYiConfig); |
||||
|
} |
||||
|
|
||||
|
@Disabled |
||||
|
@DisplayName("测试 @Disabled 注解") |
||||
|
@Test |
||||
|
public void testDisabled() { |
||||
|
System.out.println(ruoYiConfig); |
||||
|
} |
||||
|
|
||||
|
@Timeout(value = 2L, unit = TimeUnit.SECONDS) |
||||
|
@DisplayName("测试 @Timeout 注解") |
||||
|
@Test |
||||
|
public void testTimeout() throws InterruptedException { |
||||
|
Thread.sleep(3000); |
||||
|
System.out.println(ruoYiConfig); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@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 =================="); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,72 @@ |
|||||
|
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 =================="); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
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 =================="); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
<?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> |
||||
|
<artifactId>ruoyi-vue-plus</artifactId> |
||||
|
<groupId>org.dromara</groupId> |
||||
|
<version>${revision}</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> |
||||
|
</modules> |
||||
|
|
||||
|
<artifactId>ruoyi-common</artifactId> |
||||
|
<packaging>pom</packaging> |
||||
|
|
||||
|
<description> |
||||
|
common 通用模块 |
||||
|
</description> |
||||
|
|
||||
|
</project> |
@ -0,0 +1,178 @@ |
|||||
|
<?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.2.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> |
||||
|
|
||||
|
</dependencies> |
||||
|
</dependencyManagement> |
||||
|
|
||||
|
</project> |
@ -0,0 +1,104 @@ |
|||||
|
<?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> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>transmittable-thread-local</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
</dependencies> |
||||
|
|
||||
|
</project> |
@ -0,0 +1,17 @@ |
|||||
|
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 { |
||||
|
|
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
package org.dromara.common.core.config; |
||||
|
|
||||
|
import cn.hutool.core.util.ArrayUtil; |
||||
|
import org.dromara.common.core.exception.ServiceException; |
||||
|
import org.dromara.common.core.utils.SpringUtils; |
||||
|
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; |
||||
|
import org.springframework.boot.autoconfigure.AutoConfiguration; |
||||
|
import org.springframework.core.task.VirtualThreadTaskExecutor; |
||||
|
import org.springframework.scheduling.annotation.AsyncConfigurer; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
import java.util.concurrent.Executor; |
||||
|
|
||||
|
/** |
||||
|
* 异步配置 |
||||
|
* <p> |
||||
|
* 如果未使用虚拟线程则生效 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@AutoConfiguration |
||||
|
public class AsyncConfig implements AsyncConfigurer { |
||||
|
|
||||
|
/** |
||||
|
* 自定义 @Async 注解使用系统线程池 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Executor getAsyncExecutor() { |
||||
|
if(SpringUtils.isVirtual()) { |
||||
|
return new VirtualThreadTaskExecutor("async-"); |
||||
|
} |
||||
|
return SpringUtils.getBean("scheduledExecutorService"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 异步执行异常处理 |
||||
|
*/ |
||||
|
@Override |
||||
|
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { |
||||
|
return (throwable, method, objects) -> { |
||||
|
throwable.printStackTrace(); |
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
sb.append("Exception message - ").append(throwable.getMessage()) |
||||
|
.append(", Method name - ").append(method.getName()); |
||||
|
if (ArrayUtil.isNotEmpty(objects)) { |
||||
|
sb.append(", Parameter value - ").append(Arrays.toString(objects)); |
||||
|
} |
||||
|
throw new ServiceException(sb.toString()); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
package org.dromara.common.core.config; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* 读取项目相关配置 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
|
||||
|
@Data |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "ruoyi") |
||||
|
public class RuoYiConfig { |
||||
|
|
||||
|
/** |
||||
|
* 项目名称 |
||||
|
*/ |
||||
|
private String name; |
||||
|
|
||||
|
/** |
||||
|
* 版本 |
||||
|
*/ |
||||
|
private String version; |
||||
|
|
||||
|
/** |
||||
|
* 版权年份 |
||||
|
*/ |
||||
|
private String copyrightYear; |
||||
|
|
||||
|
} |
@ -0,0 +1,78 @@ |
|||||
|
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.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.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() { |
||||
|
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core, |
||||
|
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), |
||||
|
new ThreadPoolExecutor.CallerRunsPolicy()) { |
||||
|
@Override |
||||
|
protected void afterExecute(Runnable r, Throwable t) { |
||||
|
super.afterExecute(r, t); |
||||
|
Threads.printException(r, t); |
||||
|
} |
||||
|
}; |
||||
|
this.scheduledExecutorService = scheduledThreadPoolExecutor; |
||||
|
return scheduledThreadPoolExecutor; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 销毁事件 |
||||
|
*/ |
||||
|
@PreDestroy |
||||
|
public void destroy() { |
||||
|
try { |
||||
|
log.info("====关闭后台任务任务线程池===="); |
||||
|
Threads.shutdownAndAwaitTermination(scheduledExecutorService); |
||||
|
} catch (Exception e) { |
||||
|
log.error(e.getMessage(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
package org.dromara.common.core.config; |
||||
|
|
||||
|
import jakarta.validation.Validator; |
||||
|
import org.hibernate.validator.HibernateValidator; |
||||
|
import org.springframework.boot.autoconfigure.AutoConfiguration; |
||||
|
import org.springframework.context.MessageSource; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; |
||||
|
|
||||
|
import java.util.Properties; |
||||
|
|
||||
|
/** |
||||
|
* 校验框架配置类 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@AutoConfiguration |
||||
|
public class ValidatorConfig { |
||||
|
|
||||
|
/** |
||||
|
* 配置校验框架 快速返回模式 |
||||
|
*/ |
||||
|
@Bean |
||||
|
public Validator validator(MessageSource messageSource) { |
||||
|
try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { |
||||
|
// 国际化
|
||||
|
factoryBean.setValidationMessageSource(messageSource); |
||||
|
// 设置使用 HibernateValidator 校验器
|
||||
|
factoryBean.setProviderClass(HibernateValidator.class); |
||||
|
Properties properties = new Properties(); |
||||
|
// 设置 快速异常返回
|
||||
|
properties.setProperty("hibernate.validator.fail_fast", "true"); |
||||
|
factoryBean.setValidationProperties(properties); |
||||
|
// 加载配置
|
||||
|
factoryBean.afterPropertiesSet(); |
||||
|
return factoryBean.getValidator(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package org.dromara.common.core.config.properties; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
|
||||
|
/** |
||||
|
* 线程池 配置属性 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Data |
||||
|
@ConfigurationProperties(prefix = "thread-pool") |
||||
|
public class ThreadPoolProperties { |
||||
|
|
||||
|
/** |
||||
|
* 是否开启线程池 |
||||
|
*/ |
||||
|
private boolean enabled; |
||||
|
|
||||
|
/** |
||||
|
* 队列最大长度 |
||||
|
*/ |
||||
|
private int queueCapacity; |
||||
|
|
||||
|
/** |
||||
|
* 线程池维护线程所允许的空闲时间 |
||||
|
*/ |
||||
|
private int keepAliveSeconds; |
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
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:"; |
||||
|
|
||||
|
} |
@ -0,0 +1,73 @@ |
|||||
|
package org.dromara.common.core.constant; |
||||
|
|
||||
|
/** |
||||
|
* 缓存组名称常量 |
||||
|
* <p> |
||||
|
* key 格式为 cacheNames#ttl#maxIdleTime#maxSize |
||||
|
* <p> |
||||
|
* ttl 过期时间 如果设置为0则不过期 默认为0 |
||||
|
* maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 |
||||
|
* maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 |
||||
|
* <p> |
||||
|
* 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface CacheNames { |
||||
|
|
||||
|
/** |
||||
|
* 演示案例 |
||||
|
*/ |
||||
|
String DEMO_CACHE = "demo:cache#60s#10m#20"; |
||||
|
|
||||
|
/** |
||||
|
* 系统配置 |
||||
|
*/ |
||||
|
String SYS_CONFIG = "sys_config"; |
||||
|
|
||||
|
/** |
||||
|
* 数据字典 |
||||
|
*/ |
||||
|
String SYS_DICT = "sys_dict"; |
||||
|
|
||||
|
/** |
||||
|
* 租户 |
||||
|
*/ |
||||
|
String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; |
||||
|
|
||||
|
/** |
||||
|
* 客户端 |
||||
|
*/ |
||||
|
String SYS_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"; |
||||
|
|
||||
|
/** |
||||
|
* OSS配置 |
||||
|
*/ |
||||
|
String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config"; |
||||
|
|
||||
|
/** |
||||
|
* 在线用户 |
||||
|
*/ |
||||
|
String ONLINE_TOKEN = "online_tokens"; |
||||
|
|
||||
|
} |
@ -0,0 +1,81 @@ |
|||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 令牌 |
||||
|
*/ |
||||
|
String TOKEN = "token"; |
||||
|
|
||||
|
/** |
||||
|
* 顶级部门id |
||||
|
*/ |
||||
|
Long TOP_PARENT_ID = 0L; |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,39 @@ |
|||||
|
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 PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:"; |
||||
|
|
||||
|
/** |
||||
|
* 三方认证 redis key |
||||
|
*/ |
||||
|
String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
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; |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
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_]*$"; |
||||
|
|
||||
|
/** |
||||
|
* 权限标识必须符合 tool:build:list 格式,或者空字符串 |
||||
|
*/ |
||||
|
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]$"; |
||||
|
|
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
package org.dromara.common.core.constant; |
||||
|
|
||||
|
/** |
||||
|
* 租户常量信息 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface TenantConstants { |
||||
|
|
||||
|
/** |
||||
|
* 租户正常状态 |
||||
|
*/ |
||||
|
String NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 租户封禁状态 |
||||
|
*/ |
||||
|
String DISABLE = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 超级管理员ID |
||||
|
*/ |
||||
|
Long SUPER_ADMIN_ID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* 超级管理员角色 roleKey |
||||
|
*/ |
||||
|
String SUPER_ADMIN_ROLE_KEY = "superadmin"; |
||||
|
|
||||
|
/** |
||||
|
* 租户管理员角色 roleKey |
||||
|
*/ |
||||
|
String TENANT_ADMIN_ROLE_KEY = "admin"; |
||||
|
|
||||
|
/** |
||||
|
* 租户管理员角色名称 |
||||
|
*/ |
||||
|
String TENANT_ADMIN_ROLE_NAME = "管理员"; |
||||
|
|
||||
|
/** |
||||
|
* 默认租户ID |
||||
|
*/ |
||||
|
String DEFAULT_TENANT_ID = "000000"; |
||||
|
|
||||
|
} |
@ -0,0 +1,142 @@ |
|||||
|
package org.dromara.common.core.constant; |
||||
|
|
||||
|
/** |
||||
|
* 用户常量信息 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public interface UserConstants { |
||||
|
|
||||
|
/** |
||||
|
* 平台内系统用户的唯一标志 |
||||
|
*/ |
||||
|
String SYS_USER = "SYS_USER"; |
||||
|
|
||||
|
/** |
||||
|
* 正常状态 |
||||
|
*/ |
||||
|
String NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 异常状态 |
||||
|
*/ |
||||
|
String EXCEPTION = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 用户正常状态 |
||||
|
*/ |
||||
|
String USER_NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 用户封禁状态 |
||||
|
*/ |
||||
|
String USER_DISABLE = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 角色正常状态 |
||||
|
*/ |
||||
|
String ROLE_NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 角色封禁状态 |
||||
|
*/ |
||||
|
String ROLE_DISABLE = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 部门正常状态 |
||||
|
*/ |
||||
|
String DEPT_NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 部门停用状态 |
||||
|
*/ |
||||
|
String DEPT_DISABLE = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 岗位正常状态 |
||||
|
*/ |
||||
|
String POST_NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 岗位停用状态 |
||||
|
*/ |
||||
|
String POST_DISABLE = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 字典正常状态 |
||||
|
*/ |
||||
|
String DICT_NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 是否为系统默认(是) |
||||
|
*/ |
||||
|
String YES = "Y"; |
||||
|
|
||||
|
/** |
||||
|
* 是否菜单外链(是) |
||||
|
*/ |
||||
|
String YES_FRAME = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 是否菜单外链(否) |
||||
|
*/ |
||||
|
String NO_FRAME = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 菜单正常状态 |
||||
|
*/ |
||||
|
String MENU_NORMAL = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 菜单停用状态 |
||||
|
*/ |
||||
|
String MENU_DISABLE = "1"; |
||||
|
|
||||
|
/** |
||||
|
* 菜单类型(目录) |
||||
|
*/ |
||||
|
String TYPE_DIR = "M"; |
||||
|
|
||||
|
/** |
||||
|
* 菜单类型(菜单) |
||||
|
*/ |
||||
|
String TYPE_MENU = "C"; |
||||
|
|
||||
|
/** |
||||
|
* 菜单类型(按钮) |
||||
|
*/ |
||||
|
String TYPE_BUTTON = "F"; |
||||
|
|
||||
|
/** |
||||
|
* Layout组件标识 |
||||
|
*/ |
||||
|
String LAYOUT = "Layout"; |
||||
|
|
||||
|
/** |
||||
|
* ParentView组件标识 |
||||
|
*/ |
||||
|
String PARENT_VIEW = "ParentView"; |
||||
|
|
||||
|
/** |
||||
|
* InnerLink组件标识 |
||||
|
*/ |
||||
|
String INNER_LINK = "InnerLink"; |
||||
|
|
||||
|
/** |
||||
|
* 用户名长度限制 |
||||
|
*/ |
||||
|
int USERNAME_MIN_LENGTH = 2; |
||||
|
int USERNAME_MAX_LENGTH = 20; |
||||
|
|
||||
|
/** |
||||
|
* 密码长度限制 |
||||
|
*/ |
||||
|
int PASSWORD_MIN_LENGTH = 5; |
||||
|
int PASSWORD_MAX_LENGTH = 20; |
||||
|
|
||||
|
/** |
||||
|
* 超级管理员ID |
||||
|
*/ |
||||
|
Long SUPER_ADMIN_ID = 1L; |
||||
|
|
||||
|
} |
@ -0,0 +1,110 @@ |
|||||
|
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(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
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:仅本人数据权限) |
||||
|
*/ |
||||
|
private String dataScope; |
||||
|
|
||||
|
} |
@ -0,0 +1,73 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,72 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
package org.dromara.common.core.domain.event; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* 总体流程监听 |
||||
|
* |
||||
|
* @author may |
||||
|
*/ |
||||
|
|
||||
|
@Data |
||||
|
public class ProcessEvent implements Serializable { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* 流程定义key |
||||
|
*/ |
||||
|
private String key; |
||||
|
|
||||
|
/** |
||||
|
* 业务id |
||||
|
*/ |
||||
|
private String businessKey; |
||||
|
|
||||
|
/** |
||||
|
* 状态 |
||||
|
*/ |
||||
|
private String status; |
||||
|
|
||||
|
/** |
||||
|
* 当为true时为申请人节点办理 |
||||
|
*/ |
||||
|
private boolean submit; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 流程定义key |
||||
|
*/ |
||||
|
private String key; |
||||
|
|
||||
|
/** |
||||
|
* 审批节点key |
||||
|
*/ |
||||
|
private String taskDefinitionKey; |
||||
|
|
||||
|
/** |
||||
|
* 任务id |
||||
|
*/ |
||||
|
private String taskId; |
||||
|
|
||||
|
/** |
||||
|
* 业务id |
||||
|
*/ |
||||
|
private String businessKey; |
||||
|
|
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,48 @@ |
|||||
|
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; |
||||
|
|
||||
|
} |
@ -0,0 +1,142 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import org.dromara.common.core.domain.dto.RoleDTO; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 数据权限 当前角色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; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import org.hibernate.validator.constraints.Length; |
||||
|
|
||||
|
import static org.dromara.common.core.constant.UserConstants.*; |
||||
|
|
||||
|
/** |
||||
|
* 密码登录对象 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class PasswordLoginBody extends LoginBody { |
||||
|
|
||||
|
/** |
||||
|
* 用户名 |
||||
|
*/ |
||||
|
@NotBlank(message = "{user.username.not.blank}") |
||||
|
@Length(min = USERNAME_MIN_LENGTH, max = USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") |
||||
|
private String username; |
||||
|
|
||||
|
/** |
||||
|
* 用户密码 |
||||
|
*/ |
||||
|
@NotBlank(message = "{user.password.not.blank}") |
||||
|
@Length(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}") |
||||
|
private String password; |
||||
|
|
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import org.hibernate.validator.constraints.Length; |
||||
|
|
||||
|
import static org.dromara.common.core.constant.UserConstants.*; |
||||
|
|
||||
|
/** |
||||
|
* 用户注册对象 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class RegisterBody extends LoginBody { |
||||
|
|
||||
|
/** |
||||
|
* 用户名 |
||||
|
*/ |
||||
|
@NotBlank(message = "{user.username.not.blank}") |
||||
|
@Length(min = USERNAME_MIN_LENGTH, max = USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") |
||||
|
private String username; |
||||
|
|
||||
|
/** |
||||
|
* 用户密码 |
||||
|
*/ |
||||
|
@NotBlank(message = "{user.password.not.blank}") |
||||
|
@Length(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}") |
||||
|
private String password; |
||||
|
|
||||
|
private String userType; |
||||
|
|
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
/** |
||||
|
* 短信登录对象 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class SmsLoginBody extends LoginBody { |
||||
|
|
||||
|
/** |
||||
|
* 手机号 |
||||
|
*/ |
||||
|
@NotBlank(message = "{user.phonenumber.not.blank}") |
||||
|
private String phonenumber; |
||||
|
|
||||
|
/** |
||||
|
* 短信code |
||||
|
*/ |
||||
|
@NotBlank(message = "{sms.code.not.blank}") |
||||
|
private String smsCode; |
||||
|
|
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
/** |
||||
|
* 三方登录对象 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class SocialLoginBody extends LoginBody { |
||||
|
|
||||
|
/** |
||||
|
* 第三方登录平台 |
||||
|
*/ |
||||
|
@NotBlank(message = "{social.source.not.blank}") |
||||
|
private String source; |
||||
|
|
||||
|
/** |
||||
|
* 第三方登录code |
||||
|
*/ |
||||
|
@NotBlank(message = "{social.code.not.blank}") |
||||
|
private String socialCode; |
||||
|
|
||||
|
/** |
||||
|
* 第三方登录socialState |
||||
|
*/ |
||||
|
@NotBlank(message = "{social.state.not.blank}") |
||||
|
private String socialState; |
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
/** |
||||
|
* 三方登录对象 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class XcxLoginBody extends LoginBody { |
||||
|
|
||||
|
/** |
||||
|
* 小程序id(多个小程序时使用) |
||||
|
*/ |
||||
|
private String appid; |
||||
|
|
||||
|
/** |
||||
|
* 小程序code |
||||
|
*/ |
||||
|
@NotBlank(message = "{xcx.code.not.blank}") |
||||
|
private String xcxCode; |
||||
|
|
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
package org.dromara.common.core.domain.model; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 小程序登录用户身份权限 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@NoArgsConstructor |
||||
|
public class XcxLoginUser extends LoginUser { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* openid |
||||
|
*/ |
||||
|
private String openid; |
||||
|
|
||||
|
} |
@ -0,0 +1,152 @@ |
|||||
|
package org.dromara.common.core.enums; |
||||
|
|
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
import org.dromara.common.core.exception.ServiceException; |
||||
|
import org.dromara.common.core.utils.StringUtils; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* 业务状态枚举 |
||||
|
* |
||||
|
* @author may |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum BusinessStatusEnum { |
||||
|
/** |
||||
|
* 已撤销 |
||||
|
*/ |
||||
|
CANCEL("cancel", "已撤销"), |
||||
|
/** |
||||
|
* 草稿 |
||||
|
*/ |
||||
|
DRAFT("draft", "草稿"), |
||||
|
/** |
||||
|
* 待审核 |
||||
|
*/ |
||||
|
WAITING("waiting", "待审核"), |
||||
|
/** |
||||
|
* 已完成 |
||||
|
*/ |
||||
|
FINISH("finish", "已完成"), |
||||
|
/** |
||||
|
* 已作废 |
||||
|
*/ |
||||
|
INVALID("invalid", "已作废"), |
||||
|
/** |
||||
|
* 已退回 |
||||
|
*/ |
||||
|
BACK("back", "已退回"), |
||||
|
/** |
||||
|
* 已终止 |
||||
|
*/ |
||||
|
TERMINATION("termination", "已终止"); |
||||
|
|
||||
|
/** |
||||
|
* 状态 |
||||
|
*/ |
||||
|
private final String status; |
||||
|
|
||||
|
/** |
||||
|
* 描述 |
||||
|
*/ |
||||
|
private final String desc; |
||||
|
|
||||
|
/** |
||||
|
* 获取业务状态 |
||||
|
* |
||||
|
* @param status 状态 |
||||
|
*/ |
||||
|
public static String findByStatus(String status) { |
||||
|
if (StringUtils.isBlank(status)) { |
||||
|
return StrUtil.EMPTY; |
||||
|
} |
||||
|
return Arrays.stream(BusinessStatusEnum.values()) |
||||
|
.filter(statusEnum -> statusEnum.getStatus().equals(status)) |
||||
|
.findFirst() |
||||
|
.map(BusinessStatusEnum::getDesc) |
||||
|
.orElse(StrUtil.EMPTY); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 启动流程校验 |
||||
|
* |
||||
|
* @param status 状态 |
||||
|
*/ |
||||
|
public static void checkStartStatus(String status) { |
||||
|
if (WAITING.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已提交过申请,正在审批中!"); |
||||
|
} else if (FINISH.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已完成申请!"); |
||||
|
} else if (INVALID.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已作废!"); |
||||
|
} else if (TERMINATION.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已终止!"); |
||||
|
} else if (StringUtils.isBlank(status)) { |
||||
|
throw new ServiceException("流程状态为空!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 撤销流程校验 |
||||
|
* |
||||
|
* @param status 状态 |
||||
|
*/ |
||||
|
public static void checkCancelStatus(String status) { |
||||
|
if (CANCEL.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已撤销!"); |
||||
|
} else if (FINISH.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已完成申请!"); |
||||
|
} else if (INVALID.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已作废!"); |
||||
|
} else if (TERMINATION.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已终止!"); |
||||
|
} else if (BACK.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已退回!"); |
||||
|
} else if (StringUtils.isBlank(status)) { |
||||
|
throw new ServiceException("流程状态为空!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 驳回流程校验 |
||||
|
* |
||||
|
* @param status 状态 |
||||
|
*/ |
||||
|
public static void checkBackStatus(String status) { |
||||
|
if (BACK.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已退回!"); |
||||
|
} else if (FINISH.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已完成申请!"); |
||||
|
} else if (INVALID.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已作废!"); |
||||
|
} else if (TERMINATION.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已终止!"); |
||||
|
} else if (CANCEL.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已撤销!"); |
||||
|
} else if (StringUtils.isBlank(status)) { |
||||
|
throw new ServiceException("流程状态为空!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 作废,终止流程校验 |
||||
|
* |
||||
|
* @param status 状态 |
||||
|
*/ |
||||
|
public static void checkInvalidStatus(String status) { |
||||
|
if (FINISH.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已完成申请!"); |
||||
|
} else if (INVALID.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已作废!"); |
||||
|
} else if (TERMINATION.getStatus().equals(status)) { |
||||
|
throw new ServiceException("该单据已终止!"); |
||||
|
} else if (StringUtils.isBlank(status)) { |
||||
|
throw new ServiceException("流程状态为空!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
package org.dromara.common.core.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 设备类型 |
||||
|
* 针对一套 用户体系 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum DeviceType { |
||||
|
|
||||
|
/** |
||||
|
* pc端 |
||||
|
*/ |
||||
|
PC("pc"), |
||||
|
|
||||
|
/** |
||||
|
* app端 |
||||
|
*/ |
||||
|
APP("app"), |
||||
|
|
||||
|
/** |
||||
|
* 小程序端 |
||||
|
*/ |
||||
|
XCX("xcx"), |
||||
|
|
||||
|
/** |
||||
|
* social第三方端 |
||||
|
*/ |
||||
|
SOCIAL("social"); |
||||
|
|
||||
|
private final String device; |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
package org.dromara.common.core.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 登录类型 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum LoginType { |
||||
|
|
||||
|
/** |
||||
|
* 密码登录 |
||||
|
*/ |
||||
|
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), |
||||
|
|
||||
|
/** |
||||
|
* 短信登录 |
||||
|
*/ |
||||
|
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), |
||||
|
|
||||
|
/** |
||||
|
* 邮箱登录 |
||||
|
*/ |
||||
|
EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), |
||||
|
|
||||
|
/** |
||||
|
* 小程序登录 |
||||
|
*/ |
||||
|
XCX("", ""); |
||||
|
|
||||
|
/** |
||||
|
* 登录重试超出限制提示 |
||||
|
*/ |
||||
|
final String retryLimitExceed; |
||||
|
|
||||
|
/** |
||||
|
* 登录重试限制计数提示 |
||||
|
*/ |
||||
|
final String retryLimitCount; |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package org.dromara.common.core.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 用户状态 |
||||
|
* |
||||
|
* @author LionLi |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum TenantStatus { |
||||
|
/** |
||||
|
* 正常 |
||||
|
*/ |
||||
|
OK("0", "正常"), |
||||
|
/** |
||||
|
* 停用 |
||||
|
*/ |
||||
|
DISABLE("1", "停用"), |
||||
|
/** |
||||
|
* 删除 |
||||
|
*/ |
||||
|
DELETED("2", "删除"); |
||||
|
|
||||
|
private final String code; |
||||
|
private final String info; |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package org.dromara.common.core.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 用户状态 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum UserStatus { |
||||
|
/** |
||||
|
* 正常 |
||||
|
*/ |
||||
|
OK("0", "正常"), |
||||
|
/** |
||||
|
* 停用 |
||||
|
*/ |
||||
|
DISABLE("1", "停用"), |
||||
|
/** |
||||
|
* 删除 |
||||
|
*/ |
||||
|
DELETED("2", "删除"); |
||||
|
|
||||
|
private final String code; |
||||
|
private final String info; |
||||
|
|
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
package org.dromara.common.core.enums; |
||||
|
|
||||
|
import org.dromara.common.core.utils.StringUtils; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 设备类型 |
||||
|
* 针对多套 用户体系 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum UserType { |
||||
|
|
||||
|
/** |
||||
|
* pc端 |
||||
|
*/ |
||||
|
SYS_USER("sys_user"), |
||||
|
|
||||
|
/** |
||||
|
* app端 |
||||
|
*/ |
||||
|
APP_USER("app_user"); |
||||
|
|
||||
|
private final String userType; |
||||
|
|
||||
|
public static UserType getUserType(String str) { |
||||
|
for (UserType value : values()) { |
||||
|
if (StringUtils.contains(str, value.getUserType())) { |
||||
|
return value; |
||||
|
} |
||||
|
} |
||||
|
throw new RuntimeException("'UserType' not found By " + str); |
||||
|
} |
||||
|
} |
@ -0,0 +1,59 @@ |
|||||
|
package org.dromara.common.core.exception; |
||||
|
|
||||
|
import lombok.*; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 业务异常 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public final class ServiceException extends RuntimeException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* 错误码 |
||||
|
*/ |
||||
|
private Integer code; |
||||
|
|
||||
|
/** |
||||
|
* 错误提示 |
||||
|
*/ |
||||
|
private String message; |
||||
|
|
||||
|
/** |
||||
|
* 错误明细,内部调试错误 |
||||
|
*/ |
||||
|
private String detailMessage; |
||||
|
|
||||
|
public ServiceException(String message) { |
||||
|
this.message = message; |
||||
|
} |
||||
|
|
||||
|
public ServiceException(String message, Integer code) { |
||||
|
this.message = message; |
||||
|
this.code = code; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getMessage() { |
||||
|
return message; |
||||
|
} |
||||
|
|
||||
|
public ServiceException setMessage(String message) { |
||||
|
this.message = message; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public ServiceException setDetailMessage(String detailMessage) { |
||||
|
this.detailMessage = detailMessage; |
||||
|
return this; |
||||
|
} |
||||
|
} |
@ -0,0 +1,74 @@ |
|||||
|
package org.dromara.common.core.exception.base; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import org.dromara.common.core.utils.MessageUtils; |
||||
|
import org.dromara.common.core.utils.StringUtils; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 基础异常 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class BaseException extends RuntimeException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* 所属模块 |
||||
|
*/ |
||||
|
private String module; |
||||
|
|
||||
|
/** |
||||
|
* 错误码 |
||||
|
*/ |
||||
|
private String code; |
||||
|
|
||||
|
/** |
||||
|
* 错误码对应的参数 |
||||
|
*/ |
||||
|
private Object[] args; |
||||
|
|
||||
|
/** |
||||
|
* 错误消息 |
||||
|
*/ |
||||
|
private String defaultMessage; |
||||
|
|
||||
|
public BaseException(String module, String code, Object[] args) { |
||||
|
this(module, code, args, null); |
||||
|
} |
||||
|
|
||||
|
public BaseException(String module, String defaultMessage) { |
||||
|
this(module, null, null, defaultMessage); |
||||
|
} |
||||
|
|
||||
|
public BaseException(String code, Object[] args) { |
||||
|
this(null, code, args, null); |
||||
|
} |
||||
|
|
||||
|
public BaseException(String defaultMessage) { |
||||
|
this(null, null, null, defaultMessage); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getMessage() { |
||||
|
String message = null; |
||||
|
if (!StringUtils.isEmpty(code)) { |
||||
|
message = MessageUtils.message(code, args); |
||||
|
} |
||||
|
if (message == null) { |
||||
|
message = defaultMessage; |
||||
|
} |
||||
|
return message; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package org.dromara.common.core.exception.file; |
||||
|
|
||||
|
import org.dromara.common.core.exception.base.BaseException; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 文件信息异常类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class FileException extends BaseException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
public FileException(String code, Object[] args) { |
||||
|
super("file", code, args, null); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara.common.core.exception.file; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 文件名称超长限制异常类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class FileNameLengthLimitExceededException extends FileException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
public FileNameLengthLimitExceededException(int defaultFileNameLength) { |
||||
|
super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara.common.core.exception.file; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 文件名大小限制异常类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class FileSizeLimitExceededException extends FileException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
public FileSizeLimitExceededException(long defaultMaxSize) { |
||||
|
super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara.common.core.exception.user; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 验证码错误异常类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class CaptchaException extends UserException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
public CaptchaException() { |
||||
|
super("user.jcaptcha.error"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara.common.core.exception.user; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 验证码失效异常类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class CaptchaExpireException extends UserException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
public CaptchaExpireException() { |
||||
|
super("user.jcaptcha.expire"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
package org.dromara.common.core.exception.user; |
||||
|
|
||||
|
import org.dromara.common.core.exception.base.BaseException; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 用户信息异常类 |
||||
|
* |
||||
|
* @author ruoyi |
||||
|
*/ |
||||
|
public class UserException extends BaseException { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
public UserException(String code, Object... args) { |
||||
|
super("user", code, args, null); |
||||
|
} |
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
package org.dromara.common.core.factory; |
||||
|
|
||||
|
import cn.hutool.core.lang.PatternPool; |
||||
|
import org.dromara.common.core.constant.RegexConstants; |
||||
|
|
||||
|
import java.util.regex.Pattern; |
||||
|
|
||||
|
/** |
||||
|
* 正则表达式模式池工厂 |
||||
|
* <p>初始化的时候将正则表达式加入缓存池当中</p> |
||||
|
* <p>提高正则表达式的性能,避免重复编译相同的正则表达式</p> |
||||
|
* |
||||
|
* @author 21001 |
||||
|
*/ |
||||
|
public class RegexPatternPoolFactory extends PatternPool { |
||||
|
|
||||
|
/** |
||||
|
* 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) |
||||
|
*/ |
||||
|
public static final Pattern DICTIONARY_TYPE = get(RegexConstants.DICTIONARY_TYPE); |
||||
|
|
||||
|
/** |
||||
|
* 身份证号码(后6位) |
||||
|
*/ |
||||
|
public static final Pattern ID_CARD_LAST_6 = get(RegexConstants.ID_CARD_LAST_6); |
||||
|
|
||||
|
/** |
||||
|
* QQ号码 |
||||
|
*/ |
||||
|
public static final Pattern QQ_NUMBER = get(RegexConstants.QQ_NUMBER); |
||||
|
|
||||
|
/** |
||||
|
* 邮政编码 |
||||
|
*/ |
||||
|
public static final Pattern POSTAL_CODE = get(RegexConstants.POSTAL_CODE); |
||||
|
|
||||
|
/** |
||||
|
* 注册账号 |
||||
|
*/ |
||||
|
public static final Pattern ACCOUNT = get(RegexConstants.ACCOUNT); |
||||
|
|
||||
|
/** |
||||
|
* 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 |
||||
|
*/ |
||||
|
public static final Pattern PASSWORD = get(RegexConstants.PASSWORD); |
||||
|
|
||||
|
/** |
||||
|
* 通用状态(0表示正常,1表示停用) |
||||
|
*/ |
||||
|
public static final Pattern STATUS = get(RegexConstants.STATUS); |
||||
|
|
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package org.dromara.common.core.factory; |
||||
|
|
||||
|
import org.dromara.common.core.utils.StringUtils; |
||||
|
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; |
||||
|
import org.springframework.core.env.PropertiesPropertySource; |
||||
|
import org.springframework.core.env.PropertySource; |
||||
|
import org.springframework.core.io.support.DefaultPropertySourceFactory; |
||||
|
import org.springframework.core.io.support.EncodedResource; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* yml 配置源工厂 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { |
||||
|
|
||||
|
@Override |
||||
|
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { |
||||
|
String sourceName = resource.getResource().getFilename(); |
||||
|
if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) { |
||||
|
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); |
||||
|
factory.setResources(resource.getResource()); |
||||
|
factory.afterPropertiesSet(); |
||||
|
return new PropertiesPropertySource(sourceName, factory.getObject()); |
||||
|
} |
||||
|
return super.createPropertySource(name, resource); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara.common.core.service; |
||||
|
|
||||
|
/** |
||||
|
* 通用 参数配置服务 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface ConfigService { |
||||
|
|
||||
|
/** |
||||
|
* 根据参数 key 获取参数值 |
||||
|
* |
||||
|
* @param configKey 参数 key |
||||
|
* @return 参数值 |
||||
|
*/ |
||||
|
String getConfigValue(String configKey); |
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package org.dromara.common.core.service; |
||||
|
|
||||
|
/** |
||||
|
* 通用 部门服务 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface DeptService { |
||||
|
|
||||
|
/** |
||||
|
* 通过部门ID查询部门名称 |
||||
|
* |
||||
|
* @param deptIds 部门ID串逗号分隔 |
||||
|
* @return 部门名称串逗号分隔 |
||||
|
*/ |
||||
|
String selectDeptNameByIds(String deptIds); |
||||
|
|
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
package org.dromara.common.core.service; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 通用 字典服务 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface DictService { |
||||
|
|
||||
|
/** |
||||
|
* 分隔符 |
||||
|
*/ |
||||
|
String SEPARATOR = ","; |
||||
|
|
||||
|
/** |
||||
|
* 根据字典类型和字典值获取字典标签 |
||||
|
* |
||||
|
* @param dictType 字典类型 |
||||
|
* @param dictValue 字典值 |
||||
|
* @return 字典标签 |
||||
|
*/ |
||||
|
default String getDictLabel(String dictType, String dictValue) { |
||||
|
return getDictLabel(dictType, dictValue, SEPARATOR); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据字典类型和字典标签获取字典值 |
||||
|
* |
||||
|
* @param dictType 字典类型 |
||||
|
* @param dictLabel 字典标签 |
||||
|
* @return 字典值 |
||||
|
*/ |
||||
|
default String getDictValue(String dictType, String dictLabel) { |
||||
|
return getDictValue(dictType, dictLabel, SEPARATOR); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据字典类型和字典值获取字典标签 |
||||
|
* |
||||
|
* @param dictType 字典类型 |
||||
|
* @param dictValue 字典值 |
||||
|
* @param separator 分隔符 |
||||
|
* @return 字典标签 |
||||
|
*/ |
||||
|
String getDictLabel(String dictType, String dictValue, String separator); |
||||
|
|
||||
|
/** |
||||
|
* 根据字典类型和字典标签获取字典值 |
||||
|
* |
||||
|
* @param dictType 字典类型 |
||||
|
* @param dictLabel 字典标签 |
||||
|
* @param separator 分隔符 |
||||
|
* @return 字典值 |
||||
|
*/ |
||||
|
String getDictValue(String dictType, String dictLabel, String separator); |
||||
|
|
||||
|
/** |
||||
|
* 获取字典下所有的字典值与标签 |
||||
|
* |
||||
|
* @param dictType 字典类型 |
||||
|
* @return dictValue为key,dictLabel为值组成的Map |
||||
|
*/ |
||||
|
Map<String, String> getAllDictByDictType(String dictType); |
||||
|
|
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package org.dromara.common.core.service; |
||||
|
|
||||
|
import org.dromara.common.core.domain.dto.OssDTO; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 通用 OSS服务 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface OssService { |
||||
|
|
||||
|
/** |
||||
|
* 通过ossId查询对应的url |
||||
|
* |
||||
|
* @param ossIds ossId串逗号分隔 |
||||
|
* @return url串逗号分隔 |
||||
|
*/ |
||||
|
String selectUrlByIds(String ossIds); |
||||
|
|
||||
|
/** |
||||
|
* 通过ossId查询列表 |
||||
|
* |
||||
|
* @param ossIds ossId串逗号分隔 |
||||
|
* @return 列表 |
||||
|
*/ |
||||
|
List<OssDTO> selectByIds(String ossIds); |
||||
|
} |
@ -0,0 +1,69 @@ |
|||||
|
package org.dromara.common.core.service; |
||||
|
|
||||
|
import org.dromara.common.core.domain.dto.UserDTO; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 通用 用户服务 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
*/ |
||||
|
public interface UserService { |
||||
|
|
||||
|
/** |
||||
|
* 通过用户ID查询用户账户 |
||||
|
* |
||||
|
* @param userId 用户ID |
||||
|
* @return 用户账户 |
||||
|
*/ |
||||
|
String selectUserNameById(Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 通过用户ID查询用户账户 |
||||
|
* |
||||
|
* @param userId 用户ID |
||||
|
* @return 用户名称 |
||||
|
*/ |
||||
|
String selectNicknameById(Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 通过用户ID查询用户账户 |
||||
|
* |
||||
|
* @param userIds 用户ID 多个用逗号隔开 |
||||
|
* @return 用户名称 |
||||
|
*/ |
||||
|
String selectNicknameByIds(String userIds); |
||||
|
|
||||
|
/** |
||||
|
* 通过用户ID查询用户手机号 |
||||
|
* |
||||
|
* @param userId 用户id |
||||
|
* @return 用户手机号 |
||||
|
*/ |
||||
|
String selectPhonenumberById(Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 通过用户ID查询用户邮箱 |
||||
|
* |
||||
|
* @param userId 用户id |
||||
|
* @return 用户邮箱 |
||||
|
*/ |
||||
|
String selectEmailById(Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 通过用户ID查询用户列表 |
||||
|
* |
||||
|
* @param userIds 用户ids |
||||
|
* @return 用户列表 |
||||
|
*/ |
||||
|
List<UserDTO> selectListByIds(List<Long> userIds); |
||||
|
|
||||
|
/** |
||||
|
* 通过角色ID查询用户ID |
||||
|
* |
||||
|
* @param roleIds 角色ids |
||||
|
* @return 用户ids |
||||
|
*/ |
||||
|
List<Long> selectUserIdsByRoleIds(List<Long> roleIds); |
||||
|
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue