Compare commits
38 Commits
37a8b7dad3
...
v2.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5476a4b0b7 | ||
|
|
cd490aa0e5 | ||
|
|
b1ff44df4b | ||
|
|
dc6d00f0fc | ||
|
|
990da8da6f | ||
|
|
8fc7ad0359 | ||
|
|
8a89d9eb9c | ||
|
|
abfa9ae97b | ||
|
|
bde2e8ff8e | ||
|
|
4d8eb1850f | ||
|
|
5aaa3a5662 | ||
|
|
8fec96f5b2 | ||
|
|
15c306eca2 | ||
|
|
620ea1fc76 | ||
|
|
c5c375dc6d | ||
|
|
1b793e822a | ||
|
|
6281840f36 | ||
|
|
f5daa7eb78 | ||
|
|
52cb563383 | ||
|
|
69efc3261e | ||
|
|
fb19fb29cc | ||
|
|
9f257cf712 | ||
|
|
4af26fe4b4 | ||
|
|
ab2a118ee9 | ||
|
|
9cd97a4dc5 | ||
|
|
788b372e32 | ||
|
|
744f9b6c7f | ||
|
|
761d954ef1 | ||
|
|
d1006f50ad | ||
|
|
f24ff5bbdd | ||
|
|
a4314dbbde | ||
|
|
188dc1e55e | ||
|
|
731352fd04 | ||
|
|
4b53939002 | ||
|
|
b50c15755d | ||
|
|
0dc6262b39 | ||
|
|
9b32e3b3b2 | ||
|
|
09abc0b5af |
142
README.md
@@ -36,48 +36,85 @@
|
||||
|
||||
## 目录
|
||||
|
||||
- [系统体验](#系统体验)
|
||||
- [源码地址](#源码地址)
|
||||
- [特色功能](#特色功能)
|
||||
- [配套文档](#项目文档)
|
||||
- [核心功能](#核心功能)
|
||||
- [项目演示](#项目演示)
|
||||
- [后台管理](#后台管理)
|
||||
- [管理端](#管理端)
|
||||
- [用户端](#用户端)
|
||||
- [小程序端](#小程序端)
|
||||
- [开发前的配置要求](#开发前的配置要求)
|
||||
- [文件目录说明](#文件目录说明)
|
||||
- [使用到的框架](#使用到的框架)
|
||||
- [开发环境](#开发环境)
|
||||
- [项目结构](#项目结构)
|
||||
- [ruoyi-ai](#ruoyi-ai)
|
||||
- [注意事项](#注意事项)
|
||||
- [vben模板](#vben模板)
|
||||
- [贡献者](#贡献者)
|
||||
- [如何参与开源项目](#如何参与开源项目)
|
||||
- [版本控制](#版本控制)
|
||||
- [作者](#作者)
|
||||
- [鸣谢](#鸣谢)
|
||||
- [技术讨论群](#技术讨论群)
|
||||
|
||||
### 系统体验
|
||||
- 用户端:https://web.pandarobot.chat
|
||||
- 管理端:https://admin.pandarobot.chat
|
||||
|
||||
用户名: admin 密码:admin123
|
||||
|
||||
### 源码地址
|
||||
- 项目文档: https://doc.pandarobot.chat
|
||||
- 前端-后台管理: https://github.com/ageerle/ruoyi-admin
|
||||
- 前端-用户端: https://github.com/ageerle/ruoyi-web
|
||||
- 小程序端: https://github.com/ageerle/ruoyi-uniapp
|
||||
- 演示地址: https://web.pandarobot.chat
|
||||
- 后台管理: https://admin.pandarobot.chat
|
||||
- 用户名: admin 密码:admin123
|
||||
|
||||
### gitcode源码地址
|
||||
- https://gitcode.com/ageerle/ruoyi-ai
|
||||
- https://gitcode.com/ageerle/ruoyi-web
|
||||
- https://gitcode.com/ageerle/ruoyi-admin
|
||||
- https://gitcode.com/ageerle/ruoyi-uniapp
|
||||
[1]gitee
|
||||
- 前端服务-用户端: https://gitee.com/ageerle/ruoyi-web
|
||||
- 前端服务-管理端: https://gitee.com/ageerle/ruoyi-admin
|
||||
- 前端服务-小程序端: https://gitee.com/ageerle/ruoyi-uniapp
|
||||
- 后端服务:https://gitee.com/ageerle/ruoyi-ai
|
||||
|
||||
### 特色功能
|
||||
[2]github
|
||||
- 前端服务-用户端: https://github.com/ageerle/ruoyi-web
|
||||
- 前端服务-管理端: https://github.com/ageerle/ruoyi-admin
|
||||
- 前端服务-小程序端: https://github.com/ageerle/ruoyi-uniapp
|
||||
- 后端服务:https://github.com/ageerle/ruoyi-ai
|
||||
|
||||
[3]gitcode
|
||||
- 前端服务-用户端:https://gitcode.com/ageerle/ruoyi-web
|
||||
- 前端服务-管理端: https://gitcode.com/ageerle/ruoyi-admin
|
||||
- 前端服务-小程序端: https://gitcode.com/ageerle/ruoyi-uniapp
|
||||
- 后端服务:https://gitcode.com/ageerle/ruoyi-ai
|
||||
|
||||
### 配套文档
|
||||
- 配套文档: https://doc.pandarobot.chat
|
||||
- 项目部署文档:https://doc.pandarobot.chat/guide/introduction/
|
||||
|
||||
### 核心功能
|
||||
1. 全套开源系统:提供完整的前端应用、后台管理以及小程序应用,基于MIT协议,开箱即用。
|
||||
2. 本地RAG方案:集成Milvus/Weaviate向量库、本地向量化模型与Ollama,实现本地化RAG
|
||||
2. 本地RAG方案:集成Milvus/Weaviate向量库、本地向量化模型与Ollama,实现本地化RAG。
|
||||
3. 丰富插件功能:支持联网、SQL查询插件及Text2API插件,扩展系统能力与应用场景。
|
||||
4. 内置SSE、websocket等网络协议,支持对接多种大语言模型,同时还集成了MidJourney和DALLE AI绘画功能
|
||||
5. 强大的多媒体功能:支持AI翻译、PPT制作、语音克隆和翻唱等
|
||||
6. 扩展功能:支持将大模型接入个人或企业微信
|
||||
7. 支付功能:支持易支付、微信支付等多种支付方式
|
||||
4. 内置SSE、websocket等网络协议,支持对接多种大语言模型,同时还集成了MidJourney和DALLE AI绘画功能。
|
||||
5. 强大的多媒体功能:支持AI翻译、PPT制作、语音克隆和翻唱等。
|
||||
6. 扩展功能:支持将大模型接入个人或企业微信。
|
||||
7. 支付功能:支持易支付、微信支付等多种支付方式。
|
||||
|
||||
### 项目演示
|
||||
|
||||
#### 后台管理
|
||||
#### mcp支持
|
||||
|
||||
### 如何使用
|
||||
1. ruoyi-admin\src\main\resources\application.yml中mcp.client.enabled改为true
|
||||
2. application.yml中配置openai api-key(用于推理使用那个工具,并构建工具所需参数)
|
||||
3. 启动[ruoyi-mcp-server]
|
||||
4. [mcp-server.json]中配置fileSystem.command(npx本地安装路径)
|
||||
5. 指定fileSystem操作目录(本地必须存在指定的目录)
|
||||
6. 配置search1api.env.SEARCH1API_KEY 申请地址:https://www.search1api.com/
|
||||
7. 详情教程:https://blog.csdn.net/weixin_42416319/article/details/147385808
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
|
||||
<img src="image/mcp-01.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/mcp-02.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/mcp-03.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/mcp-04.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
#### 管理端
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
|
||||
<img src="image/02.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
<img src="image/03.png" alt="drawing" style="width: 600px; height: 300px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
@@ -100,7 +137,7 @@
|
||||
<img src="image/07.png" alt="drawing" style="width: 320px; height: 600px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
### 开发前的配置要求
|
||||
### 开发环境
|
||||
|
||||
1. jdk 17
|
||||
2. mysql 5.7、8.0
|
||||
@@ -108,8 +145,14 @@
|
||||
4. maven 3.8+
|
||||
5. nodejs 20+ & pnpm
|
||||
|
||||
### 文件目录说明
|
||||
RuoYi-AI
|
||||
- 附-部署配套视频:https://www.bilibili.com/video/BV1jDXkYWEba
|
||||
|
||||
<div>
|
||||
<img src="image/教程搭建.png" alt="drawing" width="600px" height="300px"/>
|
||||
</div>
|
||||
|
||||
### 项目结构
|
||||
- RuoYi-AI
|
||||
|
||||
```
|
||||
├─ ruoyi-admin // 管理模块
|
||||
@@ -158,6 +201,14 @@ RuoYi-AI
|
||||
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
- vben模板
|
||||
|
||||
|
||||
Q:vben5 的模板默认是没有的吗?
|
||||
|
||||
A:vben模板是收费的 请联系vben-vue-plus作者获取。
|
||||
|
||||
### 版本控制
|
||||
|
||||
该项目使用Git进行版本管理。您可以在repository参看当前可用版本。
|
||||
@@ -170,20 +221,16 @@ RuoYi-AI
|
||||
|
||||
### 项目现状
|
||||
|
||||
目前,项目还处于早期阶段,距离成熟还有很长的路要走。由于个人精力有限,项目的发展速度受到了一定的限制。为了加快项目的进度,我真诚地希望更多人能够参与到项目中来。无论是经验丰富的开发者,还是刚刚入门的小白,我都热烈欢迎你们提交Pull Request(PR)。即使代码修改得很少,或者存在一些错误,都没有关系。我会认真审核每一位贡献者的代码,并和大家一起完善项目。
|
||||
目前,项目还处于早期阶段,距离成熟还有很长的路要走。由于个人精力有限,项目的发展速度受到了一定的限制。为了加快项目的进度,我真诚地希望更多人能够参与到项目中来。无论是经验丰富的开发者,还是刚刚入门的小白,我都热烈欢迎你们提交Pull Request(PR)👏👏👏。即使代码修改得很少,或者存在一些错误,都没有关系。我会认真审核每一位贡献者的代码,并和大家一起完善项目⛽️⛽️⛽️。
|
||||
|
||||
### 开发计划
|
||||
|
||||
- 智能体管理
|
||||
| 主题 | 方向 | 时间节点 |
|
||||
| --- |-----------------------------------|--------|
|
||||
| 前端简化版 | 与element-plus-x框架合作,推出基于该框架的前端简化版 | 2025.5 |
|
||||
| agent2agent | Agent2Agent协议支持 | 2025.6 |
|
||||
| 流程编排 | 通过可视化界面和灵活的配置方式,快速构建AI应用 | 2025.7 |
|
||||
|
||||
通过设置提示词、插件、知识库等,用户可以快速构建一个AI应用。这将极大地简化AI应用的开发流程,降低开发门槛,使更多企业能够轻松地利用AI技术。
|
||||
<div>
|
||||
<img src="image/13.png" alt="drawing" width="600px" height="300px"/>
|
||||
</div>
|
||||
|
||||
- 流程编排
|
||||
|
||||
通过流程编排功能,用户可以将不同的模型按照业务逻辑进行有序连接。这将解决单一模型能力不足的问题,充分发挥多个模型的协同作用,从而更好地满足企业的复杂业务需求。
|
||||
|
||||
- 感谢
|
||||
|
||||
@@ -193,7 +240,7 @@ RuoYi-AI
|
||||
|
||||
#### 如何参与开源项目
|
||||
|
||||
贡献使开源社区成为一个学习、激励和创造的绝佳场所。你所作的任何贡献都是**非常感谢**的。
|
||||
贡献使开源社区成为一个学习、激励和创造的绝佳场所。你所作的任何贡献,我们都非常感谢!🙏
|
||||
|
||||
1. Fork 这个项目
|
||||
2. 创建你的功能分支 (`git checkout -b feature/dev`)
|
||||
@@ -231,4 +278,23 @@ RuoYi-AI
|
||||
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
|
||||
|
||||
|
||||
### 附:技术讨论群
|
||||
|
||||
#### 全面开放,欢迎加入
|
||||
🏠 wx:ruoyi-ai(加人备注:ruoyi-ai)
|
||||
|
||||
🏠 qq:1603234088 (加人备注:ruoyi-ai)
|
||||
|
||||
👏👏👏 ruoyi-ai官方交流1群(qq区):1034554687
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
|
||||
<img src="image/QQ区-官方交流1群.png" alt="drawing" style="width: 400px; height: 400px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
👏👏👏 ruoyi-ai官方交流4群(微信区):
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px; justify-content: center;">
|
||||
<img src="image/WX区-官方交流4群.jpg" alt="drawing" style="width: 400px; height: 400px; border: 2px solid #ddd; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);"/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
image/QQ区-官方交流1群.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
image/WX区-官方交流4群.jpg
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
image/mcp-01.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
image/mcp-02.png
Normal file
|
After Width: | Height: | Size: 251 KiB |
BIN
image/mcp-03.png
Normal file
|
After Width: | Height: | Size: 189 KiB |
BIN
image/mcp-04.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
image/qq-msg.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
BIN
image/wx-msg.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
image/wx-msg2.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
image/教程搭建.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
52
pom.xml
@@ -14,26 +14,26 @@
|
||||
|
||||
<properties>
|
||||
<revision>1.0.0</revision>
|
||||
<spring-boot.version>3.0.6</spring-boot.version>
|
||||
<spring-boot.version>3.4.4</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<mysql.version>8.0.33</mysql.version>
|
||||
<spring-boot.mybatis>3.0.1</spring-boot.mybatis>
|
||||
<mybatis.version>3.5.16</mybatis.version>
|
||||
<springdoc.version>2.1.0</springdoc.version>
|
||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||
<poi.version>5.2.3</poi.version>
|
||||
<easyexcel.version>3.2.1</easyexcel.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<satoken.version>1.34.0</satoken.version>
|
||||
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
|
||||
<mybatis-plus.version>3.5.11</mybatis-plus.version>
|
||||
<p6spy.version>3.9.1</p6spy.version>
|
||||
<hutool.version>5.8.18</hutool.version>
|
||||
<hutool.version>5.8.35</hutool.version>
|
||||
<okhttp.version>4.10.0</okhttp.version>
|
||||
<dynamic-ds.version>4.3.1</dynamic-ds.version>
|
||||
<spring-boot-admin.version>3.0.3</spring-boot-admin.version>
|
||||
<redisson.version>3.20.1</redisson.version>
|
||||
<lock4j.version>2.2.4</lock4j.version>
|
||||
<dynamic-ds.version>3.6.1</dynamic-ds.version>
|
||||
<alibaba-ttl.version>2.14.2</alibaba-ttl.version>
|
||||
<xxl-job.version>2.4.0</xxl-job.version>
|
||||
<mapstruct-plus.version>1.2.1</mapstruct-plus.version>
|
||||
@@ -42,10 +42,6 @@
|
||||
<bouncycastle.version>1.72</bouncycastle.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
|
||||
<!-- 临时修复 snakeyaml 漏洞 -->
|
||||
<snakeyaml.version>1.33</snakeyaml.version>
|
||||
|
||||
<!-- OSS 配置 -->
|
||||
<aws-java-sdk-s3.version>1.12.400</aws-java-sdk-s3.version>
|
||||
<!-- SMS 配置 -->
|
||||
@@ -202,22 +198,22 @@
|
||||
<version>${satoken.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- dynamic-datasource 多数据源-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
<version>${dynamic-ds.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${spring-boot.mybatis}</version>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>${mybatis.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -227,6 +223,13 @@
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- dynamic-datasource 多数据源-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<version>${dynamic-ds.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- sql性能分析插件 -->
|
||||
<dependency>
|
||||
<groupId>p6spy</groupId>
|
||||
@@ -277,13 +280,6 @@
|
||||
<version>${alibaba-ttl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 临时修复 snakeyaml 漏洞 -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 加密包引入 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
@@ -343,7 +339,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-demo</artifactId>
|
||||
<artifactId>ruoyi-wechat</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -354,6 +350,8 @@
|
||||
<module>ruoyi-common</module>
|
||||
<module>ruoyi-modules</module>
|
||||
<module>ruoyi-modules-api</module>
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-extend</module>
|
||||
</modules>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
99
ruoyi-admin/pom.xml
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-ai</artifactId>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ruoyi-admin</artifactId>
|
||||
|
||||
<description>
|
||||
web服务入口
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Mysql驱动包 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Oracle -->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- PostgreSql -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SqlServer -->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-chat</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-wechat</artifactId>
|
||||
</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>
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.ruoyi.system;
|
||||
package org.ruoyi;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.ruoyi.system;
|
||||
package org.ruoyi;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
@@ -1,17 +1,22 @@
|
||||
package org.ruoyi.system.controller.system;
|
||||
package org.ruoyi.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.ruoyi.common.core.constant.Constants;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
import org.ruoyi.common.core.domain.model.*;
|
||||
import org.ruoyi.common.core.domain.model.EmailLoginBody;
|
||||
import org.ruoyi.common.core.domain.model.LoginBody;
|
||||
import org.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import org.ruoyi.common.core.domain.model.SmsLoginBody;
|
||||
import org.ruoyi.common.core.domain.model.VisitorLoginBody;
|
||||
import org.ruoyi.common.core.utils.MapstructUtils;
|
||||
import org.ruoyi.common.core.utils.StreamUtils;
|
||||
import org.ruoyi.common.core.utils.StringUtils;
|
||||
import org.ruoyi.common.satoken.utils.LoginHelper;
|
||||
import org.ruoyi.common.tenant.helper.TenantHelper;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.ruoyi.system.domain.bo.SysTenantBo;
|
||||
import org.ruoyi.system.domain.vo.LoginTenantVo;
|
||||
import org.ruoyi.system.domain.vo.LoginVo;
|
||||
@@ -42,15 +47,6 @@ public class AuthController {
|
||||
private final SysRegisterService registerService;
|
||||
private final ISysTenantService tenantService;
|
||||
|
||||
|
||||
// @PostMapping("/xcxLogin")
|
||||
// public R<LoginVo> login(@Validated @RequestBody String xcxCode) throws WxErrorException {
|
||||
//
|
||||
// String openidFromCode = loginService.getOpenidFromCode((String) JSONUtil.parseObj(xcxCode).get("xcxCode"));
|
||||
// LoginVo loginVo = loginService.mpLogin(openidFromCode);
|
||||
// return R.ok(loginVo);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
*
|
||||
@@ -67,6 +63,7 @@ public class AuthController {
|
||||
body.getUsername(), body.getPassword(),
|
||||
body.getCode(), body.getUuid());
|
||||
loginVo.setToken(token);
|
||||
// 兼容后台管理登录
|
||||
loginVo.setAccess_token(token);
|
||||
loginVo.setUserInfo(LoginHelper.getLoginUser());
|
||||
return R.ok(loginVo);
|
||||
@@ -89,7 +86,6 @@ public class AuthController {
|
||||
|
||||
/**
|
||||
* 访客登录
|
||||
*
|
||||
* @param loginBody 登录信息
|
||||
* @return token信息
|
||||
*/
|
||||
@@ -128,7 +124,7 @@ public class AuthController {
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public R<Void> register(@Validated @RequestBody RegisterBody user, HttpServletRequest request) {
|
||||
String domainName = request.getServerName();
|
||||
String domainName = request.getServerName();
|
||||
user.setDomainName(domainName);
|
||||
registerService.register(user);
|
||||
return R.ok();
|
||||
@@ -1,14 +1,10 @@
|
||||
package org.ruoyi.system.controller.system;
|
||||
package org.ruoyi.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.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.ruoyi.common.core.constant.Constants;
|
||||
import org.ruoyi.common.core.constant.GlobalConstants;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
@@ -26,6 +22,10 @@ import org.ruoyi.common.web.config.properties.CaptchaProperties;
|
||||
import org.ruoyi.common.web.enums.CaptchaType;
|
||||
import org.ruoyi.system.domain.request.EmailRequest;
|
||||
import org.ruoyi.system.domain.vo.CaptchaVo;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -36,8 +36,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 验证码操作处理
|
||||
@@ -95,6 +94,7 @@ public class CaptchaController {
|
||||
String suffix = configService.getConfigValue("mail", "suffix");
|
||||
String prompt = configService.getConfigValue("mail", "prompt");
|
||||
if(StringUtils.isNotEmpty(suffix)){
|
||||
// 动态的域名列表
|
||||
String[] invalidDomains = suffix.split(",");
|
||||
for (String domain : invalidDomains) {
|
||||
if (emailRequest.getUsername().endsWith(domain)) {
|
||||
@@ -107,7 +107,7 @@ public class CaptchaController {
|
||||
String mailTitle = configService.getConfigValue("mail", "mailTitle");
|
||||
String replacedModel = model.replace("{code}", code);
|
||||
try {
|
||||
MailUtils.sendHtml(emailRequest.getUsername(), mailTitle, replacedModel);
|
||||
MailUtils.sendHtml(emailRequest.getUsername(), mailTitle, replacedModel);
|
||||
} catch (Exception e) {
|
||||
log.error("邮箱验证码发送异常 => {}", e.getMessage());
|
||||
return R.fail(e.getMessage());
|
||||
@@ -1,7 +1,8 @@
|
||||
package org.ruoyi.system.controller.system;
|
||||
package org.ruoyi.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -11,7 +12,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
* @author Lion Li
|
||||
*/
|
||||
@SaIgnore
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class IndexController {
|
||||
|
||||
@@ -20,7 +20,9 @@ public class IndexController {
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "RuoYi-AI 启动成功";
|
||||
return "RuoYi AI启动成功!";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -25,10 +25,9 @@ spring:
|
||||
master:
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: ruoyi-ai
|
||||
password: ruoyi-ai
|
||||
|
||||
url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: ry-vue
|
||||
password: xx
|
||||
|
||||
hikari:
|
||||
# 最大连接池数量
|
||||
@@ -61,9 +60,6 @@ spring.data:
|
||||
# password: 123456
|
||||
# 连接超时时间
|
||||
timeout: 10S
|
||||
# 是否开启ssl
|
||||
ssl: false
|
||||
|
||||
redisson:
|
||||
# redis key前缀
|
||||
keyPrefix:
|
||||
@@ -97,3 +93,4 @@ sms:
|
||||
signName: 测试
|
||||
# 腾讯专用
|
||||
sdkAppId:
|
||||
|
||||
@@ -49,8 +49,10 @@ server:
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
org.ruoyi: @logging.level@
|
||||
org.dromara: @logging.level@
|
||||
org.springframework: warn
|
||||
org.mybatis.spring.mapper: error
|
||||
org.apache.fury: warn
|
||||
config: classpath:logback-plus.xml
|
||||
|
||||
# 用户配置
|
||||
@@ -318,5 +320,20 @@ wechat:
|
||||
token: ''
|
||||
aesKey: ''
|
||||
|
||||
|
||||
spring:
|
||||
ai:
|
||||
openai:
|
||||
api-key: sk-xx
|
||||
base-url: https://api.pandarobot.chat/
|
||||
mcp:
|
||||
client:
|
||||
enabled: false
|
||||
name: ruoyi-ai-mcp
|
||||
sse:
|
||||
connections:
|
||||
server:
|
||||
url: http://127.0.0.1:8081
|
||||
stdio:
|
||||
servers-configuration: classpath:mcp-server.json
|
||||
request-timeout: 300s
|
||||
|
||||
22
ruoyi-admin/src/main/resources/mcp-server.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"fileSystem": {
|
||||
"command": "C:\\Program Files\\nodejs\\npx.cmd",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-filesystem",
|
||||
"D:\\"
|
||||
]
|
||||
},
|
||||
"search1api": {
|
||||
"command": "C:\\Program Files\\nodejs\\npx.cmd",
|
||||
"args": [
|
||||
"-y",
|
||||
"search1api-mcp"
|
||||
],
|
||||
"env": {
|
||||
"SEARCH1API_KEY": "xx"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,11 @@ public class ChatRequest {
|
||||
*/
|
||||
private Boolean search = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 是否开启mcp
|
||||
*/
|
||||
private Boolean isMcp = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 知识库id
|
||||
*/
|
||||
@@ -49,7 +54,7 @@ public class ChatRequest {
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private String userId;
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 应用ID
|
||||
|
||||
@@ -109,16 +109,19 @@
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-sse</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.ruoyi.common.core.constant;
|
||||
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
|
||||
/**
|
||||
* 常用正则表达式字符串
|
||||
* <p>
|
||||
* 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/
|
||||
*
|
||||
* @author Feng
|
||||
*/
|
||||
public interface RegexConstants extends RegexPool {
|
||||
|
||||
/**
|
||||
* 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)
|
||||
*/
|
||||
String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$";
|
||||
|
||||
/**
|
||||
* 权限标识必须符合以下格式:
|
||||
* 1. 标准格式:xxx:yyy:zzz
|
||||
* - 第一部分(xxx):只能包含字母、数字和下划线(_),不能使用 `*`
|
||||
* - 第二部分(yyy):可以包含字母、数字、下划线(_)和 `*`
|
||||
* - 第三部分(zzz):可以包含字母、数字、下划线(_)和 `*`
|
||||
* 2. 允许空字符串(""),表示没有权限标识
|
||||
*/
|
||||
String PERMISSION_STRING = "^$|^[a-zA-Z0-9_]+:[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]+$";
|
||||
|
||||
/**
|
||||
* 身份证号码(后6位)
|
||||
*/
|
||||
String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
|
||||
|
||||
/**
|
||||
* QQ号码
|
||||
*/
|
||||
String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$";
|
||||
|
||||
/**
|
||||
* 邮政编码
|
||||
*/
|
||||
String POSTAL_CODE = "^[1-9]\\d{5}$";
|
||||
|
||||
/**
|
||||
* 注册账号
|
||||
*/
|
||||
String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$";
|
||||
|
||||
/**
|
||||
* 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符
|
||||
*/
|
||||
String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$";
|
||||
|
||||
/**
|
||||
* 通用状态(0表示正常,1表示停用)
|
||||
*/
|
||||
String STATUS = "^[01]$";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package org.ruoyi.common.core.constant;
|
||||
|
||||
/**
|
||||
* 系统常量信息
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface SystemConstants {
|
||||
|
||||
/**
|
||||
* 正常状态
|
||||
*/
|
||||
String NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 异常状态
|
||||
*/
|
||||
String DISABLE = "1";
|
||||
|
||||
/**
|
||||
* 是否为系统默认(是)
|
||||
*/
|
||||
String YES = "Y";
|
||||
|
||||
/**
|
||||
* 是否为系统默认(否)
|
||||
*/
|
||||
String NO = "N";
|
||||
|
||||
/**
|
||||
* 是否菜单外链(是)
|
||||
*/
|
||||
String YES_FRAME = "0";
|
||||
|
||||
/**
|
||||
* 是否菜单外链(否)
|
||||
*/
|
||||
String NO_FRAME = "1";
|
||||
|
||||
/**
|
||||
* 菜单类型(目录)
|
||||
*/
|
||||
String TYPE_DIR = "M";
|
||||
|
||||
/**
|
||||
* 菜单类型(菜单)
|
||||
*/
|
||||
String TYPE_MENU = "C";
|
||||
|
||||
/**
|
||||
* 菜单类型(按钮)
|
||||
*/
|
||||
String TYPE_BUTTON = "F";
|
||||
|
||||
/**
|
||||
* Layout组件标识
|
||||
*/
|
||||
String LAYOUT = "Layout";
|
||||
|
||||
/**
|
||||
* ParentView组件标识
|
||||
*/
|
||||
String PARENT_VIEW = "ParentView";
|
||||
|
||||
/**
|
||||
* InnerLink组件标识
|
||||
*/
|
||||
String INNER_LINK = "InnerLink";
|
||||
|
||||
/**
|
||||
* 超级管理员ID
|
||||
*/
|
||||
Long SUPER_ADMIN_ID = 1L;
|
||||
|
||||
/**
|
||||
* 根部门祖级列表
|
||||
*/
|
||||
String ROOT_DEPT_ANCESTORS = "0";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.ruoyi.common.core.factory;
|
||||
|
||||
import cn.hutool.core.lang.PatternPool;
|
||||
import org.ruoyi.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,32 @@
|
||||
package org.ruoyi.common.core.factory;
|
||||
|
||||
|
||||
import org.ruoyi.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,60 @@
|
||||
package org.ruoyi.common.core.utils;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 对象工具类
|
||||
*
|
||||
* @author 秋辞未寒
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ObjectUtils extends ObjectUtil {
|
||||
|
||||
/**
|
||||
* 如果对象不为空,则获取对象中的某个字段 ObjectUtils.notNullGetter(user, User::getName);
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param func 获取方法
|
||||
* @return 对象字段
|
||||
*/
|
||||
public static <T, E> E notNullGetter(T obj, Function<T, E> func) {
|
||||
if (isNotNull(obj) && isNotNull(func)) {
|
||||
return func.apply(obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果对象不为空,则获取对象中的某个字段,否则返回默认值
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param func 获取方法
|
||||
* @param defaultValue 默认值
|
||||
* @return 对象字段
|
||||
*/
|
||||
public static <T, E> E notNullGetter(T obj, Function<T, E> func, E defaultValue) {
|
||||
if (isNotNull(obj) && isNotNull(func)) {
|
||||
return func.apply(obj);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果值不为空,则返回值,否则返回默认值
|
||||
*
|
||||
* @param obj 对象
|
||||
* @param defaultValue 默认值
|
||||
* @return 对象字段
|
||||
*/
|
||||
public static <T> T notNull(T obj, T defaultValue) {
|
||||
if (isNotNull(obj)) {
|
||||
return obj;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package org.ruoyi.common.core.utils;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.thread.Threading;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -48,7 +49,7 @@ public final class SpringUtils extends SpringUtil {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getAopProxy(T invoker) {
|
||||
return (T) AopContext.currentProxy();
|
||||
return (T) getBean(invoker.getClass());
|
||||
}
|
||||
|
||||
|
||||
@@ -59,4 +60,8 @@ public final class SpringUtils extends SpringUtil {
|
||||
return getApplicationContext();
|
||||
}
|
||||
|
||||
public static boolean isVirtual() {
|
||||
return Threading.VIRTUAL.isActive(getBean(Environment.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,11 +23,6 @@
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15to18</artifactId>
|
||||
@@ -38,6 +33,23 @@
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<brotli4j.version>1.13.0</brotli4j.version>
|
||||
<jackson-databind.version>2.16.0</jackson-databind.version>
|
||||
<hutool-all.version>5.8.24</hutool-all.version>
|
||||
<hutool-all.version>5.8.35</hutool-all.version>
|
||||
<netty-all.version>4.1.104.Final</netty-all.version>
|
||||
<logback-classic.version>1.4.12</logback-classic.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -30,12 +29,17 @@
|
||||
<!-- dynamic-datasource 多数据源-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- sql性能分析插件 -->
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 organization baomidou
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.baomidou.dynamic.datasource.processor.jakarta;
|
||||
|
||||
import com.baomidou.dynamic.datasource.processor.DsProcessor;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* @author TaoYu
|
||||
* @since 3.6.0
|
||||
*/
|
||||
public class DsJakartaHeaderProcessor extends DsProcessor {
|
||||
|
||||
/**
|
||||
* header prefix
|
||||
*/
|
||||
private static final String HEADER_PREFIX = "#header";
|
||||
|
||||
@Override
|
||||
public boolean matches(String key) {
|
||||
return key.startsWith(HEADER_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doDetermineDatasource(MethodInvocation invocation, String key) {
|
||||
HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
return request.getHeader(key.substring(8));
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 organization baomidou
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.baomidou.dynamic.datasource.processor.jakarta;
|
||||
|
||||
import com.baomidou.dynamic.datasource.processor.DsProcessor;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
|
||||
/**
|
||||
* @author TaoYu
|
||||
* @since 3.6.0
|
||||
*/
|
||||
public class DsJakartaSessionProcessor extends DsProcessor {
|
||||
|
||||
/**
|
||||
* session开头
|
||||
*/
|
||||
private static final String SESSION_PREFIX = "#session";
|
||||
|
||||
@Override
|
||||
public boolean matches(String key) {
|
||||
return key.startsWith(SESSION_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doDetermineDatasource(MethodInvocation invocation, String key) {
|
||||
HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
return request.getSession().getAttribute(key.substring(9)).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.ruoyi.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限注解,用于标记数据权限的占位符关键字和替换值
|
||||
* <p>
|
||||
* 一个注解只能对应一个模板
|
||||
* </p>
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.5.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataColumn {
|
||||
|
||||
/**
|
||||
* 数据权限模板的占位符关键字,默认为 "deptName"
|
||||
*
|
||||
* @return 占位符关键字数组
|
||||
*/
|
||||
String[] key() default "deptName";
|
||||
|
||||
/**
|
||||
* 数据权限模板的占位符替换值,默认为 "dept_id"
|
||||
*
|
||||
* @return 占位符替换值数组
|
||||
*/
|
||||
String[] value() default "dept_id";
|
||||
|
||||
/**
|
||||
* 权限标识符 用于通过菜单权限标识符来获取数据权限
|
||||
* 拥有此标识符的角色 将不会拼接此角色的数据过滤sql
|
||||
*
|
||||
* @return 权限标识符
|
||||
*/
|
||||
String permission() default "";
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.ruoyi.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限组注解,用于标记数据权限配置数组
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.5.0
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataPermission {
|
||||
|
||||
/**
|
||||
* 数据权限配置数组,用于指定数据权限的占位符关键字和替换值
|
||||
*
|
||||
* @return 数据权限配置数组
|
||||
*/
|
||||
DataColumn[] value();
|
||||
|
||||
/**
|
||||
* 权限拼接标识符(用于指定连接语句的sql符号)
|
||||
* 如不填 默认 select 用 OR 其他语句用 AND
|
||||
* 内容 OR 或者 AND
|
||||
*/
|
||||
String joinStr() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.ruoyi.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.ruoyi.annotation.DataPermission;
|
||||
import org.ruoyi.helper.DataPermissionHelper;
|
||||
|
||||
/**
|
||||
* 数据权限处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class DataPermissionAspect {
|
||||
|
||||
/**
|
||||
* 处理请求前执行
|
||||
*/
|
||||
@Before(value = "@annotation(dataPermission)")
|
||||
public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) {
|
||||
DataPermissionHelper.setPermission(dataPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理完请求后执行
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
*/
|
||||
@AfterReturning(pointcut = "@annotation(dataPermission)")
|
||||
public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) {
|
||||
DataPermissionHelper.removePermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截异常操作
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
* @param e 异常
|
||||
*/
|
||||
@AfterThrowing(value = "@annotation(dataPermission)", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) {
|
||||
DataPermissionHelper.removePermission();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.ruoyi.common.mybatis.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限
|
||||
*
|
||||
* 一个注解只能对应一个模板
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.5.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataColumn {
|
||||
|
||||
/**
|
||||
* 占位符关键字
|
||||
*/
|
||||
String[] key() default "deptName";
|
||||
|
||||
/**
|
||||
* 占位符替换值
|
||||
*/
|
||||
String[] value() default "dept_id";
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package org.ruoyi.common.mybatis.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限组
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.5.0
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataPermission {
|
||||
|
||||
DataColumn[] value();
|
||||
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
package org.ruoyi.common.mybatis.core.mapper;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.logging.LogFactory;
|
||||
import org.ruoyi.common.core.utils.MapstructUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 自定义 Mapper 接口, 实现 自定义扩展
|
||||
*
|
||||
* @param <T> table 泛型
|
||||
* @param <V> vo 泛型
|
||||
* @author Lion Li
|
||||
* @since 2021-05-13
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
||||
|
||||
Log log = LogFactory.getLog(BaseMapperPlus.class);
|
||||
|
||||
default Class<V> currentVoClass() {
|
||||
return (Class<V>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1);
|
||||
}
|
||||
|
||||
default Class<T> currentModelClass() {
|
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0);
|
||||
}
|
||||
|
||||
default List<T> selectList() {
|
||||
return this.selectList(new QueryWrapper<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入
|
||||
*/
|
||||
default boolean insertBatch(Collection<T> entityList) {
|
||||
return Db.saveBatch(entityList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新
|
||||
*/
|
||||
default boolean updateBatchById(Collection<T> entityList) {
|
||||
return Db.updateBatchById(entityList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入或更新
|
||||
*/
|
||||
default boolean insertOrUpdateBatch(Collection<T> entityList) {
|
||||
return Db.saveOrUpdateBatch(entityList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入(包含限制条数)
|
||||
*/
|
||||
default boolean insertBatch(Collection<T> entityList, int batchSize) {
|
||||
return Db.saveBatch(entityList, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新(包含限制条数)
|
||||
*/
|
||||
default boolean updateBatchById(Collection<T> entityList, int batchSize) {
|
||||
return Db.updateBatchById(entityList, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量插入或更新(包含限制条数)
|
||||
*/
|
||||
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
|
||||
return Db.saveOrUpdateBatch(entityList, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入或更新(包含限制条数)
|
||||
*/
|
||||
default boolean insertOrUpdate(T entity) {
|
||||
return Db.saveOrUpdate(entity);
|
||||
}
|
||||
|
||||
default V selectVoById(Serializable id) {
|
||||
return selectVoById(id, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 查询
|
||||
*/
|
||||
default <C> C selectVoById(Serializable id, Class<C> voClass) {
|
||||
T obj = this.selectById(id);
|
||||
if (ObjectUtil.isNull(obj)) {
|
||||
return null;
|
||||
}
|
||||
return MapstructUtils.convert(obj, voClass);
|
||||
}
|
||||
|
||||
default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
|
||||
return selectVoBatchIds(idList, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询(根据ID 批量查询)
|
||||
*/
|
||||
default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
|
||||
List<T> list = this.selectBatchIds(idList);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return MapstructUtils.convert(list, voClass);
|
||||
}
|
||||
|
||||
default List<V> selectVoByMap(Map<String, Object> map) {
|
||||
return selectVoByMap(map, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询(根据 columnMap 条件)
|
||||
*/
|
||||
default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
|
||||
List<T> list = this.selectByMap(map);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return MapstructUtils.convert(list, voClass);
|
||||
}
|
||||
|
||||
default V selectVoOne(Wrapper<T> wrapper) {
|
||||
return selectVoOne(wrapper, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 entity 条件,查询一条记录
|
||||
*/
|
||||
default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
|
||||
T obj = this.selectOne(wrapper);
|
||||
if (ObjectUtil.isNull(obj)) {
|
||||
return null;
|
||||
}
|
||||
return MapstructUtils.convert(obj, voClass);
|
||||
}
|
||||
|
||||
default List<V> selectVoList() {
|
||||
return selectVoList(new QueryWrapper<>(), this.currentVoClass());
|
||||
}
|
||||
|
||||
default List<V> selectVoList(Wrapper<T> wrapper) {
|
||||
return selectVoList(wrapper, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 entity 条件,查询全部记录
|
||||
*/
|
||||
default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
|
||||
List<T> list = this.selectList(wrapper);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return MapstructUtils.convert(list, voClass);
|
||||
}
|
||||
|
||||
default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) {
|
||||
return selectVoPage(page, wrapper, this.currentVoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询VO
|
||||
*/
|
||||
default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
|
||||
IPage<T> pageData = this.selectPage(page, wrapper);
|
||||
IPage<C> voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
|
||||
if (CollUtil.isEmpty(pageData.getRecords())) {
|
||||
return (P) voPage;
|
||||
}
|
||||
voPage.setRecords(MapstructUtils.convert(pageData.getRecords(), voClass));
|
||||
return (P) voPage;
|
||||
}
|
||||
|
||||
default <C> List<C> selectObjs(Wrapper<T> wrapper, Function<? super Object, C> mapper) {
|
||||
return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package org.ruoyi.common.mybatis.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.ruoyi.common.core.utils.StringUtils;
|
||||
import org.ruoyi.common.mybatis.helper.DataPermissionHelper;
|
||||
|
||||
/**
|
||||
* 数据权限类型
|
||||
* <p>
|
||||
* 语法支持 spel 模板表达式
|
||||
* <p>
|
||||
* 内置数据 user 当前用户 内容参考 LoginUser
|
||||
* 如需扩展数据 可使用 {@link DataPermissionHelper} 操作
|
||||
* 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService
|
||||
* 如需扩展更多自定义服务 可以参考 sdss 自行编写
|
||||
*
|
||||
* @author Lion Li
|
||||
* @version 3.5.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DataScopeType {
|
||||
|
||||
/**
|
||||
* 全部数据权限
|
||||
*/
|
||||
ALL("1", "", ""),
|
||||
|
||||
/**
|
||||
* 自定数据权限
|
||||
*/
|
||||
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""),
|
||||
|
||||
/**
|
||||
* 部门数据权限
|
||||
*/
|
||||
DEPT("3", " #{#deptName} = #{#user.deptId} ", ""),
|
||||
|
||||
/**
|
||||
* 部门及以下数据权限
|
||||
*/
|
||||
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""),
|
||||
|
||||
/**
|
||||
* 仅本人数据权限
|
||||
*/
|
||||
SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
|
||||
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 语法 采用 spel 模板表达式
|
||||
*/
|
||||
private final String sqlTemplate;
|
||||
|
||||
/**
|
||||
* 不满足 sqlTemplate 则填充
|
||||
*/
|
||||
private final String elseSql;
|
||||
|
||||
public static DataScopeType findCode(String code) {
|
||||
if (StringUtils.isBlank(code)) {
|
||||
return null;
|
||||
}
|
||||
for (DataScopeType type : values()) {
|
||||
if (type.getCode().equals(code)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package org.ruoyi.common.mybatis.handler;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.ruoyi.common.core.domain.model.LoginUser;
|
||||
import org.ruoyi.common.core.exception.ServiceException;
|
||||
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
|
||||
import org.ruoyi.common.satoken.utils.LoginHelper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* MP注入处理器
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2021/4/25
|
||||
*/
|
||||
@Slf4j
|
||||
public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
try {
|
||||
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
||||
Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime())
|
||||
? baseEntity.getCreateTime() : new Date();
|
||||
baseEntity.setCreateTime(current);
|
||||
baseEntity.setUpdateTime(current);
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (ObjectUtil.isNotNull(loginUser)) {
|
||||
Long userId = ObjectUtil.isNotNull(baseEntity.getCreateBy())
|
||||
? baseEntity.getCreateBy() : loginUser.getUserId();
|
||||
// 当前已登录 且 创建人为空 则填充
|
||||
baseEntity.setCreateBy(userId);
|
||||
// 当前已登录 且 更新人为空 则填充
|
||||
baseEntity.setUpdateBy(userId);
|
||||
baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept())
|
||||
? baseEntity.getCreateDept() : loginUser.getDeptId());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
try {
|
||||
if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
|
||||
Date current = new Date();
|
||||
// 更新时间填充(不管为不为空)
|
||||
baseEntity.setUpdateTime(current);
|
||||
LoginUser loginUser = getLoginUser();
|
||||
// 当前已登录 更新人填充(不管为不为空)
|
||||
if (ObjectUtil.isNotNull(loginUser)) {
|
||||
baseEntity.setUpdateBy(loginUser.getUserId());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户名
|
||||
*/
|
||||
private LoginUser getLoginUser() {
|
||||
LoginUser loginUser;
|
||||
try {
|
||||
loginUser = LoginHelper.getLoginUser();
|
||||
} catch (Exception e) {
|
||||
log.warn("自动注入警告 => 用户未登录");
|
||||
return null;
|
||||
}
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
}
|
||||