mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e877929a42 | |||
| 5f5970d7d5 | |||
| e05c9ddc08 | |||
| b77e9e25a3 | |||
| 8c406dcdea | |||
| 215b263d1a | |||
| 4247ffd082 | |||
| ec87621858 | |||
| bc6cf0e7b4 | |||
| 353ad058d1 | |||
| cf63b056d5 | |||
| f743622655 | |||
| 70a1f0b7db | |||
| bb4cdf93b1 | |||
| 7d7fde63ec | |||
| c22fd21233 | |||
| d4d0c884f0 | |||
| e6fe3459e4 | |||
| 9ebc3c49ec | |||
| 45e9b03e2d | |||
| 696b65240f | |||
| f4339677e7 | |||
| 0aaf0ad3ad | |||
| 0e5cd5bb3e | |||
| 24406a4cac | |||
| 1a1c840a3b | |||
| 2e257343a4 | |||
| 7871c465c8 | |||
| 714d9dc244 | |||
| f23b176cf4 | |||
| 494f5e21f5 | |||
| dea260cae3 | |||
| 0fcc08c204 | |||
| 608d2e1318 | |||
| 7e436f2efd | |||
| c18fb68e81 | |||
| 299f63c6e9 | |||
| 20037ae02b | |||
| dcdbb5ac7a | |||
| cd9ba3bac9 | |||
| 060bf2282c | |||
| d88f2f81e9 | |||
| 18cc746fcf | |||
| fcc7842e89 | |||
| e91af8cfd3 | |||
| a57cc1fa3d | |||
| 80d37f9a03 | |||
| 502ef2f65d | |||
| 62daec9c16 | |||
| 9191a8b620 | |||
| 4fb53637aa | |||
| 178a2368cb | |||
| 0813dee0d4 | |||
| 9579a60abd | |||
| 5cd5bf7a0b | |||
| c0265981d1 | |||
| 2ec13165d3 | |||
| ac5ee60364 | |||
| 5ff1b56fe2 | |||
| ea914be3a6 | |||
| cb65e1796c | |||
| ff815f1ae6 | |||
| c8ebdc162f | |||
| 76df4f8600 | |||
| a27b94c4c6 | |||
| 5ad06274cb | |||
| d38fa1901e | |||
| b4aab76057 | |||
| d87ffc11e7 | |||
| a67b3409b1 | |||
| e11d831114 | |||
| ec410456b2 | |||
| e9326cab8c | |||
| 61d2857ca7 | |||
| cba4847413 | |||
| bc56384325 | |||
| d7dc1b8dc7 | |||
| 11d9f2b4e4 | |||
| 64fcf7fcfc | |||
| e6ddeef18c | |||
| 47a074d9cb | |||
| c32f0407e8 | |||
| 22bbc23069 | |||
| b2078d502a | |||
| ed165464c8 | |||
| 9cf66e7026 | |||
| 11f8038196 | |||
| d2105dc095 | |||
| 32287d98ac | |||
| 31cf94ac7b | |||
| 0d28c92c83 | |||
| 1cc5cee92d | |||
| 26246eda7a | |||
| 10dd2a2dd0 | |||
| 5abc745496 | |||
| 353e8e2fb6 | |||
| 56661815ec | |||
| 03b6d20fcb | |||
| 2388c8c46d | |||
| 45f905ddac | |||
| 55696efcaa | |||
| 3671b81f01 | |||
| 74ad7e6f92 | |||
| 49d55a79f4 | |||
| 8395d106a2 | |||
| d716111ded | |||
| 81b4cbbe35 | |||
| 86cfc18fe8 | |||
| 98ba72ae4b | |||
| 29248561d6 | |||
| ad74b78134 | |||
| bd716417e8 | |||
| 1acb773adf | |||
| 2b0bedd263 | |||
| ac30ed67bc | |||
| ee382c0a5b | |||
| f7f6d0ff88 | |||
| 00252f392f |
163
README-AI.md
Normal file
163
README-AI.md
Normal file
@ -0,0 +1,163 @@
|
||||
AIGC应用平台介绍
|
||||
===============
|
||||
|
||||
即将发布:`最新版本 V3.8.0发布,提供Jeecg AIGC 提供AI应用平台+知识库问答`
|
||||
|
||||
|
||||
> JeecgBoot 平台的AIGC功能模块,是一套类似`Dify`的`AIGC应用开发平台`+`知识库问答`,是一款基于LLM大语言模型AI应用平台和 RAG 的知识库问答系统。
|
||||
其直观的界面结合了 AI 流程编排、RAG 管道、知识库管理、模型管理、对接向量库、实时运行可观察等,让您可以快速从原型到生产,拥有AI服务能力。
|
||||
|
||||
|
||||
### AI视频介绍
|
||||
|
||||
[](https://www.bilibili.com/video/BV1zmd7YFE4w)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Dify `VS` JEECG AI
|
||||
|
||||
> JEECG AI与Dify相比,在多个方面展现出显著的优势,特别是在文档处理、格式和图片保持方面。以下是一些具体的优点:
|
||||
> - Markdown文档库导入:
|
||||
> JEECG AI允许用户直接导入整个Markdown文档库,这不仅保留markdown格式,还支持图片的导入,确保文档内容的完整性和可视化效果。
|
||||
> - 对话回复格式美观:
|
||||
> 在对话过程中,JEECG AI能够保持回复内容的原格式,也不丢失图片,使得输出的文章更加美观,不会出现格式错乱的情况,还支持图片的渲染。
|
||||
> - PDF文档导入与格式转换:
|
||||
> JEECG AI在处理PDF文档时,能够更好地保持原始格式和图片,确保转换后的内容与原始文档一致。这哥功能在许多AI产品中表现不佳,而JEECG AI在这方面做出了显著的优化
|
||||
|
||||
|
||||
| 功能 | Dify | Jeecg AI |
|
||||
| --- | --- | --- |
|
||||
| AI工作流 | 有 | 有 |
|
||||
| RAG 管道向量搜索 | 有 | 有 |
|
||||
| AI模型管理 | 有 | 有 |
|
||||
| AI应用管理 | 有 | 有 |
|
||||
| AI知识库 | 有 | 有 |
|
||||
| 产品方向 | 一款独立的 LLM 应用开发平台 | 低代码与AIGC应用二者结合的平台 |
|
||||
| 业务集成 | 业务集成能力弱 | 更方便与业务系统集成,调用系统接口和逻辑更加方便 |
|
||||
| AI业务流 | 侧重AI逻辑流程 | AI流程编排作为低代码的业务引擎,用户可以通过AI流程配置各种业务流和AI流程 |
|
||||
| 上传markdown文档库(支持图片) | 不支持 | 支持 |
|
||||
| AI对话支持发图和展示图片 | 支持 | 支持 |
|
||||
| 实现语言 | python + react | JAVA + vue3 |
|
||||
|
||||
| 功能 | Dify | Jeecg AI |
|
||||
|------------|------------------|-----------------------------------------|
|
||||
| AI工作流 | 有 | 有 |
|
||||
| RAG 管道向量搜索 | 有 | 有 |
|
||||
| AI模型管理 | 有 | 有 |
|
||||
| AI应用管理 | 有 | 有 |
|
||||
| AI知识库 | 有 | 有 |
|
||||
| 产品方向 | 一款独立的 LLM 应用开发平台 | 低代码与AIGC应用二者结合的平台 |
|
||||
| 业务集成 | 业务集成能力弱 | 更方便与业务系统集成,调用系统接口和逻辑更加方便 |
|
||||
| AI业务流 | 侧重AI逻辑流程 | AI流程编排作为低代码的业务引擎,用户可以通过AI流程配置各种业务流和AI流程 |
|
||||
| 实现语言 | python + react | JAVA + vue3 |
|
||||
| 上传markdown文档库(支持图片) | 不支持 | 支持 |
|
||||
| AI对话支持发图和展示图片 | 支持 | 支持 |
|
||||
|
||||
|
||||
|
||||
## 功能特点
|
||||
|
||||
- AI流程: 提供强大的AI流程设计器引擎,支持编排 AI 工作过程,满足复杂业务场景,支持画布上构建和实时运行查看 AI流程运行情况。
|
||||
- AI流程即服务: 通过AI流程编排你需要的智能体,结合AI+自定义开发节点 实现功能性 API,让你瞬间拥有各种智能体API。
|
||||
- AI助手对话功能: 集成 ChatGPT、Deepseek、智普、私有大模型 等 AI 模型,提供智能对话和生成式 AI 功能,深度与知识库结合提供更精准的知识。
|
||||
- RAG 功能: 涵盖从文档摄入到检索的所有内容,支持从 PDF、PPT 和其他常见文档格式中提取文本,支持检索增强生成(RAG),将未训练数据与 AI 模型集成,提升智能交互能力。
|
||||
- AI 知识库: 通过导入文档或已有问答对进行训练,让 AI 模型能根据文档以交互式对话方式回答问题。
|
||||
- 模型管理:支持对接各种大模型,包括本地私有大模型(Deepseek/ Llama 3 / Qwen 2 等)、国内公共大模型(通义千问 / 腾讯混元 / 字节豆包 / 百度千帆 / 智谱 AI / Kimi 等)和国外公共大模型(OpenAI / Claude / Gemini 等);
|
||||
- 无缝嵌入:Iframe一键嵌入,支持将AI聊天助手快速嵌入到第三方系统,让系统快速拥有智能问答能力,提高用户满意度。
|
||||
|
||||
|
||||
|
||||
## 产品体验
|
||||
|
||||
- 使用手册:https://help.jeecg.com/aigc
|
||||
- 演示地址:https://boot3.jeecg.com
|
||||
|
||||
|
||||
## 功能列表
|
||||
|
||||
- AI应用管理(普通应用、高级流程应用)
|
||||
- AI模型管理
|
||||
- AI知识库
|
||||
- AI应用平台(普通、对接AI流程)
|
||||
- AI流程编排
|
||||
- AI聊天支持嵌入第三方
|
||||
- AI向量库对接
|
||||
|
||||
|
||||
|
||||
## 支持AI模型
|
||||
|
||||
| AI大模型 | 支持 |
|
||||
|---------------| --- |
|
||||
| DeepSeek | √ |
|
||||
| ChatGTP | √ |
|
||||
| Qwq | √ |
|
||||
| 智库 | √ |
|
||||
| Ollama本地搭建大模型 | √ |
|
||||
| 等等。。 | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
## AIGC能做什么
|
||||
|
||||
AIGC模块是一个基于AI的自动化流程编排工具和聊天应用搭建平台,它可以帮助用户快速生成AI流程接口和聊天应用,提高效率。
|
||||
以下是一些具体的应用场景和示例:
|
||||
|
||||
- 你可能需要一个翻译接口,可以通过AI流程编排搭建出来。
|
||||
- 你可能需要一个接口转换工具,可以通过AI流程编排搭建出来。(比如:jimureport所需要接口返回格式与你的系统不同,你通过AI接口实现自动转换)
|
||||
- 你可能需要一个聊天机器人,可以通过AI流程编排搭建出来。
|
||||
- 你可能需要一个自动化流程,可以通过AI流程编排搭建出来。
|
||||
- 你可能需要一个自动化处理文件的流程,可以通过AI流程结合python脚本实现操作电脑,文件等。
|
||||
|
||||
|
||||
## AI应用平台功能展示
|
||||
|
||||
AI模型列表
|
||||
|
||||

|
||||
|
||||
选择AI模型,配置你的参数
|
||||
|
||||

|
||||
|
||||
|
||||
AI知识库支持手工录入文本,导入pdf\\word\\excel等文档,支持问答对训练
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
AI流程,提供强大的AI流程设计器引擎,支持编排 AI 工作过程,满足复杂业务场景,支持画布上构建和实时运行查看 AI流程运行情况。
|
||||
|
||||

|
||||
|
||||
|
||||
目前支持的节点有:开始、结束、AI知识库节点、AI节点、分类节点、分支节点、JAVA节点、脚本节点、子流程节点、http请求节点、直接回复节点等节点
|
||||
|
||||

|
||||
|
||||
节点项配置
|
||||
|
||||

|
||||
|
||||
在线运行看结果
|
||||
|
||||

|
||||
|
||||
|
||||
AI应用配置,支持AI流程配置和简单的AI配置
|
||||
|
||||

|
||||
|
||||
可以关联多个知识库,右侧是AI智能回复,你可以搭建自己的智能体,比如搭建一个 “诗词达人” “翻译助手”
|
||||
|
||||

|
||||
|
||||
可以将创建的聊天应用,集成到第三方系统中
|
||||
|
||||

|
||||
45
README-EN.md
45
README-EN.md
@ -7,12 +7,12 @@
|
||||
JEECG BOOT AI Low Code Platform
|
||||
===============
|
||||
|
||||
Current version: 3.7.3 (Release date: 2025-02-10)
|
||||
Current version: 3.7.4 (Release date: 2025-04-07)
|
||||
|
||||
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||
[](http://www.jeecg.com)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
|
||||
@ -37,7 +37,7 @@ AI Empowering Low-Code: Currently, JeecgBoot supports AI large models such as Ch
|
||||
Technical support
|
||||
-----------------------------------
|
||||
|
||||
Problems or bugs in use can be found in [Making on the Issues](https://github.com/jeecgboot/JeecgBoot/issues/new)
|
||||
Problems or bugs in use can be found in [Making on the Issues](https://github.com/jeecgboot/JeecgBoot/issues/new?template=bug_report.md)
|
||||
|
||||
|
||||
##### Project description
|
||||
@ -49,6 +49,11 @@ Problems or bugs in use can be found in [Making on the Issues](https://github.co
|
||||
| `jeecg-uniapp` | [APP development framework, a code multi terminal adaptation, and support APP, small program, H5](https://github.com/jeecgboot/jeecg-uniapp) |
|
||||
|
||||
|
||||
### Video Introduction
|
||||
|
||||
[](https://www.bilibili.com/video/BV1Nk4y1o7Qc)
|
||||
|
||||
|
||||
|
||||
Download other source code
|
||||
-----------------------------------
|
||||
@ -64,8 +69,8 @@ Jeecg-Boot AI low code platform can be applied in the development of any J2EE pr
|
||||
Starts the project
|
||||
-----------------------------------
|
||||
|
||||
- [IDEA Quick start](https://help.jeecg.com/java/setup/idea/startup.html)
|
||||
- [Docker Quick start](https://help.jeecg.com/java/docker/quick.html)
|
||||
- [IDEA Quick start](https://help.jeecg.com/java/setup/idea/startup)
|
||||
- [Docker Quick start](https://help.jeecg.com/java/docker/quick)
|
||||
|
||||
|
||||
|
||||
@ -74,9 +79,9 @@ Technical documentation
|
||||
|
||||
- Website: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- Demo : [OnlineDemo](http://boot3.jeecg.com) | [APP](http://jeecg.com/appIndex)
|
||||
- Doc: [DocumentCenter](http://help.jeecg.com) | [AI Config](https://help.jeecg.com/java/ai/aichat.html)
|
||||
- Doc: [DocumentCenter](http://help.jeecg.com) | [AI Config](https://help.jeecg.com/java/ai/aichat)
|
||||
- Newbie guide: [Quick start](http://www.jeecg.com/doc/quickstart) | [Q&A ](http://www.jeecg.com/doc/qa) | [1 minute experience](https://my.oschina.net/jeecg/blog/3083313)
|
||||
- QQ group : ⑩716488839、⑨808791225、⑧825232878、⑦791696430、⑥730954414(full)、683903138(full)、⑤860162132(full)、④774126647(full)、③816531124(full)、②769925425(full)、①284271917(full)
|
||||
- QQ group : ⑩716488839、⑨808791225
|
||||
|
||||
|
||||
|
||||
@ -176,7 +181,7 @@ Technical Architecture:
|
||||
|
||||
#### Development Environment
|
||||
|
||||
- Language: Java 8+ (17)
|
||||
- Language: Java Default Jdk17(support jdk8、jdk21)
|
||||
|
||||
- IDE(JAVA) : IDEA (lombok plug-in must be installed)
|
||||
|
||||
@ -193,17 +198,17 @@ Technical Architecture:
|
||||
|
||||
- Basic framework: Spring Boot 2.7.18
|
||||
|
||||
- Microservice framework: Spring Cloud Alibaba 2021.0.1.0
|
||||
- Microservice framework: Spring Cloud Alibaba 2021.0.6.2
|
||||
|
||||
- Persistence layer framework: MybatisPlus 3.5.3.2
|
||||
|
||||
- Report tool: JimuReport 1.9.3
|
||||
- Report tool: JimuReport 1.9.5
|
||||
|
||||
- Security framework: Apache Shiro 1.12.0, Jwt 3.11.0
|
||||
- Security framework: Apache Shiro 1.13.0, Jwt 4.5.0
|
||||
|
||||
- Microservice technology stack: Spring Cloud Alibaba, Nacos, Gateway, Sentinel, Skywalking
|
||||
|
||||
- Database connection pool: Alibaba Druid 1.1.22
|
||||
- Database connection pool: Alibaba Druid 1.1.24
|
||||
|
||||
- Log printing: logback
|
||||
|
||||
@ -242,8 +247,16 @@ Technical Architecture:
|
||||
| --- | --- |
|
||||
| DeepSeek | √ |
|
||||
| ChatGPT | √ |
|
||||
| Qwq | √ |
|
||||
| 智库 | √ |
|
||||
| Ollama本地搭建大模型 | √ |
|
||||
| 等等。。 | √ |
|
||||
|
||||
|
||||
AI Config: https://help.jeecg.com/java/ai/aichat
|
||||
|
||||
AI APP: https://help.jeecg.com/aigc
|
||||
|
||||
AI Config: https://help.jeecg.com/java/ai/aichat.html
|
||||
|
||||
## Microservice solutions
|
||||
|
||||
@ -255,7 +268,7 @@ AI Config: https://help.jeecg.com/java/ai/aichat.html
|
||||
- 6. Distributed files Minio and Alioss √
|
||||
- 7. Unified permission control
|
||||
- 8. Service monitoring SpringBootAdmin√
|
||||
- 9. link tracking Skywalking [reference document](https://help.jeecg.com/java/springcloud/super/skywarking.html)
|
||||
- 9. link tracking Skywalking [reference document](https://help.jeecg.com/java/springcloud/super/skywarking)
|
||||
- 10. Messaging middleware RabbitMQ √
|
||||
- 11. Distributed task xxl-job √
|
||||
- 12. Distributed Transaction Seata
|
||||
@ -272,8 +285,8 @@ AI Config: https://help.jeecg.com/java/ai/aichat.html
|
||||

|
||||
|
||||
### quick start
|
||||
- Microservice Development: [Monomer upgrade to microservice](https://help.jeecg.com/java/springcloud/switchcloud/monomer.html)
|
||||
- [Docker starts the micro-service background](https://help.jeecg.com/java/docker/springcloud.html)
|
||||
- Microservice Development: [Monomer upgrade to microservice](https://help.jeecg.com/java/springcloud/switchcloud/monomer)
|
||||
- [Docker starts the micro-service background](https://help.jeecg.com/java/docker/springcloud)
|
||||
|
||||
|
||||
### Effect of system
|
||||
|
||||
115
README.md
115
README.md
@ -2,12 +2,12 @@
|
||||
JeecgBoot AI低代码平台
|
||||
===============
|
||||
|
||||
当前最新版本: 3.7.3(发布日期:2025-02-10)
|
||||
当前最新版本: 3.7.4(发布日期:2025-04-07)
|
||||
|
||||
|
||||
[](https://github.com/jeecgboot/JeecgBoot/blob/master/LICENSE)
|
||||
[](http://guojusoft.com)
|
||||
[](https://github.com/jeecgboot/JeecgBoot)
|
||||
[](https://github.com/jeecgboot/JeecgBoot)
|
||||
[](https://github.com/jeecgboot/JeecgBoot)
|
||||
[](https://github.com/jeecgboot/JeecgBoot)
|
||||
|
||||
@ -30,18 +30,25 @@ JeecgBoot 提供了一系列 `AI能力` `低代码模块`,实现在线开发`
|
||||
`AI赋能低代码:` 目前JeecgBoot支持AI大模型`ChatGPT`和`DeepSeek`,现在最新版默认使用`DeepSeek`,速度更快质量更高。目前提供了AI对话助手、AI建表、AI报表、AI写文章、AI流程编排、AI知识库问答等功能。
|
||||
|
||||
|
||||
### 视频介绍
|
||||
|
||||
[](https://www.bilibili.com/video/BV1Nk4y1o7Qc)
|
||||
|
||||
|
||||
适用项目
|
||||
-----------------------------------
|
||||
JeecgBoot AI低代码平台,可以应用在任何J2EE项目的开发中,支持信创国产化(默认适配达梦和人大金仓)。尤其适合SAAS项目、企业信息管理系统(MIS)、内部办公系统(OA)、企业资源计划系统(ERP)、客户关系管理系统(CRM)等,其半智能手工Merge的开发方式,可以显著提高开发效率70%以上,极大降低开发成本。
|
||||
|
||||
|
||||
#### 项目说明
|
||||
|
||||
项目说明
|
||||
-----------------------------------
|
||||
|
||||
| 项目名 | 说明 |
|
||||
|--------------------|------------------------|
|
||||
| `jeecg-boot` | 后端源码JAVA(SpringBoot微服务架构) |
|
||||
| `jeecgboot-vue3` | 前端源码VUE3(vue3+vite6+ts最新技术栈) |
|
||||
| `jeecg-uniapp` | [配套APP框架](https://github.com/jeecgboot/jeecg-uniapp) 适配多个终端,支持APP、小程序、H5 |
|
||||
| `JeecgUniapp` | [配套APP框架](https://github.com/jeecgboot/JeecgUniapp) 适配多个终端,支持APP、小程序、H5 |
|
||||
|
||||
|
||||
|
||||
@ -49,39 +56,70 @@ JeecgBoot AI低代码平台,可以应用在任何J2EE项目的开发中,支
|
||||
-----------------------------------
|
||||
|
||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
- 快速体验: [一分钟体验低代码](https://jeecg.blog.csdn.net/article/details/106079007?spm=1001.2014.3001.5502 "一分钟体验零代码") | [在线体验零代码](https://app.qiaoqiaoyun.com/myapps/index "在线体验零代码")
|
||||
- 开发文档: [文档中心](https://help.jeecg.com) | [AI集成配置(支持DeepSeek)](https://help.jeecg.com/java/ai/aichat.html)
|
||||
- 反馈问题: [在Github上提Issues](https://github.com/jeecgboot/JeecgBoot/issues/new)
|
||||
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart) | [入门视频](http://jeecg.com/doc/video)
|
||||
- 在线演示 : [平台演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex) | [体验低代码](https://jeecg.blog.csdn.net/article/details/106079007) | [体验零代码](https://app.qiaoqiaoyun.com/myapps/index)
|
||||
- 开发文档: [文档中心](https://help.jeecg.com) | [AIGC大模块](https://help.jeecg.com/aigc)
|
||||
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart) | [入门视频](http://jeecg.com/doc/video) | [如何反馈问题](https://github.com/jeecgboot/JeecgBoot/issues/new?template=bug_report.md)
|
||||
- QQ交流群 : ⑩716488839、⑨808791225(满)、其他(满)
|
||||
|
||||
|
||||
|
||||
|
||||
启动项目
|
||||
-----------------------------------
|
||||
|
||||
- [IDEA启动前后端项目](https://help.jeecg.com/java/setup/idea/startup.html)
|
||||
- [Docker一键启动前后端](https://help.jeecg.com/java/docker/quick.html)
|
||||
- [IDEA启动前后端项目](https://help.jeecg.com/java/setup/idea/startup)
|
||||
- [Docker一键启动前后端](https://help.jeecg.com/java/docker/quick)
|
||||
|
||||
|
||||
AIGC功能清单
|
||||
|
||||
AIGC应用平台介绍
|
||||
-----------------------------------
|
||||
|
||||
- AI对聊天助手
|
||||
> JeecgBoot 平台的AIGC功能模块,是一套类似`Dify`的`AIGC应用开发平台`+`知识库问答`,是一款基于LLM大语言模型AI应用平台和 RAG 的知识库问答系统。
|
||||
其直观的界面结合了 AI 流程编排、RAG 管道、知识库管理、模型管理、对接向量库、实时运行可观察等,让您可以快速从原型到生产,拥有AI服务能力。
|
||||
|
||||
- [AIGC专题介绍页](README-AI.md)
|
||||
- [AIGC开发文档](https://help.jeecg.com/aigc)
|
||||
|
||||
|
||||
##### AI视频介绍
|
||||
|
||||
[](https://www.bilibili.com/video/BV1zmd7YFE4w)
|
||||
|
||||
|
||||
##### Dify `VS` JEECG AI
|
||||
|
||||
> JEECG AI与Dify相比,在多个方面展现出显著的优势,特别是在文档处理、格式和图片保持方面。以下是一些具体的优点:
|
||||
> - Markdown文档库导入:
|
||||
> JEECG AI允许用户直接导入整个Markdown文档库,这不仅保留markdown格式,还支持图片的导入,确保文档内容的完整性和可视化效果。
|
||||
> - 对话回复格式美观:
|
||||
> 在对话过程中,JEECG AI能够保持回复内容的原格式,也不丢失图片,使得输出的文章更加美观,不会出现格式错乱的情况,还支持图片的渲染。
|
||||
> - PDF文档导入与格式转换:
|
||||
> JEECG AI在处理PDF文档时,能够更好地保持原始格式和图片,确保转换后的内容与原始文档一致。这哥功能在许多AI产品中表现不佳,而JEECG AI在这方面做出了显著的优化
|
||||
|
||||
##### 功能大模块
|
||||
|
||||
- AI应用开发平台
|
||||
- AI知识库系统
|
||||
- AI大模型管理
|
||||
- AI流程编排
|
||||
- AI对话支持图片
|
||||
- AI对话助手(智能问答)
|
||||
- AI建表(Online表单)
|
||||
- AI写文章(CMS)
|
||||
- AI表单建议(表单设计器)
|
||||
- AI流程编排(研发中)
|
||||
- AI知识库问答系统(研发中)
|
||||
- AI应用开发平台(研发中)
|
||||
- AI聊天窗口支持嵌入第三方(研发中)
|
||||
- AI表单字段建议(表单设计器)
|
||||
|
||||
##### AI大模型支持
|
||||
|
||||
| AI大模型 | 支持 |
|
||||
| --- | --- |
|
||||
| DeepSeek | √ |
|
||||
| ChatGTP | √ |
|
||||
| Qwq | √ |
|
||||
| 智库 | √ |
|
||||
| Ollama本地模型 | √ |
|
||||
| 等等。。 | √ |
|
||||
|
||||
|
||||
<b>关注公众号获取最新版资讯</b>
|
||||
|
||||

|
||||
|
||||
|
||||
技术架构:
|
||||
@ -90,15 +128,15 @@ AIGC功能清单
|
||||
#### 后端
|
||||
|
||||
- IDE建议: IDEA (必须安装lombok插件 )
|
||||
- 语言:Java 8+ (支持17)
|
||||
- 语言:Java 默认jdk17(支持jdk8、jdk21)
|
||||
- 依赖管理:Maven
|
||||
- 基础框架:Spring Boot 2.7.18
|
||||
- 微服务框架: Spring Cloud Alibaba 2021.0.1.0
|
||||
- 微服务框架: Spring Cloud Alibaba 2021.0.6.2
|
||||
- 持久层框架:MybatisPlus 3.5.3.2
|
||||
- 报表工具: JimuReport 1.9.3
|
||||
- 安全框架:Apache Shiro 1.12.0,Jwt 3.11.0
|
||||
- 报表工具: JimuReport 1.9.5
|
||||
- 安全框架:Apache Shiro 1.13.0,Jwt 4.5.0
|
||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.24
|
||||
- AI大模型:支持 `ChatGPT` `DeepSeek`切换
|
||||
- 日志打印:logback
|
||||
- 缓存:Redis
|
||||
@ -124,7 +162,9 @@ AIGC功能清单
|
||||
` ( 因为Vite6 需要 Node.js 18 / 20+ )`
|
||||
|
||||
|
||||
#### 支持库
|
||||
#### 平台支持数据库
|
||||
|
||||
> jeecgboot平台支持以下数据库,默认我们只提供mysql脚本,其他数据库可以参考[转库文档](https://my.oschina.net/jeecg/blog/4905722)自己转。
|
||||
|
||||
| 数据库 | 支持 |
|
||||
| --- | --- |
|
||||
@ -133,20 +173,11 @@ AIGC功能清单
|
||||
| Sqlserver2017 | √ |
|
||||
| PostgreSQL | √ |
|
||||
| MariaDB | √ |
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
| TiDB | √ |
|
||||
|
||||
#### 支持AI大模型
|
||||
|
||||
| AI大模型 | 支持 |
|
||||
| --- | --- |
|
||||
| DeepSeek | √ |
|
||||
| ChatGTP | √ |
|
||||
| Ollama本地搭建大模型 | √ |
|
||||
|
||||
AI集成文档: https://help.jeecg.com/java/ai/aichat.html
|
||||
| kingbase8 | √ |
|
||||
|
||||
|
||||
|
||||
## 微服务解决方案
|
||||
@ -160,7 +191,7 @@ AI集成文档: https://help.jeecg.com/java/ai/aichat.html
|
||||
- 6、分布式文件 Minio、阿里OSS √
|
||||
- 7、统一权限控制 JWT + Shiro √
|
||||
- 8、服务监控 SpringBootAdmin√
|
||||
- 9、链路跟踪 Skywalking [参考文档](https://help.jeecg.com/java/springcloud/super/skywarking.html)
|
||||
- 9、链路跟踪 Skywalking [参考文档](https://help.jeecg.com/java/springcloud/super/skywarking)
|
||||
- 10、消息中间件 RabbitMQ √
|
||||
- 11、分布式任务 xxl-job √
|
||||
- 12、分布式事务 Seata
|
||||
@ -172,8 +203,8 @@ AI集成文档: https://help.jeecg.com/java/ai/aichat.html
|
||||
|
||||
#### 微服务方式启动
|
||||
|
||||
- [单体快速切换微服务](https://help.jeecg.com/java/springcloud/switchcloud/monomer.html)
|
||||
- [Docker一键启动微服务前后端](https://help.jeecg.com/java/docker/quickcloud.html)
|
||||
- [单体快速切换微服务](https://help.jeecg.com/java/springcloud/switchcloud/monomer)
|
||||
- [Docker一键启动微服务前后端](https://help.jeecg.com/java/docker/quickcloud)
|
||||
|
||||
|
||||
#### 微服务架构图
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
JeecgBoot 低代码开发平台
|
||||
===============
|
||||
|
||||
当前最新版本: 3.7.3(发布日期:2025-02-10)
|
||||
当前最新版本: 3.7.4(发布日期:2025-04-10)
|
||||
|
||||
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||
[](http://jeecg.com/aboutusIndex)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
|
||||
@ -44,14 +44,14 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
启动项目
|
||||
-----------------------------------
|
||||
|
||||
- [IDEA启动前后端项目](https://help.jeecg.com/java/setup/idea/startup.html)
|
||||
- [Docker一键启动前后端](https://help.jeecg.com/java/docker/quick.html)
|
||||
- [IDEA启动前后端项目](https://help.jeecg.com/java/setup/idea/startup)
|
||||
- [Docker一键启动前后端](https://help.jeecg.com/java/docker/quick)
|
||||
|
||||
|
||||
微服务启动
|
||||
-----------------------------------
|
||||
- [单体快速切换微服务](https://help.jeecg.com/java/springcloud/switchcloud/monomer.html)
|
||||
- [Docker启动微服务后台](https://help.jeecg.com/java/docker/springcloud.html)
|
||||
- [单体快速切换微服务](https://help.jeecg.com/java/springcloud/switchcloud/monomer)
|
||||
- [Docker启动微服务后台](https://help.jeecg.com/java/docker/springcloud)
|
||||
|
||||
|
||||
|
||||
@ -66,10 +66,10 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
- 基础框架:Spring Boot 2.7.18
|
||||
- 微服务框架: Spring Cloud Alibaba 2021.0.1.0
|
||||
- 持久层框架:MybatisPlus 3.5.3.2
|
||||
- 报表工具: JimuReport 1.8.1
|
||||
- 报表工具: JimuReport 1.9.4
|
||||
- 安全框架:Apache Shiro 1.12.0,Jwt 3.11.0
|
||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.24
|
||||
- 日志打印:logback
|
||||
- 缓存:Redis
|
||||
- 其他:autopoi, fastjson,poi,Swagger-ui,quartz, lombok(简化代码)等。
|
||||
@ -113,7 +113,7 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
- 6、分布式文件 Minio、阿里OSS √
|
||||
- 7、统一权限控制 JWT + Shiro √
|
||||
- 8、服务监控 SpringBootAdmin√
|
||||
- 9、链路跟踪 Skywalking [参考文档](https://help.jeecg.com/java/springcloud/super/skywarking.html)
|
||||
- 9、链路跟踪 Skywalking [参考文档](https://help.jeecg.com/java/springcloud/super/skywarking)
|
||||
- 10、消息中间件 RabbitMQ √
|
||||
- 11、分布式任务 xxl-job √
|
||||
- 12、分布式事务 Seata
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -3,7 +3,6 @@
|
||||
> JeecgBoot属于平台级产品,每次升级改动较大,目前做不到平滑升级。
|
||||
|
||||
### 增量升级方案
|
||||
|
||||
#### 1.代码合并
|
||||
本地通过svn或git做好主干,在分支上做业务开发,jeecg每次版本发布,可以手工覆盖主干的代码,对比合并代码;
|
||||
|
||||
@ -12,12 +11,5 @@
|
||||
- 其他库请手工执行SQL, 目录: `jeecg-module-system\jeecg-system-start\src\main\resources\flyway\sql\mysql`
|
||||
> 注意: 升级sql只提供mysql版本;如果有权限升级, 还需要手工角色授权,退出重新登录才好使。
|
||||
|
||||
#### 3.其他数据库脚本说明
|
||||
原先官方默认提供oracle和SqlServer的脚本,但是维护成本太高,未提供脚本的数据库,可以参考下面的文档自己转
|
||||
https://my.oschina.net/jeecg/blog/4905722
|
||||
(注意:定时任务的表qrtz_*,需要删掉用原始的脚本重新执行一下)
|
||||
quartz-2.2.3-distribution.tar.gz放到百度网盘中,大家自己下载,执行所需数据库脚本
|
||||
https://pan.baidu.com/s/1WrmZdUuAPg3iBwJ-LoHWyg?pwd=8mdz
|
||||
|
||||
#### 4.兼容问题
|
||||
#### 3.兼容问题
|
||||
每次发版,会针对不兼容地方重点说明。
|
||||
@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-parent</artifactId>
|
||||
<version>3.7.3</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
@ -49,6 +49,16 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<!-- websocket -->
|
||||
<dependency>
|
||||
@ -163,7 +173,7 @@
|
||||
<artifactId>DmDialect-for-hibernate5.0</artifactId>
|
||||
<version>${dm8.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Quartz定时任务 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -201,14 +211,9 @@
|
||||
</dependency>
|
||||
|
||||
<!-- knife4j -->
|
||||
<!-- <dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>3.0.3</version>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
|
||||
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
|
||||
<version>${knife4j-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
|
||||
@ -218,6 +223,16 @@
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>codegenerate</artifactId>
|
||||
<version>${codegenerate.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<groupId>mysql</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- AutoPoi Excel工具类-->
|
||||
@ -247,6 +262,12 @@
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
@ -288,7 +309,6 @@
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- chatgpt -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
package org.jeecg.common.api.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
|
||||
@ -15,7 +14,7 @@ import java.io.Serializable;
|
||||
* @date 2019年1月19日
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value="接口返回对象", description="接口返回对象")
|
||||
@Schema(description="接口返回对象")
|
||||
public class Result<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -23,31 +22,31 @@ public class Result<T> implements Serializable {
|
||||
/**
|
||||
* 成功标志
|
||||
*/
|
||||
@ApiModelProperty(value = "成功标志")
|
||||
@Schema(description = "成功标志")
|
||||
private boolean success = true;
|
||||
|
||||
/**
|
||||
* 返回处理消息
|
||||
*/
|
||||
@ApiModelProperty(value = "返回处理消息")
|
||||
@Schema(description = "返回处理消息")
|
||||
private String message = "";
|
||||
|
||||
/**
|
||||
* 返回代码
|
||||
*/
|
||||
@ApiModelProperty(value = "返回代码")
|
||||
@Schema(description = "返回代码")
|
||||
private Integer code = 0;
|
||||
|
||||
/**
|
||||
* 返回数据对象 data
|
||||
*/
|
||||
@ApiModelProperty(value = "返回数据对象")
|
||||
@Schema(description = "返回数据对象")
|
||||
private T result;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
@ApiModelProperty(value = "时间戳")
|
||||
@Schema(description = "时间戳")
|
||||
private long timestamp = System.currentTimeMillis();
|
||||
|
||||
public Result() {
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package org.jeecg.common.exception;
|
||||
|
||||
/**
|
||||
* jeecgboot断言异常
|
||||
* for [QQYUN-10990]AIRAG
|
||||
* @author chenrui
|
||||
* @date 2025/2/14 14:31
|
||||
*/
|
||||
public class JeecgBootAssertException extends JeecgBootException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
public JeecgBootAssertException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JeecgBootAssertException(String message, int errCode) {
|
||||
super(message, errCode);
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,7 +23,9 @@ import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.redis.connection.PoolException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
@ -33,6 +35,7 @@ import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 异常处理器
|
||||
@ -47,6 +50,13 @@ public class JeecgBootExceptionHandler {
|
||||
@Resource
|
||||
BaseCommonService baseCommonService;
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Result<?> handleValidationExceptions(MethodArgumentNotValidException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
addSysLog(e);
|
||||
return Result.error("校验失败!" + e.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(",")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
|
||||
@ -2,6 +2,7 @@ package org.jeecg.common.system.base.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
@ -9,7 +10,6 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
@ -30,20 +30,20 @@ public class JeecgEntity implements Serializable {
|
||||
* ID
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@ApiModelProperty(value = "ID")
|
||||
@Schema(description = "ID")
|
||||
private java.lang.String id;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@ApiModelProperty(value = "创建人")
|
||||
@Schema(description = "创建人")
|
||||
@Excel(name = "创建人", width = 15)
|
||||
private java.lang.String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
@Schema(description = "创建时间")
|
||||
@Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ -52,14 +52,14 @@ public class JeecgEntity implements Serializable {
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
@ApiModelProperty(value = "更新人")
|
||||
@Schema(description = "更新人")
|
||||
@Excel(name = "更新人", width = 15)
|
||||
private java.lang.String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
@Schema(description = "更新时间")
|
||||
@Excel(name = "更新时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
@ -6,6 +6,17 @@ import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.JWTDecodeException;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
@ -20,16 +31,6 @@ import org.jeecg.common.util.DateUtils;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author Scott
|
||||
* @Date 2018-07-12 14:23
|
||||
@ -199,11 +200,13 @@ public class JwtUtil {
|
||||
}
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
// 是否存在字符串标志
|
||||
boolean multiStr = false;
|
||||
boolean multiStr;
|
||||
if(oConvertUtils.isNotEmpty(key) && key.trim().matches("^\\[\\w+]$")){
|
||||
key = key.substring(1,key.length()-1);
|
||||
multiStr = true;
|
||||
}
|
||||
} else {
|
||||
multiStr = false;
|
||||
}
|
||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
//替换为当前系统时间(年月日)
|
||||
if (key.equals(DataBaseConstant.SYS_DATE)|| key.toLowerCase().equals(DataBaseConstant.SYS_DATE_TABLE)) {
|
||||
@ -286,7 +289,15 @@ public class JwtUtil {
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
returnValue = user.getSysMultiOrgCode().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(orgCode -> "'" + orgCode + "'")
|
||||
//update-begin---author:chenrui ---date:20250224 for:[issues/7288]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
.map(orgCode -> {
|
||||
if (multiStr) {
|
||||
return "'" + orgCode + "'";
|
||||
} else {
|
||||
return orgCode;
|
||||
}
|
||||
})
|
||||
//update-end---author:chenrui ---date:20250224 for:[issues/7288]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
.collect(Collectors.joining(", "));
|
||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
}
|
||||
|
||||
@ -0,0 +1,239 @@
|
||||
package org.jeecg.common.util;
|
||||
|
||||
|
||||
import org.jeecg.common.exception.JeecgBootAssertException;
|
||||
|
||||
/**
|
||||
* 断言检查工具
|
||||
* for for [QQYUN-10990]AIRAG
|
||||
* @author chenrui
|
||||
* @date 2017-06-22 10:05:56
|
||||
*/
|
||||
public class AssertUtils {
|
||||
|
||||
/**
|
||||
* 确保对象为空,如果不为空抛出异常
|
||||
*
|
||||
* @param msg
|
||||
* @param obj
|
||||
* @throws JeecgBootAssertException
|
||||
* @author chenrui
|
||||
* @date 2017-06-22 10:05:56
|
||||
*/
|
||||
public static void assertEmpty(String msg, Object obj) {
|
||||
if (oConvertUtils.isObjectNotEmpty(obj)) {
|
||||
throw new JeecgBootAssertException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 确保对象不为空,如果为空抛出异常
|
||||
*
|
||||
* @param msg
|
||||
* @param obj
|
||||
* @throws JeecgBootAssertException
|
||||
* @author chenrui
|
||||
* @date 2017-06-22 10:05:56
|
||||
*/
|
||||
public static void assertNotEmpty(String msg, Object obj) {
|
||||
if (oConvertUtils.isObjectEmpty(obj)) {
|
||||
throw new JeecgBootAssertException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证对象是否相同
|
||||
*
|
||||
* @param message
|
||||
* @param expected
|
||||
* @param actual
|
||||
* @author chenrui
|
||||
* @date 2018/9/12 15:45
|
||||
*/
|
||||
public static void assertEquals(String message, Object expected,
|
||||
Object actual) {
|
||||
if (oConvertUtils.isEqual(expected, actual)) {
|
||||
return;
|
||||
}
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证不相同
|
||||
*
|
||||
* @param message
|
||||
* @param expected
|
||||
* @param actual
|
||||
* @author chenrui
|
||||
* @date 2018/9/12 15:45
|
||||
*/
|
||||
public static void assertNotEquals(String message, Object expected,
|
||||
Object actual) {
|
||||
if (oConvertUtils.isEqual(expected, actual)) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否相等
|
||||
*
|
||||
* @param message
|
||||
* @param expected
|
||||
* @param actual
|
||||
* @author chenrui
|
||||
* @date 2018/9/12 15:45
|
||||
*/
|
||||
public static void assertSame(String message, Object expected,
|
||||
Object actual) {
|
||||
if (expected == actual) {
|
||||
return;
|
||||
}
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证不相等
|
||||
*
|
||||
* @param message
|
||||
* @param unexpected
|
||||
* @param actual
|
||||
* @author chenrui
|
||||
* @date 2018/9/12 15:45
|
||||
*/
|
||||
public static void assertNotSame(String message, Object unexpected,
|
||||
Object actual) {
|
||||
if (unexpected == actual) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否为真
|
||||
*
|
||||
* @param message
|
||||
* @param condition
|
||||
*/
|
||||
public static void assertTrue(String message, boolean condition) {
|
||||
if (!condition) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 condition是否为false
|
||||
*
|
||||
* @param message
|
||||
* @param condition
|
||||
*/
|
||||
public static void assertFalse(String message, boolean condition) {
|
||||
assertTrue(message, !condition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证是否存在
|
||||
*
|
||||
* @param message
|
||||
* @param obj
|
||||
* @param objs
|
||||
* @param <T>
|
||||
* @throws JeecgBootAssertException
|
||||
* @author chenrui
|
||||
* @date 2018/1/31 22:14
|
||||
*/
|
||||
public static <T> void assertIn(String message, T obj, T... objs) {
|
||||
assertNotEmpty(message, obj);
|
||||
assertNotEmpty(message, objs);
|
||||
if (!oConvertUtils.isIn(obj, objs)) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否不存在
|
||||
*
|
||||
* @param message
|
||||
* @param obj
|
||||
* @param objs
|
||||
* @param <T>
|
||||
* @throws JeecgBootAssertException
|
||||
* @author chenrui
|
||||
* @date 2018/1/31 22:14
|
||||
*/
|
||||
|
||||
public static <T> void assertNotIn(String message, T obj, T... objs) {
|
||||
assertNotEmpty(message, obj);
|
||||
assertNotEmpty(message, objs);
|
||||
if (oConvertUtils.isIn(obj, objs)) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 确保src大于des
|
||||
*
|
||||
* @param message
|
||||
* @param src
|
||||
* @param des
|
||||
* @author chenrui
|
||||
* @date 2018/9/19 15:30
|
||||
*/
|
||||
public static void assertGt(String message, Number src, Number des) {
|
||||
if (oConvertUtils.isGt(src, des)) {
|
||||
return;
|
||||
}
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保src大于等于des
|
||||
*
|
||||
* @param message
|
||||
* @param src
|
||||
* @param des
|
||||
* @author chenrui
|
||||
* @date 2018/9/19 15:30
|
||||
*/
|
||||
public static void assertGe(String message, Number src, Number des) {
|
||||
if (oConvertUtils.isGe(src, des)) {
|
||||
return;
|
||||
}
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 确保src小于des
|
||||
*
|
||||
* @param message
|
||||
* @param src
|
||||
* @param des
|
||||
* @author chenrui
|
||||
* @date 2018/9/19 15:30
|
||||
*/
|
||||
public static void assertLt(String message, Number src, Number des) {
|
||||
if (oConvertUtils.isGe(src, des)) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保src小于等于des
|
||||
*
|
||||
* @param message
|
||||
* @param src
|
||||
* @param des
|
||||
* @author chenrui
|
||||
* @date 2018/9/19 15:30
|
||||
*/
|
||||
public static void assertLe(String message, Number src, Number des) {
|
||||
if (oConvertUtils.isGt(src, des)) {
|
||||
throw new JeecgBootAssertException(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -42,6 +42,7 @@ public class SsrfFileTypeFilter {
|
||||
FILE_TYPE_WHITE_LIST.add("pdf");
|
||||
FILE_TYPE_WHITE_LIST.add("csv");
|
||||
// FILE_TYPE_WHITE_LIST.add("xml");
|
||||
FILE_TYPE_WHITE_LIST.add("md");
|
||||
|
||||
//音视频文件
|
||||
FILE_TYPE_WHITE_LIST.add("mp4");
|
||||
@ -65,6 +66,10 @@ public class SsrfFileTypeFilter {
|
||||
FILE_TYPE_WHITE_LIST.add("apk");
|
||||
FILE_TYPE_WHITE_LIST.add("wgt");
|
||||
|
||||
//幻灯片文件后缀
|
||||
FILE_TYPE_WHITE_LIST.add("ppt");
|
||||
FILE_TYPE_WHITE_LIST.add("pptx");
|
||||
|
||||
//设置禁止文件的头部标记
|
||||
FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");
|
||||
FILE_TYPE_MAP.put("3c3f7068700a0a2f2a2a0a202a205048", "php");
|
||||
|
||||
@ -13,6 +13,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@ -463,7 +464,7 @@ public class oConvertUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] childs = childArray.toArray(new String[]{});
|
||||
List<String> childs = childArray.toJavaList(String.class);
|
||||
for (String v : childs) {
|
||||
if (!isIn(v, all)) {
|
||||
return false;
|
||||
@ -1028,5 +1029,109 @@ public class oConvertUtils {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断对象是否为空 <br/>
|
||||
* 支持各种类型的对象
|
||||
* for for [QQYUN-10990]AIRAG
|
||||
* @param obj
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/2/13 18:34
|
||||
*/
|
||||
public static boolean isObjectEmpty(Object obj) {
|
||||
if (null == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof CharSequence) {
|
||||
return isEmpty(obj);
|
||||
} else if (obj instanceof Map) {
|
||||
return ((Map<?, ?>) obj).isEmpty();
|
||||
} else if (obj instanceof Iterable) {
|
||||
return isObjectEmpty(((Iterable<?>) obj).iterator());
|
||||
} else if (obj instanceof Iterator) {
|
||||
return !((Iterator<?>) obj).hasNext();
|
||||
} else if (isArray(obj)) {
|
||||
return 0 == Array.getLength(obj);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* iterator 是否为空
|
||||
* for for [QQYUN-10990]AIRAG
|
||||
* @param iterator Iterator对象
|
||||
* @return 是否为空
|
||||
*/
|
||||
public static boolean isEmptyIterator(Iterator<?> iterator) {
|
||||
return null == iterator || false == iterator.hasNext();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断对象是否不为空
|
||||
* for for [QQYUN-10990]AIRAG
|
||||
* @param object
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/2/13 18:35
|
||||
*/
|
||||
public static boolean isObjectNotEmpty(Object object) {
|
||||
return !isObjectEmpty(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果src大于des返回true
|
||||
* for [QQYUN-10990]AIRAG
|
||||
* @param src
|
||||
* @param des
|
||||
* @return
|
||||
* @author: chenrui
|
||||
* @date: 2018/9/19 15:30
|
||||
*/
|
||||
public static boolean isGt(Number src, Number des) {
|
||||
if (null == src || null == des) {
|
||||
throw new IllegalArgumentException("参数不能为空");
|
||||
}
|
||||
if (src.doubleValue() > des.doubleValue()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果src大于等于des返回true
|
||||
* for [QQYUN-10990]AIRAG
|
||||
* @param src
|
||||
* @param des
|
||||
* @return
|
||||
* @author: chenrui
|
||||
* @date: 2018/9/19 15:30
|
||||
*/
|
||||
public static boolean isGe(Number src, Number des) {
|
||||
if (null == src || null == des) {
|
||||
throw new IllegalArgumentException("参数不能为空");
|
||||
}
|
||||
if (src.doubleValue() < des.doubleValue()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否存在
|
||||
* for [QQYUN-10990]AIRAG
|
||||
* @param obj
|
||||
* @param objs
|
||||
* @param <T>
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2020/9/12 15:50
|
||||
*/
|
||||
public static <T> boolean isIn(T obj, T... objs) {
|
||||
return isIn(obj, objs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,10 @@ public class JeecgBaseConfig {
|
||||
* @TODO 降低使用成本加的默认值,实际以 yml配置 为准
|
||||
*/
|
||||
private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
|
||||
/**
|
||||
* 自定义后台资源前缀,解决表单设计器无法通过前端nginx转发访问
|
||||
*/
|
||||
private String customResourcePrefixPath;
|
||||
/**
|
||||
* 需要加强校验的接口清单
|
||||
*/
|
||||
@ -68,6 +72,14 @@ public class JeecgBaseConfig {
|
||||
*/
|
||||
private BaiduApi baiduApi;
|
||||
|
||||
public String getCustomResourcePrefixPath() {
|
||||
return customResourcePrefixPath;
|
||||
}
|
||||
|
||||
public void setCustomResourcePrefixPath(String customResourcePrefixPath) {
|
||||
this.customResourcePrefixPath = customResourcePrefixPath;
|
||||
}
|
||||
|
||||
public Elasticsearch getElasticsearch() {
|
||||
return elasticsearch;
|
||||
}
|
||||
|
||||
@ -1,188 +1,182 @@
|
||||
package org.jeecg.config;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.ParameterBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.schema.ModelRef;
|
||||
import springfox.documentation.service.*;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author scott
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2WebMvc
|
||||
@Import(BeanValidatorPluginsConfiguration.class)
|
||||
public class Swagger2Config implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
*
|
||||
* 显示swagger-ui.html文档展示页,还必须注入swagger资源:
|
||||
*
|
||||
* @param registry
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
|
||||
}
|
||||
|
||||
/**
|
||||
* swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
|
||||
*
|
||||
* @return Docket
|
||||
*/
|
||||
@Bean(value = "defaultApi2")
|
||||
public Docket defaultApi2() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
//此包路径下的类,才生成接口文档
|
||||
.apis(RequestHandlerSelectors.basePackage("org.jeecg"))
|
||||
//加了ApiOperation注解的类,才生成接口文档
|
||||
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
|
||||
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
.securitySchemes(Collections.singletonList(securityScheme()))
|
||||
.securityContexts(securityContexts())
|
||||
.globalOperationParameters(setHeaderToken());
|
||||
}
|
||||
|
||||
/***
|
||||
* oauth2配置
|
||||
* 需要增加swagger授权回调地址
|
||||
* http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
SecurityScheme securityScheme() {
|
||||
return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header");
|
||||
}
|
||||
/**
|
||||
* JWT token
|
||||
* @return
|
||||
*/
|
||||
private List<Parameter> setHeaderToken() {
|
||||
ParameterBuilder tokenPar = new ParameterBuilder();
|
||||
List<Parameter> pars = new ArrayList<>();
|
||||
tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
|
||||
pars.add(tokenPar.build());
|
||||
//update-begin-author:liusq---date:2024-08-15--for: 开启多租户时,全局参数增加租户id
|
||||
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){
|
||||
ParameterBuilder tenantPar = new ParameterBuilder();
|
||||
tenantPar.name(CommonConstant.TENANT_ID).description("租户ID").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
|
||||
pars.add(tenantPar.build());
|
||||
}
|
||||
//update-end-author:liusq---date:2024-08-15--for: 开启多租户时,全局参数增加租户id
|
||||
|
||||
return pars;
|
||||
}
|
||||
|
||||
/**
|
||||
* api文档的详细信息函数,注意这里的注解引用的是哪个
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
// //大标题
|
||||
.title("JeecgBoot 后台服务API接口文档")
|
||||
// 版本号
|
||||
.version("1.0")
|
||||
// .termsOfServiceUrl("NO terms of service")
|
||||
// 描述
|
||||
.description("后台API接口")
|
||||
// 作者
|
||||
.contact(new Contact("北京国炬信息技术有限公司","www.jeccg.com","jeecgos@163.com"))
|
||||
.license("The Apache License, Version 2.0")
|
||||
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增 securityContexts 保持登录状态
|
||||
*/
|
||||
private List<SecurityContext> securityContexts() {
|
||||
return new ArrayList(
|
||||
Collections.singleton(SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.forPaths(PathSelectors.regex("^(?!auth).*$"))
|
||||
.build())
|
||||
);
|
||||
}
|
||||
|
||||
private List<SecurityReference> defaultAuth() {
|
||||
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
||||
authorizationScopes[0] = authorizationScope;
|
||||
return new ArrayList(
|
||||
Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解决springboot2.6 和springfox不兼容问题
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof WebMvcRequestHandlerProvider) {
|
||||
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
|
||||
List<T> copy = mappings.stream()
|
||||
.filter(mapping -> mapping.getPatternParser() == null)
|
||||
.collect(Collectors.toList());
|
||||
mappings.clear();
|
||||
mappings.addAll(copy);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
|
||||
try {
|
||||
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
|
||||
field.setAccessible(true);
|
||||
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//package org.jeecg.config;
|
||||
//
|
||||
//
|
||||
//import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
|
||||
//import org.jeecg.common.constant.CommonConstant;
|
||||
//import org.springframework.beans.BeansException;
|
||||
//import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.context.annotation.Import;
|
||||
//import org.springframework.util.ReflectionUtils;
|
||||
//import org.springframework.web.bind.annotation.RestController;
|
||||
//import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
//import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
//import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
|
||||
//import springfox.documentation.builders.ApiInfoBuilder;
|
||||
//import springfox.documentation.builders.ParameterBuilder;
|
||||
//import springfox.documentation.builders.PathSelectors;
|
||||
//import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
//import springfox.documentation.oas.annotations.EnableOpenApi;
|
||||
//import springfox.documentation.schema.ModelRef;
|
||||
//import springfox.documentation.service.*;
|
||||
//import springfox.documentation.spi.DocumentationType;
|
||||
//import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
//import springfox.documentation.spring.web.plugins.Docket;
|
||||
//import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
|
||||
//import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
|
||||
//import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
//
|
||||
//import java.lang.reflect.Field;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Collections;
|
||||
//import java.util.List;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
///**
|
||||
// * @Author scott
|
||||
// */
|
||||
//@Configuration
|
||||
//@EnableSwagger2 //开启 Swagger2
|
||||
//@EnableKnife4j //开启 knife4j,可以不写
|
||||
//@Import(BeanValidatorPluginsConfiguration.class)
|
||||
//public class Swagger2Config implements WebMvcConfigurer {
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * 显示swagger-ui.html文档展示页,还必须注入swagger资源:
|
||||
// *
|
||||
// * @param registry
|
||||
// */
|
||||
// @Override
|
||||
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
// registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||
// registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||
// registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
|
||||
// *
|
||||
// * @return Docket
|
||||
// */
|
||||
// @Bean(value = "defaultApi2")
|
||||
// public Docket defaultApi2() {
|
||||
// return new Docket(DocumentationType.SWAGGER_2)
|
||||
// .apiInfo(apiInfo())
|
||||
// .select()
|
||||
// //此包路径下的类,才生成接口文档
|
||||
// .apis(RequestHandlerSelectors.basePackage("org.jeecg"))
|
||||
// //加了ApiOperation注解的类,才生成接口文档
|
||||
// .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
|
||||
// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
||||
// .paths(PathSelectors.any())
|
||||
// .build()
|
||||
// .securitySchemes(Collections.singletonList(securityScheme()))
|
||||
// .securityContexts(securityContexts())
|
||||
// .globalOperationParameters(setHeaderToken());
|
||||
// }
|
||||
//
|
||||
// /***
|
||||
// * oauth2配置
|
||||
// * 需要增加swagger授权回调地址
|
||||
// * http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
|
||||
// * @return
|
||||
// */
|
||||
// @Bean
|
||||
// SecurityScheme securityScheme() {
|
||||
// return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header");
|
||||
// }
|
||||
// /**
|
||||
// * JWT token
|
||||
// * @return
|
||||
// */
|
||||
// private List<Parameter> setHeaderToken() {
|
||||
// ParameterBuilder tokenPar = new ParameterBuilder();
|
||||
// List<Parameter> pars = new ArrayList<>();
|
||||
// tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
|
||||
// pars.add(tokenPar.build());
|
||||
// return pars;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * api文档的详细信息函数,注意这里的注解引用的是哪个
|
||||
// *
|
||||
// * @return
|
||||
// */
|
||||
// private ApiInfo apiInfo() {
|
||||
// return new ApiInfoBuilder()
|
||||
// // //大标题
|
||||
// .title("JeecgBoot 后台服务API接口文档")
|
||||
// // 版本号
|
||||
// .version("1.0")
|
||||
//// .termsOfServiceUrl("NO terms of service")
|
||||
// // 描述
|
||||
// .description("后台API接口")
|
||||
// // 作者
|
||||
// .contact(new Contact("北京国炬信息技术有限公司","www.jeccg.com","jeecgos@163.com"))
|
||||
// .license("The Apache License, Version 2.0")
|
||||
// .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
|
||||
// .build();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 新增 securityContexts 保持登录状态
|
||||
// */
|
||||
// private List<SecurityContext> securityContexts() {
|
||||
// return new ArrayList(
|
||||
// Collections.singleton(SecurityContext.builder()
|
||||
// .securityReferences(defaultAuth())
|
||||
// .forPaths(PathSelectors.regex("^(?!auth).*$"))
|
||||
// .build())
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// private List<SecurityReference> defaultAuth() {
|
||||
// AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
||||
// AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
||||
// authorizationScopes[0] = authorizationScope;
|
||||
// return new ArrayList(
|
||||
// Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes)));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 解决springboot2.6 和springfox不兼容问题
|
||||
// * @return
|
||||
// */
|
||||
// @Bean
|
||||
// public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
|
||||
// return new BeanPostProcessor() {
|
||||
//
|
||||
// @Override
|
||||
// public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
// if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
|
||||
// customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
|
||||
// }
|
||||
// return bean;
|
||||
// }
|
||||
//
|
||||
// private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
|
||||
// List<T> copy = mappings.stream()
|
||||
// .filter(mapping -> mapping.getPatternParser() == null)
|
||||
// .collect(Collectors.toList());
|
||||
// mappings.clear();
|
||||
// mappings.addAll(copy);
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
|
||||
// try {
|
||||
// Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
|
||||
// field.setAccessible(true);
|
||||
// return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
|
||||
// } catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
// throw new IllegalStateException(e);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
@ -0,0 +1,102 @@
|
||||
package org.jeecg.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Contact;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
|
||||
import org.springdoc.core.filters.GlobalOpenApiMethodFilter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author eightmonth
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@PropertySource("classpath:config/default-spring-doc.properties")
|
||||
public class Swagger3Config implements WebMvcConfigurer {
|
||||
// 定义不需要注入安全要求的路径集合
|
||||
Set<String> excludedPaths = new HashSet<>(Arrays.asList(
|
||||
"/sys/randomImage/{key}",
|
||||
"/sys/login",
|
||||
"/sys/phoneLogin",
|
||||
"/sys/mLogin",
|
||||
"/sys/sms",
|
||||
"/sys/cas/client/validateLogin",
|
||||
"/test/jeecgDemo/demo3",
|
||||
"/sys/thirdLogin/**",
|
||||
"/sys/user/register"
|
||||
));
|
||||
|
||||
/**
|
||||
*
|
||||
* 显示swagger-ui.html文档展示页,还必须注入swagger资源:
|
||||
*
|
||||
* @param registry
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
|
||||
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GlobalOpenApiMethodFilter globalOpenApiMethodFilter() {
|
||||
return method -> method.isAnnotationPresent(Operation.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GlobalOpenApiCustomizer globalOpenApiCustomizer() {
|
||||
return openApi -> {
|
||||
// 全局添加鉴权参数
|
||||
if (openApi.getPaths() != null) {
|
||||
openApi.getPaths().forEach((path, pathItem) -> {
|
||||
//log.debug("path: {}", path);
|
||||
// 检查当前路径是否在排除列表中
|
||||
boolean isExcluded = excludedPaths.stream().anyMatch(excludedPath ->
|
||||
excludedPath.equals(path) ||
|
||||
(excludedPath.endsWith("**") && path.startsWith(excludedPath.substring(0, excludedPath.length() - 2)))
|
||||
);
|
||||
|
||||
if (!isExcluded) {
|
||||
// 接口添加鉴权参数
|
||||
pathItem.readOperations()
|
||||
.forEach(operation ->
|
||||
operation.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN))
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("JeecgBoot 后台服务API接口文档")
|
||||
.version("3.7.4")
|
||||
.contact(new Contact().name("北京国炬信息技术有限公司").url("www.jeccg.com").email("jeecgos@163.com"))
|
||||
.description( "后台API接口")
|
||||
.termsOfService("NO terms of service")
|
||||
.license(new License().name("Apache 2.0").url("http://www.apache.org/licenses/LICENSE-2.0.html")))
|
||||
.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN))
|
||||
.components(new Components().addSecuritySchemes(CommonConstant.X_ACCESS_TOKEN,
|
||||
new SecurityScheme().name(CommonConstant.X_ACCESS_TOKEN).type(SecurityScheme.Type.HTTP)));
|
||||
}
|
||||
}
|
||||
@ -13,13 +13,16 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
@ -37,6 +40,7 @@ import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Spring Boot 2.0 解决跨域问题
|
||||
@ -67,6 +71,8 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
|
||||
.addResourceLocations("file:" + jeecgBaseConfig.getPath().getWebapp() + "//");
|
||||
}
|
||||
resourceHandlerRegistration.addResourceLocations(staticLocations.split(","));
|
||||
// 设置缓存控制标头 Cache-Control有效期为30天
|
||||
resourceHandlerRegistration.setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,6 +150,7 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
|
||||
* 解决metrics端点不显示jvm信息的问题(zyf)
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(name = "meterRegistryPostProcessor")
|
||||
InitializingBean forcePrometheusPostProcessor(BeanPostProcessor meterRegistryPostProcessor) {
|
||||
return () -> meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, "");
|
||||
}
|
||||
|
||||
@ -60,7 +60,18 @@ public class MybatisPlusSaasConfig {
|
||||
TENANT_TABLE.add("sys_category");
|
||||
TENANT_TABLE.add("sys_data_source");
|
||||
TENANT_TABLE.add("sys_position");
|
||||
//TENANT_TABLE.add("sys_announcement");
|
||||
//b-2.仪表盘
|
||||
TENANT_TABLE.add("onl_drag_page");
|
||||
TENANT_TABLE.add("onl_drag_dataset_head");
|
||||
TENANT_TABLE.add("jimu_report_data_source");
|
||||
TENANT_TABLE.add("jimu_report");
|
||||
TENANT_TABLE.add("jimu_dict");
|
||||
//b-4.AIRAG
|
||||
TENANT_TABLE.add("airag_app");
|
||||
TENANT_TABLE.add("airag_flow");
|
||||
TENANT_TABLE.add("airag_knowledge");
|
||||
TENANT_TABLE.add("airag_knowledge_doc");
|
||||
TENANT_TABLE.add("airag_model");
|
||||
}
|
||||
|
||||
//2.示例测试
|
||||
|
||||
@ -134,7 +134,7 @@ public class ShiroConfig {
|
||||
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
||||
filterChainDefinitionMap.put("/swagger**/**", "anon");
|
||||
filterChainDefinitionMap.put("/webjars/**", "anon");
|
||||
filterChainDefinitionMap.put("/v2/**", "anon");
|
||||
filterChainDefinitionMap.put("/v3/**", "anon");
|
||||
|
||||
// update-begin--Author:sunjianlei Date:20210510 for:排除消息通告查看详情页面(用于第三方APP)
|
||||
filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon");
|
||||
@ -180,6 +180,8 @@ public class ShiroConfig {
|
||||
// 企业微信证书排除
|
||||
filterChainDefinitionMap.put("/WW_verify*", "anon");
|
||||
|
||||
filterChainDefinitionMap.put("/openapi/call/**", "anon");
|
||||
|
||||
// 添加自己的过滤器并且取名为jwt
|
||||
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
|
||||
//如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
|
||||
@ -215,6 +217,10 @@ public class ShiroConfig {
|
||||
//update-begin---author:chenrui ---date:20241202 for:[issues/7491]运行时间好长,效率慢 ------------
|
||||
registration.addUrlPatterns("/test/ai/chat/send");
|
||||
//update-end---author:chenrui ---date:20241202 for:[issues/7491]运行时间好长,效率慢 ------------
|
||||
registration.addUrlPatterns("/airag/flow/run");
|
||||
registration.addUrlPatterns("/airag/flow/debug");
|
||||
registration.addUrlPatterns("/airag/chat/send");
|
||||
registration.addUrlPatterns("/airag/app/debug");
|
||||
//支持异步
|
||||
registration.setAsyncSupported(true);
|
||||
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
|
||||
@ -314,7 +320,7 @@ public class ShiroConfig {
|
||||
|
||||
return sentinelManager;
|
||||
}
|
||||
|
||||
|
||||
// redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com
|
||||
if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) {
|
||||
RedisManager redisManager = new RedisManager();
|
||||
|
||||
@ -91,6 +91,10 @@ public class IgnoreAuthPostProcessor implements InitializingBean {
|
||||
if (bases.length > 0) {
|
||||
for (String base : bases) {
|
||||
for (String uri : uris) {
|
||||
// 如果uri包含路径占位符, 则需要将其替换为*
|
||||
if (uri.matches(".*\\{.*}.*")) {
|
||||
uri = uri.replaceAll("\\{.*?}", "*");
|
||||
}
|
||||
urls.add(prefix(base) + prefix(uri));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package org.jeecg.config.shiro.ignore;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -12,6 +14,7 @@ import java.util.List;
|
||||
public class InMemoryIgnoreAuth {
|
||||
private static final List<String> IGNORE_AUTH_LIST = new ArrayList<>();
|
||||
|
||||
private static PathMatcher MATCHER = new AntPathMatcher();
|
||||
public InMemoryIgnoreAuth() {}
|
||||
|
||||
public static void set(List<String> list) {
|
||||
@ -28,7 +31,7 @@ public class InMemoryIgnoreAuth {
|
||||
|
||||
public static boolean contains(String url) {
|
||||
for (String ignoreAuth : IGNORE_AUTH_LIST) {
|
||||
if (url.endsWith(ignoreAuth)) {
|
||||
if(MATCHER.match(ignoreAuth,url)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
springdoc.auto-tag-classes: false
|
||||
springdoc.packages-to-scan: org.jeecg
|
||||
@ -3,10 +3,10 @@ package org.jeecg.test.sqlinjection;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import org.jeecg.common.util.SqlInjectionUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -3,10 +3,10 @@ package org.jeecg.test.sqlinjection;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import org.jeecg.common.util.SqlInjectionUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -3,10 +3,10 @@ package org.jeecg.test.sqlinjection;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import org.jeecg.common.util.SqlInjectionUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -2,7 +2,7 @@ package org.jeecg.test.sqlinjection;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
|
||||
import org.jeecg.common.util.SqlInjectionUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -4,7 +4,7 @@ import net.sf.jsqlparser.JSQLParserException;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.common.util.sqlparse.JSqlParserUtils;
|
||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@ -1,17 +1,12 @@
|
||||
package org.jeecg.test.sqlparse;
|
||||
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import org.jeecg.common.util.IpUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author: scott
|
||||
* @date: 2024年04月29日 16:48
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>jeecg-boot-parent</artifactId>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<version>3.7.3</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
//update-begin---author:chenrui ---date:20240126 for:【QQYUN-7932】AI助手------------
|
||||
|
||||
/**
|
||||
* OpenAI的SSE监听
|
||||
* @author chenrui
|
||||
@ -49,7 +50,7 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
this.sseEmitter = sseEmitter;
|
||||
}
|
||||
|
||||
public OpenAISSEEventSourceListener(String topicId,SseEmitter sseEmitter){
|
||||
public OpenAISSEEventSourceListener(String topicId, SseEmitter sseEmitter){
|
||||
this.topicId = topicId;
|
||||
this.sseEmitter = sseEmitter;
|
||||
}
|
||||
@ -102,40 +103,44 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
try {
|
||||
//update-begin---author:chenrui ---date:20250207 for:[QQYUN-11102/QQYUN-11109]兼容deepseek模型,支持think标签------------
|
||||
// 兼容think标签
|
||||
Message delta = completionResponse.getChoices().get(0).getDelta();
|
||||
if (null != delta) {
|
||||
String content = delta.getContent();
|
||||
if("<think>".equals(content)){
|
||||
isThinking = true;
|
||||
content = "> ";
|
||||
delta.setContent(content);
|
||||
}
|
||||
if("</think>".equals(content)){
|
||||
isThinking = false;
|
||||
content = "\n\n";
|
||||
delta.setContent(content);
|
||||
}
|
||||
if (isThinking) {
|
||||
if (null != content && content.contains("\n")) {
|
||||
content = "\n> ";
|
||||
//update-begin---author:chenrui ---date:20250210 for:判断空,防止反悔的内容为空报错.------------
|
||||
if(null != completionResponse.getChoices()
|
||||
&& !completionResponse.getChoices().isEmpty()
|
||||
&& null != completionResponse.getChoices().get(0)) {
|
||||
//update-end---author:chenrui ---date:20250210 for:判断空,防止反悔的内容为空报错.------------
|
||||
Message delta = completionResponse.getChoices().get(0).getDelta();
|
||||
if (null != delta) {
|
||||
String content = delta.getContent();
|
||||
if ("<think>".equals(content)) {
|
||||
isThinking = true;
|
||||
content = "> ";
|
||||
delta.setContent(content);
|
||||
}
|
||||
}else {
|
||||
// 响应消息体不记录思考过程
|
||||
messageContent += null == content ? "" : content;
|
||||
if ("</think>".equals(content)) {
|
||||
isThinking = false;
|
||||
content = "\n\n";
|
||||
delta.setContent(content);
|
||||
}
|
||||
if (isThinking) {
|
||||
if (null != content && content.contains("\n")) {
|
||||
content = "\n> ";
|
||||
delta.setContent(content);
|
||||
}
|
||||
} else {
|
||||
// 响应消息体不记录思考过程
|
||||
messageContent += null == content ? "" : content;
|
||||
}
|
||||
log.info("ai-chat返回数据,发送给前端:" + content);
|
||||
sseEmitter.send(SseEmitter.event()
|
||||
.id(this.topicId)
|
||||
.data(delta)
|
||||
.reconnectTime(3000));
|
||||
}
|
||||
|
||||
|
||||
|
||||
log.info("ai-chat返回数据,发送给前端:" + content);
|
||||
sseEmitter.send(SseEmitter.event()
|
||||
.id(this.topicId)
|
||||
.data(delta)
|
||||
.reconnectTime(3000));
|
||||
}
|
||||
//update-end---author:chenrui ---date:20250207 for:[QQYUN-11102/QQYUN-11109]兼容deepseek模型,支持think标签------------
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
log.error("ai-chat返回数据,发生异常"+e.getMessage(),e);
|
||||
sseEmitter.completeWithError(e);
|
||||
eventSource.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +104,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
//超时回调
|
||||
sseEmitter.onTimeout(() -> {
|
||||
log.info("[{}]连接超时...................", uid);
|
||||
LocalCache.CACHE.remove(uid);
|
||||
});
|
||||
//异常回调
|
||||
sseEmitter.onError(
|
||||
@ -115,7 +116,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
.name("发生异常!")
|
||||
.data(Message.builder().content("发生异常请重试!").build())
|
||||
.reconnectTime(3000));
|
||||
LocalCache.CACHE.put(uid, sseEmitter);
|
||||
LocalCache.CACHE.remove(uid);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
@ -179,6 +180,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
finalMsgHistory.add(tempMessage);
|
||||
redisTemplate.opsForHash().put(cacheKey, CACHE_KEY_MSG_CONTEXT, JSONUtil.toJsonStr(finalMsgHistory));
|
||||
});
|
||||
log.info("话题:{},开始发送消息~~~", topicId);
|
||||
ChatCompletion completion = ChatCompletion
|
||||
.builder()
|
||||
.messages(msgHistory)
|
||||
|
||||
@ -8,9 +8,9 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.mgt.DefaultSecurityManager;
|
||||
@ -45,7 +45,7 @@ import java.util.List;
|
||||
* @Version:V2.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "单表DEMO")
|
||||
@Tag(name = "单表DEMO")
|
||||
@RestController
|
||||
@RequestMapping("/test/jeecgDemo")
|
||||
public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoService> {
|
||||
@ -64,7 +64,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "获取Demo数据列表", notes = "获取所有Demo数据列表")
|
||||
@Operation(summary = "获取所有Demo数据列表")
|
||||
@GetMapping(value = "/list")
|
||||
@PermissionData(pageComponent = "jeecg/JeecgDemoList")
|
||||
public Result<?> list(JeecgDemo jeecgDemo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
@ -89,7 +89,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
*/
|
||||
@PostMapping(value = "/add")
|
||||
@AutoLog(value = "添加测试DEMO")
|
||||
@ApiOperation(value = "添加DEMO", notes = "添加DEMO")
|
||||
@Operation(summary = "添加DEMO")
|
||||
public Result<?> add(@RequestBody JeecgDemo jeecgDemo) {
|
||||
jeecgDemoService.save(jeecgDemo);
|
||||
return Result.OK("添加成功!");
|
||||
@ -102,7 +102,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编辑DEMO", operateType = CommonConstant.OPERATE_TYPE_3)
|
||||
@ApiOperation(value = "编辑DEMO", notes = "编辑DEMO")
|
||||
@Operation(summary = "编辑DEMO")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||
public Result<?> edit(@RequestBody JeecgDemo jeecgDemo) {
|
||||
jeecgDemoService.updateById(jeecgDemo);
|
||||
@ -117,7 +117,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
*/
|
||||
@AutoLog(value = "删除测试DEMO")
|
||||
@DeleteMapping(value = "/delete")
|
||||
@ApiOperation(value = "通过ID删除DEMO", notes = "通过ID删除DEMO")
|
||||
@Operation(summary = "通过ID删除DEMO")
|
||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||
jeecgDemoService.removeById(id);
|
||||
return Result.OK("删除成功!");
|
||||
@ -130,7 +130,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
@ApiOperation(value = "批量删除DEMO", notes = "批量删除DEMO")
|
||||
@Operation(summary = "批量删除DEMO")
|
||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
this.jeecgDemoService.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.OK("批量删除成功!");
|
||||
@ -143,8 +143,8 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/queryById")
|
||||
@ApiOperation(value = "通过ID查询DEMO", notes = "通过ID查询DEMO")
|
||||
public Result<?> queryById(@ApiParam(name = "id", value = "示例id", required = true) @RequestParam(name = "id", required = true) String id) {
|
||||
@Operation(summary = "通过ID查询DEMO")
|
||||
public Result<?> queryById(@Parameter(name = "id", description = "示例id", required = true) @RequestParam(name = "id", required = true) String id) {
|
||||
JeecgDemo jeecgDemo = jeecgDemoService.getById(id);
|
||||
return Result.OK(jeecgDemo);
|
||||
}
|
||||
@ -477,7 +477,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
|
||||
* 测试Mono对象
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation("Mono测试")
|
||||
@Operation(summary = "Mono测试")
|
||||
@GetMapping(value ="/test")
|
||||
public Mono<String> test() {
|
||||
//解决shiro报错No SecurityManager accessible to the calling code, either bound to the org.apache.shiro
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
package org.jeecg.modules.demo.test.controller;
|
||||
|
||||
import io.lettuce.core.dynamic.annotation.Param;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
@ -21,7 +20,7 @@ import java.util.List;
|
||||
* @Date:2020-04-21
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "动态数据源测试")
|
||||
@Tag(name = "动态数据源测试")
|
||||
@RestController
|
||||
@RequestMapping("/test/dynamic")
|
||||
public class JeecgDynamicDataController extends JeecgController<JeecgDemo, IJeecgDemoService> {
|
||||
@ -37,7 +36,7 @@ public class JeecgDynamicDataController extends JeecgController<JeecgDemo, IJeec
|
||||
*/
|
||||
@PostMapping(value = "/test1")
|
||||
@AutoLog(value = "动态切换数据源")
|
||||
@ApiOperation(value = "动态切换数据源", notes = "动态切换数据源")
|
||||
@Operation(summary = "动态切换数据源")
|
||||
public Result<List<JeecgDemo>> selectSpelByKey(@RequestParam(required = false) String dsName) {
|
||||
List<JeecgDemo> list = jeecgDynamicDataService.selectSpelByKey(dsName);
|
||||
return Result.OK(list);
|
||||
|
||||
@ -3,6 +3,7 @@ package org.jeecg.modules.demo.test.entity;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.Version;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.jeecg.common.system.base.entity.JeecgEntity;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
@ -10,8 +11,6 @@ import org.springframework.format.annotation.DateTimeFormat;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
@ -25,59 +24,59 @@ import lombok.experimental.Accessors;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value="测试DEMO对象", description="测试DEMO")
|
||||
@Schema(description="测试DEMO")
|
||||
@TableName("demo")
|
||||
public class JeecgDemo extends JeecgEntity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/** 姓名 */
|
||||
@Excel(name="姓名",width=25)
|
||||
@ApiModelProperty(value = "姓名")
|
||||
@Schema(description = "姓名")
|
||||
private java.lang.String name;
|
||||
/** 关键词 */
|
||||
@ApiModelProperty(value = "关键词")
|
||||
@Schema(description = "关键词")
|
||||
@Excel(name="关键词",width=15)
|
||||
private java.lang.String keyWord;
|
||||
/** 打卡时间 */
|
||||
@ApiModelProperty(value = "打卡时间")
|
||||
@Schema(description = "打卡时间")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name="打卡时间",width=20,format="yyyy-MM-dd HH:mm:ss")
|
||||
private java.util.Date punchTime;
|
||||
/** 工资 */
|
||||
@ApiModelProperty(value = "工资",example = "0")
|
||||
@Schema(description = "工资",example = "0")
|
||||
@Excel(name="工资",type = 4,width=15)
|
||||
private java.math.BigDecimal salaryMoney;
|
||||
/** 奖金 */
|
||||
@ApiModelProperty(value = "奖金",example = "0")
|
||||
@Schema(description = "奖金",example = "0")
|
||||
@Excel(name="奖金",type = 4,width=15)
|
||||
private java.lang.Double bonusMoney;
|
||||
/** 性别 {男:1,女:2} */
|
||||
@ApiModelProperty(value = "性别")
|
||||
@Schema(description = "性别")
|
||||
@Excel(name = "性别", width = 15, dicCode = "sex")
|
||||
private java.lang.String sex;
|
||||
/** 年龄 */
|
||||
@ApiModelProperty(value = "年龄",example = "0")
|
||||
@Schema(description = "年龄",example = "0")
|
||||
@Excel(name="年龄",type = 4,width=15)
|
||||
private java.lang.Integer age;
|
||||
/** 生日 */
|
||||
@ApiModelProperty(value = "生日")
|
||||
@Schema(description = "生日")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@Excel(name="生日",format="yyyy-MM-dd")
|
||||
private java.util.Date birthday;
|
||||
/** 邮箱 */
|
||||
@ApiModelProperty(value = "邮箱")
|
||||
@Schema(description = "邮箱")
|
||||
@Excel(name="邮箱",width=30)
|
||||
private java.lang.String email;
|
||||
/** 个人简介 */
|
||||
@ApiModelProperty(value = "个人简介")
|
||||
@Schema(description = "个人简介")
|
||||
private java.lang.String content;
|
||||
/** 部门编码 */
|
||||
@Excel(name="部门编码",width=25)
|
||||
@ApiModelProperty(value = "部门编码")
|
||||
@Schema(description = "部门编码")
|
||||
private java.lang.String sysOrgCode;
|
||||
|
||||
@ApiModelProperty(value = "租户ID")
|
||||
@Schema(description = "租户ID")
|
||||
private java.lang.Integer tenantId;
|
||||
/** 乐观锁字段 */
|
||||
@Version
|
||||
|
||||
@ -26,6 +26,12 @@ public interface IJeecgDemoService extends JeecgService<JeecgDemo> {
|
||||
* @return demo对象
|
||||
*/
|
||||
public JeecgDemo getByIdCacheable(String id);
|
||||
/**
|
||||
* 通过id过去demo数据,先读缓存,在读数据库
|
||||
* @param id 数据库id
|
||||
* @return demo对象
|
||||
*/
|
||||
public JeecgDemo getByIdCacheableTTL(String id);
|
||||
|
||||
/**
|
||||
* 查询列表数据 在service中获取数据权限sql信息
|
||||
|
||||
@ -71,6 +71,22 @@ public class JeecgDemoServiceImpl extends ServiceImpl<JeecgDemoMapper, JeecgDemo
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Cacheable自定义TTL:#60(单位是秒,目前只支持这一种格式)
|
||||
* 通过注解方式,指定缓存有效期60秒
|
||||
*
|
||||
* 参考博客:https://www.cnblogs.com/h2285409/p/18324396
|
||||
*/
|
||||
@Override
|
||||
@Cacheable(cacheNames = "ceshi:redis:ttl#60", key = "#id")
|
||||
public JeecgDemo getByIdCacheableTTL(String id) {
|
||||
JeecgDemo t = jeecgDemoMapper.selectById(id);
|
||||
System.err.println("---未读缓存,读取数据库---");
|
||||
System.err.println(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IPage<JeecgDemo> queryListWithPermission(int pageSize,int pageNo) {
|
||||
Page<JeecgDemo> page = new Page<>(pageNo, pageSize);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>jeecg-system-api</artifactId>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<version>3.7.3</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>jeecg-system-api</artifactId>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<version>3.7.3</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>jeecg-module-system</artifactId>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<version>3.7.3</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-module-system</artifactId>
|
||||
<version>3.7.3</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
<!-- 企业微信/钉钉 api -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework</groupId>
|
||||
<artifactId>jeewx-api</artifactId>
|
||||
<artifactId>weixin4j</artifactId>
|
||||
</dependency>
|
||||
<!-- 积木报表 -->
|
||||
<dependency>
|
||||
|
||||
@ -26,8 +26,11 @@ public class CodeTemplateInitListener implements ApplicationListener<Application
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
try {
|
||||
log.info(" Init Code Generate Template [ 检测如果是JAR启动环境,Copy模板到config目录 ] ");
|
||||
long startTime = System.currentTimeMillis(); // 记录开始时间
|
||||
log.info(" Init Code Generate Template [ 检测如果是JAR启动,Copy模板到config目录 ] ");
|
||||
this.initJarConfigCodeGeneratorTemplate();
|
||||
long endTime = System.currentTimeMillis(); // 记录结束时间
|
||||
log.info(" Init Code Generate Template completed in " + (endTime - startTime) + " ms"); // 计算并记录耗时
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
package org.jeecg.config.init;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.tomcat.util.scan.StandardJarScanner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @Description: TomcatFactoryConfig
|
||||
* @author: scott
|
||||
* @date: 2021年01月25日 11:40
|
||||
*/
|
||||
@Configuration
|
||||
public class TomcatFactoryConfig {
|
||||
/**
|
||||
* tomcat-embed-jasper引用后提示jar找不到的问题
|
||||
*/
|
||||
@Bean
|
||||
public TomcatServletWebServerFactory tomcatFactory() {
|
||||
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory() {
|
||||
@Override
|
||||
protected void postProcessContext(Context context) {
|
||||
((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
|
||||
}
|
||||
};
|
||||
factory.addConnectorCustomizers(connector -> {
|
||||
connector.setProperty("relaxedPathChars", "[]{}");
|
||||
connector.setProperty("relaxedQueryChars", "[]{}");
|
||||
});
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
//package org.jeecg.config.init;
|
||||
//
|
||||
//import org.apache.catalina.Context;
|
||||
//import org.apache.tomcat.util.scan.StandardJarScanner;
|
||||
//import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
///**
|
||||
// * @Description: TomcatFactoryConfig
|
||||
// * @author: scott
|
||||
// * @date: 2021年01月25日 11:40
|
||||
// */
|
||||
//@Configuration
|
||||
//public class TomcatFactoryConfig {
|
||||
// /**
|
||||
// * tomcat-embed-jasper引用后提示jar找不到的问题
|
||||
// */
|
||||
// @Bean
|
||||
// public TomcatServletWebServerFactory tomcatFactory() {
|
||||
// TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory() {
|
||||
// @Override
|
||||
// protected void postProcessContext(Context context) {
|
||||
// ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
|
||||
// }
|
||||
// };
|
||||
// factory.addConnectorCustomizers(connector -> {
|
||||
// connector.setProperty("relaxedPathChars", "[]{}");
|
||||
// connector.setProperty("relaxedQueryChars", "[]{}");
|
||||
// });
|
||||
// return factory;
|
||||
// }
|
||||
//}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package org.jeecg.config.init;
|
||||
|
||||
import io.undertow.server.DefaultByteBufferPool;
|
||||
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
|
||||
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Undertow配置
|
||||
*
|
||||
* 解决启动提示: WARN io.undertow.websockets.jsr:68 - UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
|
||||
*/
|
||||
@Configuration
|
||||
public class UndertowConfiguration implements WebServerFactoryCustomizer<UndertowServletWebServerFactory>{
|
||||
|
||||
@Override
|
||||
public void customize(UndertowServletWebServerFactory factory) {
|
||||
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
|
||||
|
||||
WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
|
||||
|
||||
// 设置合理的参数
|
||||
webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 8192));
|
||||
|
||||
deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
package org.jeecg.modules.openapi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiAuth;
|
||||
import org.jeecg.modules.openapi.generator.AKSKGenerator;
|
||||
import org.jeecg.modules.openapi.service.OpenApiAuthService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:54
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/openapi/auth")
|
||||
public class OpenApiAuthController extends JeecgController<OpenApiAuth, OpenApiAuthService> {
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
* @param openApiAuth
|
||||
* @param pageNo
|
||||
* @param pageSize
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> queryPageList(OpenApiAuth openApiAuth, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
|
||||
QueryWrapper<OpenApiAuth> queryWrapper = QueryGenerator.initQueryWrapper(openApiAuth, req.getParameterMap());
|
||||
Page<OpenApiAuth> page = new Page<>(pageNo, pageSize);
|
||||
IPage<OpenApiAuth> pageList = service.page(page, queryWrapper);
|
||||
return Result.ok(pageList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param openApiAuth
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/add")
|
||||
public Result<?> add(@RequestBody OpenApiAuth openApiAuth) {
|
||||
service.save(openApiAuth);
|
||||
return Result.ok("添加成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
* @param openApiAuth
|
||||
* @return
|
||||
*/
|
||||
@PutMapping(value = "/edit")
|
||||
public Result<?> edit(@RequestBody OpenApiAuth openApiAuth) {
|
||||
service.updateById(openApiAuth);
|
||||
return Result.ok("修改成功!");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||
service.removeById(id);
|
||||
return Result.ok("删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
|
||||
this.service.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.ok("批量删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
OpenApiAuth openApiAuth = service.getById(id);
|
||||
return Result.ok(openApiAuth);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成AKSK
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("genAKSK")
|
||||
public Result<String[]> genAKSK() {
|
||||
return Result.ok(AKSKGenerator.genAKSKPair());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,386 @@
|
||||
package org.jeecg.modules.openapi.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.util.JwtUtil;
|
||||
import org.jeecg.modules.openapi.entity.OpenApi;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiAuth;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiHeader;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiParam;
|
||||
import org.jeecg.modules.openapi.generator.PathGenerator;
|
||||
import org.jeecg.modules.openapi.service.OpenApiAuthService;
|
||||
import org.jeecg.modules.openapi.service.OpenApiHeaderService;
|
||||
import org.jeecg.modules.openapi.service.OpenApiParamService;
|
||||
import org.jeecg.modules.openapi.service.OpenApiService;
|
||||
import org.jeecg.modules.openapi.swagger.*;
|
||||
import org.jeecg.modules.system.entity.SysUser;
|
||||
import org.jeecg.modules.system.service.ISysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:11
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/openapi")
|
||||
public class OpenApiController extends JeecgController<OpenApi, OpenApiService> {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Autowired
|
||||
private OpenApiParamService openApiParamService;
|
||||
@Autowired
|
||||
private OpenApiHeaderService openApiHeaderService;
|
||||
@Autowired
|
||||
private ISysUserService sysUserService;
|
||||
@Autowired
|
||||
private OpenApiAuthService openApiAuthService;
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
* @param openApi
|
||||
* @param pageNo
|
||||
* @param pageSize
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> queryPageList(OpenApi openApi, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
|
||||
QueryWrapper<OpenApi> queryWrapper = QueryGenerator.initQueryWrapper(openApi, req.getParameterMap());
|
||||
Page<OpenApi> page = new Page<>(pageNo, pageSize);
|
||||
IPage<OpenApi> pageList = service.page(page, queryWrapper);
|
||||
for (OpenApi api : pageList.getRecords()) {
|
||||
api.setParams(openApiParamService.findByApiId(api.getId()));
|
||||
api.setHeaders(openApiHeaderService.findByApiId(api.getId()));
|
||||
}
|
||||
return Result.ok(pageList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param openApi
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/add")
|
||||
public Result<?> add(@RequestBody OpenApi openApi) {
|
||||
if (service.save(openApi)) {
|
||||
if (!CollectionUtils.isEmpty(openApi.getHeaders())) {
|
||||
openApiHeaderService.saveBatch(openApi.getHeaders());
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(openApi.getParams())) {
|
||||
openApiParamService.saveBatch(openApi.getParams());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.ok("添加成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
* @param openApi
|
||||
* @return
|
||||
*/
|
||||
@PutMapping(value = "/edit")
|
||||
public Result<?> edit(@RequestBody OpenApi openApi) {
|
||||
if (service.updateById(openApi)) {
|
||||
openApiHeaderService.deleteByApiId(openApi.getId());
|
||||
openApiParamService.deleteByApiId(openApi.getId());
|
||||
|
||||
if (!CollectionUtils.isEmpty(openApi.getHeaders())) {
|
||||
openApiHeaderService.saveBatch(openApi.getHeaders());
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(openApi.getParams())) {
|
||||
openApiParamService.saveBatch(openApi.getParams());
|
||||
}
|
||||
}
|
||||
return Result.ok("修改成功!");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||
service.removeById(id);
|
||||
return Result.ok("删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
|
||||
this.service.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.ok("批量删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
OpenApi OpenApi = service.getById(id);
|
||||
return Result.ok(OpenApi);
|
||||
}
|
||||
|
||||
/**
|
||||
* 接口调用
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/call/{path}", method = {RequestMethod.GET,RequestMethod.POST})
|
||||
public Result<?> call(@PathVariable String path, @RequestBody(required = false) String json, HttpServletRequest request) {
|
||||
OpenApi openApi = service.findByPath(path);
|
||||
if (Objects.isNull(openApi)) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 404);
|
||||
result.put("data", null);
|
||||
return Result.error("失败", result);
|
||||
}
|
||||
List<OpenApiHeader> headers = openApiHeaderService.findByApiId(openApi.getId());
|
||||
|
||||
String url = openApi.getOriginUrl();
|
||||
String method = openApi.getRequestMethod();
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
for (OpenApiHeader header : headers) {
|
||||
httpHeaders.put(header.getHeaderKey(), Lists.newArrayList(request.getHeader(header.getHeaderKey())));
|
||||
}
|
||||
|
||||
String appkey = request.getHeader("appkey");
|
||||
OpenApiAuth openApiAuth = openApiAuthService.getByAppkey(appkey);
|
||||
SysUser systemUser = sysUserService.getById(openApiAuth.getSystemUserId());
|
||||
String token = JwtUtil.sign(systemUser.getUsername(), systemUser.getPassword());
|
||||
httpHeaders.put("X-Access-Token", Lists.newArrayList(token));
|
||||
|
||||
HttpEntity<String> httpEntity = new HttpEntity<>(json, httpHeaders);
|
||||
|
||||
return restTemplate.exchange(url, HttpMethod.resolve(method), httpEntity, Result.class, request.getParameterMap()).getBody();
|
||||
}
|
||||
|
||||
@GetMapping("/json")
|
||||
public SwaggerModel swaggerModel() {
|
||||
|
||||
SwaggerModel swaggerModel = new SwaggerModel();
|
||||
swaggerModel.setSwagger("2.0");
|
||||
swaggerModel.setInfo(swaggerInfo());
|
||||
swaggerModel.setHost("jeecg.com");
|
||||
swaggerModel.setBasePath("/jeecg-boot");
|
||||
swaggerModel.setSchemes(Lists.newArrayList("http", "https"));
|
||||
|
||||
SwaggerTag swaggerTag = new SwaggerTag();
|
||||
swaggerTag.setName("openapi");
|
||||
swaggerModel.setTags(Lists.newArrayList(swaggerTag));
|
||||
|
||||
pathsAndDefinitions(swaggerModel);
|
||||
|
||||
return swaggerModel;
|
||||
}
|
||||
|
||||
private void pathsAndDefinitions(SwaggerModel swaggerModel) {
|
||||
Map<String, Map<String, SwaggerOperation>> paths = new HashMap<>();
|
||||
Map<String, SwaggerDefinition> definitions = new HashMap<>();
|
||||
List<OpenApi> openapis = service.list();
|
||||
for (OpenApi openApi : openapis) {
|
||||
Map<String, SwaggerOperation> operations = new HashMap<>();
|
||||
SwaggerOperation operation = new SwaggerOperation();
|
||||
operation.setTags(Lists.newArrayList("openapi"));
|
||||
operation.setSummary(openApi.getName());
|
||||
operation.setDescription(openApi.getName());
|
||||
operation.setOperationId(openApi.getRequestUrl()+"Using"+openApi.getRequestMethod());
|
||||
operation.setProduces(Lists.newArrayList("application/json"));
|
||||
parameters(operation, openApi);
|
||||
|
||||
// body入参
|
||||
if (StringUtils.hasText(openApi.getBody())) {
|
||||
SwaggerDefinition definition = new SwaggerDefinition();
|
||||
definition.setType("object");
|
||||
Map<String, SwaggerDefinitionProperties> definitionProperties = new HashMap<>();
|
||||
definition.setProperties(definitionProperties);
|
||||
|
||||
JSONObject jsonObject = JSONObject.parseObject(openApi.getBody());
|
||||
for (Map.Entry<String, Object> properties : jsonObject.entrySet()) {
|
||||
SwaggerDefinitionProperties swaggerDefinitionProperties = new SwaggerDefinitionProperties();
|
||||
swaggerDefinitionProperties.setType("string");
|
||||
swaggerDefinitionProperties.setDescription(properties.getValue()+"");
|
||||
definitionProperties.put(properties.getKey(), swaggerDefinitionProperties);
|
||||
}
|
||||
// body的definition构建完成
|
||||
definitions.put(openApi.getRequestUrl()+"Using"+openApi.getRequestMethod()+"body", definition);
|
||||
|
||||
SwaggerOperationParameter bodyParameter = new SwaggerOperationParameter();
|
||||
bodyParameter.setDescription(openApi.getName() + " body");
|
||||
bodyParameter.setIn("body");
|
||||
bodyParameter.setName(openApi.getName() + " body");
|
||||
bodyParameter.setRequired(true);
|
||||
|
||||
Map<String, String> bodySchema = new HashMap<>();
|
||||
bodySchema.put("$ref", "#/definitions/" + openApi.getRequestUrl()+"Using"+openApi.getRequestMethod()+"body");
|
||||
bodyParameter.setSchema(bodySchema);
|
||||
|
||||
// 构建参数构建完成
|
||||
operation.getParameters().add(bodyParameter);
|
||||
|
||||
}
|
||||
|
||||
// 响应
|
||||
Map<String, SwaggerOperationResponse> responses = new HashMap<>();
|
||||
SwaggerOperationResponse resp200 = new SwaggerOperationResponse();
|
||||
resp200.setDescription("OK");
|
||||
Map<String, String> respSchema = new HashMap<>();
|
||||
respSchema.put("$ref", "#/definitions/OpenApiResult");
|
||||
resp200.setSchema(respSchema);
|
||||
|
||||
responses.put("200", resp200);
|
||||
|
||||
Map<String, String> emptySchema = new HashMap<>();
|
||||
SwaggerOperationResponse resp201 = new SwaggerOperationResponse();
|
||||
resp201.setDescription("Created");
|
||||
resp201.setSchema(emptySchema);
|
||||
responses.put("201", resp201);
|
||||
SwaggerOperationResponse resp401 = new SwaggerOperationResponse();
|
||||
resp401.setDescription("Unauthorized");
|
||||
resp401.setSchema(emptySchema);
|
||||
responses.put("401", resp401);
|
||||
SwaggerOperationResponse resp403 = new SwaggerOperationResponse();
|
||||
resp403.setDescription("Forbidden");
|
||||
resp403.setSchema(emptySchema);
|
||||
responses.put("403", resp403);
|
||||
SwaggerOperationResponse resp404 = new SwaggerOperationResponse();
|
||||
resp404.setDescription("Not Found");
|
||||
resp404.setSchema(emptySchema);
|
||||
responses.put("404", resp404);
|
||||
|
||||
// 构建响应definition
|
||||
SwaggerDefinition respDefinition = new SwaggerDefinition();
|
||||
respDefinition.setType("object");
|
||||
|
||||
Map<String, SwaggerDefinitionProperties> definitionProperties = new HashMap<>();
|
||||
respDefinition.setProperties(definitionProperties);
|
||||
|
||||
SwaggerDefinitionProperties codeProperties = new SwaggerDefinitionProperties();
|
||||
codeProperties.setType("integer");
|
||||
codeProperties.setDescription("返回代码");
|
||||
definitionProperties.put("code", codeProperties);
|
||||
SwaggerDefinitionProperties messageProperties = new SwaggerDefinitionProperties();
|
||||
messageProperties.setType("string");
|
||||
messageProperties.setDescription("返回处理消息");
|
||||
definitionProperties.put("message", messageProperties);
|
||||
SwaggerDefinitionProperties resultProperties = new SwaggerDefinitionProperties();
|
||||
resultProperties.setType("object");
|
||||
resultProperties.setDescription("返回数据对象");
|
||||
definitionProperties.put("result", resultProperties);
|
||||
SwaggerDefinitionProperties successProperties = new SwaggerDefinitionProperties();
|
||||
successProperties.setType("boolean");
|
||||
successProperties.setDescription("成功标志");
|
||||
definitionProperties.put("success", successProperties);
|
||||
SwaggerDefinitionProperties timestampProperties = new SwaggerDefinitionProperties();
|
||||
timestampProperties.setType("integer");
|
||||
timestampProperties.setDescription("时间戳");
|
||||
definitionProperties.put("timestamp", timestampProperties);
|
||||
|
||||
definitions.put("OpenApiResult", respDefinition);
|
||||
|
||||
|
||||
operation.setResponses(responses);
|
||||
operations.put(openApi.getRequestMethod().toLowerCase(), operation);
|
||||
paths.put("/openapi/call/"+openApi.getRequestUrl(), operations);
|
||||
}
|
||||
|
||||
swaggerModel.setDefinitions(definitions);
|
||||
swaggerModel.setPaths(paths);
|
||||
|
||||
}
|
||||
|
||||
private void parameters(SwaggerOperation operation, OpenApi openApi) {
|
||||
List<SwaggerOperationParameter> parameters = new ArrayList<>();
|
||||
|
||||
for (OpenApiParam openApiParam : openApiParamService.findByApiId(openApi.getId())) {
|
||||
SwaggerOperationParameter parameter = new SwaggerOperationParameter();
|
||||
parameter.setIn("path");
|
||||
parameter.setName(openApiParam.getParamKey());
|
||||
parameter.setRequired(openApiParam.getRequired() == 1);
|
||||
parameter.setDescription(openApiParam.getNote());
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
for (OpenApiHeader openApiHeader : openApiHeaderService.findByApiId(openApi.getId())) {
|
||||
SwaggerOperationParameter parameter = new SwaggerOperationParameter();
|
||||
parameter.setIn("header");
|
||||
parameter.setName(openApiHeader.getHeaderKey());
|
||||
parameter.setRequired(openApiHeader.getRequired() == 1);
|
||||
parameter.setDescription(openApiHeader.getNote());
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
operation.setParameters(parameters);
|
||||
}
|
||||
|
||||
private SwaggerInfo swaggerInfo() {
|
||||
SwaggerInfo info = new SwaggerInfo();
|
||||
|
||||
info.setDescription("OpenAPI 接口列表");
|
||||
info.setVersion("3.7.1");
|
||||
info.setTitle("OpenAPI 接口列表");
|
||||
info.setTermsOfService("https://jeecg.com");
|
||||
|
||||
SwaggerInfoContact contact = new SwaggerInfoContact();
|
||||
contact.setName("jeecg@qq.com");
|
||||
|
||||
info.setContact(contact);
|
||||
|
||||
SwaggerInfoLicense license = new SwaggerInfoLicense();
|
||||
license.setName("Apache 2.0");
|
||||
license.setUrl("http://www.apache.org/licenses/LICENSE-2.0.html");
|
||||
|
||||
info.setLicense(license);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成接口路径
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("genPath")
|
||||
public Result<String> genPath() {
|
||||
Result<String> r = new Result<String>();
|
||||
r.setSuccess(true);
|
||||
r.setCode(CommonConstant.SC_OK_200);
|
||||
r.setResult(PathGenerator.genPath());
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package org.jeecg.modules.openapi.controller;
|
||||
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.config.shiro.IgnoreAuth;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @date 2024/12/20 14:04
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/openapi/demo")
|
||||
public class OpenApiIndexController {
|
||||
|
||||
@GetMapping("index")
|
||||
@IgnoreAuth
|
||||
public Result<Map<String, String>> index() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("first", "Hello World");
|
||||
return Result.ok(result);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package org.jeecg.modules.openapi.controller;
|
||||
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiPermission;
|
||||
import org.jeecg.modules.openapi.service.OpenApiPermissionService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/openapi/permission")
|
||||
public class OpenApiPermissionController extends JeecgController<OpenApiPermission, OpenApiPermissionService> {
|
||||
|
||||
@PostMapping("add")
|
||||
public Result add(@RequestBody OpenApiPermission openApiPermission) {
|
||||
return Result.ok(service.save(openApiPermission));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
package org.jeecg.modules.openapi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiRecord;
|
||||
import org.jeecg.modules.openapi.service.OpenApiRecordService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:57
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/openapi/record")
|
||||
public class OpenApiRecordController extends JeecgController<OpenApiRecord, OpenApiRecordService> {
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
* @param openApiRecord
|
||||
* @param pageNo
|
||||
* @param pageSize
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> queryPageList(OpenApiRecord openApiRecord, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
|
||||
QueryWrapper<OpenApiRecord> queryWrapper = QueryGenerator.initQueryWrapper(openApiRecord, req.getParameterMap());
|
||||
Page<OpenApiRecord> page = new Page<>(pageNo, pageSize);
|
||||
IPage<OpenApiRecord> pageList = service.page(page, queryWrapper);
|
||||
return Result.ok(pageList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param openApiRecord
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/add")
|
||||
public Result<?> add(@RequestBody OpenApiRecord openApiRecord) {
|
||||
service.save(openApiRecord);
|
||||
return Result.ok("添加成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
* @param openApiRecord
|
||||
* @return
|
||||
*/
|
||||
@PutMapping(value = "/edit")
|
||||
public Result<?> edit(@RequestBody OpenApiRecord openApiRecord) {
|
||||
service.updateById(openApiRecord);
|
||||
return Result.ok("修改成功!");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
|
||||
service.removeById(id);
|
||||
return Result.ok("删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
|
||||
this.service.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.ok("批量删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
OpenApiRecord openApiRecord = service.getById(id);
|
||||
return Result.ok(openApiRecord);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
package org.jeecg.modules.openapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 接口表
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OpenApi implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 接口名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 请求方式,如POST、GET
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 对外开放的相对接口路径
|
||||
*/
|
||||
private String requestUrl;
|
||||
|
||||
/**
|
||||
* IP 黑名单
|
||||
*/
|
||||
private String blackList;
|
||||
|
||||
/**
|
||||
* 请求头列表
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<OpenApiHeader> headers;
|
||||
|
||||
/**
|
||||
* 请求参数列表
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<OpenApiParam> params;
|
||||
|
||||
/**
|
||||
* 目前仅支持json
|
||||
*/
|
||||
private String body;
|
||||
|
||||
/**
|
||||
* 原始接口路径
|
||||
*/
|
||||
private String originUrl;
|
||||
|
||||
/**
|
||||
* 状态(1:正常 2:废弃 )
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 删除状态(0,正常,1已删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package org.jeecg.modules.openapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 权限表
|
||||
* @date 2024/12/10 9:38
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OpenApiAuth implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5933153354153738498L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 受权名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* access key
|
||||
*/
|
||||
private String ak;
|
||||
|
||||
/**
|
||||
* secret key
|
||||
*/
|
||||
private String sk;
|
||||
|
||||
/**
|
||||
* 系统用户ID
|
||||
*/
|
||||
private String systemUserId;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package org.jeecg.modules.openapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 请求头表
|
||||
* @date 2024/12/10 14:37
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OpenApiHeader implements Serializable {
|
||||
private static final long serialVersionUID = 5032708503120184683L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 接口ID
|
||||
*/
|
||||
private String apiId;
|
||||
|
||||
/**
|
||||
* key
|
||||
*/
|
||||
private String headerKey;
|
||||
|
||||
/**
|
||||
* 是否必填(0:否,1:是)
|
||||
*/
|
||||
private Integer required;
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private String note;
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package org.jeecg.modules.openapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* query部分参数表
|
||||
* @date 2024/12/10 14:37
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OpenApiParam implements Serializable {
|
||||
private static final long serialVersionUID = -6174831468578022357L;
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 接口ID
|
||||
*/
|
||||
private String apiId;
|
||||
|
||||
/**
|
||||
* key
|
||||
*/
|
||||
private String paramKey;
|
||||
|
||||
/**
|
||||
* 是否必填(0:否,1:是)
|
||||
*/
|
||||
private Integer required;
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
private String note;
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package org.jeecg.modules.openapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @date 2024/12/19 17:41
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OpenApiPermission implements Serializable {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 接口ID
|
||||
*/
|
||||
private String apiId;
|
||||
|
||||
/**
|
||||
* 认证ID
|
||||
*/
|
||||
private String apiAuthId;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package org.jeecg.modules.openapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 调用记录表
|
||||
* @date 2024/12/10 9:41
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class OpenApiRecord implements Serializable {
|
||||
private static final long serialVersionUID = -5870384488947863579L;
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 接口ID
|
||||
*/
|
||||
private String apiId;
|
||||
|
||||
/**
|
||||
* 调用ID
|
||||
*/
|
||||
private String callAuthId;
|
||||
|
||||
/**
|
||||
* 调用时间
|
||||
*/
|
||||
private Date callTime;
|
||||
|
||||
/**
|
||||
* 耗时
|
||||
*/
|
||||
private Long usedTime;
|
||||
|
||||
/**
|
||||
* 响应时间
|
||||
*/
|
||||
private Date responseTime;
|
||||
}
|
||||
@ -0,0 +1,204 @@
|
||||
package org.jeecg.modules.openapi.filter;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.modules.openapi.entity.OpenApi;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiAuth;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiPermission;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiRecord;
|
||||
import org.jeecg.modules.openapi.service.OpenApiAuthService;
|
||||
import org.jeecg.modules.openapi.service.OpenApiPermissionService;
|
||||
import org.jeecg.modules.openapi.service.OpenApiRecordService;
|
||||
import org.jeecg.modules.openapi.service.OpenApiService;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/19 16:55
|
||||
*/
|
||||
@Slf4j
|
||||
public class ApiAuthFilter implements Filter {
|
||||
|
||||
private OpenApiRecordService openApiRecordService;
|
||||
private OpenApiAuthService openApiAuthService;
|
||||
private OpenApiPermissionService openApiPermissionService;
|
||||
private OpenApiService openApiService;
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
Date callTime = new Date();
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest)servletRequest;
|
||||
String ip = request.getRemoteAddr();
|
||||
|
||||
String appkey = request.getHeader("appkey");
|
||||
String signature = request.getHeader("signature");
|
||||
String timestamp = request.getHeader("timestamp");
|
||||
|
||||
OpenApi openApi = findOpenApi(request);
|
||||
|
||||
// IP 黑名单核验
|
||||
checkBlackList(openApi, ip);
|
||||
|
||||
// 签名核验
|
||||
checkSignValid(appkey, signature, timestamp);
|
||||
|
||||
OpenApiAuth openApiAuth = openApiAuthService.getByAppkey(appkey);
|
||||
// 认证信息核验
|
||||
checkSignature(appkey, signature, timestamp, openApiAuth);
|
||||
// 业务核验
|
||||
checkPermission(openApi, openApiAuth);
|
||||
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
OpenApiRecord record = new OpenApiRecord();
|
||||
record.setApiId(openApi.getId());
|
||||
record.setCallAuthId(openApiAuth.getId());
|
||||
record.setCallTime(callTime);
|
||||
record.setUsedTime(endTime - startTime);
|
||||
record.setResponseTime(new Date());
|
||||
openApiRecordService.save(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
ServletContext servletContext = filterConfig.getServletContext();
|
||||
WebApplicationContext applicationContext = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||
this.openApiService = applicationContext.getBean(OpenApiService.class);
|
||||
this.openApiRecordService = applicationContext.getBean(OpenApiRecordService.class);
|
||||
this.openApiAuthService = applicationContext.getBean(OpenApiAuthService.class);
|
||||
this.openApiPermissionService = applicationContext.getBean(OpenApiPermissionService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* IP 黑名单核验
|
||||
* @param openApi
|
||||
* @param ip
|
||||
*/
|
||||
protected void checkBlackList(OpenApi openApi, String ip) {
|
||||
if (!StringUtils.hasText(openApi.getBlackList())) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> blackList = Arrays.asList(openApi.getBlackList().split(","));
|
||||
if (blackList.contains(ip)) {
|
||||
throw new JeecgBootException("目标接口限制IP[" + ip + "]进行访问,IP已记录,请停止访问");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名验证
|
||||
* @param appkey
|
||||
* @param signature
|
||||
* @param timestamp
|
||||
* @return
|
||||
*/
|
||||
protected void checkSignValid(String appkey, String signature, String timestamp) {
|
||||
if (!StringUtils.hasText(appkey)) {
|
||||
throw new JeecgBootException("appkey为空");
|
||||
}
|
||||
if (!StringUtils.hasText(signature)) {
|
||||
throw new JeecgBootException("signature为空");
|
||||
}
|
||||
if (!StringUtils.hasText(timestamp)) {
|
||||
throw new JeecgBootException("timastamp时间戳为空");
|
||||
}
|
||||
if (!timestamp.matches("[0-9]*")) {
|
||||
throw new JeecgBootException("timastamp时间戳不合法");
|
||||
}
|
||||
if (System.currentTimeMillis() - Long.parseLong(timestamp) > 5 * 60 * 1000) {
|
||||
throw new JeecgBootException("signature签名已过期(超过五分钟)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证信息核验
|
||||
* @param appKey
|
||||
* @param signature
|
||||
* @param timestamp
|
||||
* @param openApiAuth
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void checkSignature(String appKey, String signature, String timestamp, OpenApiAuth openApiAuth) {
|
||||
if(openApiAuth==null){
|
||||
throw new JeecgBootException("不存在认证信息");
|
||||
}
|
||||
|
||||
if(!appKey.equals(openApiAuth.getAk())){
|
||||
throw new JeecgBootException("appkey错误");
|
||||
}
|
||||
|
||||
if (!signature.equals(md5(appKey + openApiAuth.getSk() + timestamp))) {
|
||||
throw new JeecgBootException("signature签名错误");
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPermission(OpenApi openApi, OpenApiAuth openApiAuth) {
|
||||
List<OpenApiPermission> permissionList = openApiPermissionService.findByAuthId(openApiAuth.getId());
|
||||
|
||||
boolean hasPermission = false;
|
||||
for (OpenApiPermission permission : permissionList) {
|
||||
if (permission.getApiId().equals(openApi.getId())) {
|
||||
hasPermission = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPermission) {
|
||||
throw new JeecgBootException("该appKey未授权当前接口");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String 返回类型
|
||||
* @Title: MD5
|
||||
* @Description: 【MD5加密】
|
||||
*/
|
||||
protected static String md5(String sourceStr) {
|
||||
String result = "";
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.update(sourceStr.getBytes("utf-8"));
|
||||
byte[] hash = md.digest();
|
||||
int i;
|
||||
StringBuffer buf = new StringBuffer(32);
|
||||
for (int offset = 0; offset < hash.length; offset++) {
|
||||
i = hash[offset];
|
||||
if (i < 0) {
|
||||
i += 256;
|
||||
}
|
||||
if (i < 16) {
|
||||
buf.append("0");
|
||||
}
|
||||
buf.append(Integer.toHexString(i));
|
||||
}
|
||||
result = buf.toString();
|
||||
} catch (Exception e) {
|
||||
log.error("sign签名错误", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected OpenApi findOpenApi(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
String path = uri.substring(uri.lastIndexOf("/") + 1);
|
||||
return openApiService.findByPath(path);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
System.out.println("timestamp:" + timestamp);
|
||||
System.out.println("signature:" + md5("ak-eAU25mrMxhtaZsyS" + "rjxMqB6YyUXpSHAz4DCIz8vZ5aozQQiV" + timestamp));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package org.jeecg.modules.openapi.filter;
|
||||
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @date 2024/12/19 17:09
|
||||
*/
|
||||
@Configuration
|
||||
public class ApiFilterConfig {
|
||||
|
||||
/**
|
||||
*
|
||||
* @Description: 【注册api加密过滤器】
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<ApiAuthFilter> authFilter() {
|
||||
FilterRegistrationBean<ApiAuthFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new ApiAuthFilter());
|
||||
registration.setName("apiAuthFilter");
|
||||
registration.addUrlPatterns("/openapi/call/*");
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package org.jeecg.modules.openapi.generator;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* AK/SK生成器
|
||||
*/
|
||||
public class AKSKGenerator {
|
||||
private static final String CHAR_POOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
private static final int AK_LENGTH = 16; // Adjust as per requirements
|
||||
private static final int SK_LENGTH = 32;
|
||||
|
||||
public static String[] genAKSKPair() {
|
||||
return new String[]{genAK(), genSK()};
|
||||
}
|
||||
|
||||
public static String genAK() {
|
||||
return "ak-" + generateRandomString(AK_LENGTH);
|
||||
}
|
||||
|
||||
public static String genSK() {
|
||||
return generateRandomString(SK_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
private static String generateRandomString(int length) {
|
||||
SecureRandom random = new SecureRandom();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(CHAR_POOL.charAt(random.nextInt(CHAR_POOL.length())));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package org.jeecg.modules.openapi.generator;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 10:00
|
||||
*/
|
||||
@UtilityClass
|
||||
public class PathGenerator {
|
||||
|
||||
// Base62字符集
|
||||
private static final String BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
/**
|
||||
* 生成随机路径
|
||||
* @return
|
||||
*/
|
||||
public static String genPath() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Random random = new Random();
|
||||
for (int i=0; i<8; i++) {
|
||||
result.append(BASE62.charAt(random.nextInt(62)));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package org.jeecg.modules.openapi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiAuth;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:49
|
||||
*/
|
||||
@Mapper
|
||||
public interface OpenApiAuthMapper extends BaseMapper<OpenApiAuth> {
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package org.jeecg.modules.openapi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiHeader;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 14:47
|
||||
*/
|
||||
@Mapper
|
||||
public interface OpenApiHeaderMapper extends BaseMapper<OpenApiHeader> {
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package org.jeecg.modules.openapi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.jeecg.modules.openapi.entity.OpenApi;
|
||||
|
||||
@Mapper
|
||||
public interface OpenApiMapper extends BaseMapper<OpenApi> {
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package org.jeecg.modules.openapi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiParam;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 14:48
|
||||
*/
|
||||
@Mapper
|
||||
public interface OpenApiParamMapper extends BaseMapper<OpenApiParam> {
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package org.jeecg.modules.openapi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiPermission;
|
||||
|
||||
/**
|
||||
* @date 2024/12/19 17:43
|
||||
*/
|
||||
@Mapper
|
||||
public interface OpenApiPermissionMapper extends BaseMapper<OpenApiPermission> {
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package org.jeecg.modules.openapi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiRecord;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:50
|
||||
*/
|
||||
@Mapper
|
||||
public interface OpenApiRecordMapper extends BaseMapper<OpenApiRecord> {
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package org.jeecg.modules.openapi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiAuth;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:50
|
||||
*/
|
||||
public interface OpenApiAuthService extends IService<OpenApiAuth> {
|
||||
OpenApiAuth getByAppkey(String appkey);
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package org.jeecg.modules.openapi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiHeader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 14:48
|
||||
*/
|
||||
public interface OpenApiHeaderService extends IService<OpenApiHeader> {
|
||||
|
||||
boolean deleteByApiId(String apiId);
|
||||
|
||||
List<OpenApiHeader> findByApiId(String apiId);
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package org.jeecg.modules.openapi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 14:49
|
||||
*/
|
||||
public interface OpenApiParamService extends IService<OpenApiParam> {
|
||||
boolean deleteByApiId(String apiId);
|
||||
|
||||
List<OpenApiParam> findByApiId(String apiId);
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package org.jeecg.modules.openapi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiPermission;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/19 17:44
|
||||
*/
|
||||
public interface OpenApiPermissionService extends IService<OpenApiPermission> {
|
||||
List<OpenApiPermission> findByAuthId(String authId);
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.openapi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiRecord;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:51
|
||||
*/
|
||||
public interface OpenApiRecordService extends IService<OpenApiRecord> {
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package org.jeecg.modules.openapi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.openapi.entity.OpenApi;
|
||||
|
||||
public interface OpenApiService extends IService<OpenApi> {
|
||||
OpenApi findByPath(String path);
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package org.jeecg.modules.openapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiAuth;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiAuthMapper;
|
||||
import org.jeecg.modules.openapi.service.OpenApiAuthService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:51
|
||||
*/
|
||||
@Service
|
||||
public class OpenApiAuthServiceImpl extends ServiceImpl<OpenApiAuthMapper, OpenApiAuth> implements OpenApiAuthService {
|
||||
@Override
|
||||
public OpenApiAuth getByAppkey(String appkey) {
|
||||
return baseMapper.selectOne(Wrappers.lambdaUpdate(OpenApiAuth.class).eq(OpenApiAuth::getAk, appkey), false);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package org.jeecg.modules.openapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiHeader;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiHeaderMapper;
|
||||
import org.jeecg.modules.openapi.service.OpenApiHeaderService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 14:49
|
||||
*/
|
||||
@Service
|
||||
public class OpenApiHeaderServiceImpl extends ServiceImpl<OpenApiHeaderMapper, OpenApiHeader> implements OpenApiHeaderService {
|
||||
@Override
|
||||
public boolean deleteByApiId(String apiId) {
|
||||
return baseMapper.delete(Wrappers.lambdaUpdate(OpenApiHeader.class).eq(OpenApiHeader::getApiId, apiId)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OpenApiHeader> findByApiId(String apiId) {
|
||||
return baseMapper.selectList(Wrappers.lambdaQuery(OpenApiHeader.class).eq(OpenApiHeader::getApiId, apiId));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package org.jeecg.modules.openapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiParam;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiParamMapper;
|
||||
import org.jeecg.modules.openapi.service.OpenApiParamService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 14:50
|
||||
*/
|
||||
@Service
|
||||
public class OpenApiParamServiceImpl extends ServiceImpl<OpenApiParamMapper, OpenApiParam> implements OpenApiParamService {
|
||||
@Override
|
||||
public boolean deleteByApiId(String apiId) {
|
||||
return baseMapper.delete(Wrappers.lambdaUpdate(OpenApiParam.class).eq(OpenApiParam::getApiId, apiId)) > 0;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OpenApiParam> findByApiId(String apiId) {
|
||||
return baseMapper.selectList(Wrappers.lambdaQuery(OpenApiParam.class).eq(OpenApiParam::getApiId, apiId));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package org.jeecg.modules.openapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiPermission;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiPermissionMapper;
|
||||
import org.jeecg.modules.openapi.service.OpenApiPermissionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2024/12/19 17:44
|
||||
*/
|
||||
@Service
|
||||
public class OpenApiPermissionServiceImpl extends ServiceImpl<OpenApiPermissionMapper, OpenApiPermission> implements OpenApiPermissionService {
|
||||
@Override
|
||||
public List<OpenApiPermission> findByAuthId(String authId) {
|
||||
return baseMapper.selectList(Wrappers.lambdaQuery(OpenApiPermission.class).eq(OpenApiPermission::getApiAuthId, authId));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.jeecg.modules.openapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.openapi.entity.OpenApiRecord;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiRecordMapper;
|
||||
import org.jeecg.modules.openapi.service.OpenApiRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @date 2024/12/10 9:53
|
||||
*/
|
||||
@Service
|
||||
public class OpenApiRecordServiceImpl extends ServiceImpl<OpenApiRecordMapper, OpenApiRecord> implements OpenApiRecordService {
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package org.jeecg.modules.openapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.openapi.entity.OpenApi;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiMapper;
|
||||
import org.jeecg.modules.openapi.service.OpenApiService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OpenApiServiceImpl extends ServiceImpl<OpenApiMapper, OpenApi> implements OpenApiService {
|
||||
@Override
|
||||
public OpenApi findByPath(String path) {
|
||||
return baseMapper.selectOne(Wrappers.lambdaQuery(OpenApi.class).eq(OpenApi::getRequestUrl, path), false);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:17
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerDefinition {
|
||||
private String type;
|
||||
private Map<String, SwaggerDefinitionProperties> properties;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 13:54
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerDefinitionProperties {
|
||||
private String type;
|
||||
private String example;
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:05
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerInfo {
|
||||
private String description;
|
||||
private String version;
|
||||
private String title;
|
||||
private String termsOfService;
|
||||
private SwaggerInfoContact contact;
|
||||
private SwaggerInfoLicense license;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:08
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerInfoContact {
|
||||
private String name;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:09
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerInfoLicense {
|
||||
private String name;
|
||||
private String url;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:05
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerModel {
|
||||
private String swagger;
|
||||
private SwaggerInfo info;
|
||||
private String host;
|
||||
private String basePath;
|
||||
private List<SwaggerTag> tags;
|
||||
private List<String> schemes;
|
||||
private Map<String, Map<String, SwaggerOperation>> paths;
|
||||
private Map<String, SwaggerDefinition> definitions;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:16
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerOperation {
|
||||
private List<String> tags;
|
||||
private String summary;
|
||||
private String description;
|
||||
private String operationId;
|
||||
private List<String> produces;
|
||||
private List<SwaggerOperationParameter> parameters;
|
||||
private Map<String, SwaggerOperationResponse> responses;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:43
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerOperationParameter {
|
||||
private String name;
|
||||
private String in;
|
||||
private String description;
|
||||
private Boolean required;
|
||||
private Map<String, String> schema;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:47
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerOperationResponse {
|
||||
private String description;
|
||||
private Map<String, String> schema;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:51
|
||||
*/
|
||||
public class SwaggerSchema {
|
||||
private String $ref;
|
||||
|
||||
public String get$ref() {
|
||||
return $ref;
|
||||
}
|
||||
|
||||
public void set$ref(String $ref) {
|
||||
this.$ref = $ref;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package org.jeecg.modules.openapi.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @date 2025/1/26 11:15
|
||||
*/
|
||||
@Data
|
||||
public class SwaggerTag {
|
||||
private String name;
|
||||
}
|
||||
@ -3,8 +3,8 @@ package org.jeecg.modules.quartz.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
@ -48,7 +48,7 @@ import java.util.Map;
|
||||
@RestController
|
||||
@RequestMapping("/sys/quartzJob")
|
||||
@Slf4j
|
||||
@Api(tags = "定时任务接口")
|
||||
@Tag(name = "定时任务接口")
|
||||
public class QuartzJobController {
|
||||
@Autowired
|
||||
private IQuartzJobService quartzJobService;
|
||||
@ -155,7 +155,7 @@ public class QuartzJobController {
|
||||
//@RequiresRoles("admin")
|
||||
@RequiresPermissions("system:quartzJob:pause")
|
||||
@GetMapping(value = "/pause")
|
||||
@ApiOperation(value = "停止定时任务")
|
||||
@Operation(summary = "停止定时任务")
|
||||
public Result<Object> pauseJob(@RequestParam(name = "id") String id) {
|
||||
QuartzJob job = quartzJobService.getById(id);
|
||||
if (job == null) {
|
||||
@ -174,7 +174,7 @@ public class QuartzJobController {
|
||||
//@RequiresRoles("admin")
|
||||
@RequiresPermissions("system:quartzJob:resume")
|
||||
@GetMapping(value = "/resume")
|
||||
@ApiOperation(value = "启动定时任务")
|
||||
@Operation(summary = "启动定时任务")
|
||||
public Result<Object> resumeJob(@RequestParam(name = "id") String id) {
|
||||
QuartzJob job = quartzJobService.getById(id);
|
||||
if (job == null) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package org.jeecg.modules.system.controller;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/sys/duplicate")
|
||||
@Api(tags="重复校验")
|
||||
@Tag(name="重复校验")
|
||||
public class DuplicateCheckController {
|
||||
|
||||
@Autowired
|
||||
@ -36,7 +36,7 @@ public class DuplicateCheckController {
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/check", method = RequestMethod.GET)
|
||||
@ApiOperation("重复校验接口")
|
||||
@Operation(summary ="重复校验接口")
|
||||
public Result<String> doDuplicateCheck(DuplicateCheckVo duplicateCheckVo, HttpServletRequest request) {
|
||||
log.debug("----duplicate check------:"+ duplicateCheckVo.toString());
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
@ -46,7 +46,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/sys")
|
||||
@Api(tags="用户登录")
|
||||
@Tag(name="用户登录")
|
||||
@Slf4j
|
||||
public class LoginController {
|
||||
@Autowired
|
||||
@ -70,7 +70,7 @@ public class LoginController {
|
||||
|
||||
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
|
||||
|
||||
@ApiOperation("登录接口")
|
||||
@Operation(summary = "登录接口")
|
||||
@RequestMapping(value = "/login", method = RequestMethod.POST)
|
||||
public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request){
|
||||
Result<JSONObject> result = new Result<JSONObject>();
|
||||
@ -88,8 +88,10 @@ public class LoginController {
|
||||
}
|
||||
String lowerCaseCaptcha = captcha.toLowerCase();
|
||||
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
|
||||
String origin = lowerCaseCaptcha+sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret();
|
||||
String realKey = Md5Util.md5Encode(origin, "utf-8");
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
||||
String keyPrefix = Md5Util.md5Encode(sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret(), "utf-8");
|
||||
String realKey = keyPrefix + lowerCaseCaptcha;
|
||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
||||
Object checkCode = redisUtil.get(realKey);
|
||||
//当进入登录页时,有一定几率出现验证码错误 #1714
|
||||
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
|
||||
@ -402,7 +404,7 @@ public class LoginController {
|
||||
* @param jsonObject
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation("手机号登录接口")
|
||||
@Operation(summary = "手机号登录接口")
|
||||
@PostMapping("/phoneLogin")
|
||||
public Result<JSONObject> phoneLogin(@RequestBody JSONObject jsonObject, HttpServletRequest request) {
|
||||
Result<JSONObject> result = new Result<JSONObject>();
|
||||
@ -521,7 +523,7 @@ public class LoginController {
|
||||
* @param response
|
||||
* @param key
|
||||
*/
|
||||
@ApiOperation("获取验证码")
|
||||
@Operation(summary = "获取验证码")
|
||||
@GetMapping(value = "/randomImage/{key}")
|
||||
public Result<String> randomImage(HttpServletResponse response,@PathVariable("key") String key){
|
||||
Result<String> res = new Result<String>();
|
||||
@ -533,10 +535,12 @@ public class LoginController {
|
||||
|
||||
//update-begin-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
|
||||
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
|
||||
String origin = lowerCaseCode+key+jeecgBaseConfig.getSignatureSecret();
|
||||
String realKey = Md5Util.md5Encode(origin, "utf-8");
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
||||
String keyPrefix = Md5Util.md5Encode(key+jeecgBaseConfig.getSignatureSecret(), "utf-8");
|
||||
String realKey = keyPrefix + lowerCaseCode;
|
||||
//update-end-author:taoyan date:2022-9-13 for: VUEN-2245 【漏洞】发现新漏洞待处理20220906
|
||||
|
||||
redisUtil.removeAll(keyPrefix);
|
||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
||||
redisUtil.set(realKey, lowerCaseCode, 60);
|
||||
log.info("获取验证码,Redis key = {},checkCode = {}", realKey, code);
|
||||
//返回前端
|
||||
@ -664,7 +668,7 @@ public class LoginController {
|
||||
/**
|
||||
* 登录二维码
|
||||
*/
|
||||
@ApiOperation(value = "登录二维码", notes = "登录二维码")
|
||||
@Operation(summary = "登录二维码")
|
||||
@GetMapping("/getLoginQrcode")
|
||||
public Result<?> getLoginQrcode() {
|
||||
String qrcodeId = CommonConstant.LOGIN_QRCODE_PRE+IdWorker.getIdStr();
|
||||
@ -678,7 +682,7 @@ public class LoginController {
|
||||
/**
|
||||
* 扫码二维码
|
||||
*/
|
||||
@ApiOperation(value = "扫码登录二维码", notes = "扫码登录二维码")
|
||||
@Operation(summary = "扫码登录二维码")
|
||||
@PostMapping("/scanLoginQrcode")
|
||||
public Result<?> scanLoginQrcode(@RequestParam String qrcodeId, @RequestParam String token) {
|
||||
Object check = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId);
|
||||
@ -695,7 +699,7 @@ public class LoginController {
|
||||
/**
|
||||
* 获取用户扫码后保存的token
|
||||
*/
|
||||
@ApiOperation(value = "获取用户扫码后保存的token", notes = "获取用户扫码后保存的token")
|
||||
@Operation(summary = "获取用户扫码后保存的token")
|
||||
@GetMapping("/getQrcodeToken")
|
||||
public Result getQrcodeToken(@RequestParam String qrcodeId) {
|
||||
Object token = redisUtil.get(CommonConstant.LOGIN_QRCODE_TOKEN + qrcodeId);
|
||||
|
||||
@ -4,8 +4,8 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
@ -30,7 +30,7 @@ import java.util.Arrays;
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "编码校验规则")
|
||||
@Tag(name = "编码校验规则")
|
||||
@RestController
|
||||
@RequestMapping("/sys/checkRule")
|
||||
public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCheckRuleService> {
|
||||
@ -48,7 +48,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-分页列表查询")
|
||||
@ApiOperation(value = "编码校验规则-分页列表查询", notes = "编码校验规则-分页列表查询")
|
||||
@Operation(summary = "编码校验规则-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result queryPageList(
|
||||
SysCheckRule sysCheckRule,
|
||||
@ -70,7 +70,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-通过Code校验传入的值")
|
||||
@ApiOperation(value = "编码校验规则-通过Code校验传入的值", notes = "编码校验规则-通过Code校验传入的值")
|
||||
@Operation(summary = "编码校验规则-通过Code校验传入的值")
|
||||
@GetMapping(value = "/checkByCode")
|
||||
public Result checkByCode(
|
||||
@RequestParam(name = "ruleCode") String ruleCode,
|
||||
@ -97,7 +97,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-添加")
|
||||
@ApiOperation(value = "编码校验规则-添加", notes = "编码校验规则-添加")
|
||||
@Operation(summary = "编码校验规则-添加")
|
||||
@PostMapping(value = "/add")
|
||||
public Result add(@RequestBody SysCheckRule sysCheckRule) {
|
||||
sysCheckRuleService.save(sysCheckRule);
|
||||
@ -111,7 +111,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-编辑")
|
||||
@ApiOperation(value = "编码校验规则-编辑", notes = "编码校验规则-编辑")
|
||||
@Operation(summary = "编码校验规则-编辑")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||
public Result edit(@RequestBody SysCheckRule sysCheckRule) {
|
||||
sysCheckRuleService.updateById(sysCheckRule);
|
||||
@ -125,7 +125,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-通过id删除")
|
||||
@ApiOperation(value = "编码校验规则-通过id删除", notes = "编码校验规则-通过id删除")
|
||||
@Operation(summary = "编码校验规则-通过id删除")
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result delete(@RequestParam(name = "id", required = true) String id) {
|
||||
sysCheckRuleService.removeById(id);
|
||||
@ -139,7 +139,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-批量删除")
|
||||
@ApiOperation(value = "编码校验规则-批量删除", notes = "编码校验规则-批量删除")
|
||||
@Operation(summary = "编码校验规则-批量删除")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
this.sysCheckRuleService.removeByIds(Arrays.asList(ids.split(",")));
|
||||
@ -153,7 +153,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "编码校验规则-通过id查询")
|
||||
@ApiOperation(value = "编码校验规则-通过id查询", notes = "编码校验规则-通过id查询")
|
||||
@Operation(summary = "编码校验规则-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
SysCheckRule sysCheckRule = sysCheckRuleService.getById(id);
|
||||
|
||||
@ -3,8 +3,8 @@ package org.jeecg.modules.system.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.dto.DataLogDTO;
|
||||
@ -34,7 +34,7 @@ import java.util.List;
|
||||
* @Date: 2022-07-19
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Api(tags = "系统评论回复表")
|
||||
@Tag(name = "系统评论回复表")
|
||||
@RestController
|
||||
@RequestMapping("/sys/comment")
|
||||
@Slf4j
|
||||
@ -59,7 +59,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @param sysComment
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "系统评论回复表-列表查询", notes = "系统评论回复表-列表查询")
|
||||
@Operation(summary = "系统评论回复表-列表查询")
|
||||
@GetMapping(value = "/listByForm")
|
||||
public Result<IPage<SysCommentVO>> queryListByForm(SysComment sysComment) {
|
||||
List<SysCommentVO> list = sysCommentService.queryFormCommentInfo(sysComment);
|
||||
@ -74,7 +74,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @param sysComment
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "系统评论回复表-列表查询", notes = "系统评论回复表-列表查询")
|
||||
@Operation(summary = "系统评论回复表-列表查询")
|
||||
@GetMapping(value = "/fileList")
|
||||
public Result<IPage<SysCommentFileVo>> queryFileList(SysComment sysComment) {
|
||||
List<SysCommentFileVo> list = sysCommentService.queryFormFileList(sysComment.getTableName(), sysComment.getTableDataId());
|
||||
@ -83,14 +83,14 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "系统评论表-添加文本", notes = "系统评论表-添加文本")
|
||||
@Operation(summary = "系统评论表-添加文本")
|
||||
@PostMapping(value = "/addText")
|
||||
public Result<String> addText(@RequestBody SysComment sysComment) {
|
||||
String commentId = sysCommentService.saveOne(sysComment);
|
||||
return Result.OK(commentId);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "系统评论表-添加文件", notes = "系统评论表-添加文件")
|
||||
@Operation(summary = "系统评论表-添加文件")
|
||||
@PostMapping(value = "/addFile")
|
||||
public Result<String> addFile(HttpServletRequest request) {
|
||||
try {
|
||||
@ -107,7 +107,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "系统评论表-添加文件", notes = "系统评论表-添加文件")
|
||||
@Operation(summary = "系统评论表-添加文件")
|
||||
@PostMapping(value = "/appAddFile")
|
||||
public Result<String> appAddFile(HttpServletRequest request) {
|
||||
try {
|
||||
@ -119,7 +119,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
}
|
||||
}
|
||||
|
||||
@ApiOperation(value = "系统评论回复表-通过id删除", notes = "系统评论回复表-通过id删除")
|
||||
@Operation(summary = "系统评论回复表-通过id删除")
|
||||
@DeleteMapping(value = "/deleteOne")
|
||||
public Result<String> deleteOne(@RequestParam(name = "id", required = true) String id) {
|
||||
SysComment comment = sysCommentService.getById(id);
|
||||
@ -162,7 +162,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "系统评论回复表-分页列表查询")
|
||||
@ApiOperation(value = "系统评论回复表-分页列表查询", notes = "系统评论回复表-分页列表查询")
|
||||
@Operation(summary = "系统评论回复表-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<IPage<SysComment>> queryPageList(SysComment sysComment,
|
||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@ -181,7 +181,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @param sysComment
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "系统评论回复表-添加", notes = "系统评论回复表-添加")
|
||||
@Operation(summary = "系统评论回复表-添加")
|
||||
//@RequiresPermissions("org.jeecg.modules.demo:sys_comment:add")
|
||||
@PostMapping(value = "/add")
|
||||
public Result<String> add(@RequestBody SysComment sysComment) {
|
||||
@ -196,7 +196,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "系统评论回复表-编辑")
|
||||
@ApiOperation(value = "系统评论回复表-编辑", notes = "系统评论回复表-编辑")
|
||||
@Operation(summary = "系统评论回复表-编辑")
|
||||
//@RequiresPermissions("org.jeecg.modules.demo:sys_comment:edit")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||
public Result<String> edit(@RequestBody SysComment sysComment) {
|
||||
@ -211,7 +211,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "系统评论回复表-通过id删除")
|
||||
@ApiOperation(value = "系统评论回复表-通过id删除", notes = "系统评论回复表-通过id删除")
|
||||
@Operation(summary = "系统评论回复表-通过id删除")
|
||||
//@RequiresPermissions("org.jeecg.modules.demo:sys_comment:delete")
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
||||
@ -226,7 +226,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "系统评论回复表-批量删除")
|
||||
@ApiOperation(value = "系统评论回复表-批量删除", notes = "系统评论回复表-批量删除")
|
||||
@Operation(summary = "系统评论回复表-批量删除")
|
||||
//@RequiresPermissions("org.jeecg.modules.demo:sys_comment:deleteBatch")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
@ -241,7 +241,7 @@ public class SysCommentController extends JeecgController<SysComment, ISysCommen
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "系统评论回复表-通过id查询")
|
||||
@ApiOperation(value = "系统评论回复表-通过id查询", notes = "系统评论回复表-通过id查询")
|
||||
@Operation(summary = "系统评论回复表-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<SysComment> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
SysComment sysComment = sysCommentService.getById(id);
|
||||
|
||||
@ -7,8 +7,8 @@ import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
@ -43,7 +43,7 @@ import java.util.List;
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "多数据源管理")
|
||||
@Tag(name = "多数据源管理")
|
||||
@RestController
|
||||
@RequestMapping("/sys/dataSource")
|
||||
public class SysDataSourceController extends JeecgController<SysDataSource, ISysDataSourceService> {
|
||||
@ -62,7 +62,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "多数据源管理-分页列表查询")
|
||||
@ApiOperation(value = "多数据源管理-分页列表查询", notes = "多数据源管理-分页列表查询")
|
||||
@Operation(summary = "多数据源管理-分页列表查询")
|
||||
@RequiresPermissions("system:datasource:list")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> queryPageList(
|
||||
@ -111,7 +111,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "多数据源管理-添加")
|
||||
@ApiOperation(value = "多数据源管理-添加", notes = "多数据源管理-添加")
|
||||
@Operation(summary = "多数据源管理-添加")
|
||||
@PostMapping(value = "/add")
|
||||
public Result<?> add(@RequestBody SysDataSource sysDataSource) {
|
||||
//update-begin-author:taoyan date:2022-8-10 for: jdbc连接地址漏洞问题
|
||||
@ -132,7 +132,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "多数据源管理-编辑")
|
||||
@ApiOperation(value = "多数据源管理-编辑", notes = "多数据源管理-编辑")
|
||||
@Operation(summary = "多数据源管理-编辑")
|
||||
@RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
|
||||
public Result<?> edit(@RequestBody SysDataSource sysDataSource) {
|
||||
//update-begin-author:taoyan date:2022-8-10 for: jdbc连接地址漏洞问题
|
||||
@ -153,7 +153,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "多数据源管理-通过id删除")
|
||||
@ApiOperation(value = "多数据源管理-通过id删除", notes = "多数据源管理-通过id删除")
|
||||
@Operation(summary = "多数据源管理-通过id删除")
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<?> delete(@RequestParam(name = "id") String id) {
|
||||
return sysDataSourceService.deleteDataSource(id);
|
||||
@ -166,7 +166,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "多数据源管理-批量删除")
|
||||
@ApiOperation(value = "多数据源管理-批量删除", notes = "多数据源管理-批量删除")
|
||||
@Operation(summary = "多数据源管理-批量删除")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<?> deleteBatch(@RequestParam(name = "ids") String ids) {
|
||||
List<String> idList = Arrays.asList(ids.split(","));
|
||||
@ -185,7 +185,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "多数据源管理-通过id查询")
|
||||
@ApiOperation(value = "多数据源管理-通过id查询", notes = "多数据源管理-通过id查询")
|
||||
@Operation(summary = "多数据源管理-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<?> queryById(@RequestParam(name = "id") String id) throws InterruptedException {
|
||||
SysDataSource sysDataSource = sysDataSourceService.getById(id);
|
||||
|
||||
@ -15,6 +15,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.util.JwtUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.common.util.ImportExcelUtil;
|
||||
import org.jeecg.common.util.RedisUtil;
|
||||
import org.jeecg.common.util.YouBianCodeUtil;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||
@ -65,6 +66,8 @@ public class SysDepartController {
|
||||
private ISysUserService sysUserService;
|
||||
@Autowired
|
||||
private ISysUserDepartService sysUserDepartService;
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
/**
|
||||
* 查询数据 查出我的部门,并以树结构数据格式响应给前端
|
||||
*
|
||||
@ -470,8 +473,8 @@ public class SysDepartController {
|
||||
//update-end---author:wangshuai---date:2023-10-19---for:【QQYUN-5482】系统的部门导入导出也可以改成敲敲云模式的部门路径---
|
||||
|
||||
//清空部门缓存
|
||||
Set keys3 = redisTemplate.keys(CacheConstant.SYS_DEPARTS_CACHE + "*");
|
||||
Set keys4 = redisTemplate.keys(CacheConstant.SYS_DEPART_IDS_CACHE + "*");
|
||||
List<String> keys3 = redisUtil.scan(CacheConstant.SYS_DEPARTS_CACHE + "*");
|
||||
List<String> keys4 = redisUtil.scan(CacheConstant.SYS_DEPART_IDS_CACHE + "*");
|
||||
redisTemplate.delete(keys3);
|
||||
redisTemplate.delete(keys4);
|
||||
return ImportExcelUtil.imporReturnRes(errorMessageList.size(), listSysDeparts.size() - errorMessageList.size(), errorMessageList);
|
||||
@ -664,8 +667,8 @@ public class SysDepartController {
|
||||
listSysDeparts = ExcelImportUtil.importExcel(file.getInputStream(), ExportDepartVo.class, params);
|
||||
sysDepartService.importExcel(listSysDeparts,errorMessageList);
|
||||
//清空部门缓存
|
||||
Set keys3 = redisTemplate.keys(CacheConstant.SYS_DEPARTS_CACHE + "*");
|
||||
Set keys4 = redisTemplate.keys(CacheConstant.SYS_DEPART_IDS_CACHE + "*");
|
||||
List<String> keys3 = redisUtil.scan(CacheConstant.SYS_DEPARTS_CACHE + "*");
|
||||
List<String> keys4 = redisUtil.scan(CacheConstant.SYS_DEPART_IDS_CACHE + "*");
|
||||
redisTemplate.delete(keys3);
|
||||
redisTemplate.delete(keys4);
|
||||
return ImportExcelUtil.imporReturnRes(errorMessageList.size(), listSysDeparts.size() - errorMessageList.size(), errorMessageList);
|
||||
|
||||
@ -8,6 +8,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
@ -34,8 +36,6 @@ import org.jeecg.modules.system.service.ISysPermissionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* @Description: 部门权限表
|
||||
@ -44,7 +44,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags="部门权限表")
|
||||
@Tag(name="部门权限表")
|
||||
@RestController
|
||||
@RequestMapping("/sys/sysDepartPermission")
|
||||
public class SysDepartPermissionController extends JeecgController<SysDepartPermission, ISysDepartPermissionService> {
|
||||
@ -72,7 +72,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门权限表-分页列表查询", notes="部门权限表-分页列表查询")
|
||||
@Operation(summary ="部门权限表-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> queryPageList(SysDepartPermission sysDepartPermission,
|
||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||
@ -90,7 +90,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
||||
* @param sysDepartPermission
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门权限表-添加", notes="部门权限表-添加")
|
||||
@Operation(summary ="部门权限表-添加")
|
||||
@PostMapping(value = "/add")
|
||||
public Result<?> add(@RequestBody SysDepartPermission sysDepartPermission) {
|
||||
sysDepartPermissionService.save(sysDepartPermission);
|
||||
@ -103,7 +103,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
||||
* @param sysDepartPermission
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门权限表-编辑", notes="部门权限表-编辑")
|
||||
@Operation(summary ="部门权限表-编辑")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||
public Result<?> edit(@RequestBody SysDepartPermission sysDepartPermission) {
|
||||
sysDepartPermissionService.updateById(sysDepartPermission);
|
||||
@ -116,7 +116,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门权限表-通过id删除", notes="部门权限表-通过id删除")
|
||||
@Operation(summary ="部门权限表-通过id删除")
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
||||
sysDepartPermissionService.removeById(id);
|
||||
@ -129,7 +129,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门权限表-批量删除", notes="部门权限表-批量删除")
|
||||
@Operation(summary ="部门权限表-批量删除")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||
this.sysDepartPermissionService.removeByIds(Arrays.asList(ids.split(",")));
|
||||
@ -142,7 +142,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门权限表-通过id查询", notes="部门权限表-通过id查询")
|
||||
@Operation(summary ="部门权限表-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
|
||||
SysDepartPermission sysDepartPermission = sysDepartPermissionService.getById(id);
|
||||
|
||||
@ -8,6 +8,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
@ -29,8 +31,6 @@ import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
/**
|
||||
* @Description: 部门角色
|
||||
@ -39,7 +39,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags="部门角色")
|
||||
@Tag(name="部门角色")
|
||||
@RestController
|
||||
@RequestMapping("/sys/sysDepartRole")
|
||||
public class SysDepartRoleController extends JeecgController<SysDepartRole, ISysDepartRoleService> {
|
||||
@ -70,7 +70,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门角色-分页列表查询", notes="部门角色-分页列表查询")
|
||||
@Operation(summary = "部门角色-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<?> queryPageList(SysDepartRole sysDepartRole,
|
||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||
@ -111,7 +111,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
||||
* @return
|
||||
*/
|
||||
@RequiresPermissions("system:depart:role:add")
|
||||
@ApiOperation(value="部门角色-添加", notes="部门角色-添加")
|
||||
@Operation(summary ="部门角色-添加")
|
||||
@PostMapping(value = "/add")
|
||||
public Result<?> add(@RequestBody SysDepartRole sysDepartRole) {
|
||||
sysDepartRoleService.save(sysDepartRole);
|
||||
@ -124,7 +124,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
||||
* @param sysDepartRole
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门角色-编辑", notes="部门角色-编辑")
|
||||
@Operation(summary ="部门角色-编辑")
|
||||
@RequiresPermissions("system:depart:role:edit")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
||||
public Result<?> edit(@RequestBody SysDepartRole sysDepartRole) {
|
||||
@ -139,7 +139,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "部门角色-通过id删除")
|
||||
@ApiOperation(value="部门角色-通过id删除", notes="部门角色-通过id删除")
|
||||
@Operation(summary ="部门角色-通过id删除")
|
||||
@RequiresPermissions("system:depart:role:delete")
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<?> delete(@RequestParam(name="id",required=true) String id) {
|
||||
@ -154,7 +154,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "部门角色-批量删除")
|
||||
@ApiOperation(value="部门角色-批量删除", notes="部门角色-批量删除")
|
||||
@Operation(summary ="部门角色-批量删除")
|
||||
@RequiresPermissions("system:depart:role:deleteBatch")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||
@ -169,7 +169,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value="部门角色-通过id查询", notes="部门角色-通过id查询")
|
||||
@Operation(summary ="部门角色-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
|
||||
SysDepartRole sysDepartRole = sysDepartRoleService.getById(id);
|
||||
|
||||
@ -7,8 +7,8 @@ import java.util.Date;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
@ -40,7 +40,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @Author zhangweijian
|
||||
* @since 2018-12-28
|
||||
*/
|
||||
@Api(tags = "数据字典")
|
||||
@Tag(name = "数据字典")
|
||||
@RestController
|
||||
@RequestMapping("/sys/dictItem")
|
||||
@Slf4j
|
||||
@ -162,7 +162,7 @@ public class SysDictItemController {
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/dictItemCheck", method = RequestMethod.GET)
|
||||
@ApiOperation("字典重复校验接口")
|
||||
@Operation(summary ="字典重复校验接口")
|
||||
public Result<Object> doDictItemCheck(SysDictItem sysDictItem, HttpServletRequest request) {
|
||||
Long num = Long.valueOf(0);
|
||||
LambdaQueryWrapper<SysDictItem> queryWrapper = new LambdaQueryWrapper<SysDictItem>();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user