Merge branch 'master' into 'main'
-------退款和发票:不要数据权限 See merge request pusong/pusong-crm!1
This commit is contained in:
commit
ad6938e251
36
README.en.md
Normal file
36
README.en.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# PuSong-Vue-Plus-v1.0.1
|
||||||
|
|
||||||
|
#### Description
|
||||||
|
浦颂多租户应用平台升级版
|
||||||
|
|
||||||
|
#### Software Architecture
|
||||||
|
Software architecture description
|
||||||
|
|
||||||
|
#### Installation
|
||||||
|
|
||||||
|
1. xxxx
|
||||||
|
2. xxxx
|
||||||
|
3. xxxx
|
||||||
|
|
||||||
|
#### Instructions
|
||||||
|
|
||||||
|
1. xxxx
|
||||||
|
2. xxxx
|
||||||
|
3. xxxx
|
||||||
|
|
||||||
|
#### Contribution
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Create Feat_xxx branch
|
||||||
|
3. Commit your code
|
||||||
|
4. Create Pull Request
|
||||||
|
|
||||||
|
|
||||||
|
#### Gitee Feature
|
||||||
|
|
||||||
|
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||||
|
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||||
|
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||||
|
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||||
|
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||||
|
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
249
README.md
249
README.md
@ -1,93 +1,180 @@
|
|||||||
# pusong-crm
|
<img src="https://foruda.gitee.com/images/1679673773341074847/178e8451_1766278.png" width="50%" height="50%">
|
||||||
|
<div style="height: 10px; clear: both;"></div>
|
||||||
|
|
||||||
|
- - -
|
||||||
|
## 平台简介
|
||||||
|
|
||||||
|
[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||||
|
[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus)
|
||||||
|
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
|
||||||
|
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
||||||
|
<br>
|
||||||
|
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||||
|
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
|
||||||
|
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
|
||||||
|
[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
|
||||||
|
|
||||||
|
> 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)
|
||||||
|
|
||||||
|
## 软件架构图
|
||||||
|
|
||||||
|
![Plus部署架构图](https://foruda.gitee.com/images/1678981882624240692/ae2a3f3e_1766278.png "Plus部署架构图.png")
|
||||||
|
|
||||||
|
## 如何参与贡献
|
||||||
|
|
||||||
|
[参与贡献的方式 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" />
|
||||||
|
|
||||||
|
## 演示图例
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") |
|
||||||
|
| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
|
||||||
|
|
||||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
|
||||||
|
|
||||||
## Add your files
|
|
||||||
|
|
||||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
|
||||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd existing_repo
|
|
||||||
git remote add origin http://192.168.18.119:88/pusong/pusong-crm.git
|
|
||||||
git branch -M main
|
|
||||||
git push -uf origin main
|
|
||||||
```
|
|
||||||
|
|
||||||
## Integrate with your tools
|
|
||||||
|
|
||||||
- [ ] [Set up project integrations](http://192.168.18.119:88/pusong/pusong-crm/-/settings/integrations)
|
|
||||||
|
|
||||||
## Collaborate with your team
|
|
||||||
|
|
||||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
|
||||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
|
||||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
|
||||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
|
||||||
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
|
||||||
|
|
||||||
## Test and Deploy
|
|
||||||
|
|
||||||
Use the built-in continuous integration in GitLab.
|
|
||||||
|
|
||||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
|
||||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
|
||||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
|
||||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
|
||||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
# Editing this README
|
|
||||||
|
|
||||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
|
||||||
|
|
||||||
## Suggestions for a good README
|
|
||||||
|
|
||||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
|
||||||
|
|
||||||
## Name
|
|
||||||
Choose a self-explaining name for your project.
|
|
||||||
|
|
||||||
## Description
|
|
||||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
|
||||||
|
|
||||||
## Badges
|
|
||||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
|
||||||
|
|
||||||
## Visuals
|
|
||||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
State if you are open to contributions and what your requirements are for accepting them.
|
|
||||||
|
|
||||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
|
||||||
|
|
||||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
|
||||||
|
|
||||||
## Authors and acknowledgment
|
|
||||||
Show your appreciation to those who have contributed to the project.
|
|
||||||
|
|
||||||
## License
|
|
||||||
For open source projects, say how it is licensed.
|
|
||||||
|
|
||||||
## Project status
|
|
||||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
|
||||||
|
BIN
doc/image/allZ.png
Normal file
BIN
doc/image/allZ.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 172 KiB |
BIN
doc/image/leftZ.png
Normal file
BIN
doc/image/leftZ.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
BIN
doc/image/pay.png
Normal file
BIN
doc/image/pay.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 199 KiB |
BIN
doc/image/rightZ.png
Normal file
BIN
doc/image/rightZ.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
251
doc/report.ftl
Normal file
251
doc/report.ftl
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Report</title>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
font-size:9pt;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
font-size:9.1pt;
|
||||||
|
border-collapse: collapse; /* 合并边框 */
|
||||||
|
border: 0.1pt solid black; /* 设置表格整体边框 */
|
||||||
|
}
|
||||||
|
td{
|
||||||
|
border: 0.1pt solid black; /* 设置单元格边框 */
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
text-indent:18pt;
|
||||||
|
text-align:justify;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
.content{
|
||||||
|
/*margin-bottom:0pt;*/
|
||||||
|
text-indent:27pt;
|
||||||
|
text-align:justify;
|
||||||
|
line-height:100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div style="width: 100%;">
|
||||||
|
<#-- <div style="width: 100% ;height: 5pt; "></div>-->
|
||||||
|
<#-- <div >-->
|
||||||
|
<#-- <p style="text-align:center;margin-left:300px;margin-top:1pt; margin-bottom:0pt;">-->
|
||||||
|
<#-- <span style="">合同编号:PS- </span>-->
|
||||||
|
<#-- <span style=" text-decoration:underline">${contract.contractCode} </span>-->
|
||||||
|
<#-- <span style=""> 客户编号: </span>-->
|
||||||
|
<#-- <span style=" text-decoration:underline">${contract.customId} -->
|
||||||
|
<#-- </span></p>-->
|
||||||
|
<#-- </div>-->
|
||||||
|
<#-- <div style="width: 100% ;height: 3pt; "></div>-->
|
||||||
|
<#-- <div style="width: 100% ;height: 0.75pt; background-color: black"></div>-->
|
||||||
|
|
||||||
|
<#--<div style="width: 100% ;height: 17pt; "></div>-->
|
||||||
|
<p style=" text-align:center; margin: 0 auto; font-size:14pt">
|
||||||
|
<span style=" font-weight: bold">${main.name}</span></p>
|
||||||
|
<p style=" margin: 0 auto; text-align:center; font-size:16pt">
|
||||||
|
<span style=" font-weight:bold">服务合同</span></p>
|
||||||
|
<p class="content" style="margin-left:21pt; text-indent:19pt;">本合同由缔约双方在自愿、平等、公平及诚实信用原则的基础上,本着共赢互利原则,根据《中华人民共和国民法典》等</p>
|
||||||
|
<p class="content" >相关法律、法规的规定,双方签订以下服务合同以资信守,本服务合同后附的《服务通用条款》为本服务单的有效组成部分</p>
|
||||||
|
<p class="content" >(以下合称为“本协议”),对双方均具有约束力。</p>
|
||||||
|
<div style="text-align:center">
|
||||||
|
<table style="width:526.55pt; margin-right:auto; margin-left:auto;">
|
||||||
|
<tbody>
|
||||||
|
<tr >
|
||||||
|
<td style="width:88.2pt;height: 30pt">
|
||||||
|
服务类别
|
||||||
|
</td>
|
||||||
|
<td style="width:416pt;" colspan="2">
|
||||||
|
具体内容
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<#list business as item>
|
||||||
|
<tr >
|
||||||
|
<td>
|
||||||
|
${item.businessTypeName}
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="height: 5pt;width: 1pt"></div>
|
||||||
|
<p class="content" style="text-indent:5pt">
|
||||||
|
${item.businessTypeName}-金额:${item.businessAmount}元
|
||||||
|
<#if item.businessDesc?? && item.businessDesc != "">
|
||||||
|
-备注:${item.businessDesc}
|
||||||
|
</#if>
|
||||||
|
</p>
|
||||||
|
<#list item.detailBos as detail>
|
||||||
|
<p class="content" style="text-indent:32pt">${detail.businessProjectLabel}
|
||||||
|
<#if detail.extentInfo?? && detail.extentInfo != "">
|
||||||
|
<#assign extenInfo = detail.extentInfo?split("$")>
|
||||||
|
:
|
||||||
|
<#list extenInfo as exten>
|
||||||
|
${exten?split("#")[1]}
|
||||||
|
<#if exten_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#if detail.amount??>
|
||||||
|
-金额:${detail.amount}
|
||||||
|
</#if>
|
||||||
|
<#if detail.amountDesc?? && detail.amountDesc != "">
|
||||||
|
-备注:${detail.amountDesc}
|
||||||
|
</#if>
|
||||||
|
</p>
|
||||||
|
</#list>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</#list>
|
||||||
|
<tr >
|
||||||
|
<td >
|
||||||
|
付款账号
|
||||||
|
</td>
|
||||||
|
<td colspan="2" >
|
||||||
|
<div style="height: 5pt;width: 1pt"></div>
|
||||||
|
<div style="float: left;">
|
||||||
|
<p class="content" style="text-indent:5pt">公司名称:${main.name?if_exists}</p>
|
||||||
|
<p class="content" style="text-indent:5pt">账号:${main.account?if_exists}</p>
|
||||||
|
<p class="content" style="text-indent:5pt">开户行:${main.bank?if_exists}</p>
|
||||||
|
</div>
|
||||||
|
<div style="float: left;">
|
||||||
|
<img style=" width:50pt; height:50pt; " src="${imagePath}/doc/image/pay.png"/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr >
|
||||||
|
<td colspan="3" style="width:515pt; ">
|
||||||
|
<div style="height: 5pt;width: 1pt"></div>
|
||||||
|
<p style="margin:5pt; text-indent:18pt; text-align:justify; ">
|
||||||
|
<span style="">合同金额:共计¥</span>
|
||||||
|
<span style=" text-decoration:underline"> ${contract.contractAmount}</span>
|
||||||
|
<span style="">元(大写金额:</span>
|
||||||
|
<span style=" text-decoration:underline">${contractAmount} )</span>
|
||||||
|
<span style="">,垫付项目中涉及银行开户、刻章等,实际价格以第三方机构及政府规定为准。除此之外,甲方无需向乙方支付其他任何费用。</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr >
|
||||||
|
<td >
|
||||||
|
付款方式
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="height: 5pt;width: 1pt"></div>
|
||||||
|
<p class="content" style="text-indent:5pt">${contract.payModeDesc}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr >
|
||||||
|
<td >
|
||||||
|
合同备注
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="height: 5pt;width: 1pt"></div>
|
||||||
|
<p class="content" style="text-indent:5pt">
|
||||||
|
<#if contract.signDesc?? && contract.signDesc != "">
|
||||||
|
${contract.signDesc?if_exists}
|
||||||
|
<#else>
|
||||||
|
无
|
||||||
|
</#if>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p style=" text-indent:9pt; text-align:justify; ">
|
||||||
|
<span style=""> </span></p>
|
||||||
|
<p class="title">一、服务期限</p>
|
||||||
|
<#if contract.startServiceDate??>
|
||||||
|
<p class="content">本合同中的服务周期为
|
||||||
|
${contract.startServiceDate?string('yyyy年MM月dd日')}至${contract.endServiceDate?string('yyyy年MM月dd日')}。
|
||||||
|
</p>
|
||||||
|
</#if>
|
||||||
|
<p class="content">本合同中的企业托管服务,在合同到期前 30 天,乙方有义务告知甲方。如果双方在合同期满前 30 天内未提出终止或变更要</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">求,未办理交接手续,本合同将自行延期一年。如为其他业务,则与双方约定时间为准。</p>
|
||||||
|
|
||||||
|
<p class="title">二、甲方权利与义务</p>
|
||||||
|
<p class="content">(一)甲方须按本合同约定,按时足额支付服务费用,否则乙方有权拒绝提供服务;</p>
|
||||||
|
<p class="content">(二)甲方应无保留地向乙方陈述与代理事务有关的真实情况,提供的资料必须真实合法,且法定代表人、监事、股东等信息</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">的提交须经过其本人同意,否则因此导致的所有风险与责任均由甲方自行承担;</p>
|
||||||
|
|
||||||
|
<p class="title">三、乙方权利和义务</p>
|
||||||
|
<p class="content">(一)乙方在收到甲方支付的款项后,立即启动本合同约定的服务;</p>
|
||||||
|
<p class="content">(二)乙方按照甲方提供的真实有效的企业信息,为甲方办理企业的委托服务;</p>
|
||||||
|
<p class="content">(三)乙方应及时将服务办理完毕后形成的相关资料交予甲方;</p>
|
||||||
|
<p class="content">(四)除为履行本合同所需外,未经甲方事先同意,乙方不得擅自向第三方泄露甲方的商业信息及其他资料。</p>
|
||||||
|
<p class="content">(五)甲方若有违法违规经营情形,或甲方示意乙方提供不当的服务以及其他不符合法律、行政法规的要求,乙方有权拒</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">绝;若 甲方坚持其不当要求,乙方有权单方解除本合同,本合同自乙方向甲方发出通知之日起终止,由此造成的相关责任由甲方</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">自行承担。</p>
|
||||||
|
<p class="content">(六)如甲方不按乙方要求完整、及时地准备和提供相应的资料,导致乙方受托事项办理的延误或未完成,由此所发生的一切</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">后果完全由甲方承担,乙方不承担任何责任。</p>
|
||||||
|
|
||||||
|
<p class="title">四、违约责任</p>
|
||||||
|
<p class="content">(一)甲乙双方任何一方无正当理由提前终止本合同的,应按照本合同服务总金额的 20%向守约方支付违约金,乙方扣除违约</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">金后退还剩余服务期费用;如乙方为甲方注册成立公司后,甲方无正当理由提前解除或终止合同的,乙方不予退还本合同的服务费</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">用。</p>
|
||||||
|
<p class="content">(二)若甲方拖欠乙方服务费,以应付而未付的金额为基础,按每天万分之五的日利率计收每日逾期利息。若甲方逾期支付达</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">1个月,视为甲方主动终止本合同,乙方有权终止提供服务,由此产生的经济、法律及其他责任由甲方自行承担,在甲方未按照本合</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">同约定支付服务费和其他费用的情况下,乙方有权将甲方资料予 以留置,在甲方所欠费用结清后,乙方归还甲方相关资料。</p>
|
||||||
|
<p class="content">(三)任何一方违反本合同部分条款约定的,不影响其余条款的效力和继续履行。对违约情形,守约方有权要求违约方予以更</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">正,若违约方拒绝纠正的,守约方有权单方解除本合同并要求违约方承担违约赔偿责任</p>
|
||||||
|
<p class="content">(四)由于乙方过错给甲方造成损失的,乙方应承担赔偿责任,但赔偿责任以该合作周期内所收取的该项服务的服务费用为赔</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">偿上限。</p>
|
||||||
|
|
||||||
|
<p class="title">五、不可抗力</p>
|
||||||
|
<p class="content">不可抗力是指法律规章或政策变化、社会异常事件(如罢工、骚乱、盗窃、抢劫以及其它不能预见的客观情况)、自然灾害</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">(如台风、洪水、冰雹、地震、海啸、火灾、旱灾、大雪、山崩)等对其发生和后果不能防止或避免的事件。</p>
|
||||||
|
<p class="content">发生不可抗力事件时,双方应互相协商,寻求公平合理的解决争议途经,并尽一切努力减轻不可抗力造成的不良后果。在不可</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">抗力造成本合同无法履行的情况下,双方互不承担责任,且甲方和乙方均有权选择终止本合同,乙方已收款项在扣除已经完成的服务</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">费用和已经产生的成本后进行返还。</p>
|
||||||
|
|
||||||
|
<p class="title">六、通知与送达</p>
|
||||||
|
<p>甲方确保其通信地址、联系人、联系电话的准确性及有效性,因乙方经努力而无法与甲方取得联系而引起的一切后果,由甲方承担;</p>
|
||||||
|
<p class="content">(一)如果是专人送交,则在对方签收视为已送达。</p>
|
||||||
|
<p class="content">(二)如用快递、传真发送,则在收到传输确认书的当天被视为送到,如果传输当天不是工作日,或传输时工作日已结束营</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">业,则在下一个工作日被视作已送达日。</p>
|
||||||
|
<p class="content">(三)以电子邮件、微信等工具发出的,则为发送人的邮件系统确认电子邮件发送至收件人的邮件接收系统后的当天为送达</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">日。</p>
|
||||||
|
<p class="content">(四)各方均应积极履行通知义务,且确保送达地址的有效及准确,任何一方不得以拒绝签收、无人签收、变更地址未收到等</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">理由否定送达效力。</p>
|
||||||
|
<p class="content">(五)乙方工商注册环节的企业营业执照、印章等物品的快递费用由乙方承担,注册企业之后所产生的快递(到付)费用由甲</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">方自行承担。</p>
|
||||||
|
|
||||||
|
<p class="title">七、合同份数及法律效力</p>
|
||||||
|
<p class="content">本合同一式贰份,甲方持壹份,乙方持壹份,每份合同具有相同的法律效力。本合同自双方签署后生效。</p>
|
||||||
|
|
||||||
|
<p class="title">八、其他</p>
|
||||||
|
<p class="content">(一)乙方出于宣传目的而采取发放宣传册、广告、网页推广、销售人员宣讲等方式展现的内容不具有合同效力,双方权利义</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">务内容以本合同为准。</p>
|
||||||
|
<p class="content">(二)乙方工作人员无权向甲方作出超出本合同内容的承诺以及代表乙方以个人形式签署任何文件,双方均应以加盖印章的文</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">件作为双方权利义务约定的唯一形式。</p>
|
||||||
|
<p class="content">(三)本合同内容若需做出任何修改补充,甲、乙双方共同协商,可形成补充协议,补充协议与本合同冲突的,以补充协议为准。</p>
|
||||||
|
<p class="content">(四)因本合同发生争议,双方协商解决;如果协商不成,甲、乙双方一致同意提交仲裁委员会按照其仲裁规则进行裁决,其</p>
|
||||||
|
<p class="content" style="text-indent:0pt;">裁决是终局性的,对双方具有约束力。因争议解决产生的案件受理费、律师费、保全费、公证费、鉴定费等由败诉方承担。</p>
|
||||||
|
<p class="content">(五)本合同传真及扫描件与合同原件具有同等法律效力。</p>
|
||||||
|
<p class="content"> </p>
|
||||||
|
<p class="content">甲方名称(签章): ${company.companyName?if_exists}</p>
|
||||||
|
<p class="content">甲方联系人: ${company.legalPersonName?if_exists}</p>
|
||||||
|
<p class="content">联系方式: ${company.legalPersonPhone?if_exists}</p>
|
||||||
|
<p class="content">签约日期: ${contract.applyDate?string('yyyy年MM月dd日')}
|
||||||
|
<#--<span style=" text-decoration:underline"></span> 年
|
||||||
|
<span style=" text-decoration:underline"></span> 月
|
||||||
|
<span style=" text-decoration:underline"></span> 日-->
|
||||||
|
</p>
|
||||||
|
<p class="content"> </p>
|
||||||
|
|
||||||
|
<p class="content">乙方名称(签章): ${main.name?if_exists}</p>
|
||||||
|
<p class="content">乙方联系人: ${user.nickname?if_exists}</p>
|
||||||
|
<p class="content">联系方式: ${user.phonenumber?if_exists}</p>
|
||||||
|
<p class="content">签约日期: ${contract.applyDate?string('yyyy年MM月dd日')}
|
||||||
|
<#--<span style=" text-decoration:underline"> </span> 年
|
||||||
|
<span style=" text-decoration:underline"> </span> 月
|
||||||
|
<span style=" text-decoration:underline"> </span> 日-->
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<#if isSign?? && isSign>
|
||||||
|
<div style="height: 500px;width: 100%;padding-top: -120px;padding-left: 120px">
|
||||||
|
<img style="width:150px; height:150px; " src="${imagePath}/doc/image/allZ.png"/>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
519
pom.xml
Normal file
519
pom.xml
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
<?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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-vue-plus</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
|
||||||
|
<name>PuSong-Vue-Plus</name>
|
||||||
|
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
|
||||||
|
<description>PuSong-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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-system</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-job</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-generator</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-demo</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-business</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 工作流模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-workflow</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>pusong-admin</module>
|
||||||
|
<module>pusong-common</module>
|
||||||
|
<module>pusong-extend</module>
|
||||||
|
<module>pusong-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>
|
||||||
|
<skip>true</skip>
|
||||||
|
<!-- <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>
|
||||||
|
|
||||||
|
|
24
pusong-admin/Dockerfile
Normal file
24
pusong-admin/Dockerfile
Normal file
@ -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
|
||||||
|
|
150
pusong-admin/pom.xml
Normal file
150
pusong-admin/pom.xml
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<?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>pusong-vue-plus</artifactId>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<artifactId>pusong-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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-doc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-social</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-ratelimiter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-system</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-job</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 代码生成-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-generator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- demo模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-demo</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- 主业务模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-business</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- 工作流模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-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 com.pusong;
|
||||||
|
|
||||||
|
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("(♥◠‿◠)ノ゙ pusong-vue-plus启动成功 ლ(´ڡ`ლ)゙");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.pusong;
|
||||||
|
|
||||||
|
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,220 @@
|
|||||||
|
package com.pusong.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 com.pusong.common.core.utils.*;
|
||||||
|
import com.pusong.web.service.IAuthStrategy;
|
||||||
|
import com.pusong.web.service.SysRegisterService;
|
||||||
|
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 com.pusong.common.core.constant.UserConstants;
|
||||||
|
import com.pusong.common.core.domain.R;
|
||||||
|
import com.pusong.common.core.domain.model.LoginBody;
|
||||||
|
import com.pusong.common.core.domain.model.RegisterBody;
|
||||||
|
import com.pusong.common.core.domain.model.SocialLoginBody;
|
||||||
|
import com.pusong.common.core.utils.*;
|
||||||
|
import com.pusong.common.encrypt.annotation.ApiEncrypt;
|
||||||
|
import com.pusong.common.json.utils.JsonUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.social.config.properties.SocialLoginConfigProperties;
|
||||||
|
import com.pusong.common.social.config.properties.SocialProperties;
|
||||||
|
import com.pusong.common.social.utils.SocialUtils;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.common.websocket.dto.WebSocketMessageDto;
|
||||||
|
import com.pusong.common.websocket.utils.WebSocketUtils;
|
||||||
|
import com.pusong.system.domain.bo.SysTenantBo;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.system.domain.vo.SysTenantVo;
|
||||||
|
import com.pusong.system.service.ISysClientService;
|
||||||
|
import com.pusong.system.service.ISysConfigService;
|
||||||
|
import com.pusong.system.service.ISysSocialService;
|
||||||
|
import com.pusong.system.service.ISysTenantService;
|
||||||
|
import com.pusong.web.domain.vo.LoginTenantVo;
|
||||||
|
import com.pusong.web.domain.vo.LoginVo;
|
||||||
|
import com.pusong.web.domain.vo.TenantListVo;
|
||||||
|
import com.pusong.web.service.SysLoginService;
|
||||||
|
import com.pusong.common.core.utils.*;
|
||||||
|
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("欢迎登录pusong-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 com.pusong.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 com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.constant.GlobalConstants;
|
||||||
|
import com.pusong.common.core.domain.R;
|
||||||
|
import com.pusong.common.core.utils.SpringUtils;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import com.pusong.common.core.utils.reflect.ReflectUtils;
|
||||||
|
import com.pusong.common.mail.config.properties.MailProperties;
|
||||||
|
import com.pusong.common.mail.utils.MailUtils;
|
||||||
|
import com.pusong.common.ratelimiter.annotation.RateLimiter;
|
||||||
|
import com.pusong.common.ratelimiter.enums.LimitType;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.web.config.properties.CaptchaProperties;
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.web.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import com.pusong.common.core.config.RuoYiConfig;
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.web.domain.vo;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.web.service.SysLoginService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import com.pusong.common.core.constant.CacheConstants;
|
||||||
|
import com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.domain.dto.UserOnlineDTO;
|
||||||
|
import com.pusong.common.core.utils.MessageUtils;
|
||||||
|
import com.pusong.common.core.utils.ServletUtils;
|
||||||
|
import com.pusong.common.core.utils.SpringUtils;
|
||||||
|
import com.pusong.common.core.utils.ip.AddressUtils;
|
||||||
|
import com.pusong.common.log.event.LogininforEvent;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
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,45 @@
|
|||||||
|
package com.pusong.web.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.pusong.common.core.exception.ServiceException;
|
||||||
|
import com.pusong.common.core.utils.SpringUtils;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.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,252 @@
|
|||||||
|
package com.pusong.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 com.pusong.common.core.utils.*;
|
||||||
|
import com.pusong.system.domain.vo.*;
|
||||||
|
import com.pusong.system.service.*;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
|
import com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.constant.GlobalConstants;
|
||||||
|
import com.pusong.common.core.constant.TenantConstants;
|
||||||
|
import com.pusong.common.core.domain.dto.RoleDTO;
|
||||||
|
import com.pusong.common.core.domain.model.LoginUser;
|
||||||
|
import com.pusong.common.core.enums.LoginType;
|
||||||
|
import com.pusong.common.core.enums.TenantStatus;
|
||||||
|
import com.pusong.common.core.exception.ServiceException;
|
||||||
|
import com.pusong.common.core.exception.user.UserException;
|
||||||
|
import com.pusong.common.core.utils.*;
|
||||||
|
import com.pusong.common.log.event.LogininforEvent;
|
||||||
|
import com.pusong.common.mybatis.helper.DataPermissionHelper;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.tenant.exception.TenantException;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.system.domain.SysUser;
|
||||||
|
import com.pusong.system.domain.bo.SysSocialBo;
|
||||||
|
import com.pusong.system.mapper.SysUserMapper;
|
||||||
|
import com.pusong.system.service.*;
|
||||||
|
import com.pusong.common.core.utils.*;
|
||||||
|
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.setPhonenumber(user.getPhonenumber());
|
||||||
|
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 com.pusong.web.service;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.secure.BCrypt;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.constant.GlobalConstants;
|
||||||
|
import com.pusong.common.core.domain.model.RegisterBody;
|
||||||
|
import com.pusong.common.core.enums.UserType;
|
||||||
|
import com.pusong.common.core.exception.user.CaptchaException;
|
||||||
|
import com.pusong.common.core.exception.user.CaptchaExpireException;
|
||||||
|
import com.pusong.common.core.exception.user.UserException;
|
||||||
|
import com.pusong.common.core.utils.MessageUtils;
|
||||||
|
import com.pusong.common.core.utils.ServletUtils;
|
||||||
|
import com.pusong.common.core.utils.SpringUtils;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import com.pusong.common.log.event.LogininforEvent;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.common.web.config.properties.CaptchaProperties;
|
||||||
|
import com.pusong.system.domain.SysUser;
|
||||||
|
import com.pusong.system.domain.bo.SysUserBo;
|
||||||
|
import com.pusong.system.mapper.SysUserMapper;
|
||||||
|
import com.pusong.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,105 @@
|
|||||||
|
package com.pusong.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 com.pusong.web.service.IAuthStrategy;
|
||||||
|
import com.pusong.web.service.SysLoginService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.constant.GlobalConstants;
|
||||||
|
import com.pusong.common.core.domain.model.EmailLoginBody;
|
||||||
|
import com.pusong.common.core.domain.model.LoginUser;
|
||||||
|
import com.pusong.common.core.enums.LoginType;
|
||||||
|
import com.pusong.common.core.enums.UserStatus;
|
||||||
|
import com.pusong.common.core.exception.user.CaptchaExpireException;
|
||||||
|
import com.pusong.common.core.exception.user.UserException;
|
||||||
|
import com.pusong.common.core.utils.MessageUtils;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import com.pusong.common.core.utils.ValidatorUtils;
|
||||||
|
import com.pusong.common.json.utils.JsonUtils;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.system.domain.SysUser;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.system.domain.vo.SysUserVo;
|
||||||
|
import com.pusong.system.mapper.SysUserMapper;
|
||||||
|
import com.pusong.web.domain.vo.LoginVo;
|
||||||
|
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,124 @@
|
|||||||
|
package com.pusong.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 com.pusong.web.service.IAuthStrategy;
|
||||||
|
import com.pusong.web.service.SysLoginService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.constant.GlobalConstants;
|
||||||
|
import com.pusong.common.core.domain.model.LoginUser;
|
||||||
|
import com.pusong.common.core.domain.model.PasswordLoginBody;
|
||||||
|
import com.pusong.common.core.enums.LoginType;
|
||||||
|
import com.pusong.common.core.enums.UserStatus;
|
||||||
|
import com.pusong.common.core.exception.user.CaptchaException;
|
||||||
|
import com.pusong.common.core.exception.user.CaptchaExpireException;
|
||||||
|
import com.pusong.common.core.exception.user.UserException;
|
||||||
|
import com.pusong.common.core.utils.MessageUtils;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import com.pusong.common.core.utils.ValidatorUtils;
|
||||||
|
import com.pusong.common.json.utils.JsonUtils;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.common.web.config.properties.CaptchaProperties;
|
||||||
|
import com.pusong.system.domain.SysUser;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.system.domain.vo.SysUserVo;
|
||||||
|
import com.pusong.system.mapper.SysUserMapper;
|
||||||
|
import com.pusong.web.domain.vo.LoginVo;
|
||||||
|
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,105 @@
|
|||||||
|
package com.pusong.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 com.pusong.web.service.IAuthStrategy;
|
||||||
|
import com.pusong.web.service.SysLoginService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import com.pusong.common.core.constant.Constants;
|
||||||
|
import com.pusong.common.core.constant.GlobalConstants;
|
||||||
|
import com.pusong.common.core.domain.model.LoginUser;
|
||||||
|
import com.pusong.common.core.domain.model.SmsLoginBody;
|
||||||
|
import com.pusong.common.core.enums.LoginType;
|
||||||
|
import com.pusong.common.core.enums.UserStatus;
|
||||||
|
import com.pusong.common.core.exception.user.CaptchaExpireException;
|
||||||
|
import com.pusong.common.core.exception.user.UserException;
|
||||||
|
import com.pusong.common.core.utils.MessageUtils;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import com.pusong.common.core.utils.ValidatorUtils;
|
||||||
|
import com.pusong.common.json.utils.JsonUtils;
|
||||||
|
import com.pusong.common.redis.utils.RedisUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.system.domain.SysUser;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.system.domain.vo.SysUserVo;
|
||||||
|
import com.pusong.system.mapper.SysUserMapper;
|
||||||
|
import com.pusong.web.domain.vo.LoginVo;
|
||||||
|
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 com.pusong.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 com.pusong.web.service.IAuthStrategy;
|
||||||
|
import com.pusong.web.service.SysLoginService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
|
import com.pusong.common.core.domain.model.LoginUser;
|
||||||
|
import com.pusong.common.core.domain.model.SocialLoginBody;
|
||||||
|
import com.pusong.common.core.enums.UserStatus;
|
||||||
|
import com.pusong.common.core.exception.ServiceException;
|
||||||
|
import com.pusong.common.core.exception.user.UserException;
|
||||||
|
import com.pusong.common.core.utils.ValidatorUtils;
|
||||||
|
import com.pusong.common.json.utils.JsonUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.common.social.config.properties.SocialProperties;
|
||||||
|
import com.pusong.common.social.utils.SocialUtils;
|
||||||
|
import com.pusong.common.tenant.helper.TenantHelper;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.system.domain.vo.SysSocialVo;
|
||||||
|
import com.pusong.system.domain.vo.SysUserVo;
|
||||||
|
import com.pusong.system.mapper.SysUserMapper;
|
||||||
|
import com.pusong.system.service.ISysSocialService;
|
||||||
|
import com.pusong.web.domain.vo.LoginVo;
|
||||||
|
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,91 @@
|
|||||||
|
package com.pusong.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 com.pusong.common.core.domain.model.XcxLoginBody;
|
||||||
|
import com.pusong.common.core.domain.model.XcxLoginUser;
|
||||||
|
import com.pusong.common.core.enums.UserStatus;
|
||||||
|
import com.pusong.common.core.utils.ValidatorUtils;
|
||||||
|
import com.pusong.common.json.utils.JsonUtils;
|
||||||
|
import com.pusong.common.satoken.utils.LoginHelper;
|
||||||
|
import com.pusong.system.domain.vo.SysClientVo;
|
||||||
|
import com.pusong.system.domain.vo.SysUserVo;
|
||||||
|
import com.pusong.web.domain.vo.LoginVo;
|
||||||
|
import com.pusong.web.service.IAuthStrategy;
|
||||||
|
import com.pusong.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
258
pusong-admin/src/main/resources/application-dev.yml
Normal file
258
pusong-admin/src/main/resources/application-dev.yml
Normal file
@ -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: true
|
||||||
|
# # 需要在 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://192.168.18.119:3307/pusongplus?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
|
username: root
|
||||||
|
password: Ps123456@
|
||||||
|
# 从库数据源
|
||||||
|
# slave:
|
||||||
|
# lazy: true
|
||||||
|
# type: ${spring.datasource.type}
|
||||||
|
# driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
# url: jdbc:mysql://192.168.18.119:3307/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
|
# username: root
|
||||||
|
# password: Ps123456@
|
||||||
|
# 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: 192.168.18.119
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6378
|
||||||
|
# 数据库索引
|
||||||
|
database: 8
|
||||||
|
# 密码(如没有密码请注释掉)
|
||||||
|
password: 12345
|
||||||
|
# 连接超时时间
|
||||||
|
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
|
260
pusong-admin/src/main/resources/application-prod.yml
Normal file
260
pusong-admin/src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
--- # 临时文件存储位置 避免临时文件被系统清理报错
|
||||||
|
spring.servlet.multipart.location: /home/pusong/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: true
|
||||||
|
# # 需要在 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://127.0.0.1:3306/pusongplus?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
|
username: root
|
||||||
|
password: Ps123456@
|
||||||
|
# 从库数据源
|
||||||
|
# slave:
|
||||||
|
# lazy: true
|
||||||
|
# type: ${spring.datasource.type}
|
||||||
|
# driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
|
# url: jdbc:mysql://192.168.18.119:3307/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
|
# username: root
|
||||||
|
# password: Ps123456@
|
||||||
|
# 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: 127.0.0.1
|
||||||
|
# 端口,默认为6379
|
||||||
|
port: 6379
|
||||||
|
# 数据库索引
|
||||||
|
database: 5
|
||||||
|
# 密码(如没有密码请注释掉)
|
||||||
|
password: Ps123456@
|
||||||
|
# 连接超时时间
|
||||||
|
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
|
290
pusong-admin/src/main/resources/application.yml
Normal file
290
pusong-admin/src/main/resources/application.yml
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
# 项目相关配置
|
||||||
|
ruoyi:
|
||||||
|
# 名称
|
||||||
|
name: PuSong-Vue-Plus
|
||||||
|
# 版本
|
||||||
|
version: ${revision}
|
||||||
|
# 版权年份
|
||||||
|
copyrightYear: 2024
|
||||||
|
|
||||||
|
captcha:
|
||||||
|
enable: false
|
||||||
|
# 页面 <参数设置> 可开启关闭 验证码校验
|
||||||
|
# 验证码类型 math 数组计算 char 字符验证
|
||||||
|
type: MATH
|
||||||
|
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
|
||||||
|
category: CIRCLE
|
||||||
|
# 数字验证码位数
|
||||||
|
numberLength: 1
|
||||||
|
# 字符验证码长度
|
||||||
|
charLength: 4
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
server:
|
||||||
|
# 服务器的HTTP端口,默认为8080
|
||||||
|
port: 8088
|
||||||
|
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: info
|
||||||
|
org.mybatis.spring.mapper: debug
|
||||||
|
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
|
||||||
|
- ps_salary
|
||||||
|
- ps_salary_config
|
||||||
|
- ps_salary_contract
|
||||||
|
|
||||||
|
# MyBatisPlus配置
|
||||||
|
# https://baomidou.com/config/
|
||||||
|
mybatis-plus:
|
||||||
|
# 多包名使用 例如 com.pusong.**.mapper,org.xxx.**.mapper
|
||||||
|
mapperPackage: com.pusong.**.mapper
|
||||||
|
# 对应的 XML 文件位置
|
||||||
|
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||||
|
# 实体扫描,多个package用逗号或者分号分隔
|
||||||
|
typeAliasesPackage: com.pusong.**.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: com.pusong.demo
|
||||||
|
- group: 2.通用模块
|
||||||
|
packages-to-scan: com.pusong.web
|
||||||
|
- group: 3.系统模块
|
||||||
|
packages-to-scan: com.pusong.system
|
||||||
|
- group: 4.代码生成模块
|
||||||
|
packages-to-scan: com.pusong.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
|
8
pusong-admin/src/main/resources/banner.txt
Normal file
8
pusong-admin/src/main/resources/banner.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Application Version: ${revision}
|
||||||
|
Spring Boot Version: ${spring-boot.version}
|
||||||
|
__________ _____.___.__ ____ ____ __________.__
|
||||||
|
\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______
|
||||||
|
| _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/
|
||||||
|
| | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \
|
||||||
|
|____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ >
|
||||||
|
\/ \/ \/ \/
|
61
pusong-admin/src/main/resources/i18n/messages.properties
Normal file
61
pusong-admin/src/main/resources/i18n/messages.properties
Normal file
@ -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=对不起,您的租户已过期,请联系管理员
|
BIN
pusong-admin/src/main/resources/ip2region.xdb
Normal file
BIN
pusong-admin/src/main/resources/ip2region.xdb
Normal file
Binary file not shown.
129
pusong-admin/src/main/resources/logback-plus.xml
Normal file
129
pusong-admin/src/main/resources/logback-plus.xml
Normal file
@ -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 com.pusong.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
pusong-admin/src/test/java/com/pusong/test/DemoUnitTest.java
Normal file
70
pusong-admin/src/test/java/com/pusong/test/DemoUnitTest.java
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package com.pusong.test;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.test;
|
||||||
|
|
||||||
|
import com.pusong.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 ==================");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
54
pusong-admin/src/test/java/com/pusong/test/TagUnitTest.java
Normal file
54
pusong-admin/src/test/java/com/pusong/test/TagUnitTest.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package com.pusong.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 ==================");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
45
pusong-common/pom.xml
Normal file
45
pusong-common/pom.xml
Normal file
@ -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>pusong-vue-plus</artifactId>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>pusong-common-bom</module>
|
||||||
|
<module>pusong-common-social</module>
|
||||||
|
<module>pusong-common-core</module>
|
||||||
|
<module>pusong-common-doc</module>
|
||||||
|
<module>pusong-common-excel</module>
|
||||||
|
<module>pusong-common-idempotent</module>
|
||||||
|
<module>pusong-common-job</module>
|
||||||
|
<module>pusong-common-log</module>
|
||||||
|
<module>pusong-common-mail</module>
|
||||||
|
<module>pusong-common-mybatis</module>
|
||||||
|
<module>pusong-common-oss</module>
|
||||||
|
<module>pusong-common-ratelimiter</module>
|
||||||
|
<module>pusong-common-redis</module>
|
||||||
|
<module>pusong-common-satoken</module>
|
||||||
|
<module>pusong-common-security</module>
|
||||||
|
<module>pusong-common-sms</module>
|
||||||
|
<module>pusong-common-web</module>
|
||||||
|
<module>pusong-common-translation</module>
|
||||||
|
<module>pusong-common-sensitive</module>
|
||||||
|
<module>pusong-common-json</module>
|
||||||
|
<module>pusong-common-encrypt</module>
|
||||||
|
<module>pusong-common-tenant</module>
|
||||||
|
<module>pusong-common-websocket</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<artifactId>pusong-common</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
common 通用模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
</project>
|
178
pusong-common/pusong-common-bom/pom.xml
Normal file
178
pusong-common/pusong-common-bom/pom.xml
Normal file
@ -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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-core</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 接口模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-doc</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- excel -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-excel</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 幂等 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-idempotent</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 调度模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-job</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 日志记录 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-log</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 邮件服务 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-mail</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 数据库服务 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-mybatis</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- OSS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-oss</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 限流 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-ratelimiter</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 缓存服务 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-redis</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- satoken -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-satoken</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 安全模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-security</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 短信模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-sms</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-social</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- web服务 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-web</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 翻译模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-translation</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 脱敏模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-sensitive</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 序列化模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-json</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 数据库加解密模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-encrypt</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 租户模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-tenant</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- WebSocket模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common-websocket</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
</project>
|
104
pusong-common/pusong-common-core/pom.xml
Normal file
104
pusong-common/pusong-common-core/pom.xml
Normal file
@ -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>com.pusong</groupId>
|
||||||
|
<artifactId>pusong-common</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>pusong-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 com.pusong.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 com.pusong.common.core.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import com.pusong.common.core.exception.ServiceException;
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.common.core.config;
|
||||||
|
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||||
|
import com.pusong.common.core.config.properties.ThreadPoolProperties;
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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,114 @@
|
|||||||
|
package com.pusong.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";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页查询(成交金额)
|
||||||
|
*/
|
||||||
|
String HOME_A = "home_queryA#60s";
|
||||||
|
/**
|
||||||
|
* 首页查询(回款统计与合同)
|
||||||
|
*/
|
||||||
|
String HOME_B = "home_queryB#60s";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页查询(成交金额)
|
||||||
|
*/
|
||||||
|
String HOME_C = "home_queryC#60s";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页查询
|
||||||
|
*/
|
||||||
|
String HOME_D = "home_queryD#60s";
|
||||||
|
/**
|
||||||
|
* 首页查询
|
||||||
|
*/
|
||||||
|
String HOME_E = "home_queryE#60s";
|
||||||
|
/**
|
||||||
|
* 首页查询
|
||||||
|
*/
|
||||||
|
String HOME_F = "home_queryF#60s";
|
||||||
|
/**
|
||||||
|
* 首页查询
|
||||||
|
*/
|
||||||
|
String HOME_G = "home_queryG#60s";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页查询
|
||||||
|
*/
|
||||||
|
String HOME_H = "home_queryH#60s";
|
||||||
|
/**
|
||||||
|
* 首页查询
|
||||||
|
*/
|
||||||
|
String HOME_I = "home_queryI#60s";
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.common.core.domain;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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,148 @@
|
|||||||
|
package com.pusong.common.core.domain.model;
|
||||||
|
|
||||||
|
import com.pusong.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 String phonenumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色对象
|
||||||
|
*/
|
||||||
|
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,32 @@
|
|||||||
|
package com.pusong.common.core.domain.model;
|
||||||
|
|
||||||
|
import com.pusong.common.core.constant.UserConstants;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码登录对象
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class PasswordLoginBody extends LoginBody {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "{user.username.not.blank}")
|
||||||
|
@Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户密码
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "{user.password.not.blank}")
|
||||||
|
@Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.pusong.common.core.domain.model;
|
||||||
|
|
||||||
|
import com.pusong.common.core.constant.UserConstants;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户注册对象
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class RegisterBody extends LoginBody {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "{user.username.not.blank}")
|
||||||
|
@Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户密码
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "{user.password.not.blank}")
|
||||||
|
@Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String userType;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.common.core.enums;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import com.pusong.common.core.exception.ServiceException;
|
||||||
|
|
||||||
|
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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.common.core.enums;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.common.core.exception.base;
|
||||||
|
|
||||||
|
import com.pusong.common.core.utils.MessageUtils;
|
||||||
|
import com.pusong.common.core.utils.StringUtils;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
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 com.pusong.common.core.exception.file;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.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 com.pusong.common.core.exception.user;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.common.core.factory;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.PatternPool;
|
||||||
|
import com.pusong.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 com.pusong.common.core.factory;
|
||||||
|
|
||||||
|
import com.pusong.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 com.pusong.common.core.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用 参数配置服务
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public interface ConfigService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据参数 key 获取参数值
|
||||||
|
*
|
||||||
|
* @param configKey 参数 key
|
||||||
|
* @return 参数值
|
||||||
|
*/
|
||||||
|
String getConfigValue(String configKey);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.pusong.common.core.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用 部门服务
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public interface DeptService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过部门ID查询部门名称
|
||||||
|
*
|
||||||
|
* @param deptIds 部门ID串逗号分隔
|
||||||
|
* @return 部门名称串逗号分隔
|
||||||
|
*/
|
||||||
|
String selectDeptNameByIds(String deptIds);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.pusong.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 com.pusong.common.core.service;
|
||||||
|
|
||||||
|
import com.pusong.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,18 @@
|
|||||||
|
package com.pusong.common.core.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用 岗位服务
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public interface PostService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过岗位ID查询岗位名称
|
||||||
|
*
|
||||||
|
* @param deptIds 岗位ID串逗号分隔
|
||||||
|
* @return 岗位名称串逗号分隔
|
||||||
|
*/
|
||||||
|
String selectPostNameByIds(String deptIds);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.pusong.common.core.service;
|
||||||
|
|
||||||
|
import com.pusong.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);
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package com.pusong.common.core.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用 工作流服务
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
public interface WorkflowService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息
|
||||||
|
*
|
||||||
|
* @param businessKeys 业务id
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
boolean deleteRunAndHisInstance(List<String> businessKeys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前流程状态
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
*/
|
||||||
|
String getBusinessStatusByTaskId(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前流程状态
|
||||||
|
*
|
||||||
|
* @param businessKey 业务id
|
||||||
|
*/
|
||||||
|
String getBusinessStatus(String businessKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置流程变量(全局变量)
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @param variableName 变量名称
|
||||||
|
* @param value 变量值
|
||||||
|
*/
|
||||||
|
void setVariable(String taskId, String variableName, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置流程变量(全局变量)
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @param variables 流程变量
|
||||||
|
*/
|
||||||
|
void setVariables(String taskId, Map<String, Object> variables);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置流程变量(本地变量,非全局变量)
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @param variableName 变量名称
|
||||||
|
* @param value 变量值
|
||||||
|
*/
|
||||||
|
void setVariableLocal(String taskId, String variableName, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置流程变量(本地变量,非全局变量)
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @param variables 流程变量
|
||||||
|
*/
|
||||||
|
void setVariablesLocal(String taskId, Map<String, Object> variables);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照业务id查询流程实例id
|
||||||
|
*
|
||||||
|
* @param businessKey 业务id
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
String getInstanceIdByBusinessKey(String businessKey);
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
package com.pusong.common.core.utils;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.*;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间工具类
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
|
||||||
|
|
||||||
|
public static final String YYYY = "yyyy";
|
||||||
|
|
||||||
|
public static final String YYYY_MM = "yyyy-MM";
|
||||||
|
|
||||||
|
public static final String YYYY_MM_DD = "yyyy-MM-dd";
|
||||||
|
|
||||||
|
public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
|
||||||
|
|
||||||
|
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
private static final String[] PARSE_PATTERNS = {
|
||||||
|
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
|
||||||
|
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
|
||||||
|
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前Date型日期
|
||||||
|
*
|
||||||
|
* @return Date() 当前日期
|
||||||
|
*/
|
||||||
|
public static Date getNowDate() {
|
||||||
|
return new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前日期, 默认格式为yyyy-MM-dd
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String getDate() {
|
||||||
|
return dateTimeNow(YYYY_MM_DD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTime() {
|
||||||
|
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dateTimeNow() {
|
||||||
|
return dateTimeNow(YYYYMMDDHHMMSS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dateTimeNow(final String format) {
|
||||||
|
return parseDateToStr(format, new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dateTime(final Date date) {
|
||||||
|
return parseDateToStr(YYYY_MM_DD, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String parseDateToStr(final String format, final Date date) {
|
||||||
|
return new SimpleDateFormat(format).format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date dateTime(final String format, final String ts) {
|
||||||
|
try {
|
||||||
|
return new SimpleDateFormat(format).parse(ts);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期路径 即年/月/日 如2018/08/08
|
||||||
|
*/
|
||||||
|
public static String datePath() {
|
||||||
|
Date now = new Date();
|
||||||
|
return DateFormatUtils.format(now, "yyyy/MM/dd");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期路径 即年/月/日 如20180808
|
||||||
|
*/
|
||||||
|
public static String dateTime() {
|
||||||
|
Date now = new Date();
|
||||||
|
return DateFormatUtils.format(now, "yyyyMMdd");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期型字符串转化为日期 格式
|
||||||
|
*/
|
||||||
|
public static Date parseDate(Object str) {
|
||||||
|
if (str == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return parseDate(str.toString(), PARSE_PATTERNS);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器启动时间
|
||||||
|
*/
|
||||||
|
public static Date getServerStartDate() {
|
||||||
|
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
|
||||||
|
return new Date(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算相差天数
|
||||||
|
*/
|
||||||
|
public static int differentDaysByMillisecond(Date date1, Date date2) {
|
||||||
|
return (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 计算相差天数(只计算工作日:周一到周五,包括两边)
|
||||||
|
*/
|
||||||
|
public static int calWorkDate(Date date1, Date date2) {
|
||||||
|
LocalDate startDate = date1.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
LocalDate endDate = date2.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (!startDate.isAfter(endDate)) {
|
||||||
|
if (!startDate.getDayOfWeek().equals(DayOfWeek.SATURDAY)
|
||||||
|
&& !startDate.getDayOfWeek().equals(DayOfWeek.SUNDAY)) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
startDate = startDate.plusDays(1);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两个时间差
|
||||||
|
*/
|
||||||
|
public static String getDatePoor(Date endDate, Date nowDate) {
|
||||||
|
long nd = 1000 * 24 * 60 * 60;
|
||||||
|
long nh = 1000 * 60 * 60;
|
||||||
|
long nm = 1000 * 60;
|
||||||
|
// long ns = 1000;
|
||||||
|
// 获得两个时间的毫秒时间差异
|
||||||
|
long diff = endDate.getTime() - nowDate.getTime();
|
||||||
|
// 计算差多少天
|
||||||
|
long day = diff / nd;
|
||||||
|
// 计算差多少小时
|
||||||
|
long hour = diff % nd / nh;
|
||||||
|
// 计算差多少分钟
|
||||||
|
long min = diff % nd % nh / nm;
|
||||||
|
// 计算差多少秒//输出结果
|
||||||
|
// long sec = diff % nd % nh % nm / ns;
|
||||||
|
return day + "天" + hour + "小时" + min + "分钟";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加 LocalDateTime ==> Date
|
||||||
|
*/
|
||||||
|
public static Date toDate(LocalDateTime temporalAccessor) {
|
||||||
|
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
|
||||||
|
return Date.from(zdt.toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加 LocalDate ==> Date
|
||||||
|
*/
|
||||||
|
public static Date toDate(LocalDate temporalAccessor) {
|
||||||
|
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
|
||||||
|
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
|
||||||
|
return Date.from(zdt.toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toString(LocalDate date,String from){
|
||||||
|
// 创建一个DateTimeFormatter实例来定义日期格式
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(from);
|
||||||
|
|
||||||
|
// 使用formatter转换LocalDate到字符串
|
||||||
|
return date.format(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toString(LocalDate date){
|
||||||
|
return toString(date,"yyyy-MM-dd");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long differentMonth(Date date,Date date2){
|
||||||
|
LocalDate startDate = date.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
LocalDate endDate = date2.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
return ChronoUnit.MONTHS.between(startDate.withDayOfMonth(1), endDate.withDayOfMonth(1));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package com.pusong.common.core.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import io.github.linpeilie.Converter;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapstruct 工具类
|
||||||
|
* <p>参考文档:<a href="https://mapstruct.plus/introduction/quick-start.html">mapstruct-plus</a></p>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Michelle.Chung
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class MapstructUtils {
|
||||||
|
|
||||||
|
private final static Converter CONVERTER = SpringUtils.getBean(Converter.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 T 类型对象,转换为 desc 类型的对象并返回
|
||||||
|
*
|
||||||
|
* @param source 数据来源实体
|
||||||
|
* @param desc 描述对象 转换后的对象
|
||||||
|
* @return desc
|
||||||
|
*/
|
||||||
|
public static <T, V> V convert(T source, Class<V> desc) {
|
||||||
|
if (ObjectUtil.isNull(source)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNull(desc)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CONVERTER.convert(source, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象
|
||||||
|
*
|
||||||
|
* @param source 数据来源实体
|
||||||
|
* @param desc 转换后的对象
|
||||||
|
* @return desc
|
||||||
|
*/
|
||||||
|
public static <T, V> V convert(T source, V desc) {
|
||||||
|
if (ObjectUtil.isNull(source)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNull(desc)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CONVERTER.convert(source, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 T 类型的集合,转换为 desc 类型的集合并返回
|
||||||
|
*
|
||||||
|
* @param sourceList 数据来源实体列表
|
||||||
|
* @param desc 描述对象 转换后的对象
|
||||||
|
* @return desc
|
||||||
|
*/
|
||||||
|
public static <T, V> List<V> convert(List<T> sourceList, Class<V> desc) {
|
||||||
|
if (ObjectUtil.isNull(sourceList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (CollUtil.isEmpty(sourceList)) {
|
||||||
|
return CollUtil.newArrayList();
|
||||||
|
}
|
||||||
|
return CONVERTER.convert(sourceList, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Map 转换为 beanClass 类型的集合并返回
|
||||||
|
*
|
||||||
|
* @param map 数据来源
|
||||||
|
* @param beanClass bean类
|
||||||
|
* @return bean对象
|
||||||
|
*/
|
||||||
|
public static <T> T convert(Map<String, Object> map, Class<T> beanClass) {
|
||||||
|
if (MapUtil.isEmpty(map)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNull(beanClass)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CONVERTER.convert(map, beanClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.pusong.common.core.utils;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.NoSuchMessageException;
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取i18n资源文件
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class MessageUtils {
|
||||||
|
|
||||||
|
private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据消息键和参数 获取消息 委托给spring messageSource
|
||||||
|
*
|
||||||
|
* @param code 消息键
|
||||||
|
* @param args 参数
|
||||||
|
* @return 获取国际化翻译值
|
||||||
|
*/
|
||||||
|
public static String message(String code, Object... args) {
|
||||||
|
try {
|
||||||
|
return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
|
||||||
|
} catch (NoSuchMessageException e) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user