mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
463 Commits
v3.7.1
...
v3.8.0last
| Author | SHA1 | Date | |
|---|---|---|---|
| 5972c74b43 | |||
| d69cb121fc | |||
| 10a9edd10b | |||
| c71ff3fbcc | |||
| 08612d5bfa | |||
| 2ecce8f02d | |||
| 62937f14fb | |||
| d6ccc4a326 | |||
| 1893108136 | |||
| 7980915bdc | |||
| 550997268b | |||
| 9e7d40a080 | |||
| 2c38db456b | |||
| e52538d304 | |||
| e91cbd5cd8 | |||
| 70cec8b5c6 | |||
| d2365088ce | |||
| a679571a5a | |||
| b9c74e549f | |||
| 81c1724016 | |||
| 56d59eb589 | |||
| a00fcae3a3 | |||
| 9aea5de668 | |||
| 8979dd7ae9 | |||
| a56bd05389 | |||
| 9cf3328ea4 | |||
| 286d10a50f | |||
| 37c593e1d4 | |||
| 68f36cb1e5 | |||
| 78454d3434 | |||
| 56fbc2ed8f | |||
| 197d7adaaf | |||
| 49ba40e98a | |||
| e952518d71 | |||
| 0e184eaa64 | |||
| 86a3ed9dae | |||
| 1e259c805e | |||
| 8a82141c95 | |||
| 94bff11eb1 | |||
| 590d73dfe3 | |||
| fe9630d15c | |||
| 77ae25b86a | |||
| 3b34276cf8 | |||
| cffba084fc | |||
| d1589acc41 | |||
| 888a032266 | |||
| 0d18e536f0 | |||
| 21392c44f8 | |||
| 2730d8e06f | |||
| 0002606d41 | |||
| 8bd19484ee | |||
| 5d2db92613 | |||
| c1b39d21dd | |||
| e83c9b8190 | |||
| 309c76d268 | |||
| 9bd03f467d | |||
| f78eabfc66 | |||
| e032591366 | |||
| de767e07b4 | |||
| b77d3e36ab | |||
| 7885aaed3b | |||
| 6f4c2eb77c | |||
| 3f0597a0f6 | |||
| 04a3764f00 | |||
| 68464109de | |||
| 79866c5823 | |||
| d64b8ecaef | |||
| ec9f2b146a | |||
| 69fd2888a1 | |||
| 748331d649 | |||
| cb1d8e3527 | |||
| a89b299a4b | |||
| 7a15bfc161 | |||
| 65f7eb9542 | |||
| 92808f9164 | |||
| d3ed3f49d3 | |||
| da3d39c59c | |||
| f332758179 | |||
| 61a8904e52 | |||
| b70e709e53 | |||
| b032a415aa | |||
| 81821eeddc | |||
| 5288b1fe73 | |||
| 408f192b37 | |||
| 6a9f188282 | |||
| 168f15e1c2 | |||
| ae814a7e8b | |||
| 2ba17648c4 | |||
| 7160ea32cb | |||
| 19fc610ef5 | |||
| 44146f073e | |||
| 36caab37e2 | |||
| 8abce5ad9c | |||
| 6e721e4120 | |||
| 447e439612 | |||
| 088c79238e | |||
| ad72c807f6 | |||
| db3d95e1a7 | |||
| 1a16b5550f | |||
| c6fe809013 | |||
| 677b57ae09 | |||
| 02f21de8d5 | |||
| f7ca26fff0 | |||
| 6c6aa964e8 | |||
| b0bab050dd | |||
| 87197be8f7 | |||
| 75aa1fe5a0 | |||
| 3e434ce6b4 | |||
| e07508d29f | |||
| e18e980892 | |||
| a2f18fd0d9 | |||
| 9ad7ef5ab4 | |||
| 27a7046465 | |||
| 47a2a6fbac | |||
| 83b1c8692e | |||
| 73a5f64d7e | |||
| 1d18a54b8a | |||
| e877929a42 | |||
| 5f5970d7d5 | |||
| e05c9ddc08 | |||
| b77e9e25a3 | |||
| a8bf090352 | |||
| b6c9f9db68 | |||
| 8c406dcdea | |||
| 215b263d1a | |||
| 4247ffd082 | |||
| ec87621858 | |||
| bc6cf0e7b4 | |||
| 353ad058d1 | |||
| cf63b056d5 | |||
| 60eeef14c7 | |||
| 25b30153a0 | |||
| beff2a271e | |||
| f743622655 | |||
| 70a1f0b7db | |||
| e166d916da | |||
| b79ba97614 | |||
| 4f371672d0 | |||
| 80ae183b58 | |||
| b4cac11368 | |||
| 4936e140e9 | |||
| 9fd4c3b3d2 | |||
| 4f2f1d6265 | |||
| b878f6b6be | |||
| 507289ff6c | |||
| bb4cdf93b1 | |||
| 7d7fde63ec | |||
| c22fd21233 | |||
| d4d0c884f0 | |||
| e6fe3459e4 | |||
| 9ebc3c49ec | |||
| a17b403675 | |||
| 45e9b03e2d | |||
| 696b65240f | |||
| f4339677e7 | |||
| 0aaf0ad3ad | |||
| 0e5cd5bb3e | |||
| 24406a4cac | |||
| 1a1c840a3b | |||
| 2e257343a4 | |||
| 7871c465c8 | |||
| 714d9dc244 | |||
| f23b176cf4 | |||
| 494f5e21f5 | |||
| dea260cae3 | |||
| 0fcc08c204 | |||
| 632fd72d79 | |||
| 608d2e1318 | |||
| 7e436f2efd | |||
| 15fc262675 | |||
| 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 | |||
| 6768d65e1e | |||
| 410ab7bcc3 | |||
| 76df4f8600 | |||
| a27b94c4c6 | |||
| 5ad06274cb | |||
| d38fa1901e | |||
| 174f1ae432 | |||
| eef2f7e269 | |||
| 6a0ec66d3d | |||
| b4aab76057 | |||
| d87ffc11e7 | |||
| a67b3409b1 | |||
| e11d831114 | |||
| ec410456b2 | |||
| e9326cab8c | |||
| 61d2857ca7 | |||
| cba4847413 | |||
| bc56384325 | |||
| d7dc1b8dc7 | |||
| 11d9f2b4e4 | |||
| 163b0b531f | |||
| 64fcf7fcfc | |||
| e6ddeef18c | |||
| d1af49a33f | |||
| 03265691e6 | |||
| 47a074d9cb | |||
| c32f0407e8 | |||
| 22bbc23069 | |||
| b2078d502a | |||
| ed165464c8 | |||
| 9cf66e7026 | |||
| 11f8038196 | |||
| d2105dc095 | |||
| 32287d98ac | |||
| de9cc2f30d | |||
| 31cf94ac7b | |||
| 26887959cd | |||
| 0d28c92c83 | |||
| 1cc5cee92d | |||
| 26246eda7a | |||
| 10dd2a2dd0 | |||
| 5abc745496 | |||
| 353e8e2fb6 | |||
| 56661815ec | |||
| 03b6d20fcb | |||
| 7e15e81218 | |||
| 2388c8c46d | |||
| 45f905ddac | |||
| 55696efcaa | |||
| 3671b81f01 | |||
| 74ad7e6f92 | |||
| 49d55a79f4 | |||
| 8395d106a2 | |||
| d716111ded | |||
| 81b4cbbe35 | |||
| 86cfc18fe8 | |||
| 98ba72ae4b | |||
| 8b0e0367c7 | |||
| 334f7dbb62 | |||
| 29248561d6 | |||
| ad74b78134 | |||
| bd716417e8 | |||
| e9ddd21286 | |||
| 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 | |||
| 458526075e | |||
| a1b55f0d40 | |||
| ee382c0a5b | |||
| f7f6d0ff88 | |||
| 4d058e1dce | |||
| 5c9c2dbebe | |||
| 44f7075316 | |||
| c88bfcf35a | |||
| 11d13c8305 | |||
| 0582436b9c | |||
| 00252f392f | |||
| ef16814216 | |||
| a626b6a4d0 | |||
| fca5d0e54e | |||
| 1c3b9a10f1 | |||
| b0c4194602 | |||
| 64b29f47e0 | |||
| 6198a3702f | |||
| 453acb9b4e | |||
| 565753e370 | |||
| e2aaf0f978 | |||
| 32c8370ef2 | |||
| a79004b924 | |||
| eb1612f8dd | |||
| 2f0a3bcd87 | |||
| a35555619c | |||
| b3e3951064 | |||
| 44ec26574e | |||
| 55a25caafd | |||
| 62f7b0d489 | |||
| b16fdef8dc | |||
| b5b667058b | |||
| 6c0c259742 | |||
| ca56c54aa0 | |||
| 30d3a9f17b | |||
| 74297af987 | |||
| fedb6b84b9 | |||
| fdc713339e | |||
| 03739f2837 | |||
| f28a2dbbeb | |||
| b81435aaca | |||
| d9e8bd2bc8 | |||
| 81eef5a838 | |||
| f528f72903 | |||
| 918286c144 | |||
| 512234a804 | |||
| 48805484d4 | |||
| 7fecdf94e5 | |||
| a3997dfd16 | |||
| c868d90c2f | |||
| 77aebf5dd2 | |||
| e770524f3a | |||
| c5fee07cba | |||
| 9fd20fde9e | |||
| 2af9451b7f | |||
| 575baa8d49 | |||
| 48bc76cce7 | |||
| 58c0882329 | |||
| c400ec8482 | |||
| 2068bdc112 | |||
| ffe806352e | |||
| 167a6c458c | |||
| 872e6ed024 | |||
| cacc59b8fd | |||
| c744633139 | |||
| 0e4d304878 | |||
| 17a8964487 | |||
| 8ac6989d2c | |||
| 402ab0ffc4 | |||
| 7778ede90e | |||
| 06144206df | |||
| 3d3b5850ad | |||
| 816eeb9225 | |||
| 0b42efbbbf | |||
| b8e0d4391d | |||
| 72b34d082b | |||
| 7112649a21 | |||
| fbc312c35d | |||
| b8162a4a6d | |||
| 28404d2fd3 | |||
| c92c9be49a | |||
| 58e85e0569 | |||
| 6fc34d8a39 | |||
| 790df934b5 | |||
| 8aee4011a2 | |||
| 6e0277c60a | |||
| e923654161 | |||
| 06b41ae479 | |||
| 11af85d87a | |||
| 4caff75cce | |||
| 811861a957 | |||
| 24623ba4b0 | |||
| 7c68b46943 | |||
| 7c34161369 | |||
| bc52aa918d | |||
| 9dfdd47b36 | |||
| 272a7540eb | |||
| ad796f079f | |||
| e7e7716d05 | |||
| c5d620d2b2 | |||
| cdea05ebb0 | |||
| ca9a433f3c | |||
| 2be6052cd4 | |||
| 68ed67ee49 | |||
| d5903ba52a | |||
| 3ee635eddf | |||
| 21bc68fb53 | |||
| f532e57862 | |||
| da08adbea1 | |||
| 46e3e62b59 | |||
| 3656264f8a | |||
| 3361d48cd4 | |||
| ed86ea3da1 | |||
| 3deb0e5487 | |||
| 9e4792941e | |||
| b5fd5fe782 | |||
| 33c0104a02 | |||
| 81ed5100af | |||
| 87f9dc0064 | |||
| b311fedc6b | |||
| e321a0405f | |||
| d8bc74794d | |||
| 732f05dc74 | |||
| 6ce92798c6 | |||
| f4454e9348 | |||
| d9134ae0c8 | |||
| 25180e41c8 | |||
| a99e3f2268 | |||
| d27c354bf1 | |||
| d818b1dd9d | |||
| bcdbec0091 | |||
| 098bb12b9e | |||
| 4a6c750b19 | |||
| d396e5304a | |||
| 9bed25be8c | |||
| 7109b42092 | |||
| 1667b14194 | |||
| e9514873d2 | |||
| 0ee090664e | |||
| 4a9eda4ab0 | |||
| 2416c8b251 | |||
| 5b056f9dd6 | |||
| a93998dc56 | |||
| 268c27a782 | |||
| 23ace2712a | |||
| 157feeb925 | |||
| 4e25d4162f | |||
| 47a68f31e1 |
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,请说明你使用的分支;
|
||||
12
LICENSE
12
LICENSE
@ -200,4 +200,14 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||
|
||||
开源协议中文释意如下:
|
||||
1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
2.允许基于本平台软件开展业务系统开发。
|
||||
3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
|
||||
最终解释权归:http://www.jeecg.com
|
||||
164
README-AI.md
Normal file
164
README-AI.md
Normal file
@ -0,0 +1,164 @@
|
||||
AIGC应用平台介绍
|
||||
===============
|
||||
|
||||
一个全栈式 AI 开发平台,旨在帮助开发者快速构建和部署个性化的 AI 应用。
|
||||
|
||||
> JDK说明:AI流程编排引擎暂时不支持jdk21,所以目前只能使用jdk8或者jdk17启动项目。
|
||||
|
||||
|
||||
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流程 |
|
||||
| 实现语言 | python + react | JAVA + vue3 |
|
||||
| 上传markdown文档库(支持图片) | 不支持 | 支持 |
|
||||
| AI对话支持发图和展示图片 | 支持 | 支持 |
|
||||
|
||||
|
||||
|
||||
### 安装向量库 pgvector
|
||||
|
||||
- https://help.jeecg.com/aigc/config
|
||||
|
||||
|
||||
|
||||
|
||||
## 功能特点
|
||||
|
||||
- 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聊天助手快速嵌入到第三方系统,让系统快速拥有智能问答能力,提高用户满意度。
|
||||
|
||||
|
||||
|
||||
|
||||
#### 在线体验
|
||||
|
||||
- JeecgBoot演示: https://boot3.jeecg.com
|
||||
- 敲敲云在线搭建AI知识库:https://app.qiaoqiaoyun.com
|
||||
|
||||
|
||||
## 技术交流
|
||||
|
||||
- 开发文档:https://help.jeecg.com/aigc
|
||||
- QQ群:716488839
|
||||
|
||||
|
||||
## 功能列表
|
||||
|
||||
- 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智能回复,你可以搭建自己的智能体,比如搭建一个 “诗词达人” “翻译助手”
|
||||
|
||||

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

|
||||
73
README-EN.md
73
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.8.0 (Release date: 2025-04-18)
|
||||
|
||||
|
||||
[](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</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)
|
||||
|
||||
|
||||
|
||||
@ -72,10 +78,11 @@ Technical documentation
|
||||
-----------------------------------
|
||||
|
||||
- Website: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- Doc: [http://help.jeecg.com](http://help.jeecg.com)
|
||||
- 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 : ⑨808791225、⑧825232878、⑦791696430、⑥730954414(full)、683903138(full)、⑤860162132(full)、④774126647(full)、③816531124(full)、②769925425(full)、①284271917(full)
|
||||
- Demo : [OnlineDemo](http://boot3.jeecg.com) | [APP](http://jeecg.com/appIndex)
|
||||
- Doc: [DocumentCenter](http://help.jeecg.com) | [AI Config](https://help.jeecg.com/java/ai/aichat)
|
||||
- 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
|
||||
|
||||
|
||||
|
||||
|
||||
@ -174,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)
|
||||
|
||||
@ -191,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.7.6
|
||||
- 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
|
||||
|
||||
@ -212,6 +219,14 @@ Technical Architecture:
|
||||
|
||||
- TechnologyStack:`Vue3.0+TypeScript+Vite+AntDesignVue+pinia+echarts`
|
||||
|
||||
#### Front-end environment requirements
|
||||
|
||||
* `Node.js 、npm 、pnpm`
|
||||
* pnpm `v9+` is now required.
|
||||
* Node.js Version suggestion: `v20.15.0`
|
||||
` ( Since Vite6 Node.js 18/20 + is now required )`
|
||||
|
||||
|
||||
#### Support library
|
||||
|
||||
| database | support |
|
||||
@ -223,6 +238,24 @@ Technical Architecture:
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
| 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
|
||||
@ -235,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
|
||||
@ -252,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
|
||||
|
||||
191
README.md
191
README.md
@ -1,13 +1,13 @@
|
||||
|
||||
JeecgBoot 低代码开发平台
|
||||
JeecgBoot AI低代码平台
|
||||
===============
|
||||
|
||||
当前最新版本: 3.7.1(发布日期:2024-09-12)
|
||||
当前最新版本: 3.8.0(发布日期:2025-04-18)
|
||||
|
||||
|
||||
[](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,50 +16,134 @@ JeecgBoot 低代码开发平台
|
||||
项目介绍
|
||||
-----------------------------------
|
||||
|
||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||
<h3 align="center">Java AI Low Code Platform</h3>
|
||||
|
||||
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.x,SpringCloud,Ant Design Vue3,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||
JeecgBoot是一款基于AIGC和低代码引擎的AI低代码平台,旨在帮助开发者快速实现低代码开发和构建、部署个性化的 AI 应用。
|
||||
前后端分离架构Ant Design&Vue3,SpringBoot,SpringCloud Alibaba,Mybatis-plus,Shiro,强大的代码生成器让前后端代码一键生成,无需写任何代码!
|
||||
成套AI大模型功能: AI模型管理、AI应用、知识库、AI流程编排、AI对话助手等;
|
||||
引领AI低代码开发模式: AIGC生成->OnlineCoding-> 代码生成-> 手工MERGE, 帮助Java项目解决80%的重复工作,让开发更多关注业务,快速提高效率 节省成本,同时又不失灵活性!
|
||||
|
||||
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、仪表盘设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||
|
||||
JeecgBoot 提供了一系列 `低代码能力`,实现`真正的零代码`在线开发:Online表单开发、Online报表、复杂报表设计、打印设计、在线图表设计、仪表盘设计、大屏设计、移动图表能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)
|
||||
|
||||
`AI赋能低代码:` 目前提供了AI应用、AI模型管理、AI流程编排、AI对话助手,AI建表、AI写文章、AI知识库问答、AI字段建议等功能;支持各种AI大模型ChatGPT、DeepSeek、Ollama、智普、千问等.
|
||||
|
||||
`JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`;复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
|
||||
|
||||
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
||||
|
||||
|
||||
|
||||
### 视频介绍
|
||||
|
||||
[](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%以上,极大降低开发成本。
|
||||
又是一个全栈式 AI 开发平台,快速帮助企业构建和部署个性化的 AI 应用。
|
||||
|
||||
|
||||
信创国产化
|
||||
-----------------------------------
|
||||
JeecgBoot 是一个开源低代码开发平台,支持全信创环境。它兼容多种国产操作系统和数据库,包括:
|
||||
|
||||
- 操作系统:国产麒麟、银河麒麟等国产系统几乎都是基于 Linux 内核,因此它们具有良好的兼容性。
|
||||
- 数据库:达梦、人大金仓、TiDB , [转库文档](https://my.oschina.net/jeecg/blog/4905722)
|
||||
- 中间件:东方通 TongWeb、TongRDS,宝兰德 AppServer、CacheDB, [信创配置文档](https://help.jeecg.com/java/tongweb-deploy/)
|
||||
|
||||
通过这些适配,JeecgBoot 为使用国产软件和硬件的用户提供了高效的开发解决方案。
|
||||
|
||||
|
||||
|
||||
#### 项目说明
|
||||
项目说明
|
||||
-----------------------------------
|
||||
|
||||
| 项目名 | 说明 |
|
||||
|--------------------|------------------------|
|
||||
| `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 |
|
||||
|
||||
|
||||
|
||||
技术文档
|
||||
-----------------------------------
|
||||
|
||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- 开发文档: [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)
|
||||
- QQ交流群 : ⑨808791225、其他(满)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
- 在线演示 : [平台演示](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服务能力。
|
||||
|
||||
> JDK说明:AI流程编排引擎暂时不支持jdk21,所以目前只能使用jdk8或者jdk17启动项目。
|
||||
|
||||
- [AIGC专题介绍页](README-AI.md)
|
||||
- [AIGC开发文档](https://help.jeecg.com/aigc)
|
||||
- [配置向量库PGVector](https://help.jeecg.com/aigc/config)
|
||||
|
||||
|
||||
##### AI视频介绍
|
||||
|
||||
[](https://www.bilibili.com/video/BV1zmd7YFE4w)
|
||||
|
||||
|
||||
##### 在线体验
|
||||
|
||||
- JeecgBoot演示: https://boot3.jeecg.com
|
||||
- 敲敲云在线搭建AI知识库:https://app.qiaoqiaoyun.com
|
||||
|
||||
##### 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本地模型 | √ |
|
||||
| 等等。。 | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
技术架构:
|
||||
@ -68,15 +152,16 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
#### 后端
|
||||
|
||||
- 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.7.6
|
||||
- 安全框架: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(简化代码)等。
|
||||
@ -87,13 +172,23 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
#### 前端
|
||||
|
||||
- 前端IDE建议:WebStorm、Vscode
|
||||
- 采用 Vue3.0+TypeScript+Vite+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+` 版本以上
|
||||
|
||||
` ( 因为Vite6 需要 Node.js 18 / 20+ )`
|
||||
|
||||
|
||||
#### 平台支持数据库
|
||||
|
||||
> jeecgboot平台支持以下数据库,默认我们只提供mysql脚本,其他数据库可以参考[转库文档](https://my.oschina.net/jeecg/blog/4905722)自己转。
|
||||
|
||||
| 数据库 | 支持 |
|
||||
| --- | --- |
|
||||
@ -104,7 +199,9 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
|
||||
| TiDB | √ |
|
||||
| kingbase8 | √ |
|
||||
|
||||
|
||||
|
||||
## 微服务解决方案
|
||||
@ -118,7 +215,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
- 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
|
||||
@ -130,8 +227,8 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||
#### 微服务方式启动
|
||||
|
||||
- [单体快速切换微服务](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)
|
||||
|
||||
|
||||
#### 微服务架构图
|
||||
@ -143,12 +240,12 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
-----------------------------------
|
||||
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd+vue3),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供切换机制支持单体和微服务自由切换
|
||||
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
||||
* 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导入导出,支持单表导出和一对多表模式导出,生成的代码自带导入导出功能
|
||||
@ -207,12 +304,20 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||
### 功能模块
|
||||
```
|
||||
├─AI开发
|
||||
│ ├─支持AI大模型ChatGPT和DeepSeek
|
||||
│ ├─AI对话助手
|
||||
│ ├─AI建表
|
||||
│ ├─AI写文章
|
||||
│ ├─AI流程编排
|
||||
│ ├─AI知识库问答系统
|
||||
│ ├─AI应用开发平台
|
||||
│ ├─AI聊天窗口支持嵌入第三方
|
||||
├─Online在线开发(低代码)
|
||||
│ ├─Online在线表单
|
||||
│ ├─Online代码生成器
|
||||
│ ├─Online在线报表
|
||||
│ ├─仪表盘设计器
|
||||
│ ├─AI助手
|
||||
│ ├─系统编码规则
|
||||
│ ├─系统校验规则
|
||||
├─积木报表设计器
|
||||
@ -347,6 +452,24 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||
### 系统效果
|
||||
|
||||
|
||||
##### AI功能
|
||||
|
||||
AI聊天助手
|
||||
|
||||

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

|
||||
|
||||

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

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

|
||||
|
||||
@ -365,8 +488,6 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||

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

|
||||
|
||||
|
||||
##### 仪表盘设计器
|
||||
|
||||
@ -200,4 +200,14 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||
|
||||
开源协议中文释意如下:
|
||||
1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
||||
2.允许基于本平台软件开展业务系统开发。
|
||||
3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
||||
|
||||
最终解释权归:http://www.jeecg.com
|
||||
@ -2,12 +2,12 @@
|
||||
JeecgBoot 低代码开发平台
|
||||
===============
|
||||
|
||||
当前最新版本: 3.7.1(发布日期:2024-09-12)
|
||||
当前最新版本: 3.8.0(发布日期:2025-05-16)
|
||||
|
||||
|
||||
[](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)
|
||||
|
||||
@ -35,7 +35,7 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
|
||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
||||
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart)
|
||||
- QQ交流群 : ⑨808791225、其他(满)
|
||||
- QQ交流群 : ⑩716488839、⑨808791225、其他(满)
|
||||
- 在线演示 : [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
|
||||
> 演示系统的登录账号密码,请点击 [获取账号密码](http://jeecg.com/doc/demo) 获取
|
||||
|
||||
@ -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.7.6
|
||||
- 报表工具: 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(简化代码)等。
|
||||
@ -97,6 +97,7 @@ JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端
|
||||
| MariaDB | √ |
|
||||
| 达梦 | √ |
|
||||
| 人大金仓 | √ |
|
||||
| TiDB | √ |
|
||||
|
||||
|
||||
|
||||
@ -112,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;
|
||||
|
||||
|
||||
170
jeecg-boot/db/基于AK和SK安全鉴权的OpenAPI/升级SQL脚本.sql
Normal file
170
jeecg-boot/db/基于AK和SK安全鉴权的OpenAPI/升级SQL脚本.sql
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : mysql5.7
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 50738 (5.7.38)
|
||||
Source Host : 127.0.0.1:3306
|
||||
Source Schema : jeecg-boot
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 50738 (5.7.38)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 15/05/2025 10:18:36
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for open_api
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `open_api`;
|
||||
CREATE TABLE `open_api` (
|
||||
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '接口名称',
|
||||
`request_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '请求方法',
|
||||
`request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '接口地址',
|
||||
`black_list` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'IP 黑名单',
|
||||
`body` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '请求体内容',
|
||||
`origin_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '原始地址',
|
||||
`status` int(10) NULL DEFAULT NULL COMMENT '状态',
|
||||
`del_flag` int(10) NULL DEFAULT NULL COMMENT '删除标识',
|
||||
`create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
|
||||
`headers_json` json NULL COMMENT '请求头json',
|
||||
`params_json` json NULL COMMENT '请求参数json',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '接口表' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of open_api
|
||||
-- ----------------------------
|
||||
INSERT INTO `open_api` VALUES ('1922132683346649090', '根据部门查询用户', 'GET', 'TEwcXBlr', NULL, NULL, '/sys/user/queryUserByDepId', 1, 0, 'admin', '2025-05-13 11:31:58', 'admin', '2025-05-15 10:10:01', '[]', '[{\"id\": \"row_24\", \"note\": \"\", \"paramKey\": \"id\", \"required\": \"1\", \"defaultValue\": \"\"}]');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for open_api_auth
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `open_api_auth`;
|
||||
CREATE TABLE `open_api_auth` (
|
||||
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '授权名称',
|
||||
`ak` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'AK',
|
||||
`sk` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'SK',
|
||||
`create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
|
||||
`system_user_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联系统用户名',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '权限表' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of open_api_auth
|
||||
-- ----------------------------
|
||||
INSERT INTO `open_api_auth` VALUES ('1922164194775056386', 'scott', 'ak-pFjyNHWRsJEFWlu6', '4hV5dBrZtmGAtPdbA5yseaeKRYNpzGsS', 'admin', '2025-05-13 13:37:11', NULL, NULL, 'e9ca23d68d884d4ebb19d07889727dae');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for open_api_log
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `open_api_log`;
|
||||
CREATE TABLE `open_api_log` (
|
||||
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`api_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '接口ID',
|
||||
`call_auth_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '调用ID',
|
||||
`call_time` datetime NULL DEFAULT NULL COMMENT '调用时间',
|
||||
`used_time` bigint(20) NULL DEFAULT NULL COMMENT '耗时',
|
||||
`response_time` datetime NULL DEFAULT NULL COMMENT '响应时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '调用记录表' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of open_api_log
|
||||
-- ----------------------------
|
||||
INSERT INTO `open_api_log` VALUES ('1922175238557913090', '1922132683346649090', '1922164194775056386', '2025-05-13 14:21:04', 94, '2025-05-13 14:21:04');
|
||||
INSERT INTO `open_api_log` VALUES ('1922175436256432130', '1922132683346649090', '1922164194775056386', '2025-05-13 14:21:51', 38, '2025-05-13 14:21:51');
|
||||
INSERT INTO `open_api_log` VALUES ('1922175487921868802', '1922132683346649090', '1922164194775056386', '2025-05-13 14:22:03', 31, '2025-05-13 14:22:03');
|
||||
INSERT INTO `open_api_log` VALUES ('1922176033789562883', '1922132683346649090', '1922164194775056386', '2025-05-13 14:24:13', 27, '2025-05-13 14:24:13');
|
||||
INSERT INTO `open_api_log` VALUES ('1922176583943835650', '1922132683346649090', '1922164194775056386', '2025-05-13 14:26:25', 39, '2025-05-13 14:26:25');
|
||||
INSERT INTO `open_api_log` VALUES ('1922177249969934337', '1922132683346649090', '1922164194775056386', '2025-05-13 14:28:08', 55250, '2025-05-13 14:29:03');
|
||||
INSERT INTO `open_api_log` VALUES ('1922180212645941249', '1922132683346649090', '1922164194775056386', '2025-05-13 14:40:46', 4162, '2025-05-13 14:40:50');
|
||||
INSERT INTO `open_api_log` VALUES ('1922180441692688385', '1922132683346649090', '1922164194775056386', '2025-05-13 14:41:11', 33346, '2025-05-13 14:41:44');
|
||||
INSERT INTO `open_api_log` VALUES ('1922180521686454273', '1922132683346649090', '1922164194775056386', '2025-05-13 14:42:00', 3570, '2025-05-13 14:42:03');
|
||||
INSERT INTO `open_api_log` VALUES ('1922180965825499138', '1922132683346649090', '1922164194775056386', '2025-05-13 14:42:10', 99211, '2025-05-13 14:43:49');
|
||||
INSERT INTO `open_api_log` VALUES ('1922181034515615746', '1922132683346649090', '1922164194775056386', '2025-05-13 14:43:52', 14005, '2025-05-13 14:44:06');
|
||||
INSERT INTO `open_api_log` VALUES ('1922183171307982850', '1922132683346649090', '1922164194775056386', '2025-05-13 14:52:15', 19834, '2025-05-13 14:52:35');
|
||||
INSERT INTO `open_api_log` VALUES ('1922184177068523521', '1922132683346649090', '1922164194775056386', '2025-05-13 14:56:34', 748, '2025-05-13 14:56:35');
|
||||
INSERT INTO `open_api_log` VALUES ('1922184729043107841', '1922132683346649090', '1922164194775056386', '2025-05-13 14:58:46', 1031, '2025-05-13 14:58:47');
|
||||
INSERT INTO `open_api_log` VALUES ('1922184806453182465', '1922132683346649090', '1922164194775056386', '2025-05-13 14:59:05', 68, '2025-05-13 14:59:05');
|
||||
INSERT INTO `open_api_log` VALUES ('1922184918382379009', '1922132683346649090', '1922164194775056386', '2025-05-13 14:59:10', 22155, '2025-05-13 14:59:32');
|
||||
INSERT INTO `open_api_log` VALUES ('1922185292635844610', '1922132683346649090', '1922164194775056386', '2025-05-13 15:00:55', 6267, '2025-05-13 15:01:01');
|
||||
INSERT INTO `open_api_log` VALUES ('1922186002672791554', '1922132683346649090', '1922164194775056386', '2025-05-13 15:03:23', 27554, '2025-05-13 15:03:50');
|
||||
INSERT INTO `open_api_log` VALUES ('1922187506582425601', '1922132683346649090', '1922164194775056386', '2025-05-13 15:09:45', 3464, '2025-05-13 15:09:49');
|
||||
INSERT INTO `open_api_log` VALUES ('1922187586597163011', '1922132683346649090', '1922164194775056386', '2025-05-13 15:10:08', 82, '2025-05-13 15:10:08');
|
||||
INSERT INTO `open_api_log` VALUES ('1922187924741951490', '1922132683346649090', '1922164194775056386', '2025-05-13 15:10:49', 39590, '2025-05-13 15:11:28');
|
||||
INSERT INTO `open_api_log` VALUES ('1922188138710261761', '1922132683346649090', '1922164194775056386', '2025-05-13 15:12:19', 758, '2025-05-13 15:12:19');
|
||||
INSERT INTO `open_api_log` VALUES ('1922188290661507073', '1922132683346649090', '1922164194775056386', '2025-05-13 15:12:29', 26527, '2025-05-13 15:12:56');
|
||||
INSERT INTO `open_api_log` VALUES ('1922189701755424769', '1922132683346649090', '1922164194775056386', '2025-05-13 15:18:28', 3619, '2025-05-13 15:18:32');
|
||||
INSERT INTO `open_api_log` VALUES ('1922190076784803841', '1922132683346649090', '1922164194775056386', '2025-05-13 15:20:01', 741, '2025-05-13 15:20:02');
|
||||
INSERT INTO `open_api_log` VALUES ('1922836671113101313', '1922132683346649090', '1922164194775056386', '2025-05-15 10:09:21', 186, '2025-05-15 10:09:22');
|
||||
INSERT INTO `open_api_log` VALUES ('1922836856287428610', '1922132683346649090', '1922164194775056386', '2025-05-15 10:10:06', 145, '2025-05-15 10:10:06');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for open_api_permission
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `open_api_permission`;
|
||||
CREATE TABLE `open_api_permission` (
|
||||
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`api_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '接口ID',
|
||||
`api_auth_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '认证ID',
|
||||
`create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'openapi授权' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of open_api_permission
|
||||
-- ----------------------------
|
||||
INSERT INTO `open_api_permission` VALUES ('1922164225875820545', '1922132683346649090', '1922164194775056386', 'admin', '2025-05-13 13:37:18', NULL, NULL);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('1917957565728198657', '1922109301837606914', '接口文档', '/openapi/SwaggerUI', 'openapi/SwaggerUI', 1, '', null, 1, null, '0', 1, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 23:01:32', 'admin', '2025-05-13 09:59:46', 0, 0, null, 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('1922109301837606914', '', 'OpenApi管理', '/openapi', 'layouts/RouteView', 1, '', null, 0, null, '0', 12.1, 0, 'ant-design:swap-outlined', 0, 0, 0, 0, null, 'admin', '2025-05-13 09:59:03', 'admin', '2025-05-13 10:02:43', 0, 0, null, 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193340030', '1922109301837606914', '接口管理', '/openapi/openApiList', 'openapi/OpenApiList', 1, null, null, 1, null, '1', 0, 0, null, 0, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', 'admin', '2025-05-13 09:59:24', 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193350031', '2025050104193340030', '添加接口管理', null, null, 0, null, null, 2, 'openapi:open_api:add', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193350032', '2025050104193340030', '编辑接口管理', null, null, 0, null, null, 2, 'openapi:open_api:edit', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193350033', '2025050104193340030', '删除接口管理', null, null, 0, null, null, 2, 'openapi:open_api:delete', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193350034', '2025050104193340030', '批量删除接口管理', null, null, 0, null, null, 2, 'openapi:open_api:deleteBatch', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193350035', '2025050104193340030', '导出excel_接口管理', null, null, 0, null, null, 2, 'openapi:open_api:exportXls', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050104193350036', '2025050104193340030', '导入excel_接口管理', null, null, 0, null, null, 2, 'openapi:open_api:importExcel', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 16:19:03', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940200', '1922109301837606914', '授权管理', '/openapi/openApiAuthList', 'openapi/OpenApiAuthList', 1, null, null, 1, null, '1', 0, 0, null, 0, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', 'admin', '2025-05-13 09:59:35', 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940201', '2025050105554940200', '添加授权管理', null, null, 0, null, null, 2, 'openapi:open_api_auth:add', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940202', '2025050105554940200', '编辑授权管理', null, null, 0, null, null, 2, 'openapi:open_api_auth:edit', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940203', '2025050105554940200', '删除授权管理', null, null, 0, null, null, 2, 'openapi:open_api_auth:delete', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940204', '2025050105554940200', '批量删除授权管理', null, null, 0, null, null, 2, 'openapi:open_api_auth:deleteBatch', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940205', '2025050105554940200', '导出excel_授权管理', null, null, 0, null, null, 2, 'openapi:open_api_auth:exportXls', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', null, null, 0, 0, '1', 0);
|
||||
INSERT INTO sys_permission (id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external) VALUES ('2025050105554940206', '2025050105554940200', '导入excel_授权管理', null, null, 0, null, null, 2, 'openapi:open_api_auth:importExcel', '1', null, 0, null, 1, 0, 0, 0, null, 'admin', '2025-05-01 17:55:20', null, null, 0, 0, '1', 0);
|
||||
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917957659860963330', 'f6817f48af4fb3af11b9e8bf182f618b', '1917957565728198657', null, '2025-05-01 23:01:55', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1922109760551858178', 'f6817f48af4fb3af11b9e8bf182f618b', '1922109301837606914', null, '2025-05-13 10:00:53', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071739539457', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193340030', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071806648321', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193350031', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071806648322', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193350032', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071806648323', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193350033', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071806648324', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193350034', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071806648325', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193350035', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917857071806648326', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050104193350036', null, '2025-05-01 16:22:13', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917881149426864129', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050105554940200', null, '2025-05-01 17:57:53', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917881149431058436', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050105554940203', null, '2025-05-01 17:57:53', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917881149431058437', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050105554940204', null, '2025-05-01 17:57:53', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917881149431058438', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050105554940205', null, '2025-05-01 17:57:53', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917881149431058439', 'f6817f48af4fb3af11b9e8bf182f618b', '2025050105554940206', null, '2025-05-01 17:57:53', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1917957659860963330', 'f6817f48af4fb3af11b9e8bf182f618b', '1917957565728198657', null, '2025-05-01 23:01:55', '0:0:0:0:0:0:0:1');
|
||||
INSERT INTO sys_role_permission (id, role_id, permission_id, data_rule_ids, operate_date, operate_ip) VALUES ('1922109760551858178', 'f6817f48af4fb3af11b9e8bf182f618b', '1922109301837606914', null, '2025-05-13 10:00:53', '0:0:0:0:0:0:0:1');
|
||||
@ -3,6 +3,7 @@
|
||||
> JeecgBoot属于平台级产品,每次升级改动较大,目前做不到平滑升级。
|
||||
|
||||
### 增量升级方案
|
||||
|
||||
#### 1.代码合并
|
||||
本地通过svn或git做好主干,在分支上做业务开发,jeecg每次版本发布,可以手工覆盖主干的代码,对比合并代码;
|
||||
|
||||
@ -11,5 +12,12 @@
|
||||
- 其他库请手工执行SQL, 目录: `jeecg-module-system\jeecg-system-start\src\main\resources\flyway\sql\mysql`
|
||||
> 注意: 升级sql只提供mysql版本;如果有权限升级, 还需要手工角色授权,退出重新登录才好使。
|
||||
|
||||
#### 3.兼容问题
|
||||
#### 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.兼容问题
|
||||
每次发版,会针对不兼容地方重点说明。
|
||||
@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-parent</artifactId>
|
||||
<version>3.7.1</version>
|
||||
<version>3.8.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jeecg-boot-base-core</artifactId>
|
||||
@ -43,12 +43,22 @@
|
||||
<!--jeecg-tools-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-common</artifactId>
|
||||
<artifactId>jeecg-boot-common3</artifactId>
|
||||
</dependency>
|
||||
<!--集成springmvc框架并实现自动配置 -->
|
||||
<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>
|
||||
@ -98,21 +108,32 @@
|
||||
<!-- mybatis-plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<!-- minidao -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 动态数据源 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<version>${dynamic-datasource-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
|
||||
@ -163,7 +184,7 @@
|
||||
<artifactId>DmDialect-for-hibernate5.0</artifactId>
|
||||
<version>${dm8.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Quartz定时任务 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -181,7 +202,50 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring-boot-starter</artifactId>
|
||||
<classifier>jakarta</classifier>
|
||||
<version>${shiro.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
<classifier>jakarta</classifier>
|
||||
<version>${shiro.version}</version>
|
||||
<!-- 排除仍使用了javax.servlet的依赖 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-web</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- 引入适配jakarta的依赖包 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<classifier>jakarta</classifier>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-web</artifactId>
|
||||
<classifier>jakarta</classifier>
|
||||
<version>${shiro.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- shiro-redis -->
|
||||
<dependency>
|
||||
@ -200,17 +264,23 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- knife4j -->
|
||||
<!-- <dependency>
|
||||
|
||||
<!-- <dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>3.0.3</version>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
<version>${knife4j-spring-boot-starter.version}</version>
|
||||
</dependency>-->
|
||||
<!-- knife4j 升级springboot3.4.5报错 -->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
|
||||
<artifactId>knife4j-openapi3-ui</artifactId>
|
||||
<version>${knife4j-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.7.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 代码生成器 -->
|
||||
<!-- 如下载失败,请参考此文档 https://help.jeecg.com/java/setup/maven.html -->
|
||||
@ -218,11 +288,21 @@
|
||||
<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工具类-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework</groupId>
|
||||
<groupId>org.jeecgframework.boot3</groupId>
|
||||
<artifactId>autopoi-web</artifactId>
|
||||
<version>${autopoi-web.version}</version>
|
||||
<exclusions>
|
||||
@ -247,6 +327,12 @@
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
@ -265,6 +351,16 @@
|
||||
<dependency>
|
||||
<groupId>com.xkcoding.justauth</groupId>
|
||||
<artifactId>justauth-spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
@ -288,11 +384,15 @@
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- chatgpt -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-starter-chatgpt</artifactId>
|
||||
<artifactId>jeecg-boot-starter3-chatgpt</artifactId>
|
||||
</dependency>
|
||||
<!-- minidao -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot3</groupId>
|
||||
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -2,7 +2,7 @@ package org.jeecg.common.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -20,14 +20,14 @@ import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.common.util.IpUtils;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
@ -172,7 +172,7 @@ public class AutoLogAspect {
|
||||
// 请求的方法参数值
|
||||
Object[] args = joinPoint.getArgs();
|
||||
// 请求的方法参数名称
|
||||
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
|
||||
StandardReflectionParameterNameDiscoverer u=new StandardReflectionParameterNameDiscoverer();
|
||||
String[] paramNames = u.getParameterNames(method);
|
||||
if (args != null && paramNames != null) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
|
||||
@ -21,7 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
package org.jeecg.common.exception;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
@ -23,16 +25,17 @@ 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;
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
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(",")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
|
||||
@ -23,9 +23,9 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@ -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,10 +10,10 @@ 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;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* @Description: Entity基类
|
||||
@ -30,20 +31,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 +53,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","范围查询"),
|
||||
/**查询规则 不在范围内查询*/
|
||||
|
||||
@ -5,7 +5,7 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@ -11,10 +11,13 @@ import com.google.common.base.Joiner;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
@ -63,7 +66,7 @@ public class JwtUtil {
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +85,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 +101,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 +200,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 +278,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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,7 +5,7 @@ import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@ -19,7 +19,7 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
|
||||
@ -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());
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package org.jeecg.common.util;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
@ -4,9 +4,13 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package org.jeecg.common.util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package org.jeecg.common.util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.constant.ServiceNameConstants;
|
||||
|
||||
@ -11,7 +11,7 @@ import org.jeecg.common.exception.JeecgBoot401Exception;
|
||||
import org.jeecg.common.system.util.JwtUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @Author scott
|
||||
|
||||
@ -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);
|
||||
@ -106,9 +110,10 @@ public class DynamicDBUtil {
|
||||
dataSource.getConnection().commit();
|
||||
dataSource.getConnection().close();
|
||||
dataSource.close();
|
||||
DataSourceCachePool.removeCache(dbKey);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
log.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package org.jeecg.common.util.encryption;
|
||||
|
||||
import org.apache.shiro.codec.Base64;
|
||||
|
||||
import org.apache.shiro.lang.codec.Base64;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -9,10 +9,11 @@ import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
package org.jeecg.common.util.sqlInjection;
|
||||
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor;
|
||||
import net.sf.jsqlparser.parser.SimpleNode;
|
||||
import net.sf.jsqlparser.statement.select.UnionOp;
|
||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||
|
||||
/**
|
||||
* 基于抽象语法树(AST)的注入攻击分析实现
|
||||
*
|
||||
* @author guyadong
|
||||
*/
|
||||
public class InjectionAstNodeVisitor extends CCJSqlParserDefaultVisitor {
|
||||
public InjectionAstNodeVisitor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理禁止联合查询
|
||||
*
|
||||
* @param node
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Object visit(SimpleNode node, Object data) {
|
||||
Object value = node.jjtGetValue();
|
||||
if (value instanceof UnionOp) {
|
||||
throw new JeecgSqlInjectionException("DISABLE UNION");
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,172 +0,0 @@
|
||||
package org.jeecg.common.util.sqlInjection;
|
||||
|
||||
|
||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.Join;
|
||||
import net.sf.jsqlparser.statement.select.OrderByElement;
|
||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
import net.sf.jsqlparser.statement.select.SubSelect;
|
||||
import net.sf.jsqlparser.statement.select.WithItem;
|
||||
import net.sf.jsqlparser.util.TablesNamesFinder;
|
||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||
import org.jeecg.common.util.sqlInjection.parse.ConstAnalyzer;
|
||||
import org.jeecg.common.util.sqlInjection.parse.ParserSupport;
|
||||
|
||||
/**
|
||||
* 基于SQL语法对象的SQL注入攻击分析实现
|
||||
*
|
||||
* @author guyadong
|
||||
*/
|
||||
public class InjectionSyntaxObjectAnalyzer extends TablesNamesFinder {
|
||||
/**
|
||||
* 危险函数名
|
||||
*/
|
||||
private static final String DANGROUS_FUNCTIONS = "(sleep|benchmark|extractvalue|updatexml|ST_LatFromGeoHash|ST_LongFromGeoHash|GTID_SUBSET|GTID_SUBTRACT|floor|ST_Pointfromgeohash"
|
||||
+ "|geometrycollection|multipoint|polygon|multipolygon|linestring|multilinestring)";
|
||||
|
||||
private static ThreadLocal<Boolean> disableSubselect = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private ConstAnalyzer constAnalyzer = new ConstAnalyzer();
|
||||
|
||||
public InjectionSyntaxObjectAnalyzer() {
|
||||
super();
|
||||
init(true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryExpression(BinaryExpression binaryExpression) {
|
||||
if (binaryExpression instanceof ComparisonOperator) {
|
||||
if (isConst(binaryExpression.getLeftExpression()) && isConst(binaryExpression.getRightExpression())) {
|
||||
/** 禁用恒等式 */
|
||||
throw new JeecgSqlInjectionException("DISABLE IDENTICAL EQUATION " + binaryExpression);
|
||||
}
|
||||
}
|
||||
super.visitBinaryExpression(binaryExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AndExpression andExpression) {
|
||||
super.visit(andExpression);
|
||||
checkConstExpress(andExpression.getLeftExpression());
|
||||
checkConstExpress(andExpression.getRightExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(OrExpression orExpression) {
|
||||
super.visit(orExpression);
|
||||
checkConstExpress(orExpression.getLeftExpression());
|
||||
checkConstExpress(orExpression.getRightExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Function function) {
|
||||
if (function.getName().matches(DANGROUS_FUNCTIONS)) {
|
||||
/** 禁用危险函数 */
|
||||
throw new JeecgSqlInjectionException("DANGROUS FUNCTION: " + function.getName());
|
||||
}
|
||||
super.visit(function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WithItem withItem) {
|
||||
try {
|
||||
/** 允许 WITH 语句中的子查询 */
|
||||
disableSubselect.set(false);
|
||||
super.visit(withItem);
|
||||
} finally {
|
||||
disableSubselect.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubSelect subSelect) {
|
||||
try {
|
||||
/** 允许语句中的子查询 */
|
||||
disableSubselect.set(false);
|
||||
super.visit(subSelect);
|
||||
} finally {
|
||||
disableSubselect.set(true);
|
||||
}
|
||||
// if (disableSubselect.get()) {
|
||||
// // 禁用子查询
|
||||
// throw new JeecgSqlInjectionException("DISABLE subselect " + subSelect);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Column tableColumn) {
|
||||
if (ParserSupport.isBoolean(tableColumn)) {
|
||||
throw new JeecgSqlInjectionException("DISABLE CONST BOOL " + tableColumn);
|
||||
}
|
||||
super.visit(tableColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PlainSelect plainSelect) {
|
||||
if (plainSelect.getSelectItems() != null) {
|
||||
for (SelectItem item : plainSelect.getSelectItems()) {
|
||||
item.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (plainSelect.getFromItem() != null) {
|
||||
plainSelect.getFromItem().accept(this);
|
||||
}
|
||||
|
||||
if (plainSelect.getJoins() != null) {
|
||||
for (Join join : plainSelect.getJoins()) {
|
||||
join.getRightItem().accept(this);
|
||||
for (Expression e : join.getOnExpressions()) {
|
||||
e.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (plainSelect.getWhere() != null) {
|
||||
plainSelect.getWhere().accept(this);
|
||||
checkConstExpress(plainSelect.getWhere());
|
||||
}
|
||||
|
||||
if (plainSelect.getHaving() != null) {
|
||||
plainSelect.getHaving().accept(this);
|
||||
}
|
||||
|
||||
if (plainSelect.getOracleHierarchical() != null) {
|
||||
plainSelect.getOracleHierarchical().accept(this);
|
||||
}
|
||||
if (plainSelect.getOrderByElements() != null) {
|
||||
for (OrderByElement orderByElement : plainSelect.getOrderByElements()) {
|
||||
orderByElement.getExpression().accept(this);
|
||||
}
|
||||
}
|
||||
if (plainSelect.getGroupBy() != null) {
|
||||
for (Expression expression : plainSelect.getGroupBy().getGroupByExpressionList().getExpressions()) {
|
||||
expression.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isConst(Expression expression) {
|
||||
return constAnalyzer.isConstExpression(expression);
|
||||
}
|
||||
|
||||
private void checkConstExpress(Expression expression) {
|
||||
if (constAnalyzer.isConstExpression(expression)) {
|
||||
/** 禁用常量表达式 */
|
||||
throw new JeecgSqlInjectionException("DISABLE CONST EXPRESSION " + expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
package org.jeecg.common.util.sqlInjection;
|
||||
|
||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||
import org.jeecg.common.util.sqlInjection.parse.ParserSupport;
|
||||
;
|
||||
|
||||
/**
|
||||
* SQL注入攻击分析器
|
||||
*
|
||||
* @author guyadong
|
||||
* 参考:
|
||||
* https://blog.csdn.net/10km/article/details/127767358
|
||||
* https://gitee.com/l0km/sql2java/tree/dev/sql2java-manager/src/main/java/gu/sql2java/parser
|
||||
*/
|
||||
public class SqlInjectionAnalyzer {
|
||||
|
||||
//启用/关闭注入攻击检查
|
||||
private boolean injectCheckEnable = true;
|
||||
//防止SQL注入攻击分析实现
|
||||
private final InjectionSyntaxObjectAnalyzer injectionChecker;
|
||||
private final InjectionAstNodeVisitor injectionVisitor;
|
||||
|
||||
public SqlInjectionAnalyzer() {
|
||||
this.injectionChecker = new InjectionSyntaxObjectAnalyzer();
|
||||
this.injectionVisitor = new InjectionAstNodeVisitor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/关闭注入攻击检查,默认启动
|
||||
*
|
||||
* @param enable
|
||||
* @return
|
||||
*/
|
||||
public SqlInjectionAnalyzer injectCheckEnable(boolean enable) {
|
||||
injectCheckEnable = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对解析后的SQL对象执行注入攻击分析,有注入攻击的危险则抛出异常{@link JeecgSqlInjectionException}
|
||||
*
|
||||
* @param sqlParserInfo
|
||||
* @throws JeecgSqlInjectionException
|
||||
*/
|
||||
public ParserSupport.SqlParserInfo injectAnalyse(ParserSupport.SqlParserInfo sqlParserInfo) throws JeecgSqlInjectionException {
|
||||
if (null != sqlParserInfo && injectCheckEnable) {
|
||||
/** SQL注入攻击检查 */
|
||||
sqlParserInfo.statement.accept(injectionChecker);
|
||||
sqlParserInfo.simpleNode.jjtAccept(injectionVisitor, null);
|
||||
}
|
||||
return sqlParserInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* sql校验
|
||||
*/
|
||||
public static void checkSql(String sql,boolean check){
|
||||
SqlInjectionAnalyzer sqlInjectionAnalyzer = new SqlInjectionAnalyzer();
|
||||
sqlInjectionAnalyzer.injectCheckEnable(check);
|
||||
ParserSupport.SqlParserInfo sqlParserInfo = ParserSupport.parse0(sql, null,null);
|
||||
sqlInjectionAnalyzer.injectAnalyse(sqlParserInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,569 +0,0 @@
|
||||
package org.jeecg.common.util.sqlInjection.parse;
|
||||
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.XorExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.Between;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.FullTextSearch;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GeometryDistance;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ItemsListVisitor;
|
||||
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.Matches;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.NamedExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.RegExpMySQLOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.AllColumns;
|
||||
import net.sf.jsqlparser.statement.select.AllTableColumns;
|
||||
import net.sf.jsqlparser.statement.select.OrderByElement;
|
||||
import net.sf.jsqlparser.statement.select.SubSelect;
|
||||
|
||||
/**
|
||||
* 判断表达是否为常量的分析器
|
||||
*
|
||||
* @author guyadong
|
||||
*/
|
||||
public class ConstAnalyzer implements ExpressionVisitor, ItemsListVisitor {
|
||||
|
||||
private static ThreadLocal<Boolean> constFlag = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void visit(NullValue value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Function function) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SignedExpression expr) {
|
||||
expr.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JdbcParameter parameter) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JdbcNamedParameter parameter) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DoubleValue value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LongValue value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DateValue value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TimeValue value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TimestampValue value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Parenthesis parenthesis) {
|
||||
parenthesis.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StringValue value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Addition expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Division expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IntegerDivision expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Multiplication expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Subtraction expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AndExpression expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(OrExpression expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(XorExpression expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Between expr) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
expr.getBetweenExpressionStart().accept(this);
|
||||
expr.getBetweenExpressionEnd().accept(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于处理 OverlapsCondition 类型的表达式
|
||||
* @param overlapsCondition
|
||||
*/
|
||||
@Override
|
||||
public void visit(OverlapsCondition overlapsCondition) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
/**
|
||||
* 用于处理 SafeCastExpression 类型的表达式。
|
||||
* @param safeCastExpression
|
||||
*/
|
||||
@Override
|
||||
public void visit(SafeCastExpression safeCastExpression) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EqualsTo expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GreaterThan expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GreaterThanEquals expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InExpression expr) {
|
||||
if (expr.getLeftExpression() != null) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IsNullExpression expr) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FullTextSearch expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IsBooleanExpression expr) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LikeExpression expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MinorThan expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MinorThanEquals expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NotEqualsTo expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Column column) {
|
||||
if (!ParserSupport.isBoolean(column)) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubSelect subSelect) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CaseExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhenClause expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExistsExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AnyComparisonExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Concat expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Matches expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BitwiseAnd expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BitwiseOr expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BitwiseXor expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastExpression expr) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TryCastExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Modulo expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AnalyticExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExtractExpression expr) {
|
||||
expr.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IntervalExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(OracleHierarchicalExpression expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RegExpMatchOperator expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExpressionList expressionList) {
|
||||
for (Expression expr : expressionList.getExpressions()) {
|
||||
expr.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NamedExpressionList namedExpressionList) {
|
||||
for (Expression expr : namedExpressionList.getExpressions()) {
|
||||
expr.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MultiExpressionList multiExprList) {
|
||||
for (ExpressionList list : multiExprList.getExpressionLists()) {
|
||||
visit(list);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NotExpression notExpr) {
|
||||
notExpr.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BitwiseRightShift expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BitwiseLeftShift expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
protected void visitBinaryExpression(BinaryExpression expr) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
expr.getRightExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JsonExpression jsonExpr) {
|
||||
jsonExpr.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JsonOperator expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RegExpMySQLOperator expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UserVariable var) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NumericBind bind) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(KeepExpression expr) {
|
||||
for (OrderByElement element : expr.getOrderByElements()) {
|
||||
element.getExpression().accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MySQLGroupConcat groupConcat) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ValueListExpression valueListExpression) {
|
||||
for (Expression expr : valueListExpression.getExpressionList().getExpressions()) {
|
||||
expr.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AllColumns allColumns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AllTableColumns allTableColumns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AllValue allValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IsDistinctExpression isDistinctExpression) {
|
||||
visitBinaryExpression(isDistinctExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RowGetExpression rowGetExpression) {
|
||||
rowGetExpression.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(HexValue hexValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(OracleHint hint) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TimeKeyExpression timeKeyExpression) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DateTimeLiteralExpression literal) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NextValExpression nextVal) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CollateExpression col) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SimilarToExpression expr) {
|
||||
visitBinaryExpression(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayExpression array) {
|
||||
array.getObjExpression().accept(this);
|
||||
if (array.getIndexExpression() != null) {
|
||||
array.getIndexExpression().accept(this);
|
||||
}
|
||||
if (array.getStartIndexExpression() != null) {
|
||||
array.getStartIndexExpression().accept(this);
|
||||
}
|
||||
if (array.getStopIndexExpression() != null) {
|
||||
array.getStopIndexExpression().accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayConstructor aThis) {
|
||||
for (Expression expression : aThis.getExpressions()) {
|
||||
expression.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(VariableAssignment var) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(XMLSerializeExpr expr) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TimezoneExpression expr) {
|
||||
expr.getLeftExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JsonAggregateFunction expression) {
|
||||
Expression expr = expression.getExpression();
|
||||
if (expr != null) {
|
||||
expr.accept(this);
|
||||
}
|
||||
|
||||
expr = expression.getFilterExpression();
|
||||
if (expr != null) {
|
||||
expr.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JsonFunction expression) {
|
||||
for (JsonFunctionExpression expr : expression.getExpressions()) {
|
||||
expr.getExpression().accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConnectByRootOperator connectByRootOperator) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GeometryDistance geometryDistance) {
|
||||
visitBinaryExpression(geometryDistance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RowConstructor rowConstructor) {
|
||||
constFlag.set(false);
|
||||
}
|
||||
|
||||
public boolean isConstExpression(Expression expression) {
|
||||
if (null != expression) {
|
||||
constFlag.set(true);
|
||||
expression.accept(this);
|
||||
return constFlag.get();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,177 +0,0 @@
|
||||
package org.jeecg.common.util.sqlInjection.parse;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import net.sf.jsqlparser.parser.*;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.Statement;
|
||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||
import net.sf.jsqlparser.statement.select.Select;
|
||||
import net.sf.jsqlparser.statement.select.SelectBody;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||
|
||||
/**
|
||||
* 解析sql支持
|
||||
*/
|
||||
@Slf4j
|
||||
public class ParserSupport {
|
||||
/**
|
||||
* 解析SELECT SQL语句,解析失败或非SELECT语句则抛出异常
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
public static Select parseSelect(String sql) {
|
||||
Statement stmt;
|
||||
try {
|
||||
stmt = CCJSqlParserUtil.parse(checkNotNull(sql, "sql is null"));
|
||||
} catch (JSQLParserException e) {
|
||||
throw new JeecgBootException(e);
|
||||
}
|
||||
checkArgument(stmt instanceof Select, "%s is not SELECT statment", sql);
|
||||
Select select = (Select) stmt;
|
||||
SelectBody selectBody = select.getSelectBody();
|
||||
// 暂时只支持简单的SELECT xxxx FROM ....语句不支持复杂语句如WITH
|
||||
checkArgument(selectBody instanceof PlainSelect, "ONLY SUPPORT plain select statement %s", sql);
|
||||
return (Select) stmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析SELECT SQL语句,解析失败或非SELECT语句则
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
public static Select parseSelectUnchecked(String sql) {
|
||||
try {
|
||||
return parseSelect(sql);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现SQL语句解析,解析成功则返回解析后的{@link Statement},
|
||||
* 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
|
||||
*
|
||||
* @param sql SQL语句
|
||||
* @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略
|
||||
* @param sqlSyntaxNormalizer SQL语句分析转换器,为{@code null}忽略
|
||||
* @throws JSQLParserException 输入的SQL语句有语法错误
|
||||
* @see #parse0(String, CCJSqlParserVisitor, SqlSyntaxNormalizer)
|
||||
*/
|
||||
public static Statement parse(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxNormalizer) throws JSQLParserException {
|
||||
return parse0(sql, visitor, sqlSyntaxNormalizer).statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参照{@link CCJSqlParserUtil#parseAST(String)}和{@link CCJSqlParserUtil#parse(String)}实现SQL语句解析,
|
||||
* 解析成功则返回解析后的{@link SqlParserInfo}对象,
|
||||
* 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
|
||||
*
|
||||
* @param sql SQL语句
|
||||
* @param visitor 遍历所有节点的{@link SimpleNodeVisitor}接口实例,为{@code null}忽略
|
||||
* @param sqlSyntaxAnalyzer SQL语句分析转换器,为{@code null}忽略
|
||||
* @throws JSQLParserException 输入的SQL语句有语法错误
|
||||
* @see net.sf.jsqlparser.parser.Node#jjtAccept(SimpleNodeVisitor, Object)
|
||||
*/
|
||||
public static SqlParserInfo parse0(String sql, CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxAnalyzer) throws JeecgSqlInjectionException {
|
||||
|
||||
//检查是否非select开头,暂不支持
|
||||
if(!sql.toLowerCase().trim().startsWith("select ")) {
|
||||
log.warn("传入sql 非select开头,不支持非select开头的语句解析!");
|
||||
return null;
|
||||
}
|
||||
|
||||
//检查是否存储过程,暂不支持
|
||||
if(sql.toLowerCase().trim().startsWith("call ")){
|
||||
log.warn("传入call 开头存储过程,不支持存储过程解析!");
|
||||
return null;
|
||||
}
|
||||
|
||||
//检查特殊语义的特殊字符,目前检查冒号、$、#三种特殊语义字符
|
||||
String specialCharacters = "[:$#]";
|
||||
Pattern pattern = Pattern.compile(specialCharacters);
|
||||
Matcher matcher = pattern.matcher(sql);
|
||||
if (matcher.find()) {
|
||||
sql = sql.replaceAll("[:$#]", "@");
|
||||
}
|
||||
|
||||
checkArgument(null != sql, "sql is null");
|
||||
boolean allowComplexParsing = CCJSqlParserUtil.getNestingDepth(sql) <= CCJSqlParserUtil.ALLOWED_NESTING_DEPTH;
|
||||
|
||||
CCJSqlParser parser = CCJSqlParserUtil.newParser(sql).withAllowComplexParsing(allowComplexParsing);
|
||||
Statement stmt;
|
||||
try {
|
||||
stmt = parser.Statement();
|
||||
} catch (Exception ex) {
|
||||
log.error("请注意,SQL语法可能存在问题---> {}", ex.getMessage());
|
||||
throw new JeecgSqlInjectionException("请注意,SQL语法可能存在问题:"+sql);
|
||||
}
|
||||
if (null != visitor) {
|
||||
parser.getASTRoot().jjtAccept(visitor, null);
|
||||
}
|
||||
if (null != sqlSyntaxAnalyzer) {
|
||||
stmt.accept(sqlSyntaxAnalyzer.resetChanged());
|
||||
}
|
||||
return new SqlParserInfo(stmt.toString(), stmt, (SimpleNode) parser.getASTRoot());
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用{@link CCJSqlParser}解析SQL语句部件返回解析生成的对象,如{@code 'ORDER BY id DESC'}
|
||||
*
|
||||
* @param <T>
|
||||
* @param input
|
||||
* @param method 指定调用的{@link CCJSqlParser}解析方法
|
||||
* @param targetType 返回的解析对象类型
|
||||
* @return
|
||||
* @since 3.18.3
|
||||
*/
|
||||
public static <T> T parseComponent(String input, String method, Class<T> targetType) {
|
||||
try {
|
||||
CCJSqlParser parser = new CCJSqlParser(new StringProvider(input));
|
||||
try {
|
||||
return checkNotNull(targetType, "targetType is null").cast(parser.getClass().getMethod(method).invoke(parser));
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwables.throwIfUnchecked(e.getTargetException());
|
||||
throw new RuntimeException(e.getTargetException());
|
||||
}
|
||||
} catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果{@link Column}没有定义table,且字段名为true/false(不区分大小写)则视为布尔常量
|
||||
*
|
||||
* @param column
|
||||
*/
|
||||
public static boolean isBoolean(Column column) {
|
||||
return null != column && null == column.getTable() &&
|
||||
Pattern.compile("(true|false)", Pattern.CASE_INSENSITIVE).matcher(column.getColumnName()).matches();
|
||||
}
|
||||
|
||||
public static class SqlParserInfo {
|
||||
public String nativeSql;
|
||||
public Statement statement;
|
||||
public SimpleNode simpleNode;
|
||||
|
||||
SqlParserInfo(String nativeSql, Statement statement, SimpleNode simpleNode) {
|
||||
this.nativeSql = nativeSql;
|
||||
this.statement = statement;
|
||||
this.simpleNode = simpleNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
package org.jeecg.common.util.sqlInjection.parse;
|
||||
|
||||
import net.sf.jsqlparser.util.TablesNamesFinder;
|
||||
|
||||
/**
|
||||
* SQL语句分析转换器基类<br>
|
||||
* 基于SQL语法对象实现对SQL的修改
|
||||
* (暂时用不到)
|
||||
*
|
||||
* @author guyadong
|
||||
* @since 3.17.0
|
||||
*/
|
||||
public class SqlSyntaxNormalizer extends TablesNamesFinder {
|
||||
protected static final ThreadLocal<Boolean> changed = new ThreadLocal<>();
|
||||
|
||||
public SqlSyntaxNormalizer() {
|
||||
super();
|
||||
init(true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 语句改变返回{@code true},否则返回{@code false}
|
||||
*/
|
||||
public boolean changed() {
|
||||
return Boolean.TRUE.equals(changed.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 复位线程局部变量{@link #changed}状态
|
||||
*/
|
||||
public SqlSyntaxNormalizer resetChanged() {
|
||||
changed.remove();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,255 +1,255 @@
|
||||
package org.jeecg.common.util.sqlparse;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.Statement;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 解析所有表名和字段的类
|
||||
*/
|
||||
@Slf4j
|
||||
public class JSqlParserAllTableManager {
|
||||
|
||||
private final String sql;
|
||||
private final Map<String, SelectSqlInfo> allTableMap = new HashMap<>();
|
||||
/**
|
||||
* 别名对应实际表名
|
||||
*/
|
||||
private final Map<String, String> tableAliasMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 解析后的sql
|
||||
*/
|
||||
private String parsedSql = null;
|
||||
|
||||
JSqlParserAllTableManager(String selectSql) {
|
||||
this.sql = selectSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始解析
|
||||
*
|
||||
* @return
|
||||
* @throws JSQLParserException
|
||||
*/
|
||||
public Map<String, SelectSqlInfo> parse() throws JSQLParserException {
|
||||
// 1. 创建解析器
|
||||
CCJSqlParserManager mgr = new CCJSqlParserManager();
|
||||
// 2. 使用解析器解析sql生成具有层次结构的java类
|
||||
Statement stmt = mgr.parse(new StringReader(this.sql));
|
||||
if (stmt instanceof Select) {
|
||||
Select selectStatement = (Select) stmt;
|
||||
SelectBody selectBody = selectStatement.getSelectBody();
|
||||
this.parsedSql = selectBody.toString();
|
||||
// 3. 解析select查询sql的信息
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||
// 4. 合并 fromItems
|
||||
List<FromItem> fromItems = new ArrayList<>();
|
||||
fromItems.add(plainSelect.getFromItem());
|
||||
// 4.1 处理join的表
|
||||
List<Join> joins = plainSelect.getJoins();
|
||||
if (joins != null) {
|
||||
joins.forEach(join -> fromItems.add(join.getRightItem()));
|
||||
}
|
||||
// 5. 处理 fromItems
|
||||
for (FromItem fromItem : fromItems) {
|
||||
// 5.1 通过表名的方式from
|
||||
if (fromItem instanceof Table) {
|
||||
this.addSqlInfoByTable((Table) fromItem);
|
||||
}
|
||||
// 5.2 通过子查询的方式from
|
||||
else if (fromItem instanceof SubSelect) {
|
||||
this.handleSubSelect((SubSelect) fromItem);
|
||||
}
|
||||
}
|
||||
// 6. 解析 selectFields
|
||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
for (SelectItem selectItem : selectItems) {
|
||||
// 6.1 查询的是全部字段
|
||||
if (selectItem instanceof AllColumns) {
|
||||
// 当 selectItem 为 AllColumns 时,fromItem 必定为 Table
|
||||
String tableName = plainSelect.getFromItem(Table.class).getName();
|
||||
// 此处必定不为空,因为在解析 fromItem 时,已经将表名添加到 allTableMap 中
|
||||
SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
||||
assert sqlInfo != null;
|
||||
// 设置为查询全部字段
|
||||
sqlInfo.setSelectAll(true);
|
||||
sqlInfo.setSelectFields(null);
|
||||
sqlInfo.setRealSelectFields(null);
|
||||
}
|
||||
// 6.2 查询的是带表别名( u.* )的全部字段
|
||||
else if (selectItem instanceof AllTableColumns) {
|
||||
AllTableColumns allTableColumns = (AllTableColumns) selectItem;
|
||||
String aliasName = allTableColumns.getTable().getName();
|
||||
// 通过别名获取表名
|
||||
String tableName = this.tableAliasMap.get(aliasName);
|
||||
if (tableName == null) {
|
||||
tableName = aliasName;
|
||||
}
|
||||
SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
||||
// 如果此处为空,则说明该字段是通过子查询获取的,所以可以不处理,只有实际表才需要处理
|
||||
if (sqlInfo != null) {
|
||||
// 设置为查询全部字段
|
||||
sqlInfo.setSelectAll(true);
|
||||
sqlInfo.setSelectFields(null);
|
||||
sqlInfo.setRealSelectFields(null);
|
||||
}
|
||||
}
|
||||
// 6.3 各种字段表达式处理
|
||||
else if (selectItem instanceof SelectExpressionItem) {
|
||||
SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||
Expression expression = selectExpressionItem.getExpression();
|
||||
Alias alias = selectExpressionItem.getAlias();
|
||||
this.handleExpression(expression, alias, plainSelect.getFromItem());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
||||
throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
||||
}
|
||||
} else {
|
||||
// 非 select 查询sql,不做处理
|
||||
throw new JeecgBootException("非 select 查询sql,不做处理");
|
||||
}
|
||||
return this.allTableMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理子查询
|
||||
*
|
||||
* @param subSelect
|
||||
*/
|
||||
private void handleSubSelect(SubSelect subSelect) {
|
||||
try {
|
||||
String subSelectSql = subSelect.getSelectBody().toString();
|
||||
// 递归调用解析
|
||||
Map<String, SelectSqlInfo> map = JSqlParserUtils.parseAllSelectTable(subSelectSql);
|
||||
if (map != null) {
|
||||
this.assignMap(map);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析子查询出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理查询字段表达式
|
||||
*
|
||||
* @param expression
|
||||
*/
|
||||
private void handleExpression(Expression expression, Alias alias, FromItem fromItem) {
|
||||
// 处理函数式字段 CONCAT(name,'(',age,')')
|
||||
if (expression instanceof Function) {
|
||||
Function functionExp = (Function) expression;
|
||||
List<Expression> expressions = functionExp.getParameters().getExpressions();
|
||||
for (Expression expItem : expressions) {
|
||||
this.handleExpression(expItem, null, fromItem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 处理字段上的子查询
|
||||
if (expression instanceof SubSelect) {
|
||||
this.handleSubSelect((SubSelect) expression);
|
||||
return;
|
||||
}
|
||||
// 不处理字面量
|
||||
if (expression instanceof StringValue ||
|
||||
expression instanceof NullValue ||
|
||||
expression instanceof LongValue ||
|
||||
expression instanceof DoubleValue ||
|
||||
expression instanceof HexValue ||
|
||||
expression instanceof DateValue ||
|
||||
expression instanceof TimestampValue ||
|
||||
expression instanceof TimeValue
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理字段
|
||||
if (expression instanceof Column) {
|
||||
Column column = (Column) expression;
|
||||
// 查询字段名
|
||||
String fieldName = column.getColumnName();
|
||||
String aliasName = fieldName;
|
||||
if (alias != null) {
|
||||
aliasName = alias.getName();
|
||||
}
|
||||
String tableName;
|
||||
if (column.getTable() != null) {
|
||||
// 通过列的表名获取 sqlInfo
|
||||
// 例如 user.name,这里的 tableName 就是 user
|
||||
tableName = column.getTable().getName();
|
||||
// 有可能是别名,需要转换为真实表名
|
||||
if (this.tableAliasMap.get(tableName) != null) {
|
||||
tableName = this.tableAliasMap.get(tableName);
|
||||
}
|
||||
} else {
|
||||
// 当column的table为空时,说明是 fromItem 中的字段
|
||||
tableName = ((Table) fromItem).getName();
|
||||
}
|
||||
SelectSqlInfo $sqlInfo = this.allTableMap.get(tableName);
|
||||
if ($sqlInfo != null) {
|
||||
$sqlInfo.addSelectField(aliasName, fieldName);
|
||||
} else {
|
||||
log.warn("发生意外情况,未找到表名为 {} 的 SelectSqlInfo", tableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名添加sqlInfo
|
||||
*
|
||||
* @param table
|
||||
*/
|
||||
private void addSqlInfoByTable(Table table) {
|
||||
String tableName = table.getName();
|
||||
// 解析 aliasName
|
||||
if (table.getAlias() != null) {
|
||||
this.tableAliasMap.put(table.getAlias().getName(), tableName);
|
||||
}
|
||||
SelectSqlInfo sqlInfo = new SelectSqlInfo(this.parsedSql);
|
||||
sqlInfo.setFromTableName(table.getName());
|
||||
this.allTableMap.put(sqlInfo.getFromTableName(), sqlInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并map
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
private void assignMap(Map<String, SelectSqlInfo> source) {
|
||||
for (Map.Entry<String, SelectSqlInfo> entry : source.entrySet()) {
|
||||
SelectSqlInfo sqlInfo = this.allTableMap.get(entry.getKey());
|
||||
if (sqlInfo == null) {
|
||||
this.allTableMap.put(entry.getKey(), entry.getValue());
|
||||
} else {
|
||||
// 合并
|
||||
if (sqlInfo.getSelectFields() == null) {
|
||||
sqlInfo.setSelectFields(entry.getValue().getSelectFields());
|
||||
} else {
|
||||
sqlInfo.getSelectFields().addAll(entry.getValue().getSelectFields());
|
||||
}
|
||||
if (sqlInfo.getRealSelectFields() == null) {
|
||||
sqlInfo.setRealSelectFields(entry.getValue().getRealSelectFields());
|
||||
} else {
|
||||
sqlInfo.getRealSelectFields().addAll(entry.getValue().getRealSelectFields());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//package org.jeecg.common.util.sqlparse;
|
||||
//
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import net.sf.jsqlparser.JSQLParserException;
|
||||
//import net.sf.jsqlparser.expression.*;
|
||||
//import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||
//import net.sf.jsqlparser.schema.Column;
|
||||
//import net.sf.jsqlparser.schema.Table;
|
||||
//import net.sf.jsqlparser.statement.Statement;
|
||||
//import net.sf.jsqlparser.statement.select.*;
|
||||
//import org.jeecg.common.exception.JeecgBootException;
|
||||
//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||
//
|
||||
//import java.io.StringReader;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//
|
||||
///**
|
||||
// * 解析所有表名和字段的类
|
||||
// */
|
||||
//@Slf4j
|
||||
//public class JSqlParserAllTableManager {
|
||||
//
|
||||
// private final String sql;
|
||||
// private final Map<String, SelectSqlInfo> allTableMap = new HashMap<>();
|
||||
// /**
|
||||
// * 别名对应实际表名
|
||||
// */
|
||||
// private final Map<String, String> tableAliasMap = new HashMap<>();
|
||||
//
|
||||
// /**
|
||||
// * 解析后的sql
|
||||
// */
|
||||
// private String parsedSql = null;
|
||||
//
|
||||
// JSqlParserAllTableManager(String selectSql) {
|
||||
// this.sql = selectSql;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 开始解析
|
||||
// *
|
||||
// * @return
|
||||
// * @throws JSQLParserException
|
||||
// */
|
||||
// public Map<String, SelectSqlInfo> parse() throws JSQLParserException {
|
||||
// // 1. 创建解析器
|
||||
// CCJSqlParserManager mgr = new CCJSqlParserManager();
|
||||
// // 2. 使用解析器解析sql生成具有层次结构的java类
|
||||
// Statement stmt = mgr.parse(new StringReader(this.sql));
|
||||
// if (stmt instanceof Select) {
|
||||
// Select selectStatement = (Select) stmt;
|
||||
// SelectBody selectBody = selectStatement.getSelectBody();
|
||||
// this.parsedSql = selectBody.toString();
|
||||
// // 3. 解析select查询sql的信息
|
||||
// if (selectBody instanceof PlainSelect) {
|
||||
// PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||
// // 4. 合并 fromItems
|
||||
// List<FromItem> fromItems = new ArrayList<>();
|
||||
// fromItems.add(plainSelect.getFromItem());
|
||||
// // 4.1 处理join的表
|
||||
// List<Join> joins = plainSelect.getJoins();
|
||||
// if (joins != null) {
|
||||
// joins.forEach(join -> fromItems.add(join.getRightItem()));
|
||||
// }
|
||||
// // 5. 处理 fromItems
|
||||
// for (FromItem fromItem : fromItems) {
|
||||
// // 5.1 通过表名的方式from
|
||||
// if (fromItem instanceof Table) {
|
||||
// this.addSqlInfoByTable((Table) fromItem);
|
||||
// }
|
||||
// // 5.2 通过子查询的方式from
|
||||
// else if (fromItem instanceof SubSelect) {
|
||||
// this.handleSubSelect((SubSelect) fromItem);
|
||||
// }
|
||||
// }
|
||||
// // 6. 解析 selectFields
|
||||
// List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
// for (SelectItem selectItem : selectItems) {
|
||||
// // 6.1 查询的是全部字段
|
||||
// if (selectItem instanceof AllColumns) {
|
||||
// // 当 selectItem 为 AllColumns 时,fromItem 必定为 Table
|
||||
// String tableName = plainSelect.getFromItem(Table.class).getName();
|
||||
// // 此处必定不为空,因为在解析 fromItem 时,已经将表名添加到 allTableMap 中
|
||||
// SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
||||
// assert sqlInfo != null;
|
||||
// // 设置为查询全部字段
|
||||
// sqlInfo.setSelectAll(true);
|
||||
// sqlInfo.setSelectFields(null);
|
||||
// sqlInfo.setRealSelectFields(null);
|
||||
// }
|
||||
// // 6.2 查询的是带表别名( u.* )的全部字段
|
||||
// else if (selectItem instanceof AllTableColumns) {
|
||||
// AllTableColumns allTableColumns = (AllTableColumns) selectItem;
|
||||
// String aliasName = allTableColumns.getTable().getName();
|
||||
// // 通过别名获取表名
|
||||
// String tableName = this.tableAliasMap.get(aliasName);
|
||||
// if (tableName == null) {
|
||||
// tableName = aliasName;
|
||||
// }
|
||||
// SelectSqlInfo sqlInfo = this.allTableMap.get(tableName);
|
||||
// // 如果此处为空,则说明该字段是通过子查询获取的,所以可以不处理,只有实际表才需要处理
|
||||
// if (sqlInfo != null) {
|
||||
// // 设置为查询全部字段
|
||||
// sqlInfo.setSelectAll(true);
|
||||
// sqlInfo.setSelectFields(null);
|
||||
// sqlInfo.setRealSelectFields(null);
|
||||
// }
|
||||
// }
|
||||
// // 6.3 各种字段表达式处理
|
||||
// else if (selectItem instanceof SelectExpressionItem) {
|
||||
// SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||
// Expression expression = selectExpressionItem.getExpression();
|
||||
// Alias alias = selectExpressionItem.getAlias();
|
||||
// this.handleExpression(expression, alias, plainSelect.getFromItem());
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
||||
// throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
||||
// }
|
||||
// } else {
|
||||
// // 非 select 查询sql,不做处理
|
||||
// throw new JeecgBootException("非 select 查询sql,不做处理");
|
||||
// }
|
||||
// return this.allTableMap;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理子查询
|
||||
// *
|
||||
// * @param subSelect
|
||||
// */
|
||||
// private void handleSubSelect(SubSelect subSelect) {
|
||||
// try {
|
||||
// String subSelectSql = subSelect.getSelectBody().toString();
|
||||
// // 递归调用解析
|
||||
// Map<String, SelectSqlInfo> map = JSqlParserUtils.parseAllSelectTable(subSelectSql);
|
||||
// if (map != null) {
|
||||
// this.assignMap(map);
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("解析子查询出错", e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理查询字段表达式
|
||||
// *
|
||||
// * @param expression
|
||||
// */
|
||||
// private void handleExpression(Expression expression, Alias alias, FromItem fromItem) {
|
||||
// // 处理函数式字段 CONCAT(name,'(',age,')')
|
||||
// if (expression instanceof Function) {
|
||||
// Function functionExp = (Function) expression;
|
||||
// List<Expression> expressions = functionExp.getParameters().getExpressions();
|
||||
// for (Expression expItem : expressions) {
|
||||
// this.handleExpression(expItem, null, fromItem);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// // 处理字段上的子查询
|
||||
// if (expression instanceof SubSelect) {
|
||||
// this.handleSubSelect((SubSelect) expression);
|
||||
// return;
|
||||
// }
|
||||
// // 不处理字面量
|
||||
// if (expression instanceof StringValue ||
|
||||
// expression instanceof NullValue ||
|
||||
// expression instanceof LongValue ||
|
||||
// expression instanceof DoubleValue ||
|
||||
// expression instanceof HexValue ||
|
||||
// expression instanceof DateValue ||
|
||||
// expression instanceof TimestampValue ||
|
||||
// expression instanceof TimeValue
|
||||
// ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 处理字段
|
||||
// if (expression instanceof Column) {
|
||||
// Column column = (Column) expression;
|
||||
// // 查询字段名
|
||||
// String fieldName = column.getColumnName();
|
||||
// String aliasName = fieldName;
|
||||
// if (alias != null) {
|
||||
// aliasName = alias.getName();
|
||||
// }
|
||||
// String tableName;
|
||||
// if (column.getTable() != null) {
|
||||
// // 通过列的表名获取 sqlInfo
|
||||
// // 例如 user.name,这里的 tableName 就是 user
|
||||
// tableName = column.getTable().getName();
|
||||
// // 有可能是别名,需要转换为真实表名
|
||||
// if (this.tableAliasMap.get(tableName) != null) {
|
||||
// tableName = this.tableAliasMap.get(tableName);
|
||||
// }
|
||||
// } else {
|
||||
// // 当column的table为空时,说明是 fromItem 中的字段
|
||||
// tableName = ((Table) fromItem).getName();
|
||||
// }
|
||||
// SelectSqlInfo $sqlInfo = this.allTableMap.get(tableName);
|
||||
// if ($sqlInfo != null) {
|
||||
// $sqlInfo.addSelectField(aliasName, fieldName);
|
||||
// } else {
|
||||
// log.warn("发生意外情况,未找到表名为 {} 的 SelectSqlInfo", tableName);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 根据表名添加sqlInfo
|
||||
// *
|
||||
// * @param table
|
||||
// */
|
||||
// private void addSqlInfoByTable(Table table) {
|
||||
// String tableName = table.getName();
|
||||
// // 解析 aliasName
|
||||
// if (table.getAlias() != null) {
|
||||
// this.tableAliasMap.put(table.getAlias().getName(), tableName);
|
||||
// }
|
||||
// SelectSqlInfo sqlInfo = new SelectSqlInfo(this.parsedSql);
|
||||
// sqlInfo.setFromTableName(table.getName());
|
||||
// this.allTableMap.put(sqlInfo.getFromTableName(), sqlInfo);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 合并map
|
||||
// *
|
||||
// * @param source
|
||||
// */
|
||||
// private void assignMap(Map<String, SelectSqlInfo> source) {
|
||||
// for (Map.Entry<String, SelectSqlInfo> entry : source.entrySet()) {
|
||||
// SelectSqlInfo sqlInfo = this.allTableMap.get(entry.getKey());
|
||||
// if (sqlInfo == null) {
|
||||
// this.allTableMap.put(entry.getKey(), entry.getValue());
|
||||
// } else {
|
||||
// // 合并
|
||||
// if (sqlInfo.getSelectFields() == null) {
|
||||
// sqlInfo.setSelectFields(entry.getValue().getSelectFields());
|
||||
// } else {
|
||||
// sqlInfo.getSelectFields().addAll(entry.getValue().getSelectFields());
|
||||
// }
|
||||
// if (sqlInfo.getRealSelectFields() == null) {
|
||||
// sqlInfo.setRealSelectFields(entry.getValue().getRealSelectFields());
|
||||
// } else {
|
||||
// sqlInfo.getRealSelectFields().addAll(entry.getValue().getRealSelectFields());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@ -1,184 +1,190 @@
|
||||
package org.jeecg.common.util.sqlparse;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.Statement;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class JSqlParserUtils {
|
||||
|
||||
/**
|
||||
* 解析 查询(select)sql的信息,
|
||||
* 此方法会展开所有子查询到一个map里,
|
||||
* key只存真实的表名,如果查询的没有真实的表名,则会被忽略。
|
||||
* value只存真实的字段名,如果查询的没有真实的字段名,则会被忽略。
|
||||
* <p>
|
||||
* 例如:SELECT a.*,d.age,(SELECT count(1) FROM sys_depart) AS count FROM (SELECT username AS foo, realname FROM sys_user) a, demo d
|
||||
* 解析后的结果为:{sys_user=[username, realname], demo=[age], sys_depart=[]}
|
||||
*
|
||||
* @param selectSql
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, SelectSqlInfo> parseAllSelectTable(String selectSql) throws JSQLParserException {
|
||||
if (oConvertUtils.isEmpty(selectSql)) {
|
||||
return null;
|
||||
}
|
||||
// log.info("解析查询Sql:{}", selectSql);
|
||||
JSqlParserAllTableManager allTableManager = new JSqlParserAllTableManager(selectSql);
|
||||
return allTableManager.parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 查询(select)sql的信息,子查询嵌套
|
||||
*
|
||||
* @param selectSql
|
||||
* @return
|
||||
*/
|
||||
public static SelectSqlInfo parseSelectSqlInfo(String selectSql) throws JSQLParserException {
|
||||
if (oConvertUtils.isEmpty(selectSql)) {
|
||||
return null;
|
||||
}
|
||||
// log.info("解析查询Sql:{}", selectSql);
|
||||
// 使用 JSqlParer 解析sql
|
||||
// 1、创建解析器
|
||||
CCJSqlParserManager mgr = new CCJSqlParserManager();
|
||||
// 2、使用解析器解析sql生成具有层次结构的java类
|
||||
Statement stmt = mgr.parse(new StringReader(selectSql));
|
||||
if (stmt instanceof Select) {
|
||||
Select selectStatement = (Select) stmt;
|
||||
// 3、解析select查询sql的信息
|
||||
return JSqlParserUtils.parseBySelectBody(selectStatement.getSelectBody());
|
||||
} else {
|
||||
// 非 select 查询sql,不做处理
|
||||
throw new JeecgBootException("非 select 查询sql,不做处理");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 select 查询sql的信息
|
||||
*
|
||||
* @param selectBody
|
||||
* @return
|
||||
*/
|
||||
private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) {
|
||||
// 简单的select查询
|
||||
if (selectBody instanceof PlainSelect) {
|
||||
SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody);
|
||||
PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
// 解析 aliasName
|
||||
if (fromItem.getAlias() != null) {
|
||||
sqlInfo.setFromTableAliasName(fromItem.getAlias().getName());
|
||||
}
|
||||
// 解析 表名
|
||||
if (fromItem instanceof Table) {
|
||||
// 通过表名的方式from
|
||||
Table fromTable = (Table) fromItem;
|
||||
sqlInfo.setFromTableName(fromTable.getName());
|
||||
} else if (fromItem instanceof SubSelect) {
|
||||
// 通过子查询的方式from
|
||||
SubSelect fromSubSelect = (SubSelect) fromItem;
|
||||
SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(fromSubSelect.getSelectBody());
|
||||
sqlInfo.setFromSubSelect(subSqlInfo);
|
||||
}
|
||||
// 解析 selectFields
|
||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
for (SelectItem selectItem : selectItems) {
|
||||
if (selectItem instanceof AllColumns || selectItem instanceof AllTableColumns) {
|
||||
// 全部字段
|
||||
sqlInfo.setSelectAll(true);
|
||||
sqlInfo.setSelectFields(null);
|
||||
sqlInfo.setRealSelectFields(null);
|
||||
break;
|
||||
} else if (selectItem instanceof SelectExpressionItem) {
|
||||
// 获取单个查询字段名
|
||||
SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||
Expression expression = selectExpressionItem.getExpression();
|
||||
Alias alias = selectExpressionItem.getAlias();
|
||||
JSqlParserUtils.handleExpression(sqlInfo, expression, alias);
|
||||
}
|
||||
}
|
||||
return sqlInfo;
|
||||
} else {
|
||||
log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
||||
throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理查询字段表达式
|
||||
*
|
||||
* @param sqlInfo
|
||||
* @param expression
|
||||
* @param alias 是否有别名,无传null
|
||||
*/
|
||||
private static void handleExpression(SelectSqlInfo sqlInfo, Expression expression, Alias alias) {
|
||||
// 处理函数式字段 CONCAT(name,'(',age,')')
|
||||
if (expression instanceof Function) {
|
||||
JSqlParserUtils.handleFunctionExpression((Function) expression, sqlInfo);
|
||||
return;
|
||||
}
|
||||
// 处理字段上的子查询
|
||||
if (expression instanceof SubSelect) {
|
||||
SubSelect subSelect = (SubSelect) expression;
|
||||
SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(subSelect.getSelectBody());
|
||||
// 注:字段上的子查询,必须只查询一个字段,否则会报错,所以可以放心合并
|
||||
sqlInfo.getSelectFields().addAll(subSqlInfo.getSelectFields());
|
||||
sqlInfo.getRealSelectFields().addAll(subSqlInfo.getAllRealSelectFields());
|
||||
return;
|
||||
}
|
||||
// 不处理字面量
|
||||
if (expression instanceof StringValue ||
|
||||
expression instanceof NullValue ||
|
||||
expression instanceof LongValue ||
|
||||
expression instanceof DoubleValue ||
|
||||
expression instanceof HexValue ||
|
||||
expression instanceof DateValue ||
|
||||
expression instanceof TimestampValue ||
|
||||
expression instanceof TimeValue
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询字段名
|
||||
String selectField = expression.toString();
|
||||
// 实际查询字段名
|
||||
String realSelectField = selectField;
|
||||
// 判断是否有别名
|
||||
if (alias != null) {
|
||||
selectField = alias.getName();
|
||||
}
|
||||
// 获取真实字段名
|
||||
if (expression instanceof Column) {
|
||||
Column column = (Column) expression;
|
||||
realSelectField = column.getColumnName();
|
||||
}
|
||||
sqlInfo.addSelectField(selectField, realSelectField);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理函数式字段
|
||||
*
|
||||
* @param functionExp
|
||||
* @param sqlInfo
|
||||
*/
|
||||
private static void handleFunctionExpression(Function functionExp, SelectSqlInfo sqlInfo) {
|
||||
List<Expression> expressions = functionExp.getParameters().getExpressions();
|
||||
for (Expression expression : expressions) {
|
||||
JSqlParserUtils.handleExpression(sqlInfo, expression, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//package org.jeecg.common.util.sqlparse;
|
||||
//
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import net.sf.jsqlparser.JSQLParserException;
|
||||
//import net.sf.jsqlparser.expression.*;
|
||||
//import net.sf.jsqlparser.parser.CCJSqlParserManager;
|
||||
//import net.sf.jsqlparser.schema.Column;
|
||||
//import net.sf.jsqlparser.schema.Table;
|
||||
//import net.sf.jsqlparser.statement.Statement;
|
||||
//import net.sf.jsqlparser.statement.select.*;
|
||||
//import org.jeecg.common.exception.JeecgBootException;
|
||||
//import org.jeecg.common.util.oConvertUtils;
|
||||
//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
|
||||
//
|
||||
//import java.io.StringReader;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//
|
||||
//@Slf4j
|
||||
//public class JSqlParserUtils {
|
||||
//
|
||||
// /**
|
||||
// * 解析 查询(select)sql的信息,
|
||||
// * 此方法会展开所有子查询到一个map里,
|
||||
// * key只存真实的表名,如果查询的没有真实的表名,则会被忽略。
|
||||
// * value只存真实的字段名,如果查询的没有真实的字段名,则会被忽略。
|
||||
// * <p>
|
||||
// * 例如:SELECT a.*,d.age,(SELECT count(1) FROM sys_depart) AS count FROM (SELECT username AS foo, realname FROM sys_user) a, demo d
|
||||
// * 解析后的结果为:{sys_user=[username, realname], demo=[age], sys_depart=[]}
|
||||
// *
|
||||
// * @param selectSql
|
||||
// * @return
|
||||
// */
|
||||
// public static Map<String, SelectSqlInfo> parseAllSelectTable(String selectSql) throws JSQLParserException {
|
||||
// if (oConvertUtils.isEmpty(selectSql)) {
|
||||
// return null;
|
||||
// }
|
||||
// // log.info("解析查询Sql:{}", selectSql);
|
||||
// JSqlParserAllTableManager allTableManager = new JSqlParserAllTableManager(selectSql);
|
||||
// return allTableManager.parse();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 解析 查询(select)sql的信息,子查询嵌套
|
||||
// *
|
||||
// * @param selectSql
|
||||
// * @return
|
||||
// */
|
||||
// public static SelectSqlInfo parseSelectSqlInfo(String selectSql) throws JSQLParserException {
|
||||
// if (oConvertUtils.isEmpty(selectSql)) {
|
||||
// return null;
|
||||
// }
|
||||
// // log.info("解析查询Sql:{}", selectSql);
|
||||
// // 使用 JSqlParer 解析sql
|
||||
// // 1、创建解析器
|
||||
// CCJSqlParserManager mgr = new CCJSqlParserManager();
|
||||
// // 2、使用解析器解析sql生成具有层次结构的java类
|
||||
// Statement stmt = mgr.parse(new StringReader(selectSql));
|
||||
// if (stmt instanceof Select) {
|
||||
// Select selectStatement = (Select) stmt;
|
||||
// // 3、解析select查询sql的信息
|
||||
// return JSqlParserUtils.parseBySelectBody(selectStatement.getSelectBody());
|
||||
// } else {
|
||||
// // 非 select 查询sql,不做处理
|
||||
// throw new JeecgBootException("非 select 查询sql,不做处理");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 解析 select 查询sql的信息
|
||||
// *
|
||||
// * @param selectBody
|
||||
// * @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);
|
||||
// PlainSelect plainSelect = (PlainSelect) selectBody;
|
||||
// FromItem fromItem = plainSelect.getFromItem();
|
||||
// // 解析 aliasName
|
||||
// if (fromItem.getAlias() != null) {
|
||||
// sqlInfo.setFromTableAliasName(fromItem.getAlias().getName());
|
||||
// }
|
||||
// // 解析 表名
|
||||
// if (fromItem instanceof Table) {
|
||||
// // 通过表名的方式from
|
||||
// Table fromTable = (Table) fromItem;
|
||||
// sqlInfo.setFromTableName(fromTable.getName());
|
||||
// } else if (fromItem instanceof SubSelect) {
|
||||
// // 通过子查询的方式from
|
||||
// SubSelect fromSubSelect = (SubSelect) fromItem;
|
||||
// SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(fromSubSelect.getSelectBody());
|
||||
// sqlInfo.setFromSubSelect(subSqlInfo);
|
||||
// }
|
||||
// // 解析 selectFields
|
||||
// List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
// for (SelectItem selectItem : selectItems) {
|
||||
// if (selectItem instanceof AllColumns || selectItem instanceof AllTableColumns) {
|
||||
// // 全部字段
|
||||
// sqlInfo.setSelectAll(true);
|
||||
// sqlInfo.setSelectFields(null);
|
||||
// sqlInfo.setRealSelectFields(null);
|
||||
// break;
|
||||
// } else if (selectItem instanceof SelectExpressionItem) {
|
||||
// // 获取单个查询字段名
|
||||
// SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;
|
||||
// Expression expression = selectExpressionItem.getExpression();
|
||||
// Alias alias = selectExpressionItem.getAlias();
|
||||
// JSqlParserUtils.handleExpression(sqlInfo, expression, alias);
|
||||
// }
|
||||
// }
|
||||
// return sqlInfo;
|
||||
// } else {
|
||||
// log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName());
|
||||
// throw new JeecgBootException("暂时尚未处理该类型的 SelectBody");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理查询字段表达式
|
||||
// *
|
||||
// * @param sqlInfo
|
||||
// * @param expression
|
||||
// * @param alias 是否有别名,无传null
|
||||
// */
|
||||
// private static void handleExpression(SelectSqlInfo sqlInfo, Expression expression, Alias alias) {
|
||||
// // 处理函数式字段 CONCAT(name,'(',age,')')
|
||||
// if (expression instanceof Function) {
|
||||
// JSqlParserUtils.handleFunctionExpression((Function) expression, sqlInfo);
|
||||
// return;
|
||||
// }
|
||||
// // 处理字段上的子查询
|
||||
// if (expression instanceof SubSelect) {
|
||||
// SubSelect subSelect = (SubSelect) expression;
|
||||
// SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(subSelect.getSelectBody());
|
||||
// // 注:字段上的子查询,必须只查询一个字段,否则会报错,所以可以放心合并
|
||||
// sqlInfo.getSelectFields().addAll(subSqlInfo.getSelectFields());
|
||||
// sqlInfo.getRealSelectFields().addAll(subSqlInfo.getAllRealSelectFields());
|
||||
// return;
|
||||
// }
|
||||
// // 不处理字面量
|
||||
// if (expression instanceof StringValue ||
|
||||
// expression instanceof NullValue ||
|
||||
// expression instanceof LongValue ||
|
||||
// expression instanceof DoubleValue ||
|
||||
// expression instanceof HexValue ||
|
||||
// expression instanceof DateValue ||
|
||||
// expression instanceof TimestampValue ||
|
||||
// expression instanceof TimeValue
|
||||
// ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 查询字段名
|
||||
// String selectField = expression.toString();
|
||||
// // 实际查询字段名
|
||||
// String realSelectField = selectField;
|
||||
// // 判断是否有别名
|
||||
// if (alias != null) {
|
||||
// selectField = alias.getName();
|
||||
// }
|
||||
// // 获取真实字段名
|
||||
// if (expression instanceof Column) {
|
||||
// Column column = (Column) expression;
|
||||
// realSelectField = column.getColumnName();
|
||||
// }
|
||||
// sqlInfo.addSelectField(selectField, realSelectField);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 处理函数式字段
|
||||
// *
|
||||
// * @param functionExp
|
||||
// * @param sqlInfo
|
||||
// */
|
||||
// private static void handleFunctionExpression(Function functionExp, SelectSqlInfo sqlInfo) {
|
||||
// List<Expression> expressions = functionExp.getParameters().getExpressions();
|
||||
// for (Expression expression : expressions) {
|
||||
// JSqlParserUtils.handleExpression(sqlInfo, expression, null);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@ -1,101 +1,101 @@
|
||||
package org.jeecg.common.util.sqlparse.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import net.sf.jsqlparser.statement.select.SelectBody;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* select 查询 sql 的信息
|
||||
*/
|
||||
@Data
|
||||
public class SelectSqlInfo {
|
||||
|
||||
/**
|
||||
* 查询的表名,如果是子查询,则此处为null
|
||||
*/
|
||||
private String fromTableName;
|
||||
/**
|
||||
* 表别名
|
||||
*/
|
||||
private String fromTableAliasName;
|
||||
/**
|
||||
* 通过子查询获取的表信息,例如:select name from (select * from user) u
|
||||
* 如果不是子查询,则为null
|
||||
*/
|
||||
private SelectSqlInfo fromSubSelect;
|
||||
/**
|
||||
* 查询的字段集合,如果是 * 则为null,如果设了别名则为别名
|
||||
*/
|
||||
private Set<String> selectFields;
|
||||
/**
|
||||
* 真实的查询字段集合,如果是 * 则为null,如果设了别名则为原始字段名
|
||||
*/
|
||||
private Set<String> realSelectFields;
|
||||
/**
|
||||
* 是否是查询所有字段
|
||||
*/
|
||||
private boolean selectAll;
|
||||
|
||||
/**
|
||||
* 解析之后的 SQL (关键字都是大写)
|
||||
*/
|
||||
private final String parsedSql;
|
||||
|
||||
public SelectSqlInfo(String parsedSql) {
|
||||
this.parsedSql = parsedSql;
|
||||
}
|
||||
|
||||
public SelectSqlInfo(SelectBody selectBody) {
|
||||
this.parsedSql = selectBody.toString();
|
||||
}
|
||||
|
||||
public void addSelectField(String selectField, String realSelectField) {
|
||||
if (this.selectFields == null) {
|
||||
this.selectFields = new HashSet<>();
|
||||
}
|
||||
if (this.realSelectFields == null) {
|
||||
this.realSelectFields = new HashSet<>();
|
||||
}
|
||||
this.selectFields.add(selectField);
|
||||
this.realSelectFields.add(realSelectField);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有字段,包括子查询里的。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getAllRealSelectFields() {
|
||||
Set<String> fields = new HashSet<>();
|
||||
// 递归获取所有字段,起个直观的方法名为:
|
||||
this.recursiveGetAllFields(this, fields);
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取所有字段
|
||||
*/
|
||||
private void recursiveGetAllFields(SelectSqlInfo sqlInfo, Set<String> fields) {
|
||||
if (!sqlInfo.isSelectAll() && sqlInfo.getRealSelectFields() != null) {
|
||||
fields.addAll(sqlInfo.getRealSelectFields());
|
||||
}
|
||||
if (sqlInfo.getFromSubSelect() != null) {
|
||||
recursiveGetAllFields(sqlInfo.getFromSubSelect(), fields);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SelectSqlInfo{" +
|
||||
"fromTableName='" + fromTableName + '\'' +
|
||||
", fromSubSelect=" + fromSubSelect +
|
||||
", aliasName='" + fromTableAliasName + '\'' +
|
||||
", selectFields=" + selectFields +
|
||||
", realSelectFields=" + realSelectFields +
|
||||
", selectAll=" + selectAll +
|
||||
"}";
|
||||
}
|
||||
|
||||
}
|
||||
//package org.jeecg.common.util.sqlparse.vo;
|
||||
//
|
||||
//import lombok.Data;
|
||||
//import net.sf.jsqlparser.statement.select.SelectBody;
|
||||
//
|
||||
//import java.util.HashSet;
|
||||
//import java.util.Set;
|
||||
//
|
||||
///**
|
||||
// * select 查询 sql 的信息
|
||||
// */
|
||||
//@Data
|
||||
//public class SelectSqlInfo {
|
||||
//
|
||||
// /**
|
||||
// * 查询的表名,如果是子查询,则此处为null
|
||||
// */
|
||||
// private String fromTableName;
|
||||
// /**
|
||||
// * 表别名
|
||||
// */
|
||||
// private String fromTableAliasName;
|
||||
// /**
|
||||
// * 通过子查询获取的表信息,例如:select name from (select * from user) u
|
||||
// * 如果不是子查询,则为null
|
||||
// */
|
||||
// private SelectSqlInfo fromSubSelect;
|
||||
// /**
|
||||
// * 查询的字段集合,如果是 * 则为null,如果设了别名则为别名
|
||||
// */
|
||||
// private Set<String> selectFields;
|
||||
// /**
|
||||
// * 真实的查询字段集合,如果是 * 则为null,如果设了别名则为原始字段名
|
||||
// */
|
||||
// private Set<String> realSelectFields;
|
||||
// /**
|
||||
// * 是否是查询所有字段
|
||||
// */
|
||||
// private boolean selectAll;
|
||||
//
|
||||
// /**
|
||||
// * 解析之后的 SQL (关键字都是大写)
|
||||
// */
|
||||
// private final String parsedSql;
|
||||
//
|
||||
// public SelectSqlInfo(String parsedSql) {
|
||||
// this.parsedSql = parsedSql;
|
||||
// }
|
||||
//
|
||||
// public SelectSqlInfo(SelectBody selectBody) {
|
||||
// this.parsedSql = selectBody.toString();
|
||||
// }
|
||||
//
|
||||
// public void addSelectField(String selectField, String realSelectField) {
|
||||
// if (this.selectFields == null) {
|
||||
// this.selectFields = new HashSet<>();
|
||||
// }
|
||||
// if (this.realSelectFields == null) {
|
||||
// this.realSelectFields = new HashSet<>();
|
||||
// }
|
||||
// this.selectFields.add(selectField);
|
||||
// this.realSelectFields.add(realSelectField);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取所有字段,包括子查询里的。
|
||||
// *
|
||||
// * @return
|
||||
// */
|
||||
// public Set<String> getAllRealSelectFields() {
|
||||
// Set<String> fields = new HashSet<>();
|
||||
// // 递归获取所有字段,起个直观的方法名为:
|
||||
// this.recursiveGetAllFields(this, fields);
|
||||
// return fields;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 递归获取所有字段
|
||||
// */
|
||||
// private void recursiveGetAllFields(SelectSqlInfo sqlInfo, Set<String> fields) {
|
||||
// if (!sqlInfo.isSelectAll() && sqlInfo.getRealSelectFields() != null) {
|
||||
// fields.addAll(sqlInfo.getRealSelectFields());
|
||||
// }
|
||||
// if (sqlInfo.getFromSubSelect() != null) {
|
||||
// recursiveGetAllFields(sqlInfo.getFromSubSelect(), fields);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// return "SelectSqlInfo{" +
|
||||
// "fromTableName='" + fromTableName + '\'' +
|
||||
// ", fromSubSelect=" + fromSubSelect +
|
||||
// ", aliasName='" + fromTableAliasName + '\'' +
|
||||
// ", selectFields=" + selectFields +
|
||||
// ", realSelectFields=" + realSelectFields +
|
||||
// ", selectAll=" + selectAll +
|
||||
// "}";
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@ -3,7 +3,7 @@ package org.jeecg.config;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import org.jeecg.common.api.CommonAPI;
|
||||
import org.jeecg.common.system.vo.DictModel;
|
||||
|
||||
@ -2,7 +2,9 @@ package org.jeecg.config;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.*;
|
||||
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
|
||||
import jakarta.servlet.*;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@ -11,8 +13,6 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
||||
import com.alibaba.druid.util.Utils;
|
||||
|
||||
/**
|
||||
|
||||
@ -12,6 +12,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author eightmonth@qq.com
|
||||
* 启动程序修改DruidWallConfig配置
|
||||
* 允许SELECT语句的WHERE子句是一个永真条件
|
||||
* @author eightmonth
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package org.jeecg.config;
|
||||
|
||||
import org.jeecg.config.vo.*;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@ -11,12 +14,17 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component("jeecgBaseConfig")
|
||||
@ConfigurationProperties(prefix = "jeecg")
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class JeecgBaseConfig {
|
||||
/**
|
||||
* 签名密钥串(字典等敏感接口)
|
||||
* @TODO 降低使用成本加的默认值,实际以 yml配置 为准
|
||||
*/
|
||||
private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
|
||||
/**
|
||||
* 自定义后台资源前缀,解决表单设计器无法通过前端nginx转发访问
|
||||
*/
|
||||
private String customResourcePrefixPath;
|
||||
/**
|
||||
* 需要加强校验的接口清单
|
||||
*/
|
||||
@ -68,6 +76,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.8.0")
|
||||
.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)));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package org.jeecg.config;
|
||||
|
||||
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.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class UndertowCustomizer implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
|
||||
@Override
|
||||
public void customize(UndertowServletWebServerFactory factory) {
|
||||
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
|
||||
WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
|
||||
webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(false, 1024));
|
||||
deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -10,17 +10,23 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.actuate.web.exchanges.InMemoryHttpExchangeRepository;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonProperties;
|
||||
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.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
@ -30,13 +36,13 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
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 +73,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 +152,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;
|
||||
}
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@ package org.jeecg.config.filter;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@ -7,9 +7,9 @@ import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.TokenUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@ -6,20 +6,17 @@ import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.CommonAPI;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.system.util.JwtUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.common.util.CommonUtils;
|
||||
import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.config.JeecgBaseConfig;
|
||||
import org.jeecg.config.firewall.interceptor.enums.LowCodeUrlsEnum;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Set;
|
||||
@ -70,6 +67,9 @@ public class LowCodeModeInterceptor implements HandlerInterceptor {
|
||||
Set<String> hasRoles = null;
|
||||
if (loginUser == null) {
|
||||
loginUser = commonAPI.getUserByName(JwtUtil.getUserNameByToken(SpringContextUtils.getHttpServletRequest()));
|
||||
}
|
||||
|
||||
if (loginUser != null) {
|
||||
//当前登录人拥有的角色
|
||||
hasRoles = commonAPI.queryUserRolesById(loginUser.getId());
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ import java.util.List;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import org.jeecg.common.config.TenantContext;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.constant.TenantConstant;
|
||||
@ -21,8 +23,6 @@ import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
|
||||
/**
|
||||
* 单数据源配置(jeecg.datasource.open = false时生效)
|
||||
@ -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.示例测试
|
||||
|
||||
@ -11,7 +11,7 @@ import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.config.mybatis.ThreadLocalDataHelper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
|
||||
@ -6,8 +6,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 动态数据源切换拦截器
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jeecg.config.oss;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
@ -26,7 +27,7 @@ public class MinioConfig {
|
||||
@Value(value = "${jeecg.minio.bucketName}")
|
||||
private String bucketName;
|
||||
|
||||
@Bean
|
||||
@PostConstruct
|
||||
public void initMinio(){
|
||||
if(!minioUrl.startsWith(CommonConstant.STR_HTTP)){
|
||||
minioUrl = "http://" + minioUrl;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jeecg.config.oss;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.jeecg.common.util.oss.OssBootUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@ -26,7 +27,7 @@ public class OssConfiguration {
|
||||
private String staticDomain;
|
||||
|
||||
|
||||
@Bean
|
||||
@PostConstruct
|
||||
public void initOssBootConfiguration() {
|
||||
OssBootUtil.setEndPoint(endpoint);
|
||||
OssBootUtil.setAccessKeyId(accessKeyId);
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package org.jeecg.config.shiro;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.Filter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
||||
@ -9,6 +11,7 @@ import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||
import org.apache.shiro.spring.web.ShiroUrlPathHelper;
|
||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||
import org.crazycake.shiro.*;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
@ -18,25 +21,20 @@ 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.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
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 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
@ -47,6 +45,7 @@ import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class ShiroConfig {
|
||||
|
||||
@Resource
|
||||
@ -127,13 +126,15 @@ 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:排除静态资源后缀
|
||||
|
||||
filterChainDefinitionMap.put("/druid/**", "anon");
|
||||
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");
|
||||
@ -144,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");
|
||||
@ -173,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为空 则说明是单体 需要加载跨域配置【微服务跨域切换】
|
||||
@ -190,12 +199,28 @@ public class ShiroConfig {
|
||||
}
|
||||
|
||||
//update-begin---author:chenrui ---date:20240126 for:【QQYUN-7932】AI助手------------
|
||||
|
||||
/**
|
||||
* spring过滤装饰器 <br/>
|
||||
* 因为shiro的filter不支持异步请求,导致所有的异步请求都会报错. <br/>
|
||||
* 所以需要用spring的FilterRegistrationBean再代理一下shiro的filter.为他扩展异步支持. <br/>
|
||||
* 后续所有异步的接口都需要再这里增加registration.addUrlPatterns("/xxx/xxx");
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2024/12/3 19:49
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean shiroFilterRegistration() {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setFilter(new DelegatingFilterProxy("shiroFilterFactoryBean"));
|
||||
registration.setEnabled(true);
|
||||
registration.addUrlPatterns("/*");
|
||||
//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);
|
||||
@ -295,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();
|
||||
@ -328,6 +353,18 @@ public class ShiroConfig {
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解决 ShiroRequestMappingConfig 获取 requestMappingHandlerMapping Bean 冲突
|
||||
* spring-boot-autoconfigure:3.4.5 和 spring-boot-actuator-autoconfigure:3.4.5
|
||||
*/
|
||||
@Primary
|
||||
@Bean
|
||||
public RequestMappingHandlerMapping overridedRequestMappingHandlerMapping() {
|
||||
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
|
||||
mapping.setUrlPathHelper(new ShiroUrlPathHelper());
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private List<String> rebuildUrl(String[] bases, String[] uris) {
|
||||
List<String> urls = new ArrayList<>();
|
||||
for (String base : bases) {
|
||||
|
||||
@ -20,11 +20,13 @@ import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.TokenUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -35,6 +37,7 @@ import java.util.Set;
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class ShiroRealm extends AuthorizingRealm {
|
||||
@Lazy
|
||||
@Resource
|
||||
@ -168,8 +171,8 @@ public class ShiroRealm extends AuthorizingRealm {
|
||||
|
||||
//*********************************************
|
||||
if(!isAuthorization){
|
||||
log.warn("租户异常——当前登录的租户是:" + contextTenantId);
|
||||
log.warn("租户异常——用户拥有的租户是:" + userTenantIds);
|
||||
log.info("租户异常——登录租户:" + contextTenantId);
|
||||
log.info("租户异常——用户拥有租户组:" + userTenantIds);
|
||||
throw new AuthenticationException("登录租户授权变更,请重新登陆!");
|
||||
}
|
||||
//*********************************************
|
||||
|
||||
@ -12,7 +12,7 @@ import org.apache.shiro.web.servlet.AbstractShiroFilter;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import jakarta.servlet.Filter;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
||||
@ -13,10 +13,10 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @Description: 鉴权登录拦截器
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package org.jeecg.config.shiro.filters;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.AccessControlFilter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 签名 拦截器配置
|
||||
|
||||
@ -4,8 +4,8 @@ package org.jeecg.config.sign.interceptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package org.jeecg.config.sign.util;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
|
||||
@ -14,8 +14,8 @@ import org.jeecg.common.util.SpringContextUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
springdoc.auto-tag-classes: false
|
||||
springdoc.packages-to-scan: org.jeecg
|
||||
@ -1,75 +0,0 @@
|
||||
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 static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* SQL注入攻击检查测试
|
||||
* @author: liusq
|
||||
* @date: 2023年09月08日
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestInjectWithSqlParser {
|
||||
/**
|
||||
* 注入测试
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
private boolean isExistSqlInject(String sql) {
|
||||
try {
|
||||
SqlInjectionUtil.specialFilterContentForOnlineReport(sql);
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
log.info("===================================================");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() throws JSQLParserException {
|
||||
//不存在sql注入
|
||||
assertFalse(isExistSqlInject("select * from fm_time where dept_id=:sqlparamsmap.id and time=:sqlparamsmap.time"));
|
||||
assertFalse(isExistSqlInject("select * from test"));
|
||||
assertFalse(isExistSqlInject("select load_file(\"C:\\\\benben.txt\")"));
|
||||
assertFalse(isExistSqlInject("WITH SUB1 AS (SELECT user FROM t1) SELECT * FROM T2 WHERE id > 123 "));
|
||||
|
||||
//存在sql注入
|
||||
assertTrue(isExistSqlInject("or 1= 1 --"));
|
||||
assertTrue(isExistSqlInject("select * from test where sleep(%23)"));
|
||||
assertTrue(isExistSqlInject("select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));"));
|
||||
assertTrue(isExistSqlInject("select * from users;show databases;"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id=1 and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13"));
|
||||
assertTrue(isExistSqlInject("update user set name = '123'"));
|
||||
assertTrue(isExistSqlInject("SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1=1;--"));
|
||||
assertTrue(isExistSqlInject("select * from users where id=1 and (select count(*) from information_schema.tables where table_schema='数据库名')>4 %23"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where sleep(5) %23"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id in (select id from other)"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id in (select id from other)"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where 2=2.0 or 2 != 4"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where 1!=2.0"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id=floor(2.0)"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where not true"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where 1 or id > 0"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where 'tom' or id > 0"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where '-2.3' "));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where 2 "));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where (3+2) "));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where -1 IS TRUE"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where 'hello' is null "));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where '2022-10-31' and id > 0"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id > 0 or 1!=2.0 "));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id > 0 or 1 in (1,3,4) "));
|
||||
assertTrue(isExistSqlInject("select * from dc_device UNION select name from other"));
|
||||
assertTrue(isExistSqlInject("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
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 static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* SQL注入攻击检查测试
|
||||
* @author: liusq
|
||||
* @date: 2023年09月08日
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestSqlInjectForDict {
|
||||
/**
|
||||
* 注入测试
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
private boolean isExistSqlInject(String sql) {
|
||||
try {
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(sql);
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
log.info("===================================================");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() throws JSQLParserException {
|
||||
//不存在sql注入
|
||||
assertFalse(isExistSqlInject("sys_user,realname,id"));
|
||||
assertFalse(isExistSqlInject("oa_officialdoc_organcode,organ_name,id"));
|
||||
assertFalse(isExistSqlInject("onl_cgform_head where table_type!=3 and copy_type=0,table_txt,table_name"));
|
||||
assertFalse(isExistSqlInject("onl_cgform_head where copy_type = 0,table_txt,table_name"));
|
||||
|
||||
//存在sql注入
|
||||
assertTrue(isExistSqlInject("or 1= 1 --"));
|
||||
assertTrue(isExistSqlInject("select * from test where sleep(%23)"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
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 static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* SQL注入攻击检查测试
|
||||
* @author: liusq
|
||||
* @date: 2023年09月08日
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestSqlInjectForOnlineReport {
|
||||
/**
|
||||
* 注入测试
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
private boolean isExistSqlInject(String sql) {
|
||||
try {
|
||||
SqlInjectionUtil.specialFilterContentForOnlineReport(sql);
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
log.info("===================================================");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() throws JSQLParserException {
|
||||
//不存在sql注入
|
||||
assertFalse(isExistSqlInject("select * from fm_time where dept_id=:sqlparamsmap.id and time=:sqlparamsmap.time"));
|
||||
assertFalse(isExistSqlInject("select * from test"));
|
||||
assertFalse(isExistSqlInject("select load_file(\"C:\\\\benben.txt\")"));
|
||||
assertFalse(isExistSqlInject("select * from dc_device where id in (select id from other)"));
|
||||
assertFalse(isExistSqlInject("select * from dc_device UNION select name from other"));
|
||||
|
||||
//存在sql注入
|
||||
assertTrue(isExistSqlInject("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)"));
|
||||
assertTrue(isExistSqlInject("or 1= 1 --"));
|
||||
assertTrue(isExistSqlInject("select * from test where sleep(%23)"));
|
||||
assertTrue(isExistSqlInject("select * from test where SLEEP(3)"));
|
||||
assertTrue(isExistSqlInject("select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));"));
|
||||
assertTrue(isExistSqlInject("select * from users;show databases;"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where id=1 and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13"));
|
||||
assertTrue(isExistSqlInject("update user set name = '123'"));
|
||||
assertTrue(isExistSqlInject("SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1=1;--"));
|
||||
assertTrue(isExistSqlInject("select * from users where id=1 and (select count(*) from information_schema.tables where table_schema='数据库名')>4 %23"));
|
||||
assertTrue(isExistSqlInject("select * from dc_device where sleep(5) %23"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,103 +0,0 @@
|
||||
package org.jeecg.test.sqlinjection;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
|
||||
import org.jeecg.common.util.SqlInjectionUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @Description: SQL注入测试类
|
||||
* @author: scott
|
||||
* @date: 2023年08月14日 9:55
|
||||
*/
|
||||
public class TestSqlInjection {
|
||||
|
||||
|
||||
/**
|
||||
* 表名带别名,同时有html编码字符
|
||||
*/
|
||||
@Test
|
||||
public void testSpecialSQL() {
|
||||
String tableName = "sys_user t";
|
||||
//解决使用参数tableName=sys_user t&复测,漏洞仍然存在
|
||||
if (tableName.contains(" ")) {
|
||||
tableName = tableName.substring(0, tableName.indexOf(" "));
|
||||
}
|
||||
//【issues/4393】 sys_user , (sys_user), sys_user%20, %60sys_user%60
|
||||
String reg = "\\s+|\\(|\\)|`";
|
||||
tableName = tableName.replaceAll(reg, "");
|
||||
System.out.println(tableName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试sql是否含sql注入风险
|
||||
* <p>
|
||||
* mybatis plus的方法
|
||||
*/
|
||||
@Test
|
||||
public void sqlInjectionCheck() {
|
||||
String sql = "select * from sys_user";
|
||||
System.out.println(SqlInjectionUtils.check(sql));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试sql是否有SLEEP风险
|
||||
* <p>
|
||||
* mybatisPlus的方法
|
||||
*/
|
||||
@Test
|
||||
public void sqlSleepCheck() {
|
||||
SqlInjectionUtil.checkSqlAnnotation("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试sql是否含sql注入风险
|
||||
* <p>
|
||||
* 自定义方法
|
||||
*/
|
||||
@Test
|
||||
public void sqlInjectionCheck2() {
|
||||
String sql = "select * from sys_user";
|
||||
SqlInjectionUtil.specialFilterContentForOnlineReport(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等)
|
||||
* <p>
|
||||
* 判断字段名是否符合规范
|
||||
*/
|
||||
@Test
|
||||
public void testFieldSpecification() {
|
||||
List<String> list = new ArrayList();
|
||||
list.add("Hello World!");
|
||||
list.add("Hello%20World!");
|
||||
list.add("HelloWorld!");
|
||||
list.add("Hello World");
|
||||
list.add("age");
|
||||
list.add("user_name");
|
||||
list.add("user_name%20");
|
||||
list.add("user_name%20 ");
|
||||
|
||||
for (String input : list) {
|
||||
boolean containsSpecialChars = isValidString(input);
|
||||
System.out.println("input:" + input + " ,包含空格和特殊字符: " + containsSpecialChars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等)
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
private static boolean isValidString(String input) {
|
||||
Pattern pattern = Pattern.compile("^[a-zA-Z0-9_]+$");
|
||||
return pattern.matcher(input).matches();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
package org.jeecg.test.sqlparse;
|
||||
|
||||
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 java.util.Map;
|
||||
|
||||
/**
|
||||
* 针对 JSqlParserUtils 的单元测试
|
||||
*/
|
||||
public class JSqlParserUtilsTest {
|
||||
|
||||
private static final String[] sqlList = new String[]{
|
||||
"select * from sys_user",
|
||||
"select u.* from sys_user u",
|
||||
"select u.*, c.name from sys_user u, demo c",
|
||||
"select u.age, c.name from sys_user u, demo c",
|
||||
"select sex, age, c.name from sys_user, demo c",
|
||||
// 别名测试
|
||||
"select username as realname from sys_user",
|
||||
"select username as realname, u.realname as aaa, u.id bbb from sys_user u",
|
||||
// 不存在真实地查询字段
|
||||
"select count(1) from sys_user",
|
||||
// 函数式字段
|
||||
"select max(sex), id from sys_user",
|
||||
// 复杂嵌套函数式字段
|
||||
"select CONCAT(CONCAT(' _ ', sex), ' - ' , birthday) as info, id from sys_user",
|
||||
// 更复杂的嵌套函数式字段
|
||||
"select CONCAT(CONCAT(101,'_',NULL, DATE(create_time),'_',sex),' - ',birthday) as info, id from sys_user",
|
||||
// 子查询SQL
|
||||
"select u.name1 as name2 from (select username as name1 from sys_user) u",
|
||||
// 多层嵌套子查询SQL
|
||||
"select u2.name2 as name3 from (select u1.name1 as name2 from (select username as name1 from sys_user) u1) u2",
|
||||
// 字段子查询SQL
|
||||
"select id, (select username as name1 from sys_user u2 where u1.id = u2.id) as name2 from sys_user u1",
|
||||
// 带条件的SQL(不解析where条件里的字段,但不影响解析查询字段)
|
||||
"select username as name1 from sys_user where realname LIKE '%张%'",
|
||||
// 多重复杂关联表查询解析,包含的表为:sys_user, sys_depart, sys_dict_item, demo
|
||||
"" +
|
||||
"SELECT " +
|
||||
" u.*, d.age, sd.item_text AS sex, (SELECT count(sd.id) FROM sys_depart sd) AS count " +
|
||||
"FROM " +
|
||||
" (SELECT sd.username AS foo, sd.realname FROM sys_user sd) u, " +
|
||||
" demo d " +
|
||||
"LEFT JOIN sys_dict_item AS sd ON d.sex = sd.item_value " +
|
||||
"WHERE sd.dict_id = '3d9a351be3436fbefb1307d4cfb49bf2'",
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testParseSelectSql() {
|
||||
System.out.println("-----------------------------------------");
|
||||
for (String sql : sqlList) {
|
||||
System.out.println("待测试的sql:" + sql);
|
||||
try {
|
||||
// 解析所有的表名,key=表名,value=解析后的sql信息
|
||||
Map<String, SelectSqlInfo> parsedMap = JSqlParserUtils.parseAllSelectTable(sql);
|
||||
assert parsedMap != null;
|
||||
for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
|
||||
System.out.println("表名:" + entry.getKey());
|
||||
this.printSqlInfo(entry.getValue(), 1);
|
||||
}
|
||||
} catch (JSQLParserException e) {
|
||||
System.out.println("SQL解析出现异常:" + e.getMessage());
|
||||
}
|
||||
System.out.println("-----------------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
private void printSqlInfo(SelectSqlInfo sqlInfo, int level) {
|
||||
String beforeStr = this.getBeforeStr(level);
|
||||
if (sqlInfo.getFromTableName() == null) {
|
||||
// 子查询
|
||||
System.out.println(beforeStr + "子查询:" + sqlInfo.getFromSubSelect().getParsedSql());
|
||||
this.printSqlInfo(sqlInfo.getFromSubSelect(), level + 1);
|
||||
} else {
|
||||
// 非子查询
|
||||
System.out.println(beforeStr + "查询的表名:" + sqlInfo.getFromTableName());
|
||||
}
|
||||
if (oConvertUtils.isNotEmpty(sqlInfo.getFromTableAliasName())) {
|
||||
System.out.println(beforeStr + "查询的表别名:" + sqlInfo.getFromTableAliasName());
|
||||
}
|
||||
if (sqlInfo.isSelectAll()) {
|
||||
System.out.println(beforeStr + "查询的字段:*");
|
||||
} else {
|
||||
System.out.println(beforeStr + "查询的字段:" + sqlInfo.getSelectFields());
|
||||
System.out.println(beforeStr + "真实的字段:" + sqlInfo.getRealSelectFields());
|
||||
if (sqlInfo.getFromTableName() == null) {
|
||||
System.out.println(beforeStr + "所有的字段(包括子查询):" + sqlInfo.getAllRealSelectFields());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打印前缀,根据层级来打印
|
||||
private String getBeforeStr(int level) {
|
||||
if (level == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder beforeStr = new StringBuilder();
|
||||
for (int i = 0; i < level; i++) {
|
||||
beforeStr.append(" ");
|
||||
}
|
||||
beforeStr.append("- ");
|
||||
return beforeStr.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
178
jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/pom.xml
Normal file
178
jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/pom.xml
Normal file
@ -0,0 +1,178 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-module</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>jeecg-boot-module-airag</artifactId>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>aliyun</id>
|
||||
<name>aliyun Repository</name>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jeecg</id>
|
||||
<name>jeecg Repository</name>
|
||||
<url>https://maven.jeecg.org/nexus/content/repositories/jeecg</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
<kotlin.version>1.6.21</kotlin.version>
|
||||
<liteflow.version>2.12.4.1</liteflow.version>
|
||||
<langchain4j.version>0.35.0</langchain4j.version>
|
||||
<apache-tika.version>2.9.1</apache-tika.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- system单体 api-->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-system-local-api</artifactId>
|
||||
</dependency>
|
||||
<!-- 微服务starter和system微服务 api
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-boot-starter-cloud</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot</groupId>
|
||||
<artifactId>jeecg-system-cloud-api</artifactId>
|
||||
</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot3</groupId>
|
||||
<artifactId>jeecg-aiflow</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- aiflow 脚本依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-script-graaljs</artifactId>
|
||||
<version>${liteflow.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-script-groovy</artifactId>
|
||||
<version>${liteflow.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-script-kotlin</artifactId>
|
||||
<version>${liteflow.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-scripting-jsr223</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-script-aviator</artifactId>
|
||||
<version>${liteflow.version}</version>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>aviator</artifactId>
|
||||
<groupId>com.googlecode.aviator</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- aiflow 脚本依赖 -->
|
||||
|
||||
<!-- langChain4j model support -->
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-ollama</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-zhipu-ai</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>guava</artifactId>
|
||||
<groupId>com.google.guava</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-qianfan</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-dashscope</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>okio</artifactId>
|
||||
<groupId>com.squareup.okio</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- langChain4j vextor support -->
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-pgvector</artifactId>
|
||||
<version>${langchain4j.version}</version>
|
||||
</dependency>
|
||||
<!-- langChain4j Document Parser -->
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>${apache-tika.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-parser-html-module</artifactId>
|
||||
<version>${apache-tika.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-parser-pdf-module</artifactId>
|
||||
<version>${apache-tika.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-parser-text-module</artifactId>
|
||||
<version>${apache-tika.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,12 @@
|
||||
//package org.jeecg;
|
||||
//
|
||||
//import org.springframework.boot.SpringApplication;
|
||||
//import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
//
|
||||
//@SpringBootApplication
|
||||
//public class JeecgAiRagApplication {
|
||||
//
|
||||
// public static void main(String[] args) {
|
||||
// SpringApplication.run(JeecgAiRagApplication.class, args);
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,37 @@
|
||||
package org.jeecg.modules.airag.app.consts;
|
||||
|
||||
/**
|
||||
* AI应用常量类
|
||||
*
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 14:52
|
||||
*/
|
||||
public class AiAppConsts {
|
||||
|
||||
/**
|
||||
* 状态:启用
|
||||
*/
|
||||
public static final String STATUS_ENABLE = "enable";
|
||||
/**
|
||||
* 状态:禁用
|
||||
*/
|
||||
public static final String STATUS_DISABLE = "disable";
|
||||
|
||||
|
||||
/**
|
||||
* 默认应用id
|
||||
*/
|
||||
public static final String DEFAULT_APP_ID = "default";
|
||||
|
||||
|
||||
/**
|
||||
* 应用类型:简单聊天
|
||||
*/
|
||||
public static final String APP_TYPE_CHAT_SIMPLE = "chatSimple";
|
||||
|
||||
/**
|
||||
* 应用类型:聊天流(高级编排)
|
||||
*/
|
||||
public static final String APP_TYPE_CHAT_FLOW = "chatFLow";
|
||||
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
package org.jeecg.modules.airag.app.consts;
|
||||
|
||||
/**
|
||||
* @Description: 提示词常量
|
||||
* @Author: chenrui
|
||||
* @Date: 2025/3/12 15:03
|
||||
*/
|
||||
public class Prompts {
|
||||
|
||||
/**
|
||||
* 根据提示生成智能体提示词
|
||||
*/
|
||||
public static final String GENERATE_LLM_PROMPT = "# 角色\n" +
|
||||
"你是一位专业且高效的AI提示词工程师,擅长根据用户多样化需求自动生成高质量的结构化提示词模板,具备全面而敏锐的分析能力和出色的创造力。\n" +
|
||||
"## 要求:\n" +
|
||||
"1. \"\"\"只输出提示词,不要输出多余解释\"\"\"\n" +
|
||||
"2. \"\"\"不要在前后增加代码块的md语法.\"\"\"\n" +
|
||||
"2. 贴合用户需求,描述智能助手的定位、能力、知识储备\n" +
|
||||
"3. 提示词应清晰、精确、易于理解,在保持质量的同时,尽可能简洁\n" +
|
||||
"4. 严格按照给定的流程和格式执行任务,确保输出规范准确。\n" +
|
||||
"\n" +
|
||||
"## 流程\n" +
|
||||
"### 1: 需求分析\n" +
|
||||
"1. 当用户描述需求时,严格运用SCQA框架确认核心要素,精准分析和联想:\"当前场景(Situation)是什么?主要矛盾(Complication)有哪些?需要解决的关键问题(Question)是?预期达成什么效果(Answer)?\"\n" +
|
||||
"2. 通过5W1H细致分析和联想细节:\"目标受众(Who)?使用场景(Where/When)?具体要实现什么(What)?为什么需要这些特征(Why)?如何量化效果(How)?\"\n" +
|
||||
"\n" +
|
||||
"### 2: 框架选择\n" +
|
||||
"根据需求从给定模板库中匹配最佳提示词类型:\n" +
|
||||
"* 角色扮演型:\n" +
|
||||
"```\n" +
|
||||
"你将扮演一个人物角色<角色名称>,以下是关于这个角色的详细设定,请根据这些信息来构建你的回答。 \n" +
|
||||
"\n" +
|
||||
"**人物基本信息:**\n" +
|
||||
"- 你是:<角色的名称、身份等基本介绍>\n" +
|
||||
"- 人称:第一人称\n" +
|
||||
"- 出身背景与上下文:<交代角色背景信息和上下文>\n" +
|
||||
"**性格特点:**\n" +
|
||||
"- <性格特点描述>\n" +
|
||||
"**语言风格:**\n" +
|
||||
"- <语言风格描述> \n" +
|
||||
"**人际关系:**\n" +
|
||||
"- <人际关系描述>\n" +
|
||||
"**过往经历:**\n" +
|
||||
"- <过往经历描述>\n" +
|
||||
"**经典台词或口头禅:**\n" +
|
||||
"补充信息: 即你可以将动作、神情语气、心理活动、故事背景放在()中来表示,为对话提供补充信息。\n" +
|
||||
"- 台词1:<角色台词示例1> \n" +
|
||||
"- 台词2:<角色台词示例2>\n" +
|
||||
"- ...\n" +
|
||||
"\n" +
|
||||
"要求: \n" +
|
||||
"- 要求1\n" +
|
||||
"- 要求2\n" +
|
||||
"- ... \n" +
|
||||
"```\n" +
|
||||
"* 多步骤型:\n" +
|
||||
"```\n" +
|
||||
"# 角色 \n" +
|
||||
"你是<角色设定(比如:xx领域的专家)>\n" +
|
||||
"你的目标是<希望模型执行什么任务,达成什么目标>\n" +
|
||||
"\n" +
|
||||
"{#以下可以采用先总括,再展开详细说明的方式,描述你希望智能体在每一个步骤如何进行工作,具体的工作步骤数量可以根据实际需求增删#}\n" +
|
||||
"## 工作步骤 \n" +
|
||||
"1. <工作流程1的一句话概括> \n" +
|
||||
"2. <工作流程2的一句话概括> \n" +
|
||||
"3. <工作流程3的一句话概括>\n" +
|
||||
"\n" +
|
||||
"### 第一步 <工作流程1标题> \n" +
|
||||
"<工作流程步骤1的具体工作要求和举例说明,可以分点列出希望在本步骤做哪些事情,需要完成什么阶段性的工作目标>\n" +
|
||||
"### 第二步 <工作流程2标题> \n" +
|
||||
"<工作流程步骤2的具体工作要求和举例说明,可以分点列出希望在本步骤做哪些事情,需要完成什么阶段性的工作目标>\n" +
|
||||
"### 第三步 <工作流程3标题>\n" +
|
||||
"<工作流程步骤3的具体工作要求和举例说明,可以分点列出希望在本步骤做哪些事情,需要完成什么阶段性的工作目标>\n" +
|
||||
"```\n" +
|
||||
"* 限制性模板:\n" +
|
||||
"```\n" +
|
||||
"# 角色:<角色名称>\n" +
|
||||
"<角色概述和主要职责的一句话描述>\n" +
|
||||
"\n" +
|
||||
"## 目标:\n" +
|
||||
"<角色的工作目标,如果有多目标可以分点列出,但建议更聚焦1-2个目标>\n" +
|
||||
"\n" +
|
||||
"## 技能:\n" +
|
||||
"1. <为了实现目标,角色需要具备的技能1>\n" +
|
||||
"2. <为了实现目标,角色需要具备的技能2>\n" +
|
||||
"3. <为了实现目标,角色需要具备的技能3>\n" +
|
||||
"\n" +
|
||||
"## 工作流:\n" +
|
||||
"1. <描述角色工作流程的第一步>\n" +
|
||||
"2. <描述角色工作流程的第二步>\n" +
|
||||
"3. <描述角色工作流程的第三步>\n" +
|
||||
"\n" +
|
||||
"## 输出格式:\n" +
|
||||
"<如果对角色的输出格式有特定要求,可以在这里强调并举例说明想要的输出格式>\n" +
|
||||
"\n" +
|
||||
"## 限制:\n" +
|
||||
"- <描述角色在互动过程中需要遵循的限制条件1>\n" +
|
||||
"- <描述角色在互动过程中需要遵循的限制条件2>\n" +
|
||||
"- <描述角色在互动过程中需要遵循的限制条件3>\n" +
|
||||
"```\n" +
|
||||
"\n" +
|
||||
"### 3: 生成优化\n" +
|
||||
"1. 输出时自动添加三重保障机制:\n" +
|
||||
" - 反幻觉校验:\"所有数据需标注来源,不确定信息用[需核实]标记\"\n" +
|
||||
" - 风格校准器:\"对比[目标风格]与生成内容的余弦相似度,低于0.7时启动重写\"\n" +
|
||||
" - 伦理审查模块:\"自动过滤涉及隐私/偏见/违法内容,替换为[合规表达]\"";
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
package org.jeecg.modules.airag.app.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 lombok.extern.slf4j.Slf4j;
|
||||
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.common.util.AssertUtils;
|
||||
import org.jeecg.config.shiro.IgnoreAuth;
|
||||
import org.jeecg.modules.airag.app.consts.AiAppConsts;
|
||||
import org.jeecg.modules.airag.app.entity.AiragApp;
|
||||
import org.jeecg.modules.airag.app.service.IAiragAppService;
|
||||
import org.jeecg.modules.airag.app.service.IAiragChatService;
|
||||
import org.jeecg.modules.airag.app.vo.AppDebugParams;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @Description: AI应用
|
||||
* @Author: jeecg-boot
|
||||
* @Date: 2025-02-26
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/airag/app")
|
||||
@Slf4j
|
||||
public class AiragAppController extends JeecgController<AiragApp, IAiragAppService> {
|
||||
@Autowired
|
||||
private IAiragAppService airagAppService;
|
||||
|
||||
@Autowired
|
||||
private IAiragChatService airagChatService;
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
* @param airagApp
|
||||
* @param pageNo
|
||||
* @param pageSize
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
public Result<IPage<AiragApp>> queryPageList(AiragApp airagApp,
|
||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<AiragApp> queryWrapper = QueryGenerator.initQueryWrapper(airagApp, req.getParameterMap());
|
||||
Page<AiragApp> page = new Page<AiragApp>(pageNo, pageSize);
|
||||
IPage<AiragApp> pageList = airagAppService.page(page, queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增或编辑
|
||||
*
|
||||
* @param airagApp
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||
public Result<String> edit(@RequestBody AiragApp airagApp) {
|
||||
AssertUtils.assertNotEmpty("参数异常", airagApp);
|
||||
AssertUtils.assertNotEmpty("请输入应用名称", airagApp.getName());
|
||||
AssertUtils.assertNotEmpty("请选择应用类型", airagApp.getType());
|
||||
airagApp.setStatus(AiAppConsts.STATUS_ENABLE);
|
||||
airagAppService.saveOrUpdate(airagApp);
|
||||
return Result.OK("保存完成!", airagApp.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/delete")
|
||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
||||
airagAppService.removeById(id);
|
||||
return Result.OK("删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
||||
this.airagAppService.removeByIds(Arrays.asList(ids.split(",")));
|
||||
return Result.OK("批量删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<AiragApp> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
AiragApp airagApp = airagAppService.getById(id);
|
||||
if (airagApp == null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(airagApp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 调试应用
|
||||
*
|
||||
* @param appDebugParams
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/2/28 10:49
|
||||
*/
|
||||
@PostMapping(value = "/debug")
|
||||
public SseEmitter debugApp(@RequestBody AppDebugParams appDebugParams) {
|
||||
return airagChatService.debugApp(appDebugParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据需求生成提示词
|
||||
*
|
||||
* @param prompt
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/3/12 15:30
|
||||
*/
|
||||
@GetMapping(value = "/prompt/generate")
|
||||
public Result<?> generatePrompt(@RequestParam(name = "prompt", required = true) String prompt) {
|
||||
return (Result<?>) airagAppService.generatePrompt(prompt,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据需求生成提示词
|
||||
*
|
||||
* @param prompt
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/3/12 15:30
|
||||
*/
|
||||
@PostMapping(value = "/prompt/generate")
|
||||
public SseEmitter generatePromptSse(@RequestParam(name = "prompt", required = true) String prompt) {
|
||||
return (SseEmitter) airagAppService.generatePrompt(prompt,false);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
package org.jeecg.modules.airag.app.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.config.shiro.IgnoreAuth;
|
||||
import org.jeecg.modules.airag.app.service.IAiragChatService;
|
||||
import org.jeecg.modules.airag.app.vo.ChatConversation;
|
||||
import org.jeecg.modules.airag.app.vo.ChatSendParams;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
|
||||
/**
|
||||
* airag应用-chat
|
||||
*
|
||||
* @Author: chenrui
|
||||
* @Date: 2025-02-25 11:40
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/airag/chat")
|
||||
public class AiragChatController {
|
||||
|
||||
@Autowired
|
||||
IAiragChatService chatService;
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @return 返回一个Result对象,表示发送消息的结果
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 11:42
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@PostMapping(value = "/send")
|
||||
public SseEmitter send(@RequestBody ChatSendParams chatSendParams) {
|
||||
return chatService.send(chatSendParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息 <br/>
|
||||
* 兼容旧版浏览器
|
||||
* @param content
|
||||
* @param conversationId
|
||||
* @param topicId
|
||||
* @param appId
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 18:13
|
||||
*/
|
||||
@GetMapping(value = "/send")
|
||||
public SseEmitter sendByGet(@RequestParam("content") String content,
|
||||
@RequestParam(value = "conversationId", required = false) String conversationId,
|
||||
@RequestParam(value = "topicId", required = false) String topicId,
|
||||
@RequestParam(value = "appId", required = false) String appId) {
|
||||
ChatSendParams chatSendParams = new ChatSendParams(content, conversationId, topicId, appId);
|
||||
return chatService.send(chatSendParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有对话
|
||||
*
|
||||
* @return 返回一个Result对象,包含所有对话的信息
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 11:42
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@GetMapping(value = "/conversations")
|
||||
public Result<?> getConversations(@RequestParam(value = "appId", required = false) String appId) {
|
||||
return chatService.getConversations(appId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会话
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/3/3 16:55
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@DeleteMapping(value = "/conversation/{id}")
|
||||
public Result<?> deleteConversation(@PathVariable("id") String id) {
|
||||
return chatService.deleteConversation(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话标题
|
||||
*
|
||||
* @param updateTitleParams
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/3/3 16:55
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@PutMapping(value = "/conversation/update/title")
|
||||
public Result<?> updateConversationTitle(@RequestBody ChatConversation updateTitleParams) {
|
||||
return chatService.updateConversationTitle(updateTitleParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息
|
||||
*
|
||||
* @return 返回一个Result对象,包含消息的信息
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 11:42
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@GetMapping(value = "/messages")
|
||||
public Result<?> getMessages(@RequestParam(value = "conversationId", required = true) String conversationId) {
|
||||
return chatService.getMessages(conversationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空消息
|
||||
*
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 11:42
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@GetMapping(value = "/messages/clear/{conversationId}")
|
||||
public Result<?> clearMessage(@PathVariable(value = "conversationId") String conversationId) {
|
||||
return chatService.clearMessage(conversationId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据请求ID停止某个请求的处理
|
||||
*
|
||||
* @param requestId 请求的唯一标识符,用于识别和停止特定的请求
|
||||
* @return 返回一个Result对象,表示停止请求的结果
|
||||
* @author chenrui
|
||||
* @date 2025/2/25 11:42
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@GetMapping(value = "/stop/{requestId}")
|
||||
public Result<?> stop(@PathVariable(name = "requestId", required = true) String requestId) {
|
||||
return chatService.stop(requestId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package org.jeecg.modules.airag.app.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.jeecg.common.aspect.annotation.Dict;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description: AI应用
|
||||
* @Author: jeecg-boot
|
||||
* @Date: 2025-02-26
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Data
|
||||
@TableName("airag_app")
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description="AI应用")
|
||||
public class AiragApp implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "主键")
|
||||
private String id;
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@Schema(description = "创建人")
|
||||
private String createBy;
|
||||
/**
|
||||
* 创建日期
|
||||
*/
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "创建日期")
|
||||
private java.util.Date createTime;
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
@Schema(description = "更新人")
|
||||
private String updateBy;
|
||||
/**
|
||||
* 更新日期
|
||||
*/
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "更新日期")
|
||||
private java.util.Date updateTime;
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
@Schema(description = "所属部门")
|
||||
private String sysOrgCode;
|
||||
/**
|
||||
* 租户id
|
||||
*/
|
||||
@Excel(name = "租户id", width = 15)
|
||||
@Schema(description = "租户id")
|
||||
private String tenantId;
|
||||
/**
|
||||
* 应用名称
|
||||
*/
|
||||
@Excel(name = "应用名称", width = 15)
|
||||
@Schema(description = "应用名称")
|
||||
private String name;
|
||||
/**
|
||||
* 应用描述
|
||||
*/
|
||||
@Excel(name = "应用描述", width = 15)
|
||||
@Schema(description = "应用描述")
|
||||
private String descr;
|
||||
/**
|
||||
* 应用图标
|
||||
*/
|
||||
@Excel(name = "应用图标", width = 15)
|
||||
@Schema(description = "应用图标")
|
||||
private String icon;
|
||||
/**
|
||||
* 应用类型
|
||||
*/
|
||||
@Excel(name = "应用类型", width = 15, dicCode = "ai_app_type")
|
||||
@Dict(dicCode = "ai_app_type")
|
||||
@Schema(description = "应用类型")
|
||||
private String type;
|
||||
/**
|
||||
* 开场白
|
||||
*/
|
||||
@Excel(name = "开场白", width = 15)
|
||||
@Schema(description = "开场白")
|
||||
private String prologue;
|
||||
/**
|
||||
* 预设问题
|
||||
*/
|
||||
@Excel(name = "预设问题", width = 15)
|
||||
@Schema(description = "预设问题")
|
||||
private String presetQuestion;
|
||||
/**
|
||||
* 提示词
|
||||
*/
|
||||
@Excel(name = "提示词", width = 15)
|
||||
@Schema(description = "提示词")
|
||||
private String prompt;
|
||||
/**
|
||||
* 模型配置
|
||||
*/
|
||||
@Excel(name = "模型配置", width = 15, dictTable = "airag_model where model_type = 'LLM' ", dicText = "name", dicCode = "id")
|
||||
@Dict(dictTable = "airag_model where model_type = 'LLM' ", dicText = "name", dicCode = "id")
|
||||
@Schema(description = "模型配置")
|
||||
private String modelId;
|
||||
/**
|
||||
* 历史消息数
|
||||
*/
|
||||
@Excel(name = "历史消息数", width = 15)
|
||||
@Schema(description = "历史消息数")
|
||||
private Integer msgNum;
|
||||
/**
|
||||
* 知识库
|
||||
*/
|
||||
@Excel(name = "知识库", width = 15, dictTable = "airag_knowledge where status = 'enable'", dicText = "name", dicCode = "id")
|
||||
@Dict(dictTable = "airag_knowledge where status = 'enable'", dicText = "name", dicCode = "id")
|
||||
@Schema(description = "知识库")
|
||||
private String knowledgeIds;
|
||||
/**
|
||||
* 流程
|
||||
*/
|
||||
@Excel(name = "流程", width = 15, dictTable = "airag_flow where status = 'enable' ", dicText = "name", dicCode = "id")
|
||||
@Dict(dictTable = "airag_flow where status = 'enable' ", dicText = "name", dicCode = "id")
|
||||
@Schema(description = "流程")
|
||||
private String flowId;
|
||||
/**
|
||||
* 快捷指令
|
||||
*/
|
||||
@Excel(name = "快捷指令", width = 15)
|
||||
@Schema(description = "快捷指令")
|
||||
private String quickCommand;
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@Excel(name = "状态", width = 15)
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
@Excel(name = "元数据", width = 15)
|
||||
@Schema(description = "元数据")
|
||||
private String metadata;
|
||||
|
||||
/**
|
||||
* 知识库ids
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<String> knowIds;
|
||||
|
||||
/**
|
||||
* 获取知识库id
|
||||
*
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/2/28 11:45
|
||||
*/
|
||||
public List<String> getKnowIds() {
|
||||
if (oConvertUtils.isNotEmpty(knowledgeIds)) {
|
||||
String[] knowIds = knowledgeIds.split(",");
|
||||
return Arrays.asList(knowIds);
|
||||
} else {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.jeecg.modules.airag.app.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.jeecg.modules.airag.app.entity.AiragApp;
|
||||
|
||||
/**
|
||||
* @Description: AI应用
|
||||
* @Author: jeecg-boot
|
||||
* @Date: 2025-02-26
|
||||
* @Version: V1.0
|
||||
*/
|
||||
public interface AiragAppMapper extends BaseMapper<AiragApp> {
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user