mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
180 Commits
v3.7.1last
...
v3.7.4
| 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 | |||
| 5753f3d1d9 | |||
| 46fb1cce91 | |||
| d0487e7a9d | |||
| b8c096eee5 | |||
| c84f62e418 | |||
| c2107ee74a | |||
| 48a9ba6253 | |||
| 1a4abfc89c | |||
| 9550c15d56 | |||
| 229256738a | |||
| 781432c678 | |||
| a4fba72da5 | |||
| 65f90ea84a | |||
| b8ef121fe7 | |||
| d6c6a1c01f | |||
| 7257dfe5ba | |||
| 18166a3c69 | |||
| 54abb67303 | |||
| 84f46c2142 | |||
| 63d60092dc | |||
| dd9ec47cdb | |||
| 49ce9e0763 | |||
| a7089b7b16 | |||
| 53f8c0c076 | |||
| 6ad8c3d824 | |||
| 6947f47bd3 | |||
| 973804189e | |||
| 1942980154 | |||
| 64b852e1c6 | |||
| 0277a968f2 | |||
| 79ca5ebf96 | |||
| 84a7ce9b7a | |||
| ab2469ff98 | |||
| 8fc27bb261 | |||
| d9737c891f | |||
| 17dc1916aa | |||
| a00e4684b5 | |||
| a2a3ff6709 | |||
| 266f49e72f | |||
| 6be0f94ddc | |||
| 7159df8d18 | |||
| b4cd341abc | |||
| 327f034640 | |||
| 00b1250901 | |||
| 964e9b3851 | |||
| 9c5e71476f | |||
| 80a54746b1 | |||
| 9861e1a867 | |||
| 5b2ac82e94 | |||
| c5909cae34 | |||
| b0880c373b | |||
| 2b0bedd263 | |||
| ac30ed67bc | |||
| ee382c0a5b | |||
| f7f6d0ff88 | |||
| 4d058e1dce | |||
| 5c9c2dbebe | |||
| 44f7075316 | |||
| c88bfcf35a | |||
| 11d13c8305 | |||
| 0582436b9c | |||
| 00252f392f | |||
| ef16814216 | |||
| a626b6a4d0 | |||
| fca5d0e54e | |||
| 1c3b9a10f1 | |||
| b0c4194602 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -3,3 +3,4 @@
|
||||
*.ts linguist-language=vue
|
||||
*.html linguist-language=vue
|
||||
*.sql linguist-language=Java
|
||||
*.ftl linguist-language=Java
|
||||
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
name: 提交 Bug
|
||||
about: 请告诉我框架存在的问题,我会协助你解决此问题!
|
||||
labels: bug
|
||||
assignees: getActivity
|
||||
|
||||
---
|
||||
|
||||
|
||||
##### 版本号:
|
||||
|
||||
|
||||
##### 问题描述:
|
||||
|
||||
|
||||
|
||||
##### 错误截图:
|
||||
|
||||
|
||||
|
||||
|
||||
#### 友情提示:
|
||||
- 未按格式要求发帖、描述过于简单的,会被直接删掉;
|
||||
- 描述问题请图文并茂,方便我们理解并快速定位问题;
|
||||
- 如果使用的不是master,请说明你使用的分支;
|
||||
@ -1,3 +1,12 @@
|
||||
---
|
||||
name: 提交建议
|
||||
about: 请告诉我框架的不足之处,让我做得更好!
|
||||
labels: help wanted
|
||||
assignees: getActivity
|
||||
|
||||
---
|
||||
|
||||
|
||||
##### 版本号:
|
||||
|
||||
|
||||
@ -13,4 +22,4 @@
|
||||
#### 友情提示:
|
||||
- 未按格式要求发帖、描述过于简单的,会被直接删掉;
|
||||
- 描述问题请图文并茂,方便我们理解并快速定位问题;
|
||||
- 如果使用的不是master,请说明你使用的分支;
|
||||
- 如果使用的不是master,请说明你使用的分支;
|
||||
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智能回复,你可以搭建自己的智能体,比如搭建一个 “诗词达人” “翻译助手”
|
||||
|
||||

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

|
||||
65
README-EN.md
65
README-EN.md
@ -4,15 +4,15 @@
|
||||
|
||||
|
||||
|
||||
JEECG BOOT Low Code Development Platform
|
||||
JEECG BOOT AI Low Code Platform
|
||||
===============
|
||||
|
||||
Current version: 3.7.1 (Release date: 2024-09-12)
|
||||
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)
|
||||
|
||||
@ -21,9 +21,9 @@ Current version: 3.7.1 (Release date: 2024-09-12)
|
||||
Project introduction
|
||||
-----------------------------------
|
||||
|
||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||
<h3 align="center">Java AI Low Code Platform for Enterprise web applications</h3>
|
||||
|
||||
JeecgBoot is a `low code development platform` based on code `generators`! Front and back end separation architecture SpringBoot2.x, SpringCloud, Ant Design&Vue, Mybatis plus, Shiro, JWT, support for microservices. The powerful code generator makes the front and back end of the code generation, low code development! JeecgBoot leads a new low-code development paradigm (OnlineCoding-> Code Generator -> Manual MERGE) that helps resolve 70% of the duplication in Java projects and makes development more business-focused. Not only can quickly improve efficiency, save research and development costs, but also do not lose flexibility!
|
||||
JeecgBoot is a `AI low code platform` based on code `generators`! Front and back end separation architecture SpringBoot2.x, SpringCloud, Ant Design&Vue, Mybatis plus, Shiro, JWT, support for microservices. The powerful code generator makes the front and back end of the code generation, low code development! JeecgBoot leads a new low-code development paradigm (OnlineCoding-> Code Generator -> Manual MERGE) that helps resolve 70% of the duplication in Java projects and makes development more business-focused. Not only can quickly improve efficiency, save research and development costs, but also do not lose flexibility!
|
||||
|
||||
JeecgBoot provides a series of low code modules to make Online development truly zero code: Online form development, online reports, report configuration capabilities, online chart design, large screen design, mobile configuration capabilities, form designer, online design flow, process automation configuration, plug-in capabilities (pluggable) and more!
|
||||
|
||||
@ -32,11 +32,12 @@ The purpose of JEECG is: simple functions are implemented by OnlineCoding config
|
||||
|
||||
JEECG Business process: Using workflow to implement and extend the task interface for developing and writing business logic, forms provides a variety of solutions: form designer, online configuration form, and coding form. At the same time, the separation design of process and form (loose coupling) is realized, and the flexible configuration of task nodes is supported, which not only ensures the confidentiality of the company's process, but also reduces the workload of developers.
|
||||
|
||||
AI Empowering Low-Code: Currently, JeecgBoot supports AI large models such as ChatGPT and DeepSeek. The latest version defaults to using DeepSeek, which offers faster speed and higher quality. It now provides features such as AI chat assistant, AI table creation, and AI report generation.
|
||||
|
||||
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
|
||||
@ -48,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
|
||||
-----------------------------------
|
||||
@ -57,14 +63,14 @@ Download other source code
|
||||
|
||||
For the project
|
||||
-----------------------------------
|
||||
Jeecg-Boot low code development platform can be applied in the development of any J2EE project, especially for SAAS projects, enterprise information management system (MIS), internal office system (OA), enterprise resource planning system (ERP), customer relationship management system (CRM), etc. Its semi-intelligent manual Merge development method, Can significantly improve the development efficiency of more than 70%, greatly reduce the development cost.
|
||||
Jeecg-Boot AI low code platform can be applied in the development of any J2EE project, especially for SAAS projects, enterprise information management system (MIS), internal office system (OA), enterprise resource planning system (ERP), customer relationship management system (CRM), etc. Its semi-intelligent manual Merge development method, Can significantly improve the development efficiency of more than 70%, greatly reduce the development cost.
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@ -73,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: [http://help.jeecg.com](http://help.jeecg.com)
|
||||
- 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
|
||||
|
||||
|
||||
|
||||
@ -175,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)
|
||||
|
||||
@ -192,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.8.1
|
||||
- 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
|
||||
|
||||
@ -216,9 +222,11 @@ Technical Architecture:
|
||||
#### Front-end environment requirements
|
||||
|
||||
* `Node.js 、npm 、pnpm`
|
||||
* pnpm `v9+` is now required.
|
||||
* Node.js Version suggestion: `v20.15.0`
|
||||
` ( Since Vite5 no longer supports EOL Node.js 14/16/17/19, Node.js 18/20 + is now required )`
|
||||
` ( Since Vite6 Node.js 18/20 + is now required )`
|
||||
|
||||
|
||||
#### Support library
|
||||
|
||||
| database | support |
|
||||
@ -233,6 +241,23 @@ Technical Architecture:
|
||||
| TiDB | √ |
|
||||
|
||||
|
||||
#### AI Support
|
||||
|
||||
| AI Model | Supported |
|
||||
| --- | --- |
|
||||
| DeepSeek | √ |
|
||||
| ChatGPT | √ |
|
||||
| Qwq | √ |
|
||||
| 智库 | √ |
|
||||
| Ollama本地搭建大模型 | √ |
|
||||
| 等等。。 | √ |
|
||||
|
||||
|
||||
AI Config: https://help.jeecg.com/java/ai/aichat
|
||||
|
||||
AI APP: https://help.jeecg.com/aigc
|
||||
|
||||
|
||||
## Microservice solutions
|
||||
|
||||
- 1. Service registration and discovery Nacos √
|
||||
@ -243,7 +268,7 @@ Technical Architecture:
|
||||
- 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
|
||||
@ -260,8 +285,8 @@ Technical Architecture:
|
||||

|
||||
|
||||
### 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
|
||||
|
||||
168
README.md
168
README.md
@ -1,13 +1,13 @@
|
||||
|
||||
JeecgBoot 低代码开发平台
|
||||
JeecgBoot AI低代码平台
|
||||
===============
|
||||
|
||||
当前最新版本: 3.7.1(发布日期:2024-09-12)
|
||||
当前最新版本: 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)
|
||||
|
||||
@ -16,61 +16,110 @@ JeecgBoot 低代码开发平台
|
||||
项目介绍
|
||||
-----------------------------------
|
||||
|
||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||
<h3 align="center">Java AI Low Code Platform for Enterprise web applications</h3>
|
||||
|
||||
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.x,SpringCloud,Ant Design Vue3,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot集成AI模型能力,引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||
JeecgBoot 是一款基于`BPM`和`代码生成器`的 AI低代码平台!前后端分离架构 SpringBoot2.x/3.x,SpringCloud,Ant Design Vue3,Mybatis-plus,Shiro,JWT,支持微服务、多租户;支持 AI 大模型 DeepSeek 和 ChatGPT、Ollama本地模型; 强大的代码生成器让前后端代码一键生成,无需写任何代码! JeecgBoot 引领 AI 低代码开发模式(AI生成-> OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目80%的重复工作,让开发更多关注业务。既能快速提高效率,节省成本,同时又不失灵活性!AIGC能力:AI对话助手、AI建表、AI写文章、AI流程编排、AI知识库问答等等.
|
||||
|
||||
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、仪表盘设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||
JeecgBoot 提供了一系列 `AI能力` `低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、仪表盘设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)、AI对话助手,AI建表、AI写文章、AI流程编排、AI知识库问答、AI赋能低代码等等!
|
||||
|
||||
|
||||
`JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`;复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
|
||||
|
||||
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
||||
|
||||
`AI赋能低代码:` 目前JeecgBoot支持AI大模型`ChatGPT`和`DeepSeek`,现在最新版默认使用`DeepSeek`,速度更快质量更高。目前提供了AI对话助手、AI建表、AI报表、AI写文章、AI流程编排、AI知识库问答等功能。
|
||||
|
||||
|
||||
### 视频介绍
|
||||
|
||||
[](https://www.bilibili.com/video/BV1Nk4y1o7Qc)
|
||||
|
||||
|
||||
适用项目
|
||||
-----------------------------------
|
||||
Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,支持信创国产化(默认适配达梦和人大金仓)。尤其适合SAAS项目、企业信息管理系统(MIS)、内部办公系统(OA)、企业资源计划系统(ERP)、客户关系管理系统(CRM)等,其半智能手工Merge的开发方式,可以显著提高开发效率70%以上,极大降低开发成本。
|
||||
JeecgBoot AI低代码平台,可以应用在任何J2EE项目的开发中,支持信创国产化(默认适配达梦和人大金仓)。尤其适合SAAS项目、企业信息管理系统(MIS)、内部办公系统(OA)、企业资源计划系统(ERP)、客户关系管理系统(CRM)等,其半智能手工Merge的开发方式,可以显著提高开发效率70%以上,极大降低开发成本。
|
||||
|
||||
|
||||
#### 项目说明
|
||||
|
||||
项目说明
|
||||
-----------------------------------
|
||||
|
||||
| 项目名 | 说明 |
|
||||
|--------------------|------------------------|
|
||||
| `jeecg-boot` | 后端源码JAVA(SpringBoot微服务架构) |
|
||||
| `jeecgboot-vue3` | 前端源码VUE3(vue3+vite5+ts最新技术栈) |
|
||||
| `jeecg-uniapp` | [配套APP框架](https://github.com/jeecgboot/jeecg-uniapp) 适配多个终端,支持APP、小程序、H5 |
|
||||
| `jeecgboot-vue3` | 前端源码VUE3(vue3+vite6+ts最新技术栈) |
|
||||
| `JeecgUniapp` | [配套APP框架](https://github.com/jeecgboot/JeecgUniapp) 适配多个终端,支持APP、小程序、H5 |
|
||||
|
||||
|
||||
开源协议说明
|
||||
-----------------------------------
|
||||
JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0协议,详细见 https://github.com/jeecgboot/JeecgBoot#Apache-2.0-1-ov-file
|
||||
|
||||
开源协议中文释意如下:
|
||||
- 1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
- 2.允许基于本平台软件开展业务系统开发。
|
||||
- 3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
- 4.针对企业用户我们也提供“企业级版本”,详细见 https://jeecg.com/vip
|
||||
|
||||
|
||||
技术文档
|
||||
-----------------------------------
|
||||
|
||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
- 开发文档: [https://help.jeecg.com](https://help.jeecg.com)
|
||||
- 反馈问题: [在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应用平台介绍
|
||||
-----------------------------------
|
||||
|
||||
> 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大模型 | 支持 |
|
||||
| --- | --- |
|
||||
| DeepSeek | √ |
|
||||
| ChatGTP | √ |
|
||||
| Qwq | √ |
|
||||
| 智库 | √ |
|
||||
| Ollama本地模型 | √ |
|
||||
| 等等。。 | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
技术架构:
|
||||
@ -79,15 +128,16 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
#### 后端
|
||||
|
||||
- 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.8.1
|
||||
- 安全框架: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
|
||||
- 其他:autopoi, fastjson,poi,Swagger-ui,quartz, lombok(简化代码)等。
|
||||
@ -98,20 +148,23 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
#### 前端
|
||||
|
||||
- 前端IDE建议:WebStorm、Vscode
|
||||
- 采用 Vue3.0+TypeScript+Vite5+Ant-Design-Vue等新技术方案,包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
|
||||
- 最新技术栈:Vue3.0 + TypeScript + Vite5 + ant-design-vue4 + pinia + echarts + unocss + vxe-table + qiankun + es6
|
||||
- 采用 Vue3.0+TypeScript+Vite6+Ant-Design-Vue等新技术方案,包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
|
||||
- 最新技术栈:Vue3.0 + TypeScript + Vite6 + ant-design-vue4 + pinia + echarts + unocss + vxe-table + qiankun + es6
|
||||
- 依赖管理:node、npm、pnpm
|
||||
|
||||
|
||||
#### 前端环境要求
|
||||
|
||||
* 本地环境安装 `Node.js 、npm 、pnpm`
|
||||
* pnpm 要求`9+` 版本以上
|
||||
* Node.js 版本建议`v20.15.0`,要求`Node 20+` 版本以上
|
||||
|
||||
` ( 因为Vite5 不再支持已 EOL 的 Node.js 14 / 16 / 17 / 19,现在需要 Node.js 18 / 20+ )`
|
||||
` ( 因为Vite6 需要 Node.js 18 / 20+ )`
|
||||
|
||||
|
||||
#### 支持库
|
||||
#### 平台支持数据库
|
||||
|
||||
> jeecgboot平台支持以下数据库,默认我们只提供mysql脚本,其他数据库可以参考[转库文档](https://my.oschina.net/jeecg/blog/4905722)自己转。
|
||||
|
||||
| 数据库 | 支持 |
|
||||
| --- | --- |
|
||||
@ -120,10 +173,11 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
| Sqlserver2017 | √ |
|
||||
| PostgreSQL | √ |
|
||||
| MariaDB | √ |
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
| TiDB | √ |
|
||||
| kingbase8 | √ |
|
||||
|
||||
|
||||
|
||||
## 微服务解决方案
|
||||
@ -137,7 +191,7 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
- 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
|
||||
@ -149,8 +203,8 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
|
||||
#### 微服务方式启动
|
||||
|
||||
- [单体快速切换微服务](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)
|
||||
|
||||
|
||||
#### 微服务架构图
|
||||
@ -165,9 +219,9 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;引入AI能力,支持自动建表等功能;
|
||||
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
||||
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
||||
* 6.AI能力:目前JeecgBoot支持AI大模型chatgpt和deepseek,现在最新版默认使用deepseek,速度更快质量更高。目前提供了AI对话助手、AI建表、AI报表等功能。
|
||||
* 6.低代码能力:Online在线表单(无需编码,通过在线配置表单,实现表单的增删改查,支持单表、树、一对多、一对一等模型,实现人人皆可编码)
|
||||
* 7.低代码能力:Online在线报表(无需编码,通过在线配置方式,实现数据报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)
|
||||
* 8.低代码能力:Online在线图表(无需编码,通过在线配置方式,实现曲线图,柱状图,数据报表等,支持自定义排版布局,实现人人皆可编码)
|
||||
* 7.低代码能力:Online在线报表、Online在线图表(无需编码,通过在线配置方式,实现数据报表和图形报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)
|
||||
* 9.封装完善的用户、角色、菜单、组织机构、数据字典、在线定时任务等基础功能,支持访问授权、按钮权限、数据权限等功能
|
||||
* 10.常用共通封装,各种工具类(定时任务,短信接口,邮件发送,Excel导入导出等),基本满足80%项目需求
|
||||
* 11.简易Excel导入导出,支持单表导出和一对多表模式导出,生成的代码自带导入导出功能
|
||||
@ -226,12 +280,20 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
|
||||
### 功能模块
|
||||
```
|
||||
├─AI开发
|
||||
│ ├─支持AI大模型ChatGPT和DeepSeek
|
||||
│ ├─AI对话助手
|
||||
│ ├─AI建表
|
||||
│ ├─AI写文章
|
||||
│ ├─AI流程编排(研发中)
|
||||
│ ├─AI知识库问答系统(研发中)
|
||||
│ ├─AI应用开发平台(研发中)
|
||||
│ ├─AI聊天窗口支持嵌入第三方(研发中)
|
||||
├─Online在线开发(低代码)
|
||||
│ ├─Online在线表单
|
||||
│ ├─Online代码生成器
|
||||
│ ├─Online在线报表
|
||||
│ ├─仪表盘设计器
|
||||
│ ├─AI助手
|
||||
│ ├─系统编码规则
|
||||
│ ├─系统校验规则
|
||||
├─积木报表设计器
|
||||
@ -366,6 +428,24 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
|
||||
### 系统效果
|
||||
|
||||
|
||||
##### AI功能
|
||||
|
||||
AI聊天助手
|
||||
|
||||

|
||||
|
||||
AI建表
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
AI写文章
|
||||
|
||||

|
||||
|
||||
|
||||
##### PC端
|
||||

|
||||
|
||||
@ -384,8 +464,6 @@ JeecgBoot开源版本,底层完全开源可以自主开发,遵循Apache2.0
|
||||
|
||||

|
||||
|
||||
##### AI助手
|
||||

|
||||
|
||||
|
||||
##### 仪表盘设计器
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
JeecgBoot 低代码开发平台
|
||||
===============
|
||||
|
||||
当前最新版本: 3.7.1(发布日期:2024-09-12)
|
||||
当前最新版本: 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
@ -5,115 +5,356 @@
|
||||
CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_general_ci;
|
||||
use `xxl_job`;
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
CREATE TABLE `xxl_job_info` (
|
||||
Source Server : mysql5.7
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 50738 (5.7.38)
|
||||
Source Host : 127.0.0.1:3306
|
||||
Source Schema : xxl_job
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 50738 (5.7.38)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 10/02/2025 13:49:31
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_group
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_group`;
|
||||
CREATE TABLE `xxl_job_group` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`app_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '执行器AppName',
|
||||
`title` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '执行器名称',
|
||||
`address_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '执行器地址类型:0=自动注册、1=手动录入',
|
||||
`address_list` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '执行器地址列表,多地址逗号分隔',
|
||||
`update_time` datetime NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_group
|
||||
-- ----------------------------
|
||||
INSERT INTO `xxl_job_group` VALUES (1, 'xxl-job-executor-sample', '示例执行器', 0, NULL, '2025-02-10 13:49:04');
|
||||
INSERT INTO `xxl_job_group` VALUES (2, 'jeecg-demo', '测试Demo模块', 0, NULL, '2025-02-10 13:49:04');
|
||||
INSERT INTO `xxl_job_group` VALUES (3, 'jeecg-system', '系统System模块', 0, NULL, '2025-02-10 13:49:04');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_info
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_info`;
|
||||
CREATE TABLE `xxl_job_info` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`job_group` int(11) NOT NULL COMMENT '执行器主键ID',
|
||||
`job_cron` varchar(128) NOT NULL COMMENT '任务执行CRON',
|
||||
`job_desc` varchar(255) NOT NULL,
|
||||
`add_time` datetime DEFAULT NULL,
|
||||
`update_time` datetime DEFAULT NULL,
|
||||
`author` varchar(64) DEFAULT NULL COMMENT '作者',
|
||||
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
|
||||
`executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略',
|
||||
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
|
||||
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
|
||||
`executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略',
|
||||
`executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒',
|
||||
`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',
|
||||
`glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型',
|
||||
`glue_source` mediumtext COMMENT 'GLUE源代码',
|
||||
`glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注',
|
||||
`glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间',
|
||||
`child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔',
|
||||
`trigger_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '调度状态:0-停止,1-运行',
|
||||
`trigger_last_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '上次调度时间',
|
||||
`trigger_next_time` bigint(13) NOT NULL DEFAULT '0' COMMENT '下次调度时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
`job_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`add_time` datetime NULL DEFAULT NULL,
|
||||
`update_time` datetime NULL DEFAULT NULL,
|
||||
`author` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '作者',
|
||||
`alarm_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '报警邮件',
|
||||
`schedule_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'NONE' COMMENT '调度类型',
|
||||
`schedule_conf` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '调度配置,值含义取决于调度类型',
|
||||
`misfire_strategy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略',
|
||||
`executor_route_strategy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器路由策略',
|
||||
`executor_handler` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器任务handler',
|
||||
`executor_param` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器任务参数',
|
||||
`executor_block_strategy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '阻塞处理策略',
|
||||
`executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒',
|
||||
`executor_fail_retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '失败重试次数',
|
||||
`glue_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'GLUE类型',
|
||||
`glue_source` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'GLUE源代码',
|
||||
`glue_remark` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'GLUE备注',
|
||||
`glue_updatetime` datetime NULL DEFAULT NULL COMMENT 'GLUE更新时间',
|
||||
`child_jobid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '子任务ID,多个逗号分隔',
|
||||
`trigger_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '调度状态:0-停止,1-运行',
|
||||
`trigger_last_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上次调度时间',
|
||||
`trigger_next_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '下次调度时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
CREATE TABLE `xxl_job_log` (
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_info
|
||||
-- ----------------------------
|
||||
INSERT INTO `xxl_job_info` VALUES (1, 1, '测试任务1', '2018-11-03 22:21:31', '2024-08-21 22:30:30', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJob', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', '', 1, 1729353600000, 1739203200000);
|
||||
INSERT INTO `xxl_job_info` VALUES (2, 3, '测试jeecg xxljob', '2024-08-21 22:41:10', '2024-08-21 22:41:30', 'JEECG', '', 'CRON', '* * * * * ?', 'DO_NOTHING', 'FIRST', 'demoJob', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2024-08-21 22:41:10', '', 1, 1739166572000, 1739166573000);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_lock
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_lock`;
|
||||
CREATE TABLE `xxl_job_lock` (
|
||||
`lock_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '锁名称',
|
||||
PRIMARY KEY (`lock_name`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_lock
|
||||
-- ----------------------------
|
||||
INSERT INTO `xxl_job_lock` VALUES ('schedule_lock');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_log
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_log`;
|
||||
CREATE TABLE `xxl_job_log` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`job_group` int(11) NOT NULL COMMENT '执行器主键ID',
|
||||
`job_id` int(11) NOT NULL COMMENT '任务,主键ID',
|
||||
`executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',
|
||||
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
|
||||
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
|
||||
`executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',
|
||||
`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',
|
||||
`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
|
||||
`executor_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器地址,本次执行的地址',
|
||||
`executor_handler` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器任务handler',
|
||||
`executor_param` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器任务参数',
|
||||
`executor_sharding_param` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',
|
||||
`executor_fail_retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '失败重试次数',
|
||||
`trigger_time` datetime NULL DEFAULT NULL COMMENT '调度-时间',
|
||||
`trigger_code` int(11) NOT NULL COMMENT '调度-结果',
|
||||
`trigger_msg` text COMMENT '调度-日志',
|
||||
`handle_time` datetime DEFAULT NULL COMMENT '执行-时间',
|
||||
`trigger_msg` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '调度-日志',
|
||||
`handle_time` datetime NULL DEFAULT NULL COMMENT '执行-时间',
|
||||
`handle_code` int(11) NOT NULL COMMENT '执行-状态',
|
||||
`handle_msg` text COMMENT '执行-日志',
|
||||
`alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_trigger_time` (`trigger_time`),
|
||||
KEY `I_handle_code` (`handle_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
`handle_msg` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '执行-日志',
|
||||
`alarm_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `I_trigger_time`(`trigger_time`) USING BTREE,
|
||||
INDEX `I_handle_code`(`handle_code`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 6761 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
CREATE TABLE `xxl_job_log_report` (
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_log
|
||||
-- ----------------------------
|
||||
INSERT INTO `xxl_job_log` VALUES (6618, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:09', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6619, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:10', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6620, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:11', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6621, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:12', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6622, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:13', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6623, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:14', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6624, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:15', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6625, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:16', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6626, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:17', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6627, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:18', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6628, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:19', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6629, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:20', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6630, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:21', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6631, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:22', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6632, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:23', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6633, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:24', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6634, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:25', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6635, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:26', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6636, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:27', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6637, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:28', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6638, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:29', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6639, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:30', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6640, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:31', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6641, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:32', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6642, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:33', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6643, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:34', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6644, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:35', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6645, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:36', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6646, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:37', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6647, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:38', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6648, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:39', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6649, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:40', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6650, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:41', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6651, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:42', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6652, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:43', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6653, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:44', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6654, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:45', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6655, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:46', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6656, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:47', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6657, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:48', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6658, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:49', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6659, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:50', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6660, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:51', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6661, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:52', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6662, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:53', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6663, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:54', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6664, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:55', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6665, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:56', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6666, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:57', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6667, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:58', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6668, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:47:59', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6669, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:00', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6670, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:01', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6671, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:02', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6672, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:03', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6673, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:04', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6674, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:05', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6675, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:06', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6676, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:07', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6677, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:08', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6678, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:09', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6679, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:10', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6680, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:11', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6681, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:12', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6682, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:13', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6683, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:14', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6684, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:15', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6685, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:16', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6686, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:17', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6687, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:18', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6688, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:19', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6689, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:20', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6690, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:21', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6691, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:22', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6692, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:23', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6693, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:24', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6694, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:25', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6695, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:26', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6696, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:27', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6697, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:28', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6698, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:29', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6699, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:30', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6700, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:31', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6701, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:32', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6702, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:33', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6703, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:34', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6704, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:35', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6705, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:36', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6706, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:37', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6707, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:38', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6708, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:39', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6709, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:40', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6710, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:41', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6711, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:42', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6712, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:43', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6713, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:44', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6714, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:45', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6715, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:46', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6716, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:47', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6717, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:48', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6718, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:49', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6719, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:50', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6720, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:51', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6721, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:52', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6722, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:53', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6723, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:54', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6724, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:55', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6725, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:56', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6726, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:57', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6727, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:58', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6728, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:48:59', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6729, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:00', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6730, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:01', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6731, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:02', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6732, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:03', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6733, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:04', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6734, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:05', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6735, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:06', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6736, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:07', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6737, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:08', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6738, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:09', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6739, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:10', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6740, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:11', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6741, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:12', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6742, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:13', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6743, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:14', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6744, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:15', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6745, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:16', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6746, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:17', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6747, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:18', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6748, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:19', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6749, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:20', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6750, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:21', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6751, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:22', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6752, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:23', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6753, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:24', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 2);
|
||||
INSERT INTO `xxl_job_log` VALUES (6754, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:25', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
INSERT INTO `xxl_job_log` VALUES (6755, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:26', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
INSERT INTO `xxl_job_log` VALUES (6756, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:27', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
INSERT INTO `xxl_job_log` VALUES (6757, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:28', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
INSERT INTO `xxl_job_log` VALUES (6758, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:29', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
INSERT INTO `xxl_job_log` VALUES (6759, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:30', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
INSERT INTO `xxl_job_log` VALUES (6760, 3, 2, NULL, 'demoJob', '', NULL, 0, '2025-02-10 13:49:31', 500, '任务触发类型:Cron触发<br>调度机器:192.168.1.11<br>执行器-注册方式:自动注册<br>执行器-地址列表:null<br>路由策略:第一个<br>阻塞处理策略:单机串行<br>任务超时时间:0<br>失败重试次数:0<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>调度失败:执行器地址为空<br><br>', NULL, 0, NULL, 0);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_log_report
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_log_report`;
|
||||
CREATE TABLE `xxl_job_log_report` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`trigger_day` datetime DEFAULT NULL COMMENT '调度-时间',
|
||||
`running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',
|
||||
`suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',
|
||||
`fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
`trigger_day` datetime NULL DEFAULT NULL COMMENT '调度-时间',
|
||||
`running_count` int(11) NOT NULL DEFAULT 0 COMMENT '运行中-日志数量',
|
||||
`suc_count` int(11) NOT NULL DEFAULT 0 COMMENT '执行成功-日志数量',
|
||||
`fail_count` int(11) NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量',
|
||||
`update_time` datetime NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `i_trigger_day`(`trigger_day`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
CREATE TABLE `xxl_job_logglue` (
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_log_report
|
||||
-- ----------------------------
|
||||
INSERT INTO `xxl_job_log_report` VALUES (1, '2024-08-21 00:00:00', 70, 0, 5, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (2, '2024-08-20 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (3, '2024-08-19 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (4, '2024-09-10 00:00:00', 0, 0, 56, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (5, '2024-09-09 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (6, '2024-09-08 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (7, '2024-10-19 00:00:00', 0, 0, 6391, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (8, '2024-10-18 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (9, '2024-10-17 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (10, '2025-02-10 00:00:00', 0, 0, 116, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (11, '2025-02-09 00:00:00', 0, 0, 0, NULL);
|
||||
INSERT INTO `xxl_job_log_report` VALUES (12, '2025-02-08 00:00:00', 0, 0, 0, NULL);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_logglue
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_logglue`;
|
||||
CREATE TABLE `xxl_job_logglue` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`job_id` int(11) NOT NULL COMMENT '任务,主键ID',
|
||||
`glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型',
|
||||
`glue_source` mediumtext COMMENT 'GLUE源代码',
|
||||
`glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注',
|
||||
`add_time` datetime DEFAULT NULL,
|
||||
`update_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
`glue_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'GLUE类型',
|
||||
`glue_source` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'GLUE源代码',
|
||||
`glue_remark` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'GLUE备注',
|
||||
`add_time` datetime NULL DEFAULT NULL,
|
||||
`update_time` datetime NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
CREATE TABLE `xxl_job_registry` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`registry_group` varchar(50) NOT NULL,
|
||||
`registry_key` varchar(255) NOT NULL,
|
||||
`registry_value` varchar(255) NOT NULL,
|
||||
`update_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_logglue
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `xxl_job_group` (
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_registry
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_registry`;
|
||||
CREATE TABLE `xxl_job_registry` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
|
||||
`title` varchar(12) NOT NULL COMMENT '执行器名称',
|
||||
`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入',
|
||||
`address_list` varchar(512) DEFAULT NULL COMMENT '执行器地址列表,多地址逗号分隔',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
`registry_group` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`registry_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`registry_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`update_time` datetime NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `i_g_k_v`(`registry_group`, `registry_key`, `registry_value`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
CREATE TABLE `xxl_job_user` (
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_registry
|
||||
-- ----------------------------
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xxl_job_user
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xxl_job_user`;
|
||||
CREATE TABLE `xxl_job_user` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL COMMENT '账号',
|
||||
`password` varchar(50) NOT NULL COMMENT '密码',
|
||||
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '账号',
|
||||
`password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
|
||||
`role` tinyint(4) NOT NULL COMMENT '角色:0-普通用户、1-管理员',
|
||||
`permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `i_username` (`username`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
`permission` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `i_username`(`username`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
CREATE TABLE `xxl_job_lock` (
|
||||
`lock_name` varchar(50) NOT NULL COMMENT '锁名称',
|
||||
PRIMARY KEY (`lock_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
-- ----------------------------
|
||||
-- Records of xxl_job_user
|
||||
-- ----------------------------
|
||||
INSERT INTO `xxl_job_user` VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
|
||||
|
||||
|
||||
INSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`) VALUES (1, 'xxl-job-executor-sample', '示例执行器', 0, NULL);
|
||||
INSERT INTO `xxl_job_info`(`id`, `job_group`, `job_cron`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, `executor_route_strategy`, `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`, `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`, `child_jobid`) VALUES (1, 1, '0 0 0 * * ? *', '测试任务1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', '');
|
||||
INSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
|
||||
INSERT INTO `xxl_job_lock` ( `lock_name`) VALUES ( 'schedule_lock');
|
||||
|
||||
commit;
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
|
||||
@ -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.1</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>
|
||||
|
||||
@ -84,6 +84,12 @@ public class MessageDTO implements Serializable {
|
||||
* 邮件抄送地址
|
||||
*/
|
||||
protected Set<String> ccEmailList;
|
||||
|
||||
/**
|
||||
* 是否为定时任务推送email
|
||||
*/
|
||||
private Boolean isTimeJob = false;
|
||||
|
||||
//---【邮件相关参数】-------------------------------------------------------------
|
||||
|
||||
public MessageDTO(){
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -604,6 +604,11 @@ public interface CommonConstant {
|
||||
*/
|
||||
String CHANGE_PHONE_REDIS_KEY_PRE = "sys:cache:phone:change_phone_msg:";
|
||||
|
||||
/**
|
||||
* 手机号短信验证码redis-key的前缀
|
||||
*/
|
||||
String LOG_OFF_PHONE_REDIS_KEY_PRE = "sys:cache:phone:qqy_log_off_user_msg:";
|
||||
|
||||
/**
|
||||
* 缓存用户最后一次收到消息通知的时间 KEY
|
||||
*/
|
||||
|
||||
@ -15,15 +15,7 @@ public enum DySmsEnum {
|
||||
/**修改密码短信模板编码*/
|
||||
CHANGE_PASSWORD_TEMPLATE_CODE("SMS_465391221","敲敲云","code"),
|
||||
/**注册账号短信模板编码*/
|
||||
REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code"),
|
||||
/**会议通知*/
|
||||
MEET_NOTICE_TEMPLATE_CODE("SMS_201480469","JEECG","username,title,minute,time"),
|
||||
/**我的计划通知*/
|
||||
PLAN_NOTICE_TEMPLATE_CODE("SMS_201470515","JEECG","username,title,time"),
|
||||
/**支付成功短信通知*/
|
||||
PAY_SUCCESS_NOTICE_CODE("SMS_461735163","敲敲云","realname,money,endTime"),
|
||||
/**会员到期通知提醒*/
|
||||
VIP_EXPIRE_NOTICE_CODE("SMS_461885023","敲敲云","realname,endTime");
|
||||
REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","code");
|
||||
|
||||
/**
|
||||
* 短信模板编码
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -805,7 +805,9 @@ public class QueryGenerator {
|
||||
addEasyQuery(queryWrapper, name, rule, DateUtils.str2Date(dateStr,DateUtils.datetimeFormat.get()));
|
||||
}
|
||||
}else {
|
||||
addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(dataRule.getRuleValue(), propertyType));
|
||||
//update-begin---author:chenrui ---date:20241125 for:[issues/7481]多租户模式下 数据权限使用变量:#{tenant_id} 报错------------
|
||||
addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(converRuleValue(dataRule.getRuleValue()), propertyType));
|
||||
//update-end---author:chenrui ---date:20241125 for:[issues/7481]多租户模式下 数据权限使用变量:#{tenant_id} 报错------------
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -859,7 +861,9 @@ public class QueryGenerator {
|
||||
return null;
|
||||
}
|
||||
Set<String> varParams = new HashSet<String>();
|
||||
String regex = "\\#\\{\\w+\\}";
|
||||
//update-begin---author:chenrui ---date:20250108 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
String regex = "#\\{\\[*\\w+]*}";
|
||||
//update-end---author:chenrui ---date:20250108 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
|
||||
Pattern p = Pattern.compile(regex);
|
||||
Matcher m = p.matcher(sql);
|
||||
|
||||
@ -54,8 +54,10 @@ public enum QueryRuleEnum {
|
||||
NOT_EMPTY("NOT_EMPTY","not_empty","值不为空"),
|
||||
/**查询规则 不包含*/
|
||||
NOT_IN("NOT_IN","not_in","不包含"),
|
||||
/**查询规则 多词匹配*/
|
||||
/**查询规则 多词精确匹配*/
|
||||
ELE_MATCH("ELE_MATCH","elemMatch","多词匹配"),
|
||||
/**查询规则 多词精确不匹配*/
|
||||
ELE_NOT_MATCH("ELE_NOT_MATCH","elemNotMatch","多词精确不匹配"),
|
||||
/**查询规则 范围查询*/
|
||||
RANGE("RANGE","range","范围查询"),
|
||||
/**查询规则 不在范围内查询*/
|
||||
|
||||
@ -6,11 +6,12 @@ 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 com.google.common.base.Joiner;
|
||||
|
||||
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;
|
||||
@ -63,7 +64,7 @@ public class JwtUtil {
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +83,8 @@ public class JwtUtil {
|
||||
// 效验TOKEN
|
||||
DecodedJWT jwt = verifier.verify(token);
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -97,6 +99,7 @@ public class JwtUtil {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
return jwt.getClaim("username").asString();
|
||||
} catch (JWTDecodeException e) {
|
||||
log.warn(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -195,6 +198,16 @@ public class JwtUtil {
|
||||
} else {
|
||||
key = key;
|
||||
}
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
// 是否存在字符串标志
|
||||
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)) {
|
||||
returnValue = DateUtils.formatDate();
|
||||
@ -263,11 +276,30 @@ public class JwtUtil {
|
||||
if(user==null){
|
||||
//TODO 暂时使用用户登录部门,存在逻辑缺陷,不是用户所拥有的部门
|
||||
returnValue = sysUser.getOrgCode();
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
returnValue = multiStr ? "'" + returnValue + "'" : returnValue;
|
||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
}else{
|
||||
if(user.isOneDepart()) {
|
||||
returnValue = user.getSysMultiOrgCode().get(0);
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
returnValue = multiStr ? "'" + returnValue + "'" : returnValue;
|
||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
}else {
|
||||
returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
|
||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
||||
returnValue = user.getSysMultiOrgCode().stream()
|
||||
.filter(Objects::nonNull)
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jeecg.common.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyuncs.DefaultAcsClient;
|
||||
import com.aliyuncs.IAcsClient;
|
||||
@ -8,11 +9,15 @@ import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
|
||||
import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.profile.DefaultProfile;
|
||||
import com.aliyuncs.profile.IClientProfile;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.common.constant.enums.DySmsEnum;
|
||||
import org.jeecg.config.JeecgSmsTemplateConfig;
|
||||
import org.jeecg.config.StaticConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created on 17/6/7.
|
||||
* 短信API产品的DEMO程序,工程中包含了一个SmsDemo类,直接通过
|
||||
@ -75,15 +80,33 @@ public class DySmsHelper {
|
||||
|
||||
//验证json参数
|
||||
validateParam(templateParamJson,dySmsEnum);
|
||||
|
||||
//update-begin---author:wangshuai---date:2024-11-05---for:【QQYUN-9422】短信模板管理,阿里云---
|
||||
String templateCode = dySmsEnum.getTemplateCode();
|
||||
JeecgSmsTemplateConfig baseConfig = SpringContextUtils.getBean(JeecgSmsTemplateConfig.class);
|
||||
if(baseConfig != null && CollectionUtil.isNotEmpty(baseConfig.getTemplateCode())){
|
||||
Map<String, String> smsTemplate = baseConfig.getTemplateCode();
|
||||
if(smsTemplate.containsKey(templateCode) && StringUtils.isNotEmpty(smsTemplate.get(templateCode))){
|
||||
templateCode = smsTemplate.get(templateCode);
|
||||
logger.info("yml中读取短信code{}",templateCode);
|
||||
}
|
||||
}
|
||||
//签名名称
|
||||
String signName = dySmsEnum.getSignName();
|
||||
if(baseConfig != null && StringUtils.isNotEmpty(baseConfig.getSignature())){
|
||||
logger.info("yml中读取签名名称{}",baseConfig.getSignature());
|
||||
signName = baseConfig.getSignature();
|
||||
}
|
||||
//update-end---author:wangshuai---date:2024-11-05---for:【QQYUN-9422】短信模板管理,阿里云---
|
||||
|
||||
//组装请求对象-具体描述见控制台-文档部分内容
|
||||
SendSmsRequest request = new SendSmsRequest();
|
||||
//必填:待发送手机号
|
||||
request.setPhoneNumbers(phone);
|
||||
//必填:短信签名-可在短信控制台中找到
|
||||
request.setSignName(dySmsEnum.getSignName());
|
||||
request.setSignName(signName);
|
||||
//必填:短信模板-可在短信控制台中找到
|
||||
request.setTemplateCode(dySmsEnum.getTemplateCode());
|
||||
request.setTemplateCode(templateCode);
|
||||
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
|
||||
request.setTemplateParam(templateParamJson.toJSONString());
|
||||
|
||||
|
||||
@ -6,7 +6,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
import org.jeecg.common.handler.IFillRuleHandler;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
||||
/**
|
||||
@ -42,6 +46,30 @@ public class FillRuleUtil {
|
||||
if (params == null) {
|
||||
params = new JSONObject();
|
||||
}
|
||||
|
||||
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
|
||||
|
||||
// 解析 params 中的变量
|
||||
// 优先级:queryString > 系统变量 > 默认值
|
||||
for (String key : params.keySet()) {
|
||||
// 1. 判断 queryString 中是否有该参数,如果有就优先取值
|
||||
//noinspection ConstantValue
|
||||
if (request != null) {
|
||||
String parameter = request.getParameter(key);
|
||||
if (oConvertUtils.isNotEmpty(parameter)) {
|
||||
params.put(key, parameter);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
String value = params.getString(key);
|
||||
// 2. 用于替换 系统变量的值 #{sys_user_code}
|
||||
if (value != null && value.contains(SymbolConstant.SYS_VAR_PREFIX)) {
|
||||
value = QueryGenerator.getSqlRuleValue(value);
|
||||
params.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (formData == null) {
|
||||
formData = new JSONObject();
|
||||
}
|
||||
|
||||
@ -57,8 +57,8 @@ public class RestUtil {
|
||||
|
||||
static {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setConnectTimeout(3000);
|
||||
requestFactory.setReadTimeout(3000);
|
||||
requestFactory.setConnectTimeout(30000);
|
||||
requestFactory.setReadTimeout(30000);
|
||||
RT = new RestTemplate(requestFactory);
|
||||
// 解决乱码问题
|
||||
RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||
|
||||
@ -84,6 +84,10 @@ public class DynamicDBUtil {
|
||||
} else {
|
||||
DruidDataSource dataSource = getJdbcDataSource(dbSource);
|
||||
if(dataSource!=null && dataSource.isEnable()){
|
||||
|
||||
// 【TV360X-2060】设置超时时间 6秒
|
||||
dataSource.setMaxWait(6000);
|
||||
|
||||
DataSourceCachePool.putCacheBasicDataSource(dbKey, dataSource);
|
||||
}else{
|
||||
throw new JeecgBootException("动态数据源连接失败,dbKey:"+dbKey);
|
||||
@ -109,7 +113,7 @@ public class DynamicDBUtil {
|
||||
DataSourceCachePool.removeCache(dbKey);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.info(e.getMessage(), e);
|
||||
log.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -73,6 +73,12 @@ public class JSqlParserUtils {
|
||||
* @return
|
||||
*/
|
||||
private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) {
|
||||
// 判断是否使用了union等操作
|
||||
if (selectBody instanceof SetOperationList) {
|
||||
// 如果使用了union等操作,则只解析第一个查询
|
||||
List<SelectBody> selectBodyList = ((SetOperationList) selectBody).getSelects();
|
||||
return JSqlParserUtils.parseBySelectBody(selectBodyList.get(0));
|
||||
}
|
||||
// 简单的select查询
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package org.jeecg.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description: 短信模板
|
||||
*
|
||||
* @author: wangshuai
|
||||
* @date: 2024/11/5 下午3:44
|
||||
*/
|
||||
@Data
|
||||
@Component("jeecgSmsTemplateConfig")
|
||||
@ConfigurationProperties(prefix = "jeecg.oss.sms-template")
|
||||
public class JeecgSmsTemplateConfig {
|
||||
|
||||
/**
|
||||
* 短信签名
|
||||
*/
|
||||
private String signature;
|
||||
|
||||
|
||||
/**
|
||||
* 短信模板code
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Map<String,String> templateCode;
|
||||
|
||||
}
|
||||
@ -21,6 +21,12 @@ public class StaticConfig {
|
||||
@Value(value = "${spring.mail.username:}")
|
||||
private String emailFrom;
|
||||
|
||||
/**
|
||||
* 是否开启定时发送
|
||||
*/
|
||||
@Value(value = "${spring.mail.timeJobSend:false}")
|
||||
private Boolean timeJobSend;
|
||||
|
||||
// /**
|
||||
// * 签名密钥串
|
||||
// */
|
||||
|
||||
@ -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, "");
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public class WebSocketConfig {
|
||||
FilterRegistrationBean bean = new FilterRegistrationBean();
|
||||
bean.setFilter(websocketFilter());
|
||||
//TODO 临时注释掉,测试下线上socket总断的问题
|
||||
bean.addUrlPatterns("/taskCountSocket/*", "/websocket/*","/eoaSocket/*","/eoaNewChatSocket/*", "/newsWebsocket/*", "/vxeSocket/*");
|
||||
bean.addUrlPatterns("/taskCountSocket/*", "/websocket/*","/eoaSocket/*","/eoaNewChatSocket/*", "/newsWebsocket/*", "/dragChannelSocket/*", "/vxeSocket/*");
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
@ -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.示例测试
|
||||
|
||||
@ -17,15 +17,17 @@ import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
|
||||
import org.jeecg.config.shiro.filters.JwtFilter;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
@ -33,6 +35,7 @@ import redis.clients.jedis.JedisCluster;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -123,7 +126,6 @@ public class ShiroConfig {
|
||||
filterChainDefinitionMap.put("/**/*.ttf", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.woff", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.woff2", "anon");
|
||||
|
||||
filterChainDefinitionMap.put("/**/*.glb", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.wasm", "anon");
|
||||
//update-end--Author:scott Date:20221116 for:排除静态资源后缀
|
||||
@ -132,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");
|
||||
@ -143,12 +145,18 @@ public class ShiroConfig {
|
||||
filterChainDefinitionMap.put("/**/*.js.map", "anon");
|
||||
filterChainDefinitionMap.put("/**/*.css.map", "anon");
|
||||
|
||||
//拖拽仪表盘设计器排除
|
||||
//积木BI大屏和仪表盘排除
|
||||
filterChainDefinitionMap.put("/drag/view", "anon");
|
||||
filterChainDefinitionMap.put("/drag/page/queryById", "anon");
|
||||
filterChainDefinitionMap.put("/drag/page/addVisitsNumber", "anon");
|
||||
filterChainDefinitionMap.put("/drag/page/queryTemplateList", "anon");
|
||||
filterChainDefinitionMap.put("/drag/share/view/**", "anon");
|
||||
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getAllChartData", "anon");
|
||||
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getTotalData", "anon");
|
||||
filterChainDefinitionMap.put("/drag/mock/json/**", "anon");
|
||||
filterChainDefinitionMap.put("/jimubi/view", "anon");
|
||||
filterChainDefinitionMap.put("/jimubi/share/view/**", "anon");
|
||||
|
||||
//大屏模板例子
|
||||
filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
|
||||
filterChainDefinitionMap.put("/bigscreen/template1/**", "anon");
|
||||
@ -172,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为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
|
||||
@ -207,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);
|
||||
@ -306,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();
|
||||
|
||||
@ -168,8 +168,8 @@ public class ShiroRealm extends AuthorizingRealm {
|
||||
|
||||
//*********************************************
|
||||
if(!isAuthorization){
|
||||
log.warn("租户异常——当前登录的租户是:" + contextTenantId);
|
||||
log.warn("租户异常——用户拥有的租户是:" + userTenantIds);
|
||||
log.info("租户异常——登录租户:" + contextTenantId);
|
||||
log.info("租户异常——用户拥有租户组:" + userTenantIds);
|
||||
throw new AuthenticationException("登录租户授权变更,请重新登陆!");
|
||||
}
|
||||
//*********************************************
|
||||
|
||||
@ -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.1</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -14,8 +14,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
//update-begin---author:chenrui ---date:20240126 for:【QQYUN-7932】AI助手------------
|
||||
|
||||
/**
|
||||
* OpenAI的SSE监听
|
||||
* @author chenrui
|
||||
@ -29,22 +31,47 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
private SseEmitter sseEmitter;
|
||||
|
||||
private String topicId;
|
||||
/**
|
||||
* 回复消息内容
|
||||
*/
|
||||
private String messageContent = "";
|
||||
|
||||
/**
|
||||
* 完成回复回调
|
||||
*/
|
||||
private Consumer<String> doneCallback;
|
||||
|
||||
/**
|
||||
* 是否正在思考
|
||||
*/
|
||||
private boolean isThinking = false;
|
||||
|
||||
public OpenAISSEEventSourceListener(SseEmitter sseEmitter) {
|
||||
this.sseEmitter = sseEmitter;
|
||||
}
|
||||
|
||||
public OpenAISSEEventSourceListener(String topicId,SseEmitter sseEmitter){
|
||||
public OpenAISSEEventSourceListener(String topicId, SseEmitter sseEmitter){
|
||||
this.topicId = topicId;
|
||||
this.sseEmitter = sseEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息完成响应时的回调
|
||||
* for [QQYUN-11102/QQYUN-11109]兼容deepseek模型,支持tink标签
|
||||
* @param doneCallback
|
||||
* @author chenrui
|
||||
* @date 2025/2/7 18:14
|
||||
*/
|
||||
public void onDone(Consumer<String> doneCallback){
|
||||
this.doneCallback = doneCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) {
|
||||
log.info("OpenAI建立sse连接...");
|
||||
log.info("ai-chat建立sse连接...");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,10 +80,12 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void onEvent(@NotNull EventSource eventSource, String id, String type, @NotNull String data) {
|
||||
log.debug("OpenAI返回数据:{}", data);
|
||||
log.debug("ai-chat返回数据:{}", data);
|
||||
tokens += 1;
|
||||
if (data.equals("[DONE]")) {
|
||||
log.info("OpenAI返回数据结束了");
|
||||
log.info("ai-chat返回数据结束了");
|
||||
this.doneCallback.accept(messageContent);
|
||||
messageContent = "";
|
||||
sseEmitter.send(SseEmitter.event()
|
||||
.id("[TOKENS]")
|
||||
.data("<br/><br/>tokens:" + tokens())
|
||||
@ -72,12 +101,46 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
ChatCompletionResponse completionResponse = mapper.readValue(data, ChatCompletionResponse.class); // 读取Json
|
||||
try {
|
||||
sseEmitter.send(SseEmitter.event()
|
||||
.id(this.topicId)
|
||||
.data(completionResponse.getChoices().get(0).getDelta())
|
||||
.reconnectTime(3000));
|
||||
//update-begin---author:chenrui ---date:20250207 for:[QQYUN-11102/QQYUN-11109]兼容deepseek模型,支持think标签------------
|
||||
// 兼容think标签
|
||||
//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);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
//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();
|
||||
}
|
||||
}
|
||||
@ -86,7 +149,7 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
@Override
|
||||
public void onClosed(@NotNull EventSource eventSource) {
|
||||
log.info("流式输出返回值总共{}tokens", tokens() - 2);
|
||||
log.info("OpenAI关闭sse连接...");
|
||||
log.info("ai-chat关闭sse连接...");
|
||||
}
|
||||
|
||||
|
||||
@ -96,10 +159,10 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
|
||||
String errMsg = "";
|
||||
ResponseBody body = null == response ? null:response.body();
|
||||
if (Objects.nonNull(body)) {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", body.string(), t.getMessage());
|
||||
log.error("ai-chat sse连接异常data:{},异常:{}", body.string(), t.getMessage());
|
||||
errMsg = body.string();
|
||||
} else {
|
||||
log.error("OpenAI sse连接异常data:{},异常:{}", response, t.getMessage());
|
||||
log.error("ai-chat sse连接异常data:{},异常:{}", response, t.getMessage());
|
||||
errMsg = t.getMessage();
|
||||
}
|
||||
eventSource.cancel();
|
||||
|
||||
@ -9,6 +9,7 @@ import com.unfbx.chatgpt.entity.chat.Message;
|
||||
import com.unfbx.chatgpt.exception.BaseException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.chatgpt.prop.AiChatProperties;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
@ -58,6 +59,11 @@ public class ChatServiceImpl implements ChatService {
|
||||
|
||||
private OpenAiStreamClient openAiStreamClient = null;
|
||||
|
||||
/**
|
||||
* ai聊天配置
|
||||
* for [QQYUN-10943]【AI 重要】jeecg-boot-starter-chatgpt 支持deepseek等国产模型
|
||||
*/
|
||||
private AiChatProperties aiChatProperties;
|
||||
//update-begin---author:chenrui ---date:20240131 for:[QQYUN-8212]fix 没有配置启动报错------------
|
||||
|
||||
/**
|
||||
@ -66,17 +72,17 @@ public class ChatServiceImpl implements ChatService {
|
||||
* @author chenrui
|
||||
* @date 2024/2/3 23:08
|
||||
*/
|
||||
private OpenAiStreamClient ensureClient(){
|
||||
private void ensureClient(){
|
||||
if (null == this.openAiStreamClient){
|
||||
//update-begin---author:chenrui ---date:20240625 for:[TV360X-1570]给于更友好的提示,提示未配置ai------------
|
||||
try {
|
||||
this.openAiStreamClient = SpringContextUtils.getBean(OpenAiStreamClient.class);
|
||||
this.aiChatProperties = SpringContextUtils.getBean(AiChatProperties.class);
|
||||
} catch (Exception ignored) {
|
||||
sendErrorMsg("如果您想使用AI助手,请先设置相应配置!");
|
||||
}
|
||||
//update-end---author:chenrui ---date:20240625 for:[TV360X-1570]给于更友好的提示,提示未配置ai------------
|
||||
}
|
||||
return this.openAiStreamClient;
|
||||
}
|
||||
//update-end---author:chenrui ---date:20240131 for:[QQYUN-8212]fix 没有配置启动报错------------
|
||||
|
||||
@ -98,6 +104,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
//超时回调
|
||||
sseEmitter.onTimeout(() -> {
|
||||
log.info("[{}]连接超时...................", uid);
|
||||
LocalCache.CACHE.remove(uid);
|
||||
});
|
||||
//异常回调
|
||||
sseEmitter.onError(
|
||||
@ -109,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);
|
||||
}
|
||||
@ -138,6 +145,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
|
||||
@Override
|
||||
public void sendMessage(String topicId, String message) {
|
||||
ensureClient();
|
||||
String uid = getUserId();
|
||||
if (StrUtil.isBlank(message)) {
|
||||
log.info("参数异常,message为null");
|
||||
@ -164,18 +172,22 @@ public class ChatServiceImpl implements ChatService {
|
||||
throw new JeecgBootException("聊天消息推送失败uid:[{}],没有创建连接,请重试。~");
|
||||
}
|
||||
//update-begin---author:chenrui ---date:20240625 for:[TV360X-1570]给于更友好的提示,提示未配置ai------------
|
||||
OpenAiStreamClient client = ensureClient();
|
||||
if (null != client) {
|
||||
if (null != openAiStreamClient) {
|
||||
OpenAISSEEventSourceListener openAIEventSourceListener = new OpenAISSEEventSourceListener(topicId, sseEmitter);
|
||||
List<Message> finalMsgHistory = msgHistory;
|
||||
openAIEventSourceListener.onDone(respMessage -> {
|
||||
Message tempMessage = Message.builder().content(respMessage).role(Message.Role.ASSISTANT).build();
|
||||
finalMsgHistory.add(tempMessage);
|
||||
redisTemplate.opsForHash().put(cacheKey, CACHE_KEY_MSG_CONTEXT, JSONUtil.toJsonStr(finalMsgHistory));
|
||||
});
|
||||
log.info("话题:{},开始发送消息~~~", topicId);
|
||||
ChatCompletion completion = ChatCompletion
|
||||
.builder()
|
||||
.messages(msgHistory)
|
||||
.model(ChatCompletion.Model.GPT_3_5_TURBO.getName())
|
||||
.model(aiChatProperties.getModel())
|
||||
.build();
|
||||
client.streamChatCompletion(completion, openAIEventSourceListener);
|
||||
redisTemplate.opsForHash().put(cacheKey, CACHE_KEY_MSG_CONTEXT, JSONUtil.toJsonStr(msgHistory));
|
||||
openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
|
||||
//update-end---author:chenrui ---date:20240223 for:[QQYUN-8225]聊天记录保存------------
|
||||
Result.ok(completion.tokens());
|
||||
}
|
||||
//update-end---author:chenrui ---date:20240625 for:[TV360X-1570]给于更友好的提示,提示未配置ai------------
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,370 @@
|
||||
{
|
||||
"list": [
|
||||
{
|
||||
"key": "1717072932495_439966",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"isContainer": true,
|
||||
"list": [
|
||||
{
|
||||
"type": "input",
|
||||
"name": "名称",
|
||||
"className": "form-input",
|
||||
"icon": "icon-input",
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"defaultValue": "",
|
||||
"required": true,
|
||||
"dataType": null,
|
||||
"pattern": "",
|
||||
"placeholder": "",
|
||||
"clearable": false,
|
||||
"readonly": false,
|
||||
"disabled": false,
|
||||
"fillRuleCode": "",
|
||||
"showPassword": false,
|
||||
"unique": false,
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"autoWidth": 50
|
||||
},
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "string",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"remoteAPI": {
|
||||
"url": "",
|
||||
"executed": false
|
||||
},
|
||||
"key": "1717072932495_556479",
|
||||
"model": "input_1717072932495_556479",
|
||||
"modelType": "main",
|
||||
"rules": [
|
||||
{
|
||||
"required": true,
|
||||
"message": "${title}必须填写"
|
||||
}
|
||||
],
|
||||
"isSubItem": false
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"name": "数字",
|
||||
"className": "form-number",
|
||||
"icon": "icon-number",
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"width": "",
|
||||
"required": false,
|
||||
"defaultValue": 0,
|
||||
"placeholder": "",
|
||||
"controls": false,
|
||||
"min": 0,
|
||||
"minUnlimited": true,
|
||||
"max": 100,
|
||||
"maxUnlimited": true,
|
||||
"step": 1,
|
||||
"disabled": false,
|
||||
"controlsPosition": "right",
|
||||
"unitText": "",
|
||||
"unitPosition": "suffix",
|
||||
"showPercent": false,
|
||||
"align": "left",
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"autoWidth": 50
|
||||
},
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "number",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"remoteAPI": {
|
||||
"url": "",
|
||||
"executed": false
|
||||
},
|
||||
"key": "1717072985868_606195",
|
||||
"model": "number_1717072985868_606195",
|
||||
"modelType": "main",
|
||||
"rules": [],
|
||||
"isSubItem": false
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"required": false,
|
||||
"hiddenOnAdd": false,
|
||||
"hidden": false,
|
||||
"fieldNote": ""
|
||||
},
|
||||
"model": "card_1717072932495_439966",
|
||||
"hideTitle": false,
|
||||
"modelType": "main"
|
||||
},
|
||||
{
|
||||
"key": "1717072988159_545097",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"isContainer": true,
|
||||
"list": [
|
||||
{
|
||||
"type": "money",
|
||||
"name": "金额",
|
||||
"className": "form-money",
|
||||
"icon": "icon-money",
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"width": "180px",
|
||||
"placeholder": "请输入金额",
|
||||
"required": false,
|
||||
"unitText": "元",
|
||||
"unitPosition": "suffix",
|
||||
"precision": 2,
|
||||
"hidden": false,
|
||||
"disabled": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"autoWidth": 50
|
||||
},
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "number",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"remoteAPI": {
|
||||
"url": "",
|
||||
"executed": false
|
||||
},
|
||||
"key": "1717072988159_568693",
|
||||
"model": "money_1717072988159_568693",
|
||||
"modelType": "main",
|
||||
"rules": [],
|
||||
"isSubItem": false
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "下拉选择框",
|
||||
"className": "form-select",
|
||||
"icon": "icon-select",
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"defaultValue": "",
|
||||
"multiple": false,
|
||||
"disabled": false,
|
||||
"clearable": true,
|
||||
"placeholder": "",
|
||||
"required": false,
|
||||
"showLabel": false,
|
||||
"showType": "default",
|
||||
"width": "",
|
||||
"useColor": false,
|
||||
"colorIteratorIndex": 3,
|
||||
"options": [
|
||||
{
|
||||
"value": "下拉框1",
|
||||
"itemColor": "#2196F3"
|
||||
},
|
||||
{
|
||||
"value": "下拉框2",
|
||||
"itemColor": "#08C9C9"
|
||||
},
|
||||
{
|
||||
"value": "下拉框3",
|
||||
"itemColor": "#00C345"
|
||||
}
|
||||
],
|
||||
"remote": false,
|
||||
"filterable": false,
|
||||
"remoteOptions": [],
|
||||
"props": {
|
||||
"value": "value",
|
||||
"label": "label"
|
||||
},
|
||||
"remoteFunc": "",
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"autoWidth": 50
|
||||
},
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "string",
|
||||
"allowFunc": true,
|
||||
"valueSplit": ",",
|
||||
"customConfig": true
|
||||
}
|
||||
},
|
||||
"remoteAPI": {
|
||||
"url": "",
|
||||
"executed": false
|
||||
},
|
||||
"key": "1717072991431_622198",
|
||||
"model": "select_1717072991431_622198",
|
||||
"modelType": "main",
|
||||
"rules": [],
|
||||
"isSubItem": false
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"required": false,
|
||||
"hiddenOnAdd": false,
|
||||
"hidden": false,
|
||||
"fieldNote": ""
|
||||
},
|
||||
"model": "card_1717072988159_545097",
|
||||
"hideTitle": false,
|
||||
"modelType": "main"
|
||||
},
|
||||
{
|
||||
"key": "1717072932495_382575",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"isContainer": true,
|
||||
"list": [
|
||||
{
|
||||
"type": "imgupload",
|
||||
"name": "图片上传",
|
||||
"className": "form-tupian",
|
||||
"icon": "icon-tupian",
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"defaultValue": [],
|
||||
"size": {
|
||||
"width": 100,
|
||||
"height": 100
|
||||
},
|
||||
"width": "",
|
||||
"tokenFunc": "funcGetToken",
|
||||
"token": "",
|
||||
"domain": "http://img.h5huodong.com",
|
||||
"disabled": false,
|
||||
"length": 9,
|
||||
"multiple": true,
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"required": false,
|
||||
"fieldNote": "",
|
||||
"autoWidth": 50
|
||||
},
|
||||
"key": "1717072996509_795340",
|
||||
"model": "imgupload_1717072996509_795340",
|
||||
"modelType": "main",
|
||||
"rules": [],
|
||||
"isSubItem": false
|
||||
},
|
||||
{
|
||||
"type": "file-upload",
|
||||
"name": "附件",
|
||||
"className": "form-file-upload",
|
||||
"icon": "icon-shangchuan",
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"defaultValue": [],
|
||||
"token": "",
|
||||
"length": 1,
|
||||
"drag": false,
|
||||
"multiple": false,
|
||||
"disabled": false,
|
||||
"buttonText": "添加附件",
|
||||
"tokenFunc": "funcGetToken",
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"required": false,
|
||||
"fieldNote": "",
|
||||
"autoWidth": 50
|
||||
},
|
||||
"key": "1717072932495_669325",
|
||||
"model": "file_upload_1717072932495_669325",
|
||||
"modelType": "main",
|
||||
"rules": [],
|
||||
"isSubItem": false
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"required": false,
|
||||
"hiddenOnAdd": false,
|
||||
"hidden": false,
|
||||
"fieldNote": ""
|
||||
},
|
||||
"model": "card_1717072932495_382575",
|
||||
"hideTitle": false,
|
||||
"modelType": "main"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"titleField": "input_1717072932495_556479",
|
||||
"showHeaderTitle": true,
|
||||
"labelWidth": 100,
|
||||
"labelPosition": "top",
|
||||
"size": "small",
|
||||
"dialogOptions": {
|
||||
"top": 20,
|
||||
"width": 1000,
|
||||
"padding": {
|
||||
"top": 25,
|
||||
"right": 25,
|
||||
"bottom": 30,
|
||||
"left": 25
|
||||
}
|
||||
},
|
||||
"disabledAutoGrid": false,
|
||||
"designMobileView": false,
|
||||
"enableComment": true,
|
||||
"hasWidgets": [
|
||||
"input",
|
||||
"number",
|
||||
"card",
|
||||
"money",
|
||||
"select",
|
||||
"imgupload",
|
||||
"file-upload"
|
||||
],
|
||||
"expand": {
|
||||
"js": "",
|
||||
"css": "",
|
||||
"url": {
|
||||
"js": "",
|
||||
"css": ""
|
||||
}
|
||||
},
|
||||
"transactional": true,
|
||||
"customRequestURL": [
|
||||
{
|
||||
"url": ""
|
||||
}
|
||||
],
|
||||
"allowExternalLink": false,
|
||||
"externalLinkShowData": false,
|
||||
"headerImgUrl": "",
|
||||
"externalTitle": "",
|
||||
"enableNotice": false,
|
||||
"noticeMode": "external",
|
||||
"noticeType": "system",
|
||||
"noticeReceiver": "",
|
||||
"allowPrint": false,
|
||||
"allowJmReport": false,
|
||||
"jmReportURL": "",
|
||||
"bizRuleConfig": [],
|
||||
"bigDataMode": false
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,496 @@
|
||||
{
|
||||
"list": [
|
||||
{
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"required": false
|
||||
},
|
||||
"isContainer": true,
|
||||
"model": "card_1717072902303_783177",
|
||||
"modelType": "main",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"list": [
|
||||
{
|
||||
"isSubItem": false,
|
||||
"remoteAPI": {
|
||||
"executed": false,
|
||||
"url": ""
|
||||
},
|
||||
"icon": "icon-input",
|
||||
"className": "form-input",
|
||||
"rules": [
|
||||
{
|
||||
"required": true,
|
||||
"message": "${title}必须填写"
|
||||
}
|
||||
],
|
||||
"modelType": "main",
|
||||
"type": "input",
|
||||
"hideTitle": false,
|
||||
"name": "名称",
|
||||
"options": {
|
||||
"clearable": false,
|
||||
"hidden": false,
|
||||
"defaultValue": "",
|
||||
"pattern": "",
|
||||
"fillRuleCode": "",
|
||||
"fieldNote": "",
|
||||
"required": true,
|
||||
"readonly": false,
|
||||
"unique": false,
|
||||
"hiddenOnAdd": false,
|
||||
"width": "100%",
|
||||
"autoWidth": 100,
|
||||
"showPassword": false,
|
||||
"disabled": false,
|
||||
"placeholder": ""
|
||||
},
|
||||
"model": "input_1717072902303_477529",
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "string",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"key": "1717072902303_477529"
|
||||
}
|
||||
],
|
||||
"key": "1717072902303_783177"
|
||||
},
|
||||
{
|
||||
"options": {
|
||||
"required": false,
|
||||
"hiddenOnAdd": false,
|
||||
"hidden": false,
|
||||
"fieldNote": ""
|
||||
},
|
||||
"isContainer": true,
|
||||
"model": "card_1717073019436_526262",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"list": [
|
||||
{
|
||||
"isSubItem": false,
|
||||
"remoteAPI": {
|
||||
"executed": false,
|
||||
"url": ""
|
||||
},
|
||||
"icon": "icon-number",
|
||||
"className": "form-number",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "number",
|
||||
"hideTitle": false,
|
||||
"name": "数字",
|
||||
"options": {
|
||||
"controls": false,
|
||||
"showPercent": false,
|
||||
"hidden": false,
|
||||
"max": 100,
|
||||
"defaultValue": 0,
|
||||
"unitPosition": "suffix",
|
||||
"fieldNote": "",
|
||||
"maxUnlimited": true,
|
||||
"align": "left",
|
||||
"required": false,
|
||||
"min": 0,
|
||||
"minUnlimited": true,
|
||||
"hiddenOnAdd": false,
|
||||
"width": "",
|
||||
"autoWidth": 50,
|
||||
"step": 1,
|
||||
"disabled": false,
|
||||
"placeholder": "",
|
||||
"controlsPosition": "right",
|
||||
"unitText": ""
|
||||
},
|
||||
"model": "number_1717073019436_586474",
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "number",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"key": "1717073019436_586474"
|
||||
},
|
||||
{
|
||||
"isSubItem": false,
|
||||
"remoteAPI": {
|
||||
"executed": false,
|
||||
"url": ""
|
||||
},
|
||||
"icon": "icon-money",
|
||||
"className": "form-money",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "money",
|
||||
"hideTitle": false,
|
||||
"name": "金额",
|
||||
"options": {
|
||||
"hidden": false,
|
||||
"precision": 2,
|
||||
"hiddenOnAdd": false,
|
||||
"width": "180px",
|
||||
"autoWidth": 50,
|
||||
"unitPosition": "suffix",
|
||||
"disabled": false,
|
||||
"fieldNote": "",
|
||||
"placeholder": "请输入金额",
|
||||
"required": false,
|
||||
"unitText": "元"
|
||||
},
|
||||
"model": "money_1717073021100_526660",
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "number",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"key": "1717073021100_526660"
|
||||
}
|
||||
],
|
||||
"key": "1717073019436_526262",
|
||||
"hideTitle": false,
|
||||
"modelType": "main"
|
||||
},
|
||||
{
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"required": false
|
||||
},
|
||||
"isContainer": true,
|
||||
"model": "card_1717072902303_118977",
|
||||
"modelType": "main",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"list": [
|
||||
{
|
||||
"isSubItem": false,
|
||||
"remoteAPI": {
|
||||
"executed": false,
|
||||
"url": ""
|
||||
},
|
||||
"icon": "icon-select",
|
||||
"className": "form-select",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "select",
|
||||
"hideTitle": false,
|
||||
"name": "下拉选择框",
|
||||
"options": {
|
||||
"remoteFunc": "",
|
||||
"filterable": false,
|
||||
"clearable": true,
|
||||
"hidden": false,
|
||||
"defaultValue": "",
|
||||
"remoteOptions": [],
|
||||
"multiple": false,
|
||||
"fieldNote": "",
|
||||
"remote": false,
|
||||
"required": false,
|
||||
"showLabel": false,
|
||||
"useColor": false,
|
||||
"props": {
|
||||
"label": "label",
|
||||
"value": "value"
|
||||
},
|
||||
"colorIteratorIndex": 3,
|
||||
"hiddenOnAdd": false,
|
||||
"width": "",
|
||||
"options": [
|
||||
{
|
||||
"itemColor": "#2196F3",
|
||||
"value": "下拉框1"
|
||||
},
|
||||
{
|
||||
"itemColor": "#08C9C9",
|
||||
"value": "下拉框2"
|
||||
},
|
||||
{
|
||||
"itemColor": "#00C345",
|
||||
"value": "下拉框3"
|
||||
}
|
||||
],
|
||||
"autoWidth": 50,
|
||||
"showType": "default",
|
||||
"disabled": false,
|
||||
"placeholder": ""
|
||||
},
|
||||
"model": "select_1717073033259_273399",
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "string",
|
||||
"allowFunc": true,
|
||||
"valueSplit": ",",
|
||||
"customConfig": true
|
||||
}
|
||||
},
|
||||
"key": "1717073033259_273399"
|
||||
},
|
||||
{
|
||||
"isSubItem": false,
|
||||
"remoteAPI": {
|
||||
"executed": false,
|
||||
"url": ""
|
||||
},
|
||||
"icon": "icon-textarea",
|
||||
"className": "form-textarea",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "textarea",
|
||||
"hideTitle": false,
|
||||
"name": "描述",
|
||||
"options": {
|
||||
"readonly": false,
|
||||
"hidden": false,
|
||||
"defaultValue": "",
|
||||
"unique": false,
|
||||
"hiddenOnAdd": false,
|
||||
"width": "100%",
|
||||
"pattern": "",
|
||||
"autoWidth": 50,
|
||||
"disabled": false,
|
||||
"fieldNote": "",
|
||||
"placeholder": "",
|
||||
"required": false
|
||||
},
|
||||
"model": "textarea_1717072902303_129466",
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "string",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": false
|
||||
}
|
||||
},
|
||||
"key": "1717072902303_129466"
|
||||
}
|
||||
],
|
||||
"key": "1717072902303_118977"
|
||||
},
|
||||
{
|
||||
"hideTitle": false,
|
||||
"options": {
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": "",
|
||||
"required": false
|
||||
},
|
||||
"isContainer": true,
|
||||
"model": "card_1717072902304_736053",
|
||||
"modelType": "main",
|
||||
"type": "card",
|
||||
"isAutoGrid": true,
|
||||
"list": [
|
||||
{
|
||||
"hideTitle": false,
|
||||
"isSubItem": false,
|
||||
"name": "图片上传",
|
||||
"icon": "icon-tupian",
|
||||
"options": {
|
||||
"hidden": false,
|
||||
"defaultValue": [],
|
||||
"length": 9,
|
||||
"multiple": true,
|
||||
"fieldNote": "",
|
||||
"required": false,
|
||||
"token": "",
|
||||
"size": {
|
||||
"width": 100,
|
||||
"height": 100
|
||||
},
|
||||
"tokenFunc": "funcGetToken",
|
||||
"domain": "http://img.h5huodong.com",
|
||||
"hiddenOnAdd": false,
|
||||
"width": "",
|
||||
"autoWidth": 50,
|
||||
"disabled": false
|
||||
},
|
||||
"className": "form-tupian",
|
||||
"model": "imgupload_1717073025137_563739",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "imgupload",
|
||||
"key": "1717073025137_563739"
|
||||
},
|
||||
{
|
||||
"hideTitle": false,
|
||||
"isSubItem": false,
|
||||
"name": "附件",
|
||||
"icon": "icon-shangchuan",
|
||||
"options": {
|
||||
"buttonText": "添加附件",
|
||||
"hidden": false,
|
||||
"defaultValue": [],
|
||||
"length": 1,
|
||||
"multiple": false,
|
||||
"fieldNote": "",
|
||||
"required": false,
|
||||
"token": "",
|
||||
"tokenFunc": "funcGetToken",
|
||||
"hiddenOnAdd": false,
|
||||
"autoWidth": 50,
|
||||
"disabled": false,
|
||||
"drag": false
|
||||
},
|
||||
"className": "form-file-upload",
|
||||
"model": "file_upload_1717072902304_442777",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "file-upload",
|
||||
"key": "1717072902304_442777"
|
||||
}
|
||||
],
|
||||
"key": "1717072902304_736053"
|
||||
},
|
||||
{
|
||||
"isSubItem": false,
|
||||
"remoteAPI": {
|
||||
"url": "",
|
||||
"executed": false
|
||||
},
|
||||
"icon": "icon-link",
|
||||
"className": "form-link-record",
|
||||
"rules": [],
|
||||
"modelType": "main",
|
||||
"type": "link-record",
|
||||
"hideTitle": false,
|
||||
"name": "主表@表单控件",
|
||||
"options": {
|
||||
"sourceCode": "ai_control_main",
|
||||
"showMode": "single",
|
||||
"showType": "card",
|
||||
"titleField": "wen_ben",
|
||||
"showFields": [],
|
||||
"allowView": true,
|
||||
"allowEdit": true,
|
||||
"allowAdd": true,
|
||||
"allowSelect": true,
|
||||
"buttonText": "添加记录",
|
||||
"twoWayModel": "sub_table_design_1717137038626_791984",
|
||||
"dataSelectAuth": "all",
|
||||
"filters": [
|
||||
{
|
||||
"matchType": "AND",
|
||||
"rules": []
|
||||
}
|
||||
],
|
||||
"search": {
|
||||
"enabled": false,
|
||||
"field": "",
|
||||
"rule": "like",
|
||||
"afterShow": false,
|
||||
"fields": []
|
||||
},
|
||||
"createMode": {
|
||||
"add": true,
|
||||
"select": false,
|
||||
"params": {
|
||||
"selectLinkModel": ""
|
||||
}
|
||||
},
|
||||
"width": "100%",
|
||||
"defaultValue": "",
|
||||
"defaultValType": "none",
|
||||
"required": false,
|
||||
"disabled": false,
|
||||
"hidden": false,
|
||||
"hiddenOnAdd": false,
|
||||
"fieldNote": ""
|
||||
},
|
||||
"model": "link_record_1717137044235_306956",
|
||||
"advancedSetting": {
|
||||
"defaultValue": {
|
||||
"type": "compose",
|
||||
"value": "",
|
||||
"format": "string",
|
||||
"allowFunc": true,
|
||||
"valueSplit": "",
|
||||
"customConfig": true
|
||||
}
|
||||
},
|
||||
"key": "1717137044235_306956"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"jmReportURL": "",
|
||||
"enableComment": true,
|
||||
"dialogOptions": {
|
||||
"padding": {
|
||||
"top": 25,
|
||||
"left": 25,
|
||||
"bottom": 30,
|
||||
"right": 25
|
||||
},
|
||||
"top": 20,
|
||||
"width": 1000
|
||||
},
|
||||
"allowJmReport": false,
|
||||
"labelWidth": 100,
|
||||
"headerImgUrl": "",
|
||||
"noticeMode": "external",
|
||||
"noticeReceiver": "",
|
||||
"designMobileView": false,
|
||||
"labelPosition": "top",
|
||||
"allowPrint": false,
|
||||
"enableNotice": false,
|
||||
"bizRuleConfig": [],
|
||||
"showHeaderTitle": true,
|
||||
"bigDataMode": false,
|
||||
"titleField": "input_1717072902303_477529",
|
||||
"externalTitle": "",
|
||||
"noticeType": "system",
|
||||
"customRequestURL": [
|
||||
{
|
||||
"url": ""
|
||||
}
|
||||
],
|
||||
"hasWidgets": [
|
||||
"input",
|
||||
"card",
|
||||
"number",
|
||||
"money",
|
||||
"select",
|
||||
"textarea",
|
||||
"imgupload",
|
||||
"file-upload",
|
||||
"link-record"
|
||||
],
|
||||
"expand": {
|
||||
"css": "",
|
||||
"js": "",
|
||||
"url": {
|
||||
"css": "",
|
||||
"js": ""
|
||||
}
|
||||
},
|
||||
"size": "small",
|
||||
"disabledAutoGrid": false,
|
||||
"allowExternalLink": false,
|
||||
"externalLinkShowData": false,
|
||||
"transactional": true
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>jeecg-system-api</artifactId>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<version>3.7.1</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.1</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.1</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.1</version>
|
||||
<version>3.7.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -27,23 +27,22 @@
|
||||
<!-- 企业微信/钉钉 api -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework</groupId>
|
||||
<artifactId>jeewx-api</artifactId>
|
||||
<artifactId>weixin4j</artifactId>
|
||||
</dependency>
|
||||
<!-- 积木报表 -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-nosql-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 积木BI -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimubi-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 积木报表 mongo redis 支持包
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.jimureport</groupId>
|
||||
<artifactId>jimureport-nosql-starter</artifactId>
|
||||
</dependency>-->
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -82,4 +82,30 @@ public class JimuReportTokenService implements JmReportTokenServiceI {
|
||||
// 将所有信息存放至map 解析sql/api会根据map的键值解析
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将jeecgboot平台的权限传递给积木报表
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String[] getPermissions(String token) {
|
||||
// 获取用户信息
|
||||
String username = JwtUtil.getUsername(token);
|
||||
SysUserCacheInfo userInfo = null;
|
||||
try {
|
||||
userInfo = sysBaseApi.getCacheUser(username);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户信息异常:"+ e.getMessage());
|
||||
}
|
||||
if(userInfo == null){
|
||||
return null;
|
||||
}
|
||||
// 查询权限
|
||||
Set<String> userPermissions = sysBaseApi.getUserPermissionSet(userInfo.getSysUserId());
|
||||
if(CollectionUtils.isEmpty(userPermissions)){
|
||||
return null;
|
||||
}
|
||||
return userPermissions.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,12 +5,15 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.jeecg.common.api.dto.message.MessageDTO;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.constant.enums.MessageTypeEnum;
|
||||
import org.jeecg.common.system.util.JwtUtil;
|
||||
import org.jeecg.common.util.RedisUtil;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.config.StaticConfig;
|
||||
import org.jeecg.modules.message.entity.SysMessage;
|
||||
import org.jeecg.modules.message.handle.ISendMsgHandle;
|
||||
import org.jeecg.modules.message.mapper.SysMessageMapper;
|
||||
import org.jeecg.modules.system.entity.SysUser;
|
||||
import org.jeecg.modules.system.mapper.SysUserMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -43,6 +46,9 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Autowired
|
||||
private SysMessageMapper sysMessageMapper;
|
||||
|
||||
/**
|
||||
* 真实姓名变量
|
||||
@ -78,6 +84,23 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
|
||||
|
||||
@Override
|
||||
public void sendMessage(MessageDTO messageDTO) {
|
||||
String content = messageDTO.getContent();
|
||||
String title = messageDTO.getTitle();
|
||||
//update-begin---author:wangshuai---date:2024-11-20---for:【QQYUN-8523】敲敲云发邮件通知,不稳定---
|
||||
boolean timeJobSendEmail = this.isTimeJobSendEmail(messageDTO.getToUser(), title, content);
|
||||
if(timeJobSendEmail){
|
||||
return;
|
||||
}
|
||||
//update-end---author:wangshuai---date:2024-11-20---for:【QQYUN-8523】敲敲云发邮件通知,不稳定---
|
||||
this.sendEmailMessage(messageDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接发送邮件
|
||||
*
|
||||
* @param messageDTO
|
||||
*/
|
||||
public void sendEmailMessage(MessageDTO messageDTO) {
|
||||
String[] arr = messageDTO.getToUser().split(",");
|
||||
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<SysUser>().in(SysUser::getUsername, arr);
|
||||
List<SysUser> list = sysUserMapper.selectList(query);
|
||||
@ -213,4 +236,35 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
|
||||
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 1 / 1000);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否定时发送邮箱
|
||||
* @param toUser
|
||||
* @param title
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
private boolean isTimeJobSendEmail(String toUser, String title, String content) {
|
||||
StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class);
|
||||
Boolean timeJobSend = staticConfig.getTimeJobSend();
|
||||
if(null != timeJobSend && timeJobSend){
|
||||
this.addSysSmsSend(toUser,title,content);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存到短信发送表
|
||||
*/
|
||||
private void addSysSmsSend(String toUser, String title, String content) {
|
||||
SysMessage sysMessage = new SysMessage();
|
||||
sysMessage.setEsTitle(title);
|
||||
sysMessage.setEsContent(content);
|
||||
sysMessage.setEsReceiver(toUser);
|
||||
sysMessage.setEsSendStatus("0");
|
||||
sysMessage.setEsSendNum(0);
|
||||
sysMessage.setEsType(MessageTypeEnum.YJ.getType());
|
||||
sysMessageMapper.insert(sysMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +51,9 @@ public class SendMsgJob implements Job {
|
||||
md.setToUser(sysMessage.getEsReceiver());
|
||||
md.setType(sysMessage.getEsType());
|
||||
md.setToAll(false);
|
||||
//update-begin---author:wangshuai---date:2024-11-12---for:【QQYUN-8523】敲敲云发邮件通知,不稳定---
|
||||
md.setIsTimeJob(true);
|
||||
//update-end---author:wangshuai---date:2024-11-12---for:【QQYUN-8523】敲敲云发邮件通知,不稳定---
|
||||
sysBaseAPI.sendTemplateMessage(md);
|
||||
//发送消息成功
|
||||
sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode());
|
||||
|
||||
@ -18,7 +18,7 @@ import static org.springframework.boot.actuate.endpoint.annotation.Selector.Matc
|
||||
* @Date: 2024/5/13 17:02
|
||||
*/
|
||||
@Component
|
||||
@Endpoint(id = "httptrace-new")
|
||||
@Endpoint(id = "jeecghttptrace")
|
||||
public class CustomHttpTraceEndpoint{
|
||||
private final CustomInMemoryHttpTraceRepository repository;
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user