mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
35 Commits
1d3bde9fe7
...
v3.6.3_spr
| Author | SHA1 | Date | |
|---|---|---|---|
| e616c5d8fe | |||
| cddf23c787 | |||
| 70a37309dd | |||
| 48555b5219 | |||
| 06d58f202f | |||
| 628870af9b | |||
| b46a6438e6 | |||
| 5488f99723 | |||
| 6bc1fe8d21 | |||
| 7cac16320c | |||
| 24dbd1db39 | |||
| 46b026b989 | |||
| 94c45f5e0f | |||
| 8950e19d4e | |||
| 99eb88f71c | |||
| 824d7839d8 | |||
| c88f9d95d4 | |||
| beb0bc2f64 | |||
| f741db874c | |||
| d684c09392 | |||
| 364be22dd0 | |||
| 20efa3bf9a | |||
| c7977dda3d | |||
| c27c5a9a9b | |||
| 0ab280f812 | |||
| c3066dac17 | |||
| b650d512b3 | |||
| 925ec9447d | |||
| 411a73c1bf | |||
| 84077e6e24 | |||
| 184cf97304 | |||
| 5f425b49b2 | |||
| 3ac8ee304a | |||
| 0faac01bb7 | |||
| 74d88a8fcc |
5
.gitattributes
vendored
5
.gitattributes
vendored
@ -1,6 +1,5 @@
|
|||||||
*.js linguist-language=Java
|
*.js linguist-language=Java
|
||||||
*.css linguist-language=Java
|
*.css linguist-language=Java
|
||||||
*.ts linguist-language=vue
|
*.html linguist-language=Java
|
||||||
*.html linguist-language=vue
|
*.vue linguist-language=Java
|
||||||
*.sql linguist-language=Java
|
*.sql linguist-language=Java
|
||||||
*.ftl linguist-language=Java
|
|
||||||
21
.github/ISSUE_TEMPLATE.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
##### 版本号:
|
||||||
|
|
||||||
|
|
||||||
|
##### 前端版本:vue3版?还是 vue2版?
|
||||||
|
|
||||||
|
|
||||||
|
##### 问题描述:
|
||||||
|
|
||||||
|
|
||||||
|
##### 截图&代码:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 友情提示(为了提高issue处理效率):
|
||||||
|
- 未按格式要求发帖,会被直接删掉;
|
||||||
|
- 描述过于简单或模糊,导致无法处理的,会被直接删掉;
|
||||||
|
- 请自己初判问题描述是否清楚,是否方便我们调查处理;
|
||||||
|
- 针对问题请说明是Online在线功能(需说明用的主题模板),还是生成的代码功能;
|
||||||
|
|
||||||
|
|
||||||
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: 提交 Bug
|
|
||||||
about: 请告诉我框架存在的问题,我会协助你解决此问题!
|
|
||||||
labels: bug
|
|
||||||
assignees: getActivity
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
##### 版本号:
|
|
||||||
|
|
||||||
|
|
||||||
##### 分支:
|
|
||||||
|
|
||||||
|
|
||||||
##### 问题描述:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 错误截图:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 友情提示:
|
|
||||||
- 未按格式要求发帖、描述过于简单的,会被直接删掉;
|
|
||||||
- 描述问题请图文并茂,方便我们理解并快速定位问题;
|
|
||||||
- 如果使用的不是master,请说明你使用的分支;
|
|
||||||
27
.github/ISSUE_TEMPLATE/feature_request.md
vendored
27
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,27 +0,0 @@
|
|||||||
---
|
|
||||||
name: 提交建议
|
|
||||||
about: 请告诉我框架的不足之处,让我做得更好!
|
|
||||||
labels: help wanted
|
|
||||||
assignees: getActivity
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
##### 版本号:
|
|
||||||
|
|
||||||
|
|
||||||
##### 分支:
|
|
||||||
|
|
||||||
|
|
||||||
##### 问题描述:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 错误截图:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 友情提示:
|
|
||||||
- 未按格式要求发帖、描述过于简单的,会被直接删掉;
|
|
||||||
- 描述问题请图文并茂,方便我们理解并快速定位问题;
|
|
||||||
- 如果使用的不是master,请说明你使用的分支;
|
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -10,8 +10,5 @@ rebel.xml
|
|||||||
## front
|
## front
|
||||||
**/*.lock
|
**/*.lock
|
||||||
os_del.cmd
|
os_del.cmd
|
||||||
os_del_doc.cmd
|
|
||||||
.svn
|
*.log
|
||||||
derby.log
|
|
||||||
.cursor
|
|
||||||
.history
|
|
||||||
23
LICENSE
23
LICENSE
@ -201,13 +201,16 @@
|
|||||||
limitations under the License.
|
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
|
开源协议补充
|
||||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||||
|
本软件受适用的国家软件著作权法(包括国际条约)和双重保护许可。
|
||||||
开源协议中文释意如下:
|
|
||||||
1.JeecgBoot开源版本无任何限制,在遵循本开源协议条款下,允许商用使用,不会造成侵权行为。
|
1.允许基于本平台软件开展业务系统开发。
|
||||||
2.允许基于本平台软件开展业务系统开发。
|
2.JeecgBoot底层依赖的非开源功能:online lib依赖、仪表盘lib依赖等,统一采用LGPL开源协议(不二次改造、不拆分出jeecgboot之外使用,就不产生侵权)
|
||||||
3.在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件。
|
3.不得基于该平台软件的基础,修改包装成一个与JeecgBoot平台软件功能类似的产品进行发布、销售,或与JeecgBoot参与同类软件产品市场的竞争。
|
||||||
|
违反此条款属于侵权行为,须赔偿侵权经济损失,同时立即停止著作权侵权行为。
|
||||||
最终解释权归:http://www.jeecg.com
|
|
||||||
|
总结:在遵循Apache开源协议和开源协议补充条款下,允许商用使用,不会造成侵权行为!
|
||||||
|
解释权归:http://www.jeecg.com
|
||||||
|
|
||||||
177
README-AI.md
177
README-AI.md
@ -1,177 +0,0 @@
|
|||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
##### 功能大模块
|
|
||||||
|
|
||||||
- AI应用开发平台
|
|
||||||
- AI知识库系统
|
|
||||||
- AI大模型管理
|
|
||||||
- AI流程编排
|
|
||||||
- AI对话支持图片
|
|
||||||
- AI对话助手(智能问答)
|
|
||||||
- AI建表(Online表单)
|
|
||||||
- AI写文章(CMS)
|
|
||||||
- AI表单字段建议(表单设计器)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 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对话支持发图和展示图片 | 支持 | 支持 |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 技术文档
|
|
||||||
|
|
||||||
- [AIGC开发文档](https://help.jeecg.com/aigc)
|
|
||||||
- [安装向量库 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群:964611995、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智能回复,你可以搭建自己的智能体,比如搭建一个 “诗词达人” “翻译助手”
|
|
||||||
|
|
||||||

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

|
|
||||||
336
README-EN.md
336
README-EN.md
@ -4,15 +4,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
JEECG BOOT AI Low Code Platform
|
JEECG BOOT Low Code Development Platform
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Current version: 3.9.0 (Release date: 2025-12-01)
|
当前最新版本: 3.6.1(发布日期:2023-12-11)
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||||
[](http://www.jeecg.com)
|
[](http://www.jeecg.com)
|
||||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
[](https://jeecg.blog.csdn.net)
|
||||||
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[](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 +22,9 @@ Current version: 3.9.0 (Release date: 2025-12-01)
|
|||||||
Project introduction
|
Project introduction
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
<h3 align="center">Java AI Low Code Platform</h3>
|
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||||
|
|
||||||
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 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 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!
|
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,13 +33,23 @@ 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.
|
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
|
Technical support
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
Problems or bugs in use can be found in [Making on the Issues](https://github.com/jeecgboot/JeecgBoot/issues/new?template=bug_report.md)
|
Problems or bugs in use can be found in [Making on the Issues](https://github.com/jeecgboot/jeecg-boot/issues/new)
|
||||||
|
|
||||||
|
Official Support: http://jeecg.com/doc/help
|
||||||
|
|
||||||
|
|
||||||
|
Download the source code
|
||||||
|
-----------------------------------
|
||||||
|
项目源码
|
||||||
|
-----------------------------------
|
||||||
|
| Source |Front-end source (Vue3 version) | The background source |
|
||||||
|
|-|-|-|
|
||||||
|
| Github | [jeecgboot-vue3](https://github.com/jeecgboot/jeecgboot-vue3) | [jeecg-boot](https://github.com/jeecgboot/jeecg-boot) |
|
||||||
|
| Gitee | [jeecgboot-vue3](https://gitee.com/jeecg/jeecgboot-vue3) | [jeecg-boot](https://gitee.com/jeecg/jeecg-boot) |
|
||||||
|
|
||||||
##### Project description
|
##### Project description
|
||||||
|
|
||||||
@ -47,49 +58,45 @@ Problems or bugs in use can be found in [Making on the Issues](https://github.co
|
|||||||
| `jeecg-boot` | SpringBoot background source code (support microservices) |
|
| `jeecg-boot` | SpringBoot background source code (support microservices) |
|
||||||
| `jeecgboot-vue3` | Vue3+TS new front-end source code|
|
| `jeecgboot-vue3` | Vue3+TS new front-end source code|
|
||||||
| `jeecg-uniapp` | [APP development framework, a code multi terminal adaptation, and support APP, small program, H5](https://github.com/jeecgboot/jeecg-uniapp) |
|
| `jeecg-uniapp` | [APP development framework, a code multi terminal adaptation, and support APP, small program, H5](https://github.com/jeecgboot/jeecg-uniapp) |
|
||||||
|
| `SpringBoot3+JDK17` | [BranchSourceCode](https://github.com/jeecgboot/jeecg-boot/tree/springboot3) [UpgradeBlog](https://blog.csdn.net/zhangdaiscott/article/details/134805602) |
|
||||||
|
| `More` | [Download more source code](http://jeecg.com/download) |
|
||||||
|
|
||||||
|
|
||||||
### Video Introduction
|
|
||||||
|
|
||||||
[](https://www.bilibili.com/video/BV1Nk4y1o7Qc)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Download other source code
|
|
||||||
-----------------------------------
|
|
||||||
- APP SourceCode:https://github.com/jeecgboot/jeecg-uniapp
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
For the project
|
For the project
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|
||||||
Starts the project
|
|
||||||
|
Docker starts the project
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
> Default account password: admin/123456
|
- [Docker starts the monomer background](https://help.jeecg.com/java/setup/docker/up.html)
|
||||||
|
- [Docker starts the Vue3 front-end](http://help.jeecg.com/publish/docker.html)
|
||||||
|
- [Docker starts the micro-service background](https://help.jeecg.com/java/springcloud/docker.html)
|
||||||
|
|
||||||
|
|
||||||
- [Development Environment setup](https://help.jeecg.com/java/setup/tools)
|
|
||||||
- [IDEA Quick start(single model)](https://help.jeecg.com/java/setup/idea/startup)
|
|
||||||
- [Docker Quick start(single model)](https://help.jeecg.com/java/docker/quick)
|
|
||||||
- [IDEA Quick start(microservices model)](https://help.jeecg.com/java/springcloud/switchcloud/monomer)
|
|
||||||
- [Docker Quick start(microservices model)](https://help.jeecg.com/java/docker/quickcloud)
|
|
||||||
|
|
||||||
|
|
||||||
Technical documentation
|
Technical documentation
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- Website: [http://www.jeecg.com](http://www.jeecg.com)
|
- Website: [http://www.jeecg.com](http://www.jeecg.com)
|
||||||
- Demo : [OnlineDemo](http://boot3.jeecg.com) | [APP](http://jeecg.com/appIndex)
|
- Doc: [http://help.jeecg.com](http://help.jeecg.com)
|
||||||
- Doc: [DocumentCenter](http://help.jeecg.com) | [AI Config](https://help.jeecg.com/java/ai/aichat)
|
- Newbie guide: [Quick start](http://www.jeecg.com/doc/quickstart) | [video](https://space.bilibili.com/454617261/channel/series) | [Q&A ](http://www.jeecg.com/doc/qa) | [help](http://jeecg.com/doc/help) | [1 minute experience](https://my.oschina.net/jeecg/blog/3083313)
|
||||||
- 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)
|
- Microservice Development: [Monomer upgrade to microservice](https://help.jeecg.com/java/springcloud/switchcloud/monomer.html)
|
||||||
- QQ group : 964611995、⑩716488839(满)、⑨808791225(满)
|
- QQ group : ⑧825232878、⑦791696430、⑥730954414(full)、683903138(full)、⑤860162132(full)、④774126647(full)、③816531124(full)、②769925425(full)、①284271917(full)
|
||||||
|
- Demo : [Vue3](http://boot3.jeecg.com) | [Vue2](http://boot.jeecg.com) | [APP](http://jeecg.com/appIndex)
|
||||||
|
> [please click obtain account password to obtain](http://jeecg.com/doc/demo)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Thinking
|
||||||
|
-----------------------------------
|
||||||
|
> We are pursuing the goal of implementing complex business systems without writing code! That has been done so far
|
||||||
|
- https://www.qiaoqiaoyun.com
|
||||||
|
|
||||||
|
|
||||||
Star charts
|
Star charts
|
||||||
@ -154,7 +161,7 @@ Why JeecgBoot?
|
|||||||
* Support SAAS service model and provide SaaS multi-tenant architecture solution.
|
* Support SAAS service model and provide SaaS multi-tenant architecture solution.
|
||||||
* Distributed file service, integration of minio, Ali OSS and other excellent third parties, to provide convenient file upload and management, but also support local storage.
|
* Distributed file service, integration of minio, Ali OSS and other excellent third parties, to provide convenient file upload and management, but also support local storage.
|
||||||
* Mainstream database compatibility, a set of code is fully compatible with Mysql, Postgresql, Oracle, Sqlserver, MariaDB, dream and other mainstream databases.
|
* Mainstream database compatibility, a set of code is fully compatible with Mysql, Postgresql, Oracle, Sqlserver, MariaDB, dream and other mainstream databases.
|
||||||
* Integrate workflow flowable and realize only the configuration of flow direction in the page, which can greatly simplify the development of bpm workflow; Using bpm's process designer to draw the flow direction, a workflow is basically complete with a small amount of java code;
|
* Integrate workflow activiti and realize only the configuration of flow direction in the page, which can greatly simplify the development of bpm workflow; Using bpm's process designer to draw the flow direction, a workflow is basically complete with a small amount of java code;
|
||||||
* Low code ability: online process design, using open source Activiti process engine, to achieve online drawing process, custom form, form attachment, business flow
|
* Low code ability: online process design, using open source Activiti process engine, to achieve online drawing process, custom form, form attachment, business flow
|
||||||
* Multi-data source: its simple way of use, online configuration of data source configuration, convenient to grab data from other data;
|
* Multi-data source: its simple way of use, online configuration of data source configuration, convenient to grab data from other data;
|
||||||
* Provide single sign-on CAS integration solution, and complete docking code has been provided in the project
|
* Provide single sign-on CAS integration solution, and complete docking code has been provided in the project
|
||||||
@ -185,7 +192,7 @@ Technical Architecture:
|
|||||||
|
|
||||||
#### Development Environment
|
#### Development Environment
|
||||||
|
|
||||||
- Language: Java Default Jdk17(support jdk8、jdk21)
|
- Language: Java 8+ (less than 17)
|
||||||
|
|
||||||
- IDE(JAVA) : IDEA (lombok plug-in must be installed)
|
- IDE(JAVA) : IDEA (lombok plug-in must be installed)
|
||||||
|
|
||||||
@ -195,24 +202,24 @@ Technical Architecture:
|
|||||||
|
|
||||||
- Cache: Redis
|
- Cache: Redis
|
||||||
|
|
||||||
- Database: MySQL5.7 + [More Databases](https://my.oschina.net/jeecg/blog/4905722)
|
- Database: MySQL5.7 + & Oracle 11 g & Sqlserver2017 [More Databases](https://my.oschina.net/jeecg/blog/4905722)
|
||||||
|
|
||||||
|
|
||||||
#### backend
|
#### backend
|
||||||
|
|
||||||
- Basic framework: Spring Boot 2.7.18
|
- Basic framework: Spring Boot 2.6.14
|
||||||
|
|
||||||
- Microservice framework: Spring Cloud Alibaba 2021.0.6.2
|
- Microservice framework: Spring Cloud Alibaba 2021.0.1.0
|
||||||
|
|
||||||
- Persistence layer framework: MybatisPlus 3.5.3.2
|
- Persistence layer framework: MybatisPlus 3.5.1
|
||||||
|
|
||||||
- Report tool: JimuReport 1.9.5
|
- Report tool: JimuReport 1.5.8
|
||||||
|
|
||||||
- Security framework: Apache Shiro 1.13.0, Jwt 4.5.0
|
- Security framework: Apache Shiro 1.10.0, Jwt 3.11.0
|
||||||
|
|
||||||
- Microservice technology stack: Spring Cloud Alibaba, Nacos, Gateway, Sentinel, Skywalking
|
- Microservice technology stack: Spring Cloud Alibaba, Nacos, Gateway, Sentinel, Skywalking
|
||||||
|
|
||||||
- Database connection pool: Alibaba Druid 1.1.24
|
- Database connection pool: Alibaba Druid 1.1.22
|
||||||
|
|
||||||
- Log printing: logback
|
- Log printing: logback
|
||||||
|
|
||||||
@ -221,15 +228,8 @@ Technical Architecture:
|
|||||||
|
|
||||||
#### The front end
|
#### The front end
|
||||||
|
|
||||||
- TechnologyStack:`Vue3.0+TypeScript+Vite+AntDesignVue+pinia+echarts`
|
- Vue2 version:`Vue2.6+@vue/cli+AntDesignVue+Viser-vue+Vuex` [detail](https://github.com/jeecgboot/ant-design-vue-jeecg)
|
||||||
|
- Vue3 version:`Vue3.0+TypeScript+Vite+AntDesignVue+pinia+echarts` [detail](https://github.com/jeecgboot/jeecgboot-vue3)
|
||||||
#### 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
|
#### Support library
|
||||||
|
|
||||||
@ -240,46 +240,44 @@ Technical Architecture:
|
|||||||
| Sqlserver2017 | √ |
|
| Sqlserver2017 | √ |
|
||||||
| PostgreSQL | √ |
|
| PostgreSQL | √ |
|
||||||
| MariaDB | √ |
|
| 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
|
## Microservice solutions
|
||||||
|
|
||||||
- 1. Service registration and discovery Nacos √
|
|
||||||
- 2. Nacos √
|
1. Service registration and discovery Nacos √
|
||||||
- 3. Route gateway gateway(Three loading modes) √
|
|
||||||
- 4. Distributed http feign √
|
2. Nacos √
|
||||||
- 5. fuse degrade current limiting Sentinel √
|
|
||||||
- 6. Distributed files Minio and Alioss √
|
3. Route gateway gateway(Three loading modes) √
|
||||||
- 7. Unified permission control
|
|
||||||
- 8. Service monitoring SpringBootAdmin√
|
4. Distributed http feign √
|
||||||
- 9. link tracking Skywalking [reference document](https://help.jeecg.com/java/springcloud/super/skywarking)
|
|
||||||
- 10. Messaging middleware RabbitMQ √
|
5. fuse degrade current limiting Sentinel √
|
||||||
- 11. Distributed task xxl-job √
|
|
||||||
- 12. Distributed Transaction Seata
|
6. Distributed files Minio and Alioss √
|
||||||
- 13. Distributed log Loki+grafana
|
|
||||||
- 14. Support docker-compose, k8s, jenkins
|
7. Unified permission control
|
||||||
- 15. CAS SSO √
|
|
||||||
- 16. Route traffic limiting √
|
8. Service monitoring SpringBootAdmin√
|
||||||
|
|
||||||
|
9. link tracking Skywalking [reference document](https://help.jeecg.com/java/springcloud/super/skywarking.html)
|
||||||
|
|
||||||
|
10. Messaging middleware RabbitMQ √
|
||||||
|
|
||||||
|
11. Distributed task xxl-job √
|
||||||
|
|
||||||
|
12. Distributed Transaction Seata
|
||||||
|
|
||||||
|
13. Distributed log elk + kafka
|
||||||
|
|
||||||
|
14. Support docker-compose, k8s, jenkins
|
||||||
|
|
||||||
|
15. CAS SSO √
|
||||||
|
|
||||||
|
16. Route traffic limiting √
|
||||||
|
|
||||||
|
|
||||||
#### Microservice architecture diagram
|
#### Microservice architecture diagram
|
||||||
@ -288,17 +286,161 @@ AI APP: https://help.jeecg.com/aigc
|
|||||||
### Jeecg Boot product functionality blueprint
|
### Jeecg Boot product functionality blueprint
|
||||||

|

|
||||||
|
|
||||||
### quick start
|
|
||||||
- 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)
|
|
||||||
|
### Function module
|
||||||
|
```
|
||||||
|
├─系统管理
|
||||||
|
│ ├─用户管理
|
||||||
|
│ ├─角色管理
|
||||||
|
│ ├─菜单管理
|
||||||
|
│ ├─权限设置(支持按钮权限、数据权限)
|
||||||
|
│ ├─表单权限(控制字段禁用、隐藏)
|
||||||
|
│ ├─部门管理
|
||||||
|
│ ├─我的部门(二级管理员)
|
||||||
|
│ └─字典管理
|
||||||
|
│ └─分类字典
|
||||||
|
│ └─系统公告
|
||||||
|
│ └─职务管理
|
||||||
|
│ └─通讯录
|
||||||
|
│ └─多租户管理
|
||||||
|
├─消息中心
|
||||||
|
│ ├─消息管理
|
||||||
|
│ ├─模板管理
|
||||||
|
├─代码生成器(低代码)
|
||||||
|
│ ├─代码生成器功能(一键生成前后端代码,生成后无需修改直接用,绝对是后端开发福音)
|
||||||
|
│ ├─代码生成器模板(提供4套模板,分别支持单表和一对多模型,不同风格选择)
|
||||||
|
│ ├─代码生成器模板(生成代码,自带excel导入导出)
|
||||||
|
│ ├─查询过滤器(查询逻辑无需编码,系统根据页面配置自动生成)
|
||||||
|
│ ├─高级查询器(弹窗自动组合查询条件)
|
||||||
|
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
||||||
|
│ ├─平台移动自适应支持
|
||||||
|
├─系统监控
|
||||||
|
│ ├─Gateway路由网关
|
||||||
|
│ ├─性能扫描监控
|
||||||
|
│ │ ├─监控 Redis
|
||||||
|
│ │ ├─Tomcat
|
||||||
|
│ │ ├─jvm
|
||||||
|
│ │ ├─服务器信息
|
||||||
|
│ │ ├─请求追踪
|
||||||
|
│ │ ├─磁盘监控
|
||||||
|
│ ├─定时任务
|
||||||
|
│ ├─系统日志
|
||||||
|
│ ├─消息中心(支持短信、邮件、微信推送等等)
|
||||||
|
│ ├─数据日志(记录数据快照,可对比快照,查看数据变更情况)
|
||||||
|
│ ├─系统通知
|
||||||
|
│ ├─SQL监控
|
||||||
|
│ ├─swagger-ui(在线接口文档)
|
||||||
|
│─报表示例
|
||||||
|
│ ├─曲线图
|
||||||
|
│ └─饼状图
|
||||||
|
│ └─柱状图
|
||||||
|
│ └─折线图
|
||||||
|
│ └─面积图
|
||||||
|
│ └─雷达图
|
||||||
|
│ └─仪表图
|
||||||
|
│ └─进度条
|
||||||
|
│ └─排名列表
|
||||||
|
│ └─等等
|
||||||
|
│─大屏模板
|
||||||
|
│ ├─作战指挥中心大屏
|
||||||
|
│ └─物流服务中心大屏
|
||||||
|
│─常用示例
|
||||||
|
│ ├─自定义组件
|
||||||
|
│ ├─对象存储(对接阿里云)
|
||||||
|
│ ├─JVXETable示例(各种复杂ERP布局示例)
|
||||||
|
│ ├─单表模型例子
|
||||||
|
│ └─一对多模型例子
|
||||||
|
│ └─打印例子
|
||||||
|
│ └─一对多TAB例子
|
||||||
|
│ └─内嵌table例子
|
||||||
|
│ └─常用选择组件
|
||||||
|
│ └─异步树table
|
||||||
|
│ └─接口模拟测试
|
||||||
|
│ └─表格合计示例
|
||||||
|
│ └─异步树列表示例
|
||||||
|
│ └─一对多JEditable
|
||||||
|
│ └─JEditable组件示例
|
||||||
|
│ └─图片拖拽排序
|
||||||
|
│ └─图片翻页
|
||||||
|
│ └─图片预览
|
||||||
|
│ └─PDF预览
|
||||||
|
│ └─分屏功能
|
||||||
|
│─封装通用组件
|
||||||
|
│ ├─行编辑表格JEditableTable
|
||||||
|
│ └─省略显示组件
|
||||||
|
│ └─时间控件
|
||||||
|
│ └─高级查询
|
||||||
|
│ └─用户选择组件
|
||||||
|
│ └─报表组件封装
|
||||||
|
│ └─字典组件
|
||||||
|
│ └─下拉多选组件
|
||||||
|
│ └─选人组件
|
||||||
|
│ └─选部门组件
|
||||||
|
│ └─通过部门选人组件
|
||||||
|
│ └─封装曲线、柱状图、饼状图、折线图等等报表的组件(经过封装,使用简单)
|
||||||
|
│ └─在线code编辑器
|
||||||
|
│ └─上传文件组件
|
||||||
|
│ └─验证码组件
|
||||||
|
│ └─树列表组件
|
||||||
|
│ └─表单禁用组件
|
||||||
|
│ └─等等
|
||||||
|
│─更多页面模板
|
||||||
|
│ ├─各种高级表单
|
||||||
|
│ ├─各种列表效果
|
||||||
|
│ └─结果页面
|
||||||
|
│ └─异常页面
|
||||||
|
│ └─个人页面
|
||||||
|
├─高级功能
|
||||||
|
│ ├─系统编码规则
|
||||||
|
│ ├─提供单点登录CAS集成方案
|
||||||
|
│ ├─提供APP发布方案
|
||||||
|
│ ├─集成Websocket消息通知机制
|
||||||
|
├─Online在线开发(低代码)
|
||||||
|
│ ├─Online在线表单 - 功能已开放
|
||||||
|
│ ├─Online代码生成器 - 功能已开放
|
||||||
|
│ ├─Online在线报表 - 功能已开放
|
||||||
|
│ ├─Online在线图表(未开源)
|
||||||
|
│ ├─Online图表模板配置(未开源)
|
||||||
|
│ ├─Online布局设计(未开源)
|
||||||
|
│ ├─多数据源管理 - 功能已开放
|
||||||
|
├─积木报表设计器(低代码)
|
||||||
|
│ ├─打印设计器
|
||||||
|
│ ├─数据报表设计
|
||||||
|
│ ├─图形报表设计(支持echart)
|
||||||
|
│ ├─大屏设计器(未开源)
|
||||||
|
│─流程模块功能 (未开源)
|
||||||
|
│ ├─流程设计器
|
||||||
|
│ ├─表单设计器
|
||||||
|
├─大屏设计器
|
||||||
|
├─门户设计/仪表盘设计器
|
||||||
|
│ └─我的任务
|
||||||
|
│ └─历史流程
|
||||||
|
│ └─历史流程
|
||||||
|
│ └─流程实例管理
|
||||||
|
│ └─流程监听管理
|
||||||
|
│ └─流程表达式
|
||||||
|
│ └─我发起的流程
|
||||||
|
│ └─我的抄送
|
||||||
|
│ └─流程委派、抄送、跳转
|
||||||
|
│ └─。。。
|
||||||
|
│─OA办公组件 (未开源)
|
||||||
|
│ ├─更多功能
|
||||||
|
│ └─。。。
|
||||||
|
└─其他模块
|
||||||
|
└─更多功能开发中。。
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Effect of system
|
### Effect of system
|
||||||
|
|
||||||
##### ChatGPT AI Dialog
|
|
||||||
> Go to the JeecgBoot background home page and click "AI Assistant" in the middle of the right side of the home page. The AI Assistant dialog screen is displayed.
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
##### PC
|
##### PC
|
||||||

|

|
||||||
@ -337,22 +479,10 @@ AI APP: https://help.jeecg.com/aigc
|
|||||||

|

|
||||||
|
|
||||||
##### dashboard Designer
|
##### dashboard Designer
|
||||||
|

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### report Designer
|
##### report Designer
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@ -1,126 +0,0 @@
|
|||||||
|
|
||||||
JeecgBoot低代码平台(商业版介绍)
|
|
||||||
===============
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
项目介绍
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
<h3 align="center">企业级AI低代码平台</h3>
|
|
||||||
|
|
||||||
|
|
||||||
JeecgBoot是一款集成AI应用的,基于BPM流程的低代码平台,旨在帮助企业快速实现低代码开发和构建个性化AI应用,支持MCP和插件,实现聊天式业务操作(如 “一句话创建用户”)!
|
|
||||||
|
|
||||||
前后端分离架构Ant Design&Vue3,SpringBoot,SpringCloud Alibaba,Mybatis-plus,Shiro。强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE, 帮助Java项目解决80%的重复工作,让开发更多关注业务,提高效率、节省成本,同时又不失灵活性!低代码能力:Online表单、表单设计、流程设计、Online报表、大屏/仪表盘设计、报表设计; AI应用平台功能:AI知识库问答、AI模型管理、AI流程编排、AI聊天等,支持含ChatGPT、DeepSeek、Ollama等多种AI大模型
|
|
||||||
|
|
||||||
JeecgBoot 提供了一系列 `低代码能力`,实现`真正的零代码`在线开发:Online表单开发、Online报表、复杂报表设计、打印设计、在线图表设计、仪表盘设计、大屏设计、移动图表能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)
|
|
||||||
|
|
||||||
`AI赋能低代码:` 目前提供了AI应用、AI模型管理、AI流程编排、AI对话助手,AI建表、AI写文章、AI知识库问答、AI字段建议等功能;支持各种AI大模型ChatGPT、DeepSeek、Ollama、智普、千问等.
|
|
||||||
|
|
||||||
`JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`;复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
|
|
||||||
|
|
||||||
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### JeecgBoot商业版与同类产品区别
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
- 灵活性:jeecgboot基于开源技术栈,设计初考虑到可插拔性和集成灵活性,确保平台的智能性与灵活性,避免因平台过于庞大而导致的扩展困难。
|
|
||||||
- 流程管理:支持一个表单挂接多个流程,同时一个流程可以连接多个表单,增强了流程的灵活性和复杂性管理。
|
|
||||||
- 符合中国国情的流程:针对中国市场的特定需求,jeecgboot能够实现各种符合中国国情的业务流程。
|
|
||||||
- 强大的表单设计器:jeecgboot的表单设计器与敲敲云共享,具备高质量和智能化的特点,能够满足零代码应用的需求,业内同类产品中不多见。
|
|
||||||
- 报表功能:自主研发的报表工具,拥有独立知识产权,功能上比业内老牌产品如帆软更智能,操作简便。
|
|
||||||
- BI产品整合:提供大屏、仪表盘、门户等功能,完美解决这些需求,并支持移动面板的设计与渲染。
|
|
||||||
- 自主研发的模块:jeecgboot的所有模块均为自主研发,具有独立的知识产权。
|
|
||||||
- 颗粒度和功能细致:在功能细致度和颗粒度上,jeecgboot远超同类产品,尤其在零代码能力方面表现突出。
|
|
||||||
- 零代码应用管理:最新版支持与敲敲云的零代码应用管理能力的集成,使得jeecgboot既具备低代码,又具备零代码的应用能力,业内独一无二。
|
|
||||||
- 强大的代码生成器:作为开源代码生成器的先锋,jeecgboot在代码生成的智能化和在线低代码与代码生成的结合方面,优势明显。
|
|
||||||
- 精细化权限管理:提供行级和列级的数据权限控制,满足企业在ERP和OA领域对权限管理的严格需求。
|
|
||||||
- 多平台支持的APP:目前采用uniapp3实现,支持小程序、H5、App及鸿蒙、鸿蒙Next、Electron桌面应用等多种终端。
|
|
||||||
|
|
||||||
> 综上所述,jeecgboot不仅在功能上具备丰富性和灵活性,还在技术架构、权限管理和用户体验等方面展现出明显的优势,是一个综合性能强大的低代码平台。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
商业版演示
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
JeecgBoot vs 敲敲云
|
|
||||||
> - JeecgBoot是低代码产品拥有系列低代码能力,比如流程设计、表单设计、大屏设计,代码生成器,适合半开发模式(开发+低代码结合),也可以集成零代码应用管理模块.
|
|
||||||
> - 敲敲云是零代码产品,完全不写代码,通过配置搭建业务系统,其在jeecgboot基础上研发而成,删除了online、代码生成、OA等需要编码功能,只保留应用管理功能和聊天、日程、文件三个OA组件.
|
|
||||||
|
|
||||||
|
|
||||||
- JeecgBoot低代码: https://boot3.jeecg.com
|
|
||||||
- 敲敲云零代码:https://app.qiaoqiaoyun.com
|
|
||||||
- APP演示(多端): http://jeecg.com/appIndex
|
|
||||||
|
|
||||||
|
|
||||||
### 流程视频介绍
|
|
||||||
|
|
||||||
[](https://www.bilibili.com/video/BV1Nk4y1o7Qc)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 商业版功能简述
|
|
||||||
|
|
||||||
> 详细的功能介绍,[请联系官方](https://jeecg.com/vip)
|
|
||||||
|
|
||||||
```
|
|
||||||
│─更多商业功能
|
|
||||||
│ ├─流程设计器
|
|
||||||
│ ├─简流设计器(类钉钉版)
|
|
||||||
│ ├─门户设计(NEW)
|
|
||||||
│ ├─表单设计器
|
|
||||||
│ ├─大屏设计器
|
|
||||||
│ └─我的任务
|
|
||||||
│ └─历史流程
|
|
||||||
│ └─历史流程
|
|
||||||
│ └─流程实例管理
|
|
||||||
│ └─流程监听管理
|
|
||||||
│ └─流程表达式
|
|
||||||
│ └─我发起的流程
|
|
||||||
│ └─我的抄送
|
|
||||||
│ └─流程委派、抄送、跳转
|
|
||||||
│ └─OA办公组件
|
|
||||||
│ └─零代码应用管理(无需编码,在线搭建应用系统)
|
|
||||||
│ ├─积木报表企业版(含jimureport、jimubi)
|
|
||||||
│ ├─AI流程设计器源码
|
|
||||||
│ ├─Online全模块功能和源码
|
|
||||||
│ ├─AI写文章(CMS)
|
|
||||||
│ ├─AI表单字段建议(表单设计器)
|
|
||||||
│ ├─OA办公协同组件
|
|
||||||
│ ├─在线聊天功能
|
|
||||||
│ ├─设计表单移动适配
|
|
||||||
│ ├─设计表单支持外部填报
|
|
||||||
│ ├─设计表单AI字段建议
|
|
||||||
│ ├─设计表单视图功能(支持多种类型含日历、表格、看板、甘特图)
|
|
||||||
│ └─。。。
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 流程设计
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 表单设计器
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
586
README.md
586
README.md
@ -1,195 +1,271 @@
|
|||||||
|
|
||||||
JeecgBoot AI低代码平台
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
JEECG BOOT 低代码开发平台
|
||||||
===============
|
===============
|
||||||
|
|
||||||
当前最新版本: 3.9.0(发布日期:2025-12-01)
|
当前最新版本: 3.6.1(发布日期:2023-12-11)
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/jeecgboot/JeecgBoot/blob/master/LICENSE)
|
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||||
[](https://jeecg.com)
|
[](http://jeecg.com/aboutusIndex)
|
||||||
[](https://jeecg.blog.csdn.net)
|
[](https://jeecg.blog.csdn.net)
|
||||||
[](https://github.com/jeecgboot/JeecgBoot)
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[](https://github.com/jeecgboot/JeecgBoot)
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[](https://github.com/jeecgboot/JeecgBoot)
|
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
项目介绍
|
项目介绍
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
<h3 align="center">企业级AI低代码平台</h3>
|
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||||
|
|
||||||
JeecgBoot 是一款基于BPM流程和代码生成的AI低代码平台,助力企业快速实现低代码开发和构建AI应用,支持MCP和插件,实现聊天式业务操作(如 “一句话创建用户”)!
|
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||||
|
|
||||||
采用前后端分离架构(Ant Design&Vue3,SpringBoot3,SpringCloud Alibaba,Mybatis-plus),强大代码生成器实现前后端一键生成,无需手写代码。
|
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||||
平台引领AI低代码开发模式:AI生成→在线编码→代码生成→手工合并,解决Java项目80%重复工作,提升效率,节省成本,兼顾灵活性。
|
|
||||||
具备强大且颗粒化的权限控制,支持按钮权限和数据权限设置,满足大型业务系统需求。功能涵盖在线表单、表单设计、流程设计、门户设计、报表与大屏设计、OA办公、AI应用、AI知识库、大模型管理、AI流程编排、AI聊天,支持ChatGPT、DeepSeek、Ollama等多种AI大模型。
|
|
||||||
|
|
||||||
`AI赋能报表:` 积木报表是一款自主研发的强大开源企业级Web报表与大屏工具。它通过零编码的拖拽式操作,赋能用户如同搭积木般轻松构建各类复杂报表和数据大屏,全面满足企业数据可视化与分析需求,助力企业级数据产品的高效打造与应用。
|
|
||||||
|
|
||||||
`AI赋能低代码:` 提供完善成熟的AI应用平台,涵盖AI应用管理、AI模型管理、智能对话助手、知识库问答、流程编排与设计器、AI建表等多项功能。平台兼容多种主流大模型,包括ChatGPT、DeepSeek、Ollama、智普、千问等,助力企业高效构建智能化应用,推动低代码开发与AI深度融合。
|
|
||||||
|
|
||||||
`JEECG宗旨是:` JEECG旨在通过OnlineCoding平台实现简单功能的零代码快速搭建,同时针对复杂功能采用代码生成器生成代码并手工合并,打造智能且灵活的低代码开发模式,有效解决了当前低代码产品普遍缺乏灵活性的问题,提升开发效率的同时兼顾系统的扩展性和定制化能力。
|
|
||||||
|
|
||||||
`JEECG业务流程:` JEECG业务流程采用BPM工作流引擎实现业务审批,扩展任务接口供开发人员编写业务逻辑,表单提供表单设计器、在线配置表单和编码表单等多种解决方案。通过流程与表单的分离设计(松耦合)及任务节点的灵活配置,既保障了企业流程的安全性与保密性,又大幅降低了开发人员的工作量。
|
|
||||||
|
|
||||||
|
|
||||||
|
`JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`;复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
|
||||||
|
|
||||||
|
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
|
||||||
|
|
||||||
|
遇到技术问题,[请在这里反馈BUG](https://github.com/jeecgboot/jeecg-boot/issues/new)
|
||||||
|
|
||||||
适用项目
|
适用项目
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
JeecgBoot低代码平台兼容所有J2EE项目开发,支持信创国产化,特别适用于SAAS、企业信息管理系统(MIS)、内部办公系统(OA)、企业资源计划系统(ERP)、客户关系管理系统(CRM)及AI知识库等场景。其半智能手工Merge开发模式,可显著提升70%以上的开发效率,极大降低开发成本。同时,JeecgBoot还是一款全栈式AI开发平台,助力企业快速构建和部署个性化AI应用。。
|
Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,尤其适合SAAS项目、企业信息管理系统(MIS)、内部办公系统(OA)、企业资源计划系统(ERP)、客户关系管理系统(CRM)等,其半智能手工Merge的开发方式,可以显著提高开发效率70%以上,极大降低开发成本。
|
||||||
|
|
||||||
|
|
||||||
**信创兼容说明**
|
|
||||||
- 操作系统:国产麒麟、银河麒麟等国产系统几乎都是基于 Linux 内核,因此它们具有良好的兼容性。
|
|
||||||
- 数据库:达梦、人大金仓、TiDB
|
|
||||||
- 中间件:东方通 TongWeb、TongRDS,宝兰德 AppServer、CacheDB, [信创配置文档](https://help.jeecg.com/java/tongweb-deploy/)
|
|
||||||
|
|
||||||
|
|
||||||
版本说明
|
项目源码
|
||||||
|
-----------------------------------
|
||||||
|
| 仓库 |前端源码 Vue3版 | 后端JAVA源码 |
|
||||||
|
|-|-|-|
|
||||||
|
| Github | [jeecgboot-vue3](https://github.com/jeecgboot/jeecgboot-vue3) | [jeecg-boot](https://github.com/jeecgboot/jeecg-boot) |
|
||||||
|
| 码云 | [jeecgboot-vue3](https://gitee.com/jeecg/jeecgboot-vue3) | [jeecg-boot](https://gitee.com/jeecg/jeecg-boot) |
|
||||||
|
|
||||||
|
|
||||||
|
#### 项目说明
|
||||||
|
|
||||||
|
| 项目名 | 说明 |
|
||||||
|
|--------------------|------------------------|
|
||||||
|
| `jeecgboot-vue3` | 前端源码 (Vue3版本) |
|
||||||
|
| `jeecg-boot` | 后端JAVA源码(支持微服务) |
|
||||||
|
| `jeecg-uniapp` | [APP开发框架,一份代码多终端适配,同时支持APP、小程序、H5](https://github.com/jeecgboot/jeecg-uniapp) |
|
||||||
|
| `SpringBoot3+JDK17 后端分支` | [分支源码](https://github.com/jeecgboot/jeecg-boot/tree/springboot3) [升级博客](https://blog.csdn.net/zhangdaiscott/article/details/134805602) |
|
||||||
|
| `更多开源项目` | [更多底层源码下载](http://jeecg.com/download) |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
快速搭建开发环境
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
|下载 | SpringBoot3.5 + Shiro |SpringBoot3.5+ SpringAuthorizationServer | SpringBoot3.5 + Sa-Token | SpringBoot2.7(JDK17/JDK8) |
|
- [通过IDEA导入项目](https://help.jeecg.com/java/setup/idea.html)
|
||||||
|------|---------------------------------------------------------|----------------------------|-------------------|--------------------------------------------|
|
- [通过IDEA启动前后端项目](https://help.jeecg.com/java/setup/idea/startup.html)
|
||||||
| Github | [`main`](https://github.com/jeecgboot/JeecgBoot) | [`springboot3_sas`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3_sas) 分支 | [`springboot3-satoken`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3-satoken) 分支|[`springboot2`](https://github.com/jeecgboot/JeecgBoot/tree/springboot2) 分支|
|
- [Vue3前端项目快速启动](http://help.jeecg.com/setup/startup.html)
|
||||||
| Gitee | [`main`](https://github.com/jeecgboot/JeecgBoot) | [`springboot3_sas`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3_sas) 分支| [`springboot3-satoken`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3-satoken) 分支|[`springboot2`](https://github.com/jeecgboot/JeecgBoot/tree/springboot2) 分支 |
|
- [单体快速切换为微服务版](https://help.jeecg.com/java/springcloud/switchcloud/monomer.html)
|
||||||
|
|
||||||
|
|
||||||
- `jeecg-boot` 是后端JAVA源码项目Springboot3+Shiro+Mybatis+SpringCloudAlibaba(支持单体和微服务切换).
|
Docker快速启动项目
|
||||||
- `jeecgboot-vue3` 是前端VUE3源码项目(vue3+vite6+ts最新技术栈).
|
|
||||||
- `JeecgUniapp` 是[配套APP框架](https://github.com/jeecgboot/JeecgUniapp) 适配多个终端,支持APP、小程序、H5、鸿蒙、鸿蒙Next.
|
|
||||||
- `jeecg-boot-starter` 是[jeecg-boot对应的底层封装starter](https://github.com/jeecgboot/jeecg-boot-starter) :微服务启动、xxljob、分布式锁starter、rabbitmq、分布式事务、分库分表shardingsphere等.
|
|
||||||
- 参考 [文档](https://help.jeecg.com/ui/2dev/mini) 可以删除不需要的demo,制作一个精简版本
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
启动项目
|
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
> 默认账号密码: admin/123456
|
- [Docker启动单体后台](https://help.jeecg.com/java/setup/docker/up.html)
|
||||||
|
- [Docker启动Vue3前端](http://help.jeecg.com/publish/docker.html)
|
||||||
- [开发环境搭建](https://help.jeecg.com/java/setup/tools)
|
- [Docker启动微服务后台](https://help.jeecg.com/java/springcloud/docker.html)
|
||||||
- [IDEA启动前后端(单体模式)](https://help.jeecg.com/java/setup/idea/startup)
|
|
||||||
- [Docker一键启动(单体模式)](https://help.jeecg.com/java/docker/quick)
|
|
||||||
- [IDEA启动前后端(微服务方式)](https://help.jeecg.com/java/springcloud/switchcloud/monomer)
|
|
||||||
- [Docker一键启动(微服务方式)](https://help.jeecg.com/java/docker/quickcloud)
|
|
||||||
|
|
||||||
|
|
||||||
技术文档
|
技术文档
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
|
- 项目官网: [http://www.jeecg.com](http://www.jeecg.com)
|
||||||
- 在线演示: [平台演示](https://boot3.jeecg.com) | [APP演示](https://jeecg.com/appIndex)
|
- 开发文档: [http://help.jeecg.com](http://help.jeecg.com)
|
||||||
- 入门指南: [快速入门](http://www.jeecg.com/doc/quickstart) | [代码生成使用](https://help.jeecg.com/java/codegen/online) | [开发文档](https://help.jeecg.com) | [AI应用手册](https://help.jeecg.com/aigc) | [视频教程](http://jeecg.com/doc/video)
|
- 新手指南: [快速入门](http://www.jeecg.com/doc/quickstart) | [常见问题 ](http://www.jeecg.com/doc/qa) | [视频教程](https://space.bilibili.com/454617261/channel/series) | [1分钟低代码体验](https://my.oschina.net/jeecg/blog/3083313)
|
||||||
- AI编程实战视频: [JEECG低代码与Cursor+GitHub Copilot实现AI高效编程实战](https://www.bilibili.com/video/BV11XyaBVEoH)
|
|
||||||
- 技术支持: [反馈问题](https://github.com/jeecgboot/JeecgBoot/issues/new?template=bug_report.md) | [低代码体验一分钟](https://jeecg.blog.csdn.net/article/details/106079007)
|
- 在线演示 : [Vue3演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex) | [敲敲云零代码](https://qiaoqiaoyun.com)
|
||||||
- QQ交流群 : 964611995、⑩716488839(满)、⑨808791225(满)、其他(满)
|
> 演示系统的登录账号密码,请点击 [获取账号密码](http://jeecg.com/doc/demo) 获取
|
||||||
|
>
|
||||||
|
- QQ交流群 : ⑧825232878、⑦791696430(满)、⑥730954414(满)、683903138(满)、⑤860162132(满)、④774126647(满)、③816531124(满)、②769925425(满)、①284271917(满)
|
||||||
|
> ` 提醒:【QQ群是自助服务群,建议给帮助您解决问题的同学发送指定红包,表示感谢!】 `
|
||||||
|
|
||||||
|
|
||||||
AI 应用平台介绍
|
大龄码农的思考
|
||||||
|
-----------------------------------
|
||||||
|
> 作为码农年纪大了写不动代码了怎么办??哎!!
|
||||||
|
所以我们团队在追求不写代码也可实现复杂业务系统!目前已经做到了,不信你到敲敲云零代码试试(通过流程串联修改业务数据)
|
||||||
|
|
||||||
|
- https://www.qiaoqiaoyun.com
|
||||||
|
|
||||||
|
|
||||||
|
技术支持
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
一个全栈式 AI 开发平台,旨在帮助开发者快速构建和部署个性化的 AI 应用。
|
关闭gitee的issue通道,使用中遇到问题或者BUG可以在 [Github上提Issues](https://github.com/jeecgboot/jeecg-boot/issues/new)
|
||||||
|
|
||||||
JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类似`Dify`的`AIGC应用开发平台`+`知识库问答`,是一款基于LLM大语言模型AI应用平台和 RAG 的知识库问答系统。
|
官方支持: [http://jeecg.com/doc/help](http://jeecg.com/doc/help)
|
||||||
其直观的界面结合了 AI 流程编排、RAG 管道、知识库管理、模型管理、对接向量库、实时运行可观察等,让您可以快速从原型到生产,拥有AI服务能力。
|
|
||||||
|
|
||||||
- [详细专题介绍,请点击查看](README-AI.md)
|
|
||||||
|
|
||||||
- AI视频介绍
|
|
||||||
|
|
||||||
[](https://www.bilibili.com/video/BV1zmd7YFE4w)
|
|
||||||
|
VUE2版本专题介绍
|
||||||
|
-----------------------------------
|
||||||
|
#### 项目介绍
|
||||||
|
- 项目名称:ant-design-vue-jeecg
|
||||||
|
- 说明:JeecgBoot前端提供两套解决方案,一套VUE2和一套VUE3版本,目前vue2版本最新代码只支持到jeecgboot 3.4.3版本,一定注意。
|
||||||
|
|
||||||
|
#### 源码下载
|
||||||
|
| 源码 | 源码地址 |
|
||||||
|
|--------------------|------------------------|
|
||||||
|
| 后端JAVA源码 `Vue2版` |https://gitee.com/jeecg/jeecg-boot/tree/v3.4.3last |
|
||||||
|
| 前端vue2源码 `Vue2版` |https://gitee.com/jeecg/ant-design-vue-jeecg |
|
||||||
|
|
||||||
|
#### Vue2与Vue3版本区别
|
||||||
|
> - VUE3版本彻底抛弃IE兼容,不兼容IE和低版本浏览器,只适配高版本谷歌和Edge
|
||||||
|
(政府、事业类单位项目需要谨慎选择——国产化迁移是一个漫长的过程,万一过程中要求IE兼容,这个不可逆)
|
||||||
|
> - 所以如果对浏览器有要求的项目,请选择VUE2版本。
|
||||||
|
> - VUE3版是全新的技术栈,紧跟主流(前端重写),各个功能都做了优化,拥有更好的体验效果
|
||||||
|
|
||||||
|
#### 技术文档
|
||||||
|
- 在线演示:[Vue2版演示](http://boot.jeecg.com)
|
||||||
|
- 开发文档:| [开发文档](http://doc.jeecg.com) | [Vue2前端快速启动](http://doc.jeecg.com/2678320) | [Vue2前端采用Docker启动](http://doc.jeecg.com/3043612)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Star走势图
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
[](https://star-history.com/#jeecgboot/jeecg-boot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
后台目录结构
|
||||||
|
-----------------------------------
|
||||||
|
```
|
||||||
|
项目结构
|
||||||
|
├─jeecg-boot-parent(父POM: 项目依赖、modules组织)
|
||||||
|
│ ├─jeecg-boot-base-core(共通模块: 工具类、config、权限、查询过滤器、注解等)
|
||||||
|
│ ├─jeecg-module-demo 示例代码
|
||||||
|
│ ├─jeecg-module-system System系统管理目录
|
||||||
|
│ │ ├─jeecg-system-biz System系统管理权限等功能
|
||||||
|
│ │ ├─jeecg-system-start System单体启动项目(8080)
|
||||||
|
│ │ ├─jeecg-system-api System系统管理模块对外api
|
||||||
|
│ │ │ ├─jeecg-system-cloud-api System模块对外提供的微服务接口
|
||||||
|
│ │ │ ├─jeecg-system-local-api System模块对外提供的单体接口
|
||||||
|
│ ├─jeecg-server-cloud --微服务模块
|
||||||
|
├─jeecg-cloud-gateway --微服务网关模块(9999)
|
||||||
|
├─jeecg-cloud-nacos --Nacos服务模块(8848)
|
||||||
|
├─jeecg-system-cloud-start --System微服务启动项目(7001)
|
||||||
|
├─jeecg-demo-cloud-start --Demo微服务启动项目(7002)
|
||||||
|
├─jeecg-visual
|
||||||
|
├─jeecg-cloud-monitor --微服务监控模块 (9111)
|
||||||
|
├─jeecg-cloud-xxljob --微服务xxljob定时任务服务端 (9080)
|
||||||
|
├─jeecg-cloud-sentinel --sentinel服务端 (9000)
|
||||||
|
├─jeecg-cloud-test -- 微服务测试示例(各种例子)
|
||||||
|
├─jeecg-cloud-test-more -- 微服务测试示例(feign、熔断降级、xxljob、分布式锁)
|
||||||
|
├─jeecg-cloud-test-rabbitmq -- 微服务测试示例(rabbitmq)
|
||||||
|
├─jeecg-cloud-test-seata -- 微服务测试示例(seata分布式事务)
|
||||||
|
├─jeecg-cloud-test-shardingsphere -- 微服务测试示例(分库分表)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
为什么选择JeecgBoot?
|
为什么选择JeecgBoot?
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
- 1.采用最新主流前后分离框架(Spring Boot3 + MyBatis + Shiro/SpringAuthorizationServer + Ant Design4 + Vue3),容易上手;代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发。
|
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||||
- 2.前端大版本换代,最新版采用 Vue3.0 + TypeScript + Vite6 + Ant Design Vue4 等新技术方案。
|
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供切换机制支持单体和微服务自由切换
|
||||||
- 3.支持微服务Spring Cloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供简易机制,支持单体和微服务自由切换(这样可以满足各类项目需求)。
|
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
||||||
- 4.开发效率高,支持在线建表和AI建表,提供强大代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用。
|
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
||||||
- 5.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)。
|
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
||||||
- 6.提供强大的报表和大屏可视化工具,支持丰富的数据源连接,能够通过拖拉拽方式快速制作报表、大屏和门户设计;支持多种图表类型:柱形图、折线图、散点图、饼图、环形图、面积图、漏斗图、进度图、仪表盘、雷达图、地图等。
|
* 6.低代码能力:Online在线表单(无需编码,通过在线配置表单,实现表单的增删改查,支持单表、树、一对多、一对一等模型,实现人人皆可编码)
|
||||||
- 7.低代码能力:在线表单(无需编码,通过在线配置表单,实现表单的增删改查,支持单表、树、一对多、一对一等模型,实现人人皆可编码),在线配置零代码开发、所见即所得支持23种类控件。
|
* 7.低代码能力:Online在线报表(无需编码,通过在线配置方式,实现数据报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)
|
||||||
- 8.低代码能力:在线报表、在线图表(无需编码,通过在线配置方式,实现数据报表和图形报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)。
|
* 8.低代码能力:Online在线图表(无需编码,通过在线配置方式,实现曲线图,柱状图,数据报表等,支持自定义排版布局,实现人人皆可编码)
|
||||||
- 9.Online支持在线增强开发,提供在线代码编辑器,支持代码高亮、代码提示等功能,支持多种语言(Java、SQL、JavaScript等)。
|
* 9.封装完善的用户、角色、菜单、组织机构、数据字典、在线定时任务等基础功能,支持访问授权、按钮权限、数据权限等功能
|
||||||
- 10.封装完善的用户、角色、菜单、组织机构、数据字典、在线定时任务等基础功能,支持访问授权、按钮权限、数据权限等功能。
|
* 10.常用共通封装,各种工具类(定时任务,短信接口,邮件发送,Excel导入导出等),基本满足80%项目需求
|
||||||
- 11.前端UI提供丰富的组件库,支持各种常用组件,如表格、树形控件、下拉框、日期选择器等,满足各种复杂的业务需求 [UI组件库文档](https://help.jeecg.com/category/ui%E7%BB%84%E4%BB%B6%E5%BA%93)。
|
* 11.简易Excel导入导出,支持单表导出和一对多表模式导出,生成的代码自带导入导出功能
|
||||||
- 12.提供APP配套框架,一份多代码多终端适配,一份代码多终端适配,小程序、H5、安卓、iOS、鸿蒙Next。
|
* 12.集成简易报表工具,图像报表和数据导出非常方便,可极其方便的生成图形报表、pdf、excel、word等报表;
|
||||||
- 13.新版APP框架采用Uniapp、Vue3.0、Vite、Wot-design-uni、TypeScript等最新技术栈,包括二次封装组件、路由拦截、请求拦截等功能。实现了与JeecgBoot完美对接:目前已经实现登录、用户信息、通讯录、公告、移动首页、九宫格、聊天、Online表单、仪表盘等功能,提供了丰富的组件。
|
* 13.采用前后分离技术,页面UI风格精美,针对常用组件做了封装:时间、行表格控件、截取显示控件、报表组件,编辑器等等
|
||||||
- 14.提供了一套成熟的AI应用平台功能,从AI模型、知识库到AI应用搭建,助力企业快速落地AI服务,加速智能化升级。
|
* 14.查询过滤器:查询功能自动生成,后台动态拼SQL追加查询条件;支持多种匹配方式(全匹配/模糊查询/包含查询/不匹配查询);
|
||||||
- 15.AI能力:目前JeecgBoot支持AI大模型chatgpt和deepseek,现在最新版默认使用deepseek,速度更快质量更高。目前提供了AI对话助手、AI知识库、AI应用、AI建表、AI报表等功能。
|
* 15.数据权限(精细化数据权限控制,控制到行级,列表级,表单字段级,实现不同人看不同数据,不同人对同一个页面操作不同字段
|
||||||
- 16.提供新行编辑表格JVXETable,轻松满足各种复杂ERP布局,拥有更高的性能、更灵活的扩展、更强大的功能。
|
* 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
|
||||||
- 17.平台首页风格,提供多种组合模式,支持自定义风格;支持门户设计,支持自定义首页。
|
* 17.支持SAAS服务模式,提供SaaS多租户架构方案。
|
||||||
- 18.常用共通封装,各种工具类(定时任务、短信接口、邮件发送、Excel导入导出等),基本满足80%项目需求。
|
* 18.分布式文件服务,集成minio、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
||||||
- 19.简易Excel导入导出,支持单表导出和一对多表模式导出,生成的代码自带导入导出功能。
|
* 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle、Sqlserver、MariaDB、达梦等主流数据库。
|
||||||
- 20.集成智能报表工具,报表打印、图像报表和数据导出非常方便,可极其方便地生成PDF、Excel、Word等报表。
|
* 20.集成工作流activiti、flowable,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的java代码;
|
||||||
- 21.采用前后分离技术,页面UI风格精美,针对常用组件做了封装:时间、行表格控件、截取显示控件、报表组件、编辑器等。
|
* 21.低代码能力:在线流程设计,采用开源Activiti流程引擎,实现在线画流程,自定义表单,表单挂靠,业务流转
|
||||||
- 22.查询过滤器:查询功能自动生成,后台动态拼SQL追加查询条件;支持多种匹配方式(全匹配/模糊查询/包含查询/不匹配查询)。
|
* 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
|
||||||
- 23.数据权限(精细化数据权限控制,控制到行级、列表级、表单字段级,实现不同人看不同数据,不同人对同一个页面操作不同字段)。
|
* 23.提供单点登录CAS集成方案,项目中已经提供完善的对接代码
|
||||||
- 24.接口安全机制,可细化控制接口授权,非常简便实现不同客户端只看自己数据等控制;也提供了基于AK和SK认证鉴权的OpenAPI功能。
|
* 24.低代码能力:表单设计器,支持用户自定义表单布局,支持单表,一对多表单、支持select、radio、checkbox、textarea、date、popup、列表、宏等控件
|
||||||
- 25.活跃的社区支持;近年来,随着网络威胁的日益增加,团队在安全和漏洞管理方面积累了丰富的经验,能够为企业提供全面的安全解决方案。
|
* 25.专业接口对接机制,统一采用restful接口方式,集成swagger-ui在线接口文档,Jwt token安全验证,方便客户端对接
|
||||||
- 26.权限控制采用RBAC(Role-Based Access Control,基于角色的访问控制)。
|
* 26.接口安全机制,可细化控制接口授权,非常简便实现不同客户端只看自己数据等控制
|
||||||
- 27.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等)。
|
* 27.高级组合查询功能,在线配置支持主子表关联查询,可保存查询历史
|
||||||
- 28.支持SaaS服务模式,提供SaaS多租户架构方案。
|
* 28.提供各种系统监控,实时跟踪系统运行情况(监控 Redis、Tomcat、jvm、服务器信息、请求追踪、SQL监控)
|
||||||
- 29.分布式文件服务,集成MinIO、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
* 29.消息中心(支持短信、邮件、微信推送等等)
|
||||||
- 30.主流数据库兼容,一套代码完全兼容MySQL、PostgreSQL、Oracle、SQL Server、MariaDB、达梦、人大金仓等主流数据库。
|
* 30.集成Websocket消息通知机制
|
||||||
- 31.集成工作流Flowable,并实现了只需在页面配置流程转向,可极大简化BPM工作流的开发;用BPM的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的Java代码。
|
* 31.移动自适应效果优秀,提供APP发布方案:
|
||||||
- 32.低代码能力:在线流程设计,采用开源Flowable流程引擎,实现在线画流程、自定义表单、表单挂靠、业务流转。
|
* 32.支持多语言,提供国际化方案;
|
||||||
- 33.多数据源:极其简易的使用方式,在线配置数据源配置,便捷地从其他数据抓取数据。
|
* 33.数据变更记录日志,可记录数据每次变更内容,通过版本对比功能查看历史变化
|
||||||
- 34.提供单点登录CAS集成方案,项目中已经提供完善的对接代码。
|
* 34.平台UI强大,实现了移动自适应
|
||||||
- 35.低代码能力:表单设计器,支持用户自定义表单布局,支持单表、一对多表单,支持select、radio、checkbox、textarea、date、popup、列表、宏等控件。
|
* 35.平台首页风格,提供多种组合模式,支持自定义风格
|
||||||
- 36.专业接口对接机制,统一采用RESTful接口方式,集成Swagger-UI在线接口文档,JWT token安全验证,方便客户端对接。
|
* 36.提供简单易用的打印插件,支持谷歌、火狐、IE11+ 等各种浏览器
|
||||||
- 37.高级组合查询功能,在线配置支持主子表关联查询,可保存查询历史。
|
* 37.示例代码丰富,提供很多学习案例参考
|
||||||
- 38.提供各种系统监控,实时跟踪系统运行情况(监控Redis、Tomcat、JVM、服务器信息、请求追踪、SQL监控)。
|
* 38.采用maven分模块开发方式
|
||||||
- 39.消息中心(支持短信、邮件、微信推送等);集成WebSocket消息通知机制。
|
* 39.支持菜单动态路由
|
||||||
- 40.支持多语言,提供国际化方案。
|
* 40.权限控制采用 RBAC(Role-Based Access Control,基于角色的访问控制)
|
||||||
- 41.数据变更记录日志,可记录数据每次变更内容,通过版本对比功能查看历史变化。
|
* 41.提供新行编辑表格JVXETable,轻松满足各种复杂ERP布局,拥有更高的性能、更灵活的扩展、更强大的功能
|
||||||
- 42.提供简单易用的打印插件,支持谷歌、火狐、IE11+等各种浏览器。
|
|
||||||
- 43.后端采用Maven分模块开发方式;前端支持菜单动态路由。
|
|
||||||
- 44.提供丰富的示例代码,涵盖了常用的业务场景,便于学习和参考。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
技术架构:
|
技术架构:
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
#### 开发环境
|
||||||
|
|
||||||
#### 前端
|
- 语言:Java 8+ (小于17)
|
||||||
|
|
||||||
- 前端环境要求:Node.js要求`Node 20+` 版本以上、pnpm 要求`9+` 版本以上
|
- IDE(JAVA): IDEA (必须安装lombok插件 )
|
||||||
|
|
||||||
` ( Vite 不再支持已结束生命周期(EOL)的 Node.js 18。现在需要使用 Node.js 20.19+ 或 22.12+)`
|
- IDE(前端): Vscode、WebStorm、IDEA
|
||||||
|
|
||||||
- 依赖管理:node、npm、pnpm
|
- 依赖管理:Maven
|
||||||
- 前端IDE建议:IDEA、WebStorm、Vscode
|
|
||||||
- 采用 Vue3.0+TypeScript+Vite6+Ant-Design-Vue4等新技术方案,包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
|
- 缓存:Redis
|
||||||
- 最新技术栈:Vue3.0 + TypeScript + Vite6 + ant-design-vue4 + pinia + echarts + unocss + vxe-table + qiankun + es6
|
|
||||||
|
- 数据库脚本:MySQL5.7+ & Oracle 11g & Sqlserver2017(其他数据库,[需要自己转](https://my.oschina.net/jeecg/blog/4905722))
|
||||||
|
|
||||||
|
|
||||||
#### 后端
|
#### 后端
|
||||||
|
|
||||||
- IDE建议: IDEA (必须安装lombok插件 )
|
- 基础框架:Spring Boot 2.6.14
|
||||||
- 语言:Java 默认jdk17(jdk21、jdk24)
|
|
||||||
- 依赖管理:Maven
|
- 微服务框架: Spring Cloud Alibaba 2021.0.1.0
|
||||||
- 基础框架:Spring Boot 3.5.5
|
|
||||||
- 微服务框架: Spring Cloud Alibaba 2023.0.3.3
|
- 持久层框架:MybatisPlus 3.5.1
|
||||||
- 持久层框架:MybatisPlus 3.5.12
|
|
||||||
- 报表工具: JimuReport 2.1.3
|
- 报表工具: JimuReport 1.5.8
|
||||||
- 安全框架:Apache Shiro 2.0.4,Jwt 4.5.0
|
|
||||||
|
- 安全框架:Apache Shiro 1.10.0,Jwt 3.11.0
|
||||||
|
|
||||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||||
- 数据库连接池:阿里巴巴Druid 1.2.24
|
|
||||||
- AI大模型:支持 `ChatGPT` `DeepSeek` `千问`等各种常规模式
|
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||||
|
|
||||||
- 日志打印:logback
|
- 日志打印:logback
|
||||||
- 缓存:Redis
|
|
||||||
- 其他:autopoi, fastjson,poi,Swagger-ui,quartz, lombok(简化代码)等。
|
- 其他:autopoi, fastjson,poi,Swagger-ui,quartz, lombok(简化代码)等。
|
||||||
- 默认提供MySQL5.7+数据库脚本
|
|
||||||
|
|
||||||
#### 数据库支持
|
|
||||||
|
|
||||||
> jeecgboot平台支持以下数据库,默认我们只提供mysql脚本,其他数据库可以参考[转库文档](https://my.oschina.net/jeecg/blog/4905722)自己转。
|
#### 前端
|
||||||
|
|
||||||
|
- Vue2版本:`Vue2.6+@vue/cli+AntDesignVue+Viser-vue+Vuex等` [详细查看](https://github.com/jeecgboot/ant-design-vue-jeecg)
|
||||||
|
- Vue3版本:`Vue3.0+TypeScript+Vite+AntDesignVue+pinia+echarts等新方案` [详细查看](https://github.com/jeecgboot/jeecgboot-vue3)
|
||||||
|
|
||||||
|
#### 支持库
|
||||||
|
|
||||||
| 数据库 | 支持 |
|
| 数据库 | 支持 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@ -198,70 +274,61 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||
| Sqlserver2017 | √ |
|
| Sqlserver2017 | √ |
|
||||||
| PostgreSQL | √ |
|
| PostgreSQL | √ |
|
||||||
| MariaDB | √ |
|
| MariaDB | √ |
|
||||||
| 达梦 | √ |
|
| 达梦、人大金仓 | √ |
|
||||||
| 人大金仓 | √ |
|
|
||||||
| TiDB | √ |
|
|
||||||
| kingbase8 | √ |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 微服务解决方案
|
## 微服务解决方案
|
||||||
|
|
||||||
- 1、服务注册和发现 Nacos √
|
|
||||||
- 2、统一配置中心 Nacos √
|
|
||||||
- 3、路由网关 gateway(三种加载方式) √
|
|
||||||
- 4、分布式 http feign √
|
|
||||||
- 5、熔断降级限流 Sentinel √
|
|
||||||
- 6、分布式文件 Minio、阿里OSS √
|
|
||||||
- 7、统一权限控制 JWT + Shiro √
|
|
||||||
- 8、服务监控 SpringBootAdmin√
|
|
||||||
- 9、链路跟踪 Skywalking [参考文档](https://help.jeecg.com/java/springcloud/super/skywarking)
|
|
||||||
- 10、消息中间件 RabbitMQ √
|
|
||||||
- 11、分布式任务 xxl-job √
|
|
||||||
- 12、分布式事务 Seata
|
|
||||||
- 13、轻量分布式日志 Loki+grafana套件
|
|
||||||
- 14、支持 docker-compose、k8s、jenkins
|
|
||||||
- 15、CAS 单点登录 √
|
|
||||||
- 16、路由限流 √
|
|
||||||
|
|
||||||
|
1、服务注册和发现 Nacos √
|
||||||
|
|
||||||
|
2、统一配置中心 Nacos √
|
||||||
|
|
||||||
|
3、路由网关 gateway(三种加载方式) √
|
||||||
|
|
||||||
|
4、分布式 http feign √
|
||||||
|
|
||||||
|
5、熔断降级限流 Sentinel √
|
||||||
|
|
||||||
|
6、分布式文件 Minio、阿里OSS √
|
||||||
|
|
||||||
|
7、统一权限控制 JWT + Shiro √
|
||||||
|
|
||||||
|
8、服务监控 SpringBootAdmin√
|
||||||
|
|
||||||
|
9、链路跟踪 Skywalking [参考文档](https://help.jeecg.com/java/springcloud/super/skywarking.html)
|
||||||
|
|
||||||
|
10、消息中间件 RabbitMQ √
|
||||||
|
|
||||||
|
11、分布式任务 xxl-job √
|
||||||
|
|
||||||
|
12、分布式事务 Seata
|
||||||
|
|
||||||
|
13、分布式日志 elk + kafka
|
||||||
|
|
||||||
|
14、支持 docker-compose、k8s、jenkins
|
||||||
|
|
||||||
|
15、CAS 单点登录 √
|
||||||
|
|
||||||
|
16、路由限流 √
|
||||||
|
|
||||||
|
|
||||||
#### 微服务架构图
|
#### 微服务架构图
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
开源版与企业版区别?
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
- JeecgBoot开源版采用 [Apache-2.0 license](LICENSE) 协议附加补充条款:允许商用使用,不会造成侵权行为,允许基于本平台软件开展业务系统开发(但在任何情况下,您不得使用本软件开发可能被认为与本软件竞争的软件).
|
|
||||||
- 商业版与开源版主要区别在于商业版提供了技术支持 和 更多的企业级功能(例如:Online图表、流程监控、流程设计、流程审批、表单设计器、表单视图、积木报表企业版、OA办公、商业APP、零代码应用、Online模块源码等功能). [更多商业功能介绍,点击查看](README-Enterprise.md)
|
|
||||||
- JeecgBoot未来发展方向是:零代码平台的建设,也就是团队的另外一款产品 [敲敲云零代码](https://www.qiaoqiaoyun.com) ,无需编码即可通过拖拽快速搭建企业级应用,与JeecgBoot低代码平台形成互补,满足从简单业务到复杂系统的全场景开发需求,目前已经开源,[欢迎下载](https://qiaoqiaoyun.com/downloadCode)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Jeecg Boot 产品功能蓝图
|
### Jeecg Boot 产品功能蓝图
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 系统功能架构图
|
|
||||||
|
|
||||||

|
### 功能模块
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 开源版功能清单
|
|
||||||
```
|
```
|
||||||
├─系统管理
|
├─系统管理
|
||||||
│ ├─用户管理
|
│ ├─用户管理
|
||||||
│ ├─角色管理
|
│ ├─角色管理
|
||||||
│ ├─菜单管理
|
│ ├─菜单管理
|
||||||
│ ├─首页配置
|
|
||||||
│ ├─权限设置(支持按钮权限、数据权限)
|
│ ├─权限设置(支持按钮权限、数据权限)
|
||||||
│ ├─表单权限(控制字段禁用、隐藏)
|
│ ├─表单权限(控制字段禁用、隐藏)
|
||||||
│ ├─部门管理
|
│ ├─部门管理
|
||||||
@ -271,37 +338,7 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||
│ └─系统公告
|
│ └─系统公告
|
||||||
│ └─职务管理
|
│ └─职务管理
|
||||||
│ └─通讯录
|
│ └─通讯录
|
||||||
│ ├─多数据源管理
|
│ └─多租户管理
|
||||||
│ ├─白名单管理
|
|
||||||
│ ├─第三方配置(对接钉钉和企业微信)
|
|
||||||
│ └─多租户管理(租户管理、租户角色、我的租户、租户默认套餐管理)
|
|
||||||
├─Online在线开发(低代码)
|
|
||||||
│ ├─Online在线表单
|
|
||||||
│ ├─Online代码生成器
|
|
||||||
│ ├─Online在线报表
|
|
||||||
│ ├─仪表盘设计器
|
|
||||||
│ ├─系统编码规则
|
|
||||||
│ ├─系统校验规则
|
|
||||||
│ ├─APP版本管理
|
|
||||||
├─AI应用平台
|
|
||||||
│ ├─AI知识库问答系统
|
|
||||||
│ ├─AI大模型管理
|
|
||||||
│ ├─AI流程编排
|
|
||||||
│ ├─AI流程设计器
|
|
||||||
│ ├─AI对话支持图片
|
|
||||||
│ ├─AI对话助手(智能问答)
|
|
||||||
│ ├─AI建表(Online表单)
|
|
||||||
│ ├─AI聊天窗口支持嵌入第三方
|
|
||||||
│ ├─AI聊天窗口支持移动端
|
|
||||||
│ ├─支持常见大模型ChatGPT和DeepSeek、ollama等等
|
|
||||||
│ ├─AI OCR示例
|
|
||||||
├─数据可视化
|
|
||||||
│ ├─报表设计器(支持打印设计)
|
|
||||||
│ ├─大屏设和仪表盘设计
|
|
||||||
├─OpenAPI(基于AK和SK认证鉴权)
|
|
||||||
│ ├─接口管理
|
|
||||||
│ ├─接口授权
|
|
||||||
│ ├─接口文档
|
|
||||||
├─消息中心
|
├─消息中心
|
||||||
│ ├─消息管理
|
│ ├─消息管理
|
||||||
│ ├─模板管理
|
│ ├─模板管理
|
||||||
@ -313,12 +350,8 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||
│ ├─高级查询器(弹窗自动组合查询条件)
|
│ ├─高级查询器(弹窗自动组合查询条件)
|
||||||
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
│ ├─Excel导入导出工具集成(支持单表,一对多 导入导出)
|
||||||
│ ├─平台移动自适应支持
|
│ ├─平台移动自适应支持
|
||||||
│ ├─提供新版uniapp3的代码生成器模板
|
|
||||||
├─系统监控
|
├─系统监控
|
||||||
│ ├─Gateway路由网关
|
│ ├─Gateway路由网关
|
||||||
│ ├─基于AK和SK认证鉴权OpenAPI功能
|
|
||||||
│ ├─定时任务
|
|
||||||
│ ├─数据源管理
|
|
||||||
│ ├─性能扫描监控
|
│ ├─性能扫描监控
|
||||||
│ │ ├─监控 Redis
|
│ │ ├─监控 Redis
|
||||||
│ │ ├─Tomcat
|
│ │ ├─Tomcat
|
||||||
@ -326,11 +359,13 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||
│ │ ├─服务器信息
|
│ │ ├─服务器信息
|
||||||
│ │ ├─请求追踪
|
│ │ ├─请求追踪
|
||||||
│ │ ├─磁盘监控
|
│ │ ├─磁盘监控
|
||||||
|
│ ├─定时任务
|
||||||
│ ├─系统日志
|
│ ├─系统日志
|
||||||
│ ├─消息中心(支持短信、邮件、微信推送等等)
|
│ ├─消息中心(支持短信、邮件、微信推送等等)
|
||||||
│ ├─数据日志(记录数据快照,可对比快照,查看数据变更情况)
|
│ ├─数据日志(记录数据快照,可对比快照,查看数据变更情况)
|
||||||
|
│ ├─系统通知
|
||||||
│ ├─SQL监控
|
│ ├─SQL监控
|
||||||
│ ├─在线用户
|
│ ├─swagger-ui(在线接口文档)
|
||||||
│─报表示例
|
│─报表示例
|
||||||
│ ├─曲线图
|
│ ├─曲线图
|
||||||
│ └─饼状图
|
│ └─饼状图
|
||||||
@ -392,19 +427,57 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||
│ └─异常页面
|
│ └─异常页面
|
||||||
│ └─个人页面
|
│ └─个人页面
|
||||||
├─高级功能
|
├─高级功能
|
||||||
|
│ ├─系统编码规则
|
||||||
│ ├─提供单点登录CAS集成方案
|
│ ├─提供单点登录CAS集成方案
|
||||||
│ ├─提供APP发布方案
|
│ ├─提供APP发布方案
|
||||||
│ ├─集成Websocket消息通知机制
|
│ ├─集成Websocket消息通知机制
|
||||||
│ ├─支持electron桌面应用打包(支持windows、linux、macOS三大平台)
|
├─Online在线开发(低代码)
|
||||||
│ ├─docker容器支持
|
│ ├─Online在线表单 - 功能已开放
|
||||||
│ ├─提供移动APP框架及源码(Uniapp3版本)支持H5、小程序、APP、鸿蒙Next
|
│ ├─Online代码生成器 - 功能已开放
|
||||||
│ ├─提供移动APP低代码设计(Online表单、仪表盘)
|
│ ├─Online在线报表 - 功能已开放
|
||||||
|
│ ├─Online在线图表(未开源)
|
||||||
|
│ ├─Online图表模板配置(未开源)
|
||||||
|
│ ├─Online布局设计(未开源)
|
||||||
|
│ ├─多数据源管理 - 功能已开放
|
||||||
|
├─积木报表设计器(低代码)
|
||||||
|
│ ├─打印设计器
|
||||||
|
│ ├─数据报表设计
|
||||||
|
│ ├─图形报表设计(支持echart)
|
||||||
|
│ ├─大屏设计器(未开源)
|
||||||
|
│─更多商业功能 (未开源)
|
||||||
|
│ ├─流程设计器
|
||||||
|
│ ├─表单设计器
|
||||||
|
├─大屏设计器
|
||||||
|
├─门户设计/仪表盘设计器
|
||||||
|
│ └─我的任务
|
||||||
|
│ └─历史流程
|
||||||
|
│ └─历史流程
|
||||||
|
│ └─流程实例管理
|
||||||
|
│ └─流程监听管理
|
||||||
|
│ └─流程表达式
|
||||||
|
│ └─我发起的流程
|
||||||
|
│ └─我的抄送
|
||||||
|
│ └─流程委派、抄送、跳转
|
||||||
|
│ └─。。。
|
||||||
|
│─OA办公组件 (未开源)
|
||||||
|
│ ├─更多功能
|
||||||
|
│ └─。。。
|
||||||
|
└─其他模块
|
||||||
|
└─更多功能开发中。。
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 流程引擎推荐
|
||||||
|
|
||||||
|
JeecgBoot企业版本默认集成了activiti和flowable两套方案,大家在使用本开源项目时,如果想进一步集成流程引擎,推荐结合贺波老师的书 [《深入Activiti流程引擎:核心原理与高阶实战》](https://item.m.jd.com/product/13928958.html?gx=RnAomTM2bmCImZxDqYAkVCoIHuIYVqc)
|
||||||
|
|
||||||
|
<img src="https://jeecgos.oss-cn-beijing.aliyuncs.com/files/tuijian20231220161656.png" width="25%" height="auto">
|
||||||
|
|
||||||
|
|
||||||
### 系统效果
|
### 系统效果
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### PC端
|
##### PC端
|
||||||

|

|
||||||
|
|
||||||
@ -424,38 +497,28 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块,是一套类
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
##### AI功能
|
##### 流程设计
|
||||||
|

|
||||||
|
|
||||||
AI聊天助手
|

|
||||||
|
|
||||||

|

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

|
||||||
|
|
||||||

|
##### 简版流程设计
|
||||||
|
|
||||||

|

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

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
##### 仪表盘设计器
|
##### 仪表盘设计器
|
||||||
|

|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
##### 报表设计器
|
##### 报表设计器
|
||||||

|

|
||||||
|
|
||||||
@ -465,6 +528,38 @@ AI写文章
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
##### 表单设计器
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
##### 大屏设计器
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
##### UNIAPP效果
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
##### 零代码应用
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
##### 手机端
|
##### 手机端
|
||||||

|

|
||||||
@ -487,31 +582,6 @@ AI写文章
|
|||||||
##### 在线接口文档
|
##### 在线接口文档
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
##### UNIAPP效果
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
##### 大屏设计器
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 捐赠
|
## 捐赠
|
||||||
|
|
||||||
如果觉得还不错,请作者喝杯咖啡吧 ☺
|
如果觉得还不错,请作者喝杯咖啡吧 ☺
|
||||||
|
|||||||
@ -1,216 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from typing import Tuple, Optional
|
|
||||||
|
|
||||||
def run_command(cmd: str) -> Tuple[int, str]:
|
|
||||||
"""执行命令并返回退出码和输出"""
|
|
||||||
try:
|
|
||||||
result = subprocess.run(cmd, shell=True, check=False,
|
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
||||||
text=True)
|
|
||||||
return result.returncode, result.stdout.strip()
|
|
||||||
except Exception as e:
|
|
||||||
return -1, str(e)
|
|
||||||
|
|
||||||
def check_java() -> bool:
|
|
||||||
"""检查JDK 17+是否安装"""
|
|
||||||
print("\n检查JDK 17+...")
|
|
||||||
rc, output = run_command("java -version 2>&1")
|
|
||||||
if rc != 0:
|
|
||||||
print("❌ 未检测到Java,请安装JDK 17+")
|
|
||||||
return False
|
|
||||||
|
|
||||||
version_pattern = r'"(\d+)(?:\.\d+)*(?:_\d+)?'
|
|
||||||
match = re.search(version_pattern, output)
|
|
||||||
if not match:
|
|
||||||
print("❌ 无法解析Java版本")
|
|
||||||
return False
|
|
||||||
|
|
||||||
version = int(match.group(1))
|
|
||||||
if version >= 17:
|
|
||||||
print(f"✅ JDK版本 {version} (满足17+要求)")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"❌ JDK版本 {version} (需要17+)")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_maven() -> bool:
|
|
||||||
"""检查Maven是否安装"""
|
|
||||||
print("\n检查Maven...")
|
|
||||||
rc, output = run_command("mvn -v")
|
|
||||||
if rc == 0:
|
|
||||||
print("✅ Maven已安装")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print("❌ Maven未安装")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_node() -> bool:
|
|
||||||
"""检查Node.js 20+是否安装"""
|
|
||||||
print("\n检查Node.js 20+...")
|
|
||||||
rc, output = run_command("node -v")
|
|
||||||
if rc != 0:
|
|
||||||
print("❌ Node.js未安装")
|
|
||||||
return False
|
|
||||||
|
|
||||||
version_pattern = r'v(\d+)\.\d+\.\d+'
|
|
||||||
match = re.search(version_pattern, output)
|
|
||||||
if not match:
|
|
||||||
print("❌ 无法解析Node.js版本")
|
|
||||||
return False
|
|
||||||
|
|
||||||
version = int(match.group(1))
|
|
||||||
if version >= 20:
|
|
||||||
print(f"✅ Node.js版本 {version} (满足20+要求)")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"❌ Node.js版本 {version} (需要20+)")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_pnpm() -> bool:
|
|
||||||
"""检查PNPM 9+是否安装"""
|
|
||||||
print("\n检查PNPM 9+...")
|
|
||||||
rc, output = run_command("pnpm -v")
|
|
||||||
if rc != 0:
|
|
||||||
print("❌ PNPM未安装")
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 处理可能的版本号格式:v9.0.0 或 9.0.0 或 9
|
|
||||||
version_str = output.strip().lstrip('v').split('.')[0]
|
|
||||||
version = int(version_str)
|
|
||||||
|
|
||||||
if version >= 9:
|
|
||||||
print(f"✅ PNPM版本 {output.strip()} (满足9+要求)")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"❌ PNPM版本 {output.strip()} (需要9+)")
|
|
||||||
return False
|
|
||||||
except (ValueError, IndexError):
|
|
||||||
print(f"❌ 无法解析PNPM版本: {output.strip()}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_redis_connection() -> bool:
|
|
||||||
"""检查Redis连接"""
|
|
||||||
print("\n检查Redis连接...")
|
|
||||||
print("⚠️ 请确保已配置Redis连接信息并在jeecg-boot项目中正确配置")
|
|
||||||
print("⚠️ 此检查需要根据实际项目配置进行验证")
|
|
||||||
print("⚠️ 配置文件位置: jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_mysql_connection() -> bool:
|
|
||||||
"""检查MySQL连接"""
|
|
||||||
print("\n检查MySQL连接...")
|
|
||||||
print("⚠️ 请确保已配置MySQL连接信息并在jeecg-boot项目中正确配置")
|
|
||||||
print("⚠️ 此检查需要根据实际项目配置进行验证")
|
|
||||||
print("⚠️ 配置文件位置: jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def print_mysql_config():
|
|
||||||
"""打印MySQL配置并提示需要修改的位置"""
|
|
||||||
print("\nMySQL配置参考 (请检查以下配置是否正确):")
|
|
||||||
print("""
|
|
||||||
spring.datasource.dynamic.datasource:
|
|
||||||
master:
|
|
||||||
url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
|
||||||
username: root # ← 可能需要修改
|
|
||||||
password: root # ← 可能需要修改
|
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
|
||||||
""")
|
|
||||||
|
|
||||||
def check_ai_vector_db() -> bool:
|
|
||||||
"""检查AI向量库(pgvector)配置"""
|
|
||||||
print("\n检查AI知识库向量库配置...")
|
|
||||||
print("⚠️ 如果需要使用AI知识库功能,请配置pgvector向量库")
|
|
||||||
print("⚠️ 配置文件位置: jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml")
|
|
||||||
print("\n配置参考:")
|
|
||||||
print("""
|
|
||||||
jeecg.ai-rag:
|
|
||||||
embed-store:
|
|
||||||
host: 127.0.0.1 # ← 可能需要修改
|
|
||||||
port: 5432 # ← 可能需要修改
|
|
||||||
database: postgres # ← 可能需要修改
|
|
||||||
user: postgres # ← 可能需要修改
|
|
||||||
password: postgres # ← 可能需要修改
|
|
||||||
table: embeddings # ← 可能需要修改
|
|
||||||
""")
|
|
||||||
print("⚠️ 注意: 请确保已安装PostgreSQL并添加pgvector扩展!docker安装参考:https://help.jeecg.com/aigc/config")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_ai_config() -> bool:
|
|
||||||
"""检查AI账号配置"""
|
|
||||||
print("\n检查AI功能配置...")
|
|
||||||
print("⚠️ 如果需要使用AI聊天功能,请配置AI账号信息")
|
|
||||||
print("⚠️ 配置文件位置: jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml")
|
|
||||||
print("\n配置参考:")
|
|
||||||
print("""
|
|
||||||
jeecg:
|
|
||||||
# AI集成
|
|
||||||
ai-chat:
|
|
||||||
enabled: true # ← 启用AI功能
|
|
||||||
model: deepseek-chat # ← 模型名称
|
|
||||||
apiKey: ?? # ← 必须修改为您的API Key
|
|
||||||
apiHost: https://api.deepseek.com/v1 # ← API地址
|
|
||||||
timeout: 60 # ← 超时时间(秒)
|
|
||||||
""")
|
|
||||||
print("⚠️ 注意: 请确保已获取有效的API Key并正确配置!AI账号注册获取参考: https://help.jeecg.com/java/deepSeekSupport")
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def print_redis_config():
|
|
||||||
"""打印Redis配置并提示需要修改的位置"""
|
|
||||||
print("\nRedis配置参考 (请检查以下配置是否正确):")
|
|
||||||
print("""
|
|
||||||
spring.redis:
|
|
||||||
database: 0
|
|
||||||
host: 127.0.0.1 # ← 可能需要修改
|
|
||||||
port: 6379 # ← 可能需要修改
|
|
||||||
password: '' # ← 如果需要密码请修改
|
|
||||||
""")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
print("="*50)
|
|
||||||
print("JeecgBoot 运行环境检查脚本")
|
|
||||||
print("="*50)
|
|
||||||
|
|
||||||
all_checks_passed = True
|
|
||||||
|
|
||||||
# 检查各项依赖
|
|
||||||
if not check_java():
|
|
||||||
all_checks_passed = False
|
|
||||||
|
|
||||||
if not check_maven():
|
|
||||||
all_checks_passed = False
|
|
||||||
|
|
||||||
if not check_node():
|
|
||||||
all_checks_passed = False
|
|
||||||
|
|
||||||
if not check_pnpm():
|
|
||||||
all_checks_passed = False
|
|
||||||
|
|
||||||
# 数据库提示
|
|
||||||
print("="*50)
|
|
||||||
check_redis_connection()
|
|
||||||
print_redis_config()
|
|
||||||
print("="*50)
|
|
||||||
check_mysql_connection()
|
|
||||||
print_mysql_config()
|
|
||||||
print("="*50)
|
|
||||||
check_ai_config()
|
|
||||||
print("="*50)
|
|
||||||
check_ai_vector_db()
|
|
||||||
|
|
||||||
print("\n" + "="*50)
|
|
||||||
if all_checks_passed:
|
|
||||||
print("✅ 所有基础环境检查通过")
|
|
||||||
print("⚠️ 注意: 请确保Redis和MySQL、AI账号、向量库pgvector 已正确配置并连接成功")
|
|
||||||
else:
|
|
||||||
print("❌ 部分环境检查未通过,请根据上述提示解决问题")
|
|
||||||
|
|
||||||
print("="*50)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
input("\n按回车键退出...") # 等待用户输入
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
FROM registry.cn-hangzhou.aliyuncs.com/jeecgdocker/mysql:8.0.19
|
FROM mysql:8.0.19
|
||||||
|
|
||||||
MAINTAINER jeecgos@163.com
|
MAINTAINER jeecgos@163.com
|
||||||
|
|
||||||
7782
db/jeecgboot-mysql-5.7.sql
Normal file
7782
db/jeecgboot-mysql-5.7.sql
Normal file
File diff suppressed because one or more lines are too long
325
db/tables_nacos.sql
Normal file
325
db/tables_nacos.sql
Normal file
File diff suppressed because one or more lines are too long
119
db/tables_xxl_job.sql
Normal file
119
db/tables_xxl_job.sql
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#
|
||||||
|
# XXL-JOB v2.2.0
|
||||||
|
# Copyright (c) 2015-present, xuxueli.
|
||||||
|
|
||||||
|
CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_general_ci;
|
||||||
|
use `xxl_job`;
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 '调度-时间',
|
||||||
|
`trigger_code` int(11) NOT NULL COMMENT '调度-结果',
|
||||||
|
`trigger_msg` text COMMENT '调度-日志',
|
||||||
|
`handle_time` datetime 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
CREATE TABLE `xxl_job_group` (
|
||||||
|
`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;
|
||||||
|
|
||||||
|
CREATE TABLE `xxl_job_user` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(50) NOT NULL COMMENT '账号',
|
||||||
|
`password` varchar(50) 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;
|
||||||
|
|
||||||
|
CREATE TABLE `xxl_job_lock` (
|
||||||
|
`lock_name` varchar(50) NOT NULL COMMENT '锁名称',
|
||||||
|
PRIMARY KEY (`lock_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
BIN
db/其他数据库/jeecgboot-oracle11g.dmp
Normal file
BIN
db/其他数据库/jeecgboot-oracle11g.dmp
Normal file
Binary file not shown.
16429
db/其他数据库/jeecgboot-oracle11g.sql
Normal file
16429
db/其他数据库/jeecgboot-oracle11g.sql
Normal file
File diff suppressed because one or more lines are too long
31596
db/其他数据库/jeecgboot-sqlserver2019.sql
Normal file
31596
db/其他数据库/jeecgboot-sqlserver2019.sql
Normal file
File diff suppressed because one or more lines are too long
11
db/增量SQL/3.6.0升级到3.6.1升级脚本.sql
Normal file
11
db/增量SQL/3.6.0升级到3.6.1升级脚本.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-- 新增风格一对多内嵌和Tab风格
|
||||||
|
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 ('1691031996d5931315212', '1455100420297859074', 'AUTO在线一对多内嵌', '/online/cgformInnerTableList/:id', 'super/online/cgform/auto/innerTable/OnlCgformInnerTableList', 1, '', NULL, 1, NULL, '0', 1.00, 0, NULL, 1, 0, 1, 0, NULL, 'admin', '2023-08-14 18:20:20', 'admin', '2023-08-14 18:46:18', 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 ('1691031996d5931315213', '1455100420297859074', 'AUTO在线Tab风格', '/online/cgformTabList/:id', 'super/online/cgform/auto/tab/OnlCgformTabList', 1, '', NULL, 1, NULL, '0', 1.00, 0, NULL, 1, 0, 1, 0, NULL, 'admin', '2023-08-14 18:20:20', 'admin', '2023-08-14 18:46:18', 0, 0, NULL, 0);
|
||||||
|
|
||||||
|
-- 【安全】online敏感接口,加权限注解(sql解析接口、同步数据库接口、导入表接口)
|
||||||
|
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 ('1699374704168534017', '1460888189937176577', 'SQL解析', NULL, NULL, 0, NULL, NULL, 2, 'online:report:parseSql', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-09-06 18:51:17', 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 ('1699374509749960705', '1455101470794850305', '查询数据库表名', NULL, NULL, 0, NULL, NULL, 2, 'online:form:queryTables', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-09-06 18:50:31', 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 ('1699374269152100354', '1455101470794850305', '同步数据库', NULL, NULL, 0, NULL, NULL, 2, 'online:form:syncDb', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2023-09-06 18:49:33', NULL, NULL, 0, 0, '1', 0);
|
||||||
|
update sys_permission set is_leaf=0 where id in ('1460888189937176577','1455101470794850305');
|
||||||
45
db/增量SQL/sas升级脚本.sql
Normal file
45
db/增量SQL/sas升级脚本.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
CREATE TABLE `oauth2_registered_client` (
|
||||||
|
`id` varchar(100) NOT NULL,
|
||||||
|
`client_id` varchar(100) NOT NULL,
|
||||||
|
`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`client_secret` varchar(200) DEFAULT NULL,
|
||||||
|
`client_secret_expires_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`client_name` varchar(200) NOT NULL,
|
||||||
|
`client_authentication_methods` varchar(1000) NOT NULL,
|
||||||
|
`authorization_grant_types` varchar(1000) NOT NULL,
|
||||||
|
`redirect_uris` varchar(1000) DEFAULT NULL,
|
||||||
|
`post_logout_redirect_uris` varchar(1000) DEFAULT NULL,
|
||||||
|
`scopes` varchar(1000) NOT NULL,
|
||||||
|
`client_settings` varchar(2000) NOT NULL,
|
||||||
|
`token_settings` varchar(2000) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
INSERT INTO `oauth2_registered_client`
|
||||||
|
(`id`,
|
||||||
|
`client_id`,
|
||||||
|
`client_id_issued_at`,
|
||||||
|
`client_secret`,
|
||||||
|
`client_secret_expires_at`,
|
||||||
|
`client_name`,
|
||||||
|
`client_authentication_methods`,
|
||||||
|
`authorization_grant_types`,
|
||||||
|
`redirect_uris`,
|
||||||
|
`post_logout_redirect_uris`,
|
||||||
|
`scopes`,
|
||||||
|
`client_settings`,
|
||||||
|
`token_settings`)
|
||||||
|
VALUES
|
||||||
|
('3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
|
||||||
|
'jeecg-client',
|
||||||
|
now(),
|
||||||
|
'secret',
|
||||||
|
null,
|
||||||
|
'3eacac0e-0de9-4727-9a64-6bdd4be2ee1f',
|
||||||
|
'client_secret_basic',
|
||||||
|
'refresh_token,authorization_code,password,app,phone,social',
|
||||||
|
'http://127.0.0.1:8080/jeecg-',
|
||||||
|
'http://127.0.0.1:8080/',
|
||||||
|
'*',
|
||||||
|
'{"@class":"java.util.Collections$UnmodifiableMap","settings.client.require-proof-key":false,"settings.client.require-authorization-consent":true}',
|
||||||
|
'{"@class":"java.util.Collections$UnmodifiableMap","settings.token.reuse-refresh-tokens":true,"settings.token.id-token-signature-algorithm":["org.springframework.security.oauth2.jose.jws.SignatureAlgorithm","RS256"],"settings.token.access-token-time-to-live":["java.time.Duration",300000.000000000],"settings.token.access-token-format":{"@class":"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat","value":"self-contained"},"settings.token.refresh-token-time-to-live":["java.time.Duration",3600.000000000],"settings.token.authorization-code-time-to-live":["java.time.Duration",300000.000000000],"settings.token.device-code-time-to-live":["java.time.Duration",300000.000000000]}');
|
||||||
11
db/增量SQL/版本升级说明.txt
Normal file
11
db/增量SQL/版本升级说明.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
版本升级方法?
|
||||||
|
|
||||||
|
JeecgBoot属于平台级产品,每次升级改动内容较多,目前做不到平滑升级。
|
||||||
|
|
||||||
|
升级方案建议:
|
||||||
|
1.代码升级 => 本地版本通过svn或者git做好主干,在分支上做业务开发,jeecg每次版本发布,可以手工覆盖主干的代码,对比合并代码;
|
||||||
|
2.数据库升级 => 针对数据库我们每次发布会提供增量升级SQL,可以通过执行增量SQL实现数据库的升级。
|
||||||
|
3.兼容问题 => 每次版本发布会针对不兼容地方标注说明,需要手工修改不兼容的代码。
|
||||||
|
|
||||||
|
注意: 升级sql目前只提供mysql版本,执行完脚步后,新菜单需要手工进行角色授权,刷新首页才会出现。
|
||||||
|
【20230820 放开了系统管理等模块权限注解,如果没权限请通过角色授权授权对应的按钮权限】
|
||||||
@ -1,154 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
jeecg-boot-mysql:
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/db
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: root
|
|
||||||
MYSQL_ROOT_HOST: '%'
|
|
||||||
TZ: Asia/Shanghai
|
|
||||||
restart: always
|
|
||||||
container_name: jeecg-boot-mysql
|
|
||||||
image: jeecg-boot-mysql
|
|
||||||
command:
|
|
||||||
--character-set-server=utf8mb4
|
|
||||||
--collation-server=utf8mb4_general_ci
|
|
||||||
--explicit_defaults_for_timestamp=true
|
|
||||||
--lower_case_table_names=1
|
|
||||||
--max_allowed_packet=128M
|
|
||||||
--default-authentication-plugin=caching_sha2_password
|
|
||||||
ports:
|
|
||||||
- 13306:3306
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-redis:
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/jeecgdocker/redis:5.0
|
|
||||||
# ports:
|
|
||||||
# - 6379:6379
|
|
||||||
restart: always
|
|
||||||
hostname: jeecg-boot-redis
|
|
||||||
container_name: jeecg-boot-redis
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-pgvector:
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/jeecgdocker/pgvector
|
|
||||||
container_name: jeecg-boot-pgvector
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: vector_db
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-nacos:
|
|
||||||
restart: always
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/jeecg-server-cloud/jeecg-cloud-nacos
|
|
||||||
ports:
|
|
||||||
- 8848:8848
|
|
||||||
container_name: jeecg-boot-nacos
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-mysql
|
|
||||||
hostname: jeecg-boot-nacos
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-system:
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-nacos
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/jeecg-server-cloud/jeecg-system-cloud-start
|
|
||||||
container_name: jeecg-system-start
|
|
||||||
hostname: jeecg-boot-system
|
|
||||||
restart: on-failure
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-demo:
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-nacos
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/jeecg-server-cloud/jeecg-demo-cloud-start
|
|
||||||
container_name: jeecg-demo-start
|
|
||||||
hostname: jeecg-boot-demo
|
|
||||||
restart: on-failure
|
|
||||||
environment:
|
|
||||||
- TZ=Asia/Shanghai
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-gateway:
|
|
||||||
restart: on-failure
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/jeecg-server-cloud/jeecg-cloud-gateway
|
|
||||||
ports:
|
|
||||||
- 9999:9999
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-nacos
|
|
||||||
- jeecg-boot-system
|
|
||||||
container_name: jeecg-boot-gateway
|
|
||||||
hostname: jeecg-boot-gateway
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
# jeecg-boot-rabbitmq:
|
|
||||||
# image: rabbitmq:3.7.7-management
|
|
||||||
# ports:
|
|
||||||
# - 5672:5672
|
|
||||||
# - 15672:15672
|
|
||||||
# restart: always
|
|
||||||
# container_name: jeecg-boot-rabbitmq
|
|
||||||
# hostname: jeecg-boot-rabbitmq
|
|
||||||
# environment:
|
|
||||||
# RABBITMQ_DEFAULT_USER: guest
|
|
||||||
# RABBITMQ_DEFAULT_PASS: guest
|
|
||||||
|
|
||||||
jeecg-boot-sentinel:
|
|
||||||
restart: on-failure
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-sentinel
|
|
||||||
ports:
|
|
||||||
- 9000:9000
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-nacos
|
|
||||||
- jeecg-boot-demo
|
|
||||||
- jeecg-boot-system
|
|
||||||
- jeecg-boot-gateway
|
|
||||||
container_name: jeecg-boot-sentinel
|
|
||||||
hostname: jeecg-boot-sentinel
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-xxljob:
|
|
||||||
build:
|
|
||||||
context: ./jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob
|
|
||||||
ports:
|
|
||||||
- 9080:9080
|
|
||||||
container_name: jeecg-boot-xxljob
|
|
||||||
hostname: jeecg-boot-xxljob
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-vue:
|
|
||||||
build:
|
|
||||||
context: ./jeecgboot-vue3
|
|
||||||
dockerfile: Dockerfile.cloud
|
|
||||||
container_name: jeecgboot-vue3-nginx
|
|
||||||
image: jeecgboot-vue3
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-system
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
|
|
||||||
networks:
|
|
||||||
jeecg-boot:
|
|
||||||
name: jeecg_boot
|
|
||||||
@ -2,7 +2,7 @@ version: '2'
|
|||||||
services:
|
services:
|
||||||
jeecg-boot-mysql:
|
jeecg-boot-mysql:
|
||||||
build:
|
build:
|
||||||
context: ./jeecg-boot/db
|
context: ./db
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: root
|
MYSQL_ROOT_PASSWORD: root
|
||||||
MYSQL_ROOT_HOST: '%'
|
MYSQL_ROOT_HOST: '%'
|
||||||
@ -18,36 +18,23 @@ services:
|
|||||||
--max_allowed_packet=128M
|
--max_allowed_packet=128M
|
||||||
--default-authentication-plugin=caching_sha2_password
|
--default-authentication-plugin=caching_sha2_password
|
||||||
ports:
|
ports:
|
||||||
- 13306:3306
|
- 3306:3306
|
||||||
networks:
|
networks:
|
||||||
- jeecg-boot
|
- jeecg-boot
|
||||||
|
|
||||||
jeecg-boot-redis:
|
jeecg-boot-redis:
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/jeecgdocker/redis:5.0
|
image: redis:5.0
|
||||||
# ports:
|
ports:
|
||||||
# - 3792:6379
|
- 6379:6379
|
||||||
restart: always
|
restart: always
|
||||||
hostname: jeecg-boot-redis
|
hostname: jeecg-boot-redis
|
||||||
container_name: jeecg-boot-redis
|
container_name: jeecg-boot-redis
|
||||||
networks:
|
networks:
|
||||||
- jeecg-boot
|
- jeecg-boot
|
||||||
|
|
||||||
jeecg-boot-pgvector:
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/jeecgdocker/pgvector
|
|
||||||
container_name: jeecg-boot-pgvector
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: vector_db
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
|
|
||||||
jeecg-boot-system:
|
jeecg-boot-system:
|
||||||
build:
|
build:
|
||||||
context: ./jeecg-boot/jeecg-module-system/jeecg-system-start
|
context: ./jeecg-module-system/jeecg-system-start
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
depends_on:
|
depends_on:
|
||||||
- jeecg-boot-mysql
|
- jeecg-boot-mysql
|
||||||
@ -59,17 +46,6 @@ services:
|
|||||||
- 8080:8080
|
- 8080:8080
|
||||||
networks:
|
networks:
|
||||||
- jeecg-boot
|
- jeecg-boot
|
||||||
jeecg-vue:
|
|
||||||
build:
|
|
||||||
context: ./jeecgboot-vue3
|
|
||||||
container_name: jeecgboot-vue3-nginx
|
|
||||||
image: jeecgboot-vue3
|
|
||||||
depends_on:
|
|
||||||
- jeecg-boot-system
|
|
||||||
networks:
|
|
||||||
- jeecg-boot
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
jeecg-boot:
|
jeecg-boot:
|
||||||
|
|||||||
@ -2,13 +2,17 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-boot-parent</artifactId>
|
<artifactId>jeecg-boot-parent</artifactId>
|
||||||
<version>3.9.0</version>
|
<version>3.6.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>jeecg-boot-base-core</artifactId>
|
<artifactId>jeecg-boot-base-core</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<spring-boot.version>3.1.5</spring-boot.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>aliyun</id>
|
<id>aliyun</id>
|
||||||
@ -42,19 +46,23 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<!--jeecg-tools-->
|
<!--jeecg-tools-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-boot-common</artifactId>
|
<artifactId>jeecg-boot-common3</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--集成springmvc框架并实现自动配置 -->
|
<!--集成springmvc框架并实现自动配置 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<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>
|
</dependency>
|
||||||
<!-- websocket -->
|
<!-- websocket -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -88,7 +96,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>${commons-io.version}</version>
|
<version>${commons.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-lang</groupId>
|
<groupId>commons-lang</groupId>
|
||||||
@ -104,19 +112,9 @@
|
|||||||
<!-- mybatis-plus -->
|
<!-- mybatis-plus -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
<version>${mybatis-plus.version}</version>
|
<version>${mybatis-plus.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.baomidou</groupId>
|
|
||||||
<artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
|
|
||||||
<version>${mybatis-plus.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- minidao -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- druid -->
|
<!-- druid -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -143,7 +141,7 @@
|
|||||||
<!-- sqlserver-->
|
<!-- sqlserver-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.microsoft.sqlserver</groupId>
|
<groupId>com.microsoft.sqlserver</groupId>
|
||||||
<artifactId>mssql-jdbc</artifactId>
|
<artifactId>sqljdbc4</artifactId>
|
||||||
<version>${sqljdbc4.version}</version>
|
<version>${sqljdbc4.version}</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -161,24 +159,7 @@
|
|||||||
<version>${postgresql.version}</version>
|
<version>${postgresql.version}</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--人大金仓驱动 版本号V008R006C005B0013 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jeecgframework</groupId>
|
|
||||||
<artifactId>kingbase8</artifactId>
|
|
||||||
<version>${kingbase8.version}</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<!--达梦数据库驱动 版本号1-3-26-2023.07.26-197096-20046-ENT -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.dameng</groupId>
|
|
||||||
<artifactId>DmJdbcDriver18</artifactId>
|
|
||||||
<version>${dm8.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.dameng</groupId>
|
|
||||||
<artifactId>DmDialect-for-hibernate5.0</artifactId>
|
|
||||||
<version>${dm8.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- Quartz定时任务 -->
|
<!-- Quartz定时任务 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -192,87 +173,26 @@
|
|||||||
<version>${java-jwt.version}</version>
|
<version>${java-jwt.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--shiro-->
|
|
||||||
<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>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-beanutils</groupId>
|
|
||||||
<artifactId>commons-beanutils</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</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>
|
|
||||||
<groupId>org.crazycake</groupId>
|
|
||||||
<artifactId>shiro-redis</artifactId>
|
|
||||||
<version>${shiro-redis.version}</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.shiro</groupId>
|
|
||||||
<artifactId>shiro-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>checkstyle</artifactId>
|
|
||||||
<groupId>com.puppycrawl.tools</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.xiaoymin</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>knife4j-openapi3-ui</artifactId>
|
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
|
||||||
<version>${knife4j-spring-boot-starter.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springdoc</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||||
<version>2.7.0</version>
|
</dependency>
|
||||||
|
<!-- 添加spring security cas支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-cas</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- knife4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||||
|
<version>${knife4j-spring-boot-starter.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 代码生成器 -->
|
<!-- 代码生成器 -->
|
||||||
@ -281,22 +201,23 @@
|
|||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>codegenerate</artifactId>
|
<artifactId>codegenerate</artifactId>
|
||||||
<version>${codegenerate.version}</version>
|
<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>
|
</dependency>
|
||||||
|
|
||||||
<!-- AutoPoi Excel工具类-->
|
<!-- AutoPoi Excel工具类-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework</groupId>
|
<groupId>org.jeecgframework.boot3</groupId>
|
||||||
<artifactId>autopoi-spring-boot-3-starter</artifactId>
|
<artifactId>autopoi-web</artifactId>
|
||||||
|
<version>${autopoi-web.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>xercesImpl</artifactId>
|
||||||
|
<groupId>xerces</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>xerces</groupId>
|
<groupId>xerces</groupId>
|
||||||
@ -309,20 +230,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.minio</groupId>
|
<groupId>io.minio</groupId>
|
||||||
<artifactId>minio</artifactId>
|
<artifactId>minio</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>checker-qual</artifactId>
|
|
||||||
<groupId>org.checkerframework</groupId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.google.errorprone</groupId>
|
|
||||||
<artifactId>error_prone_annotations</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 阿里云短信 -->
|
<!-- 阿里云短信 -->
|
||||||
@ -374,26 +281,6 @@
|
|||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-crypto</artifactId>
|
<artifactId>hutool-crypto</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- chatgpt -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jeecgframework.boot3</groupId>
|
|
||||||
<artifactId>jeecg-boot-starter-chatgpt</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- 腾讯云 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.tencentcloudapi</groupId>
|
|
||||||
<artifactId>tencentcloud-sdk-java-sms</artifactId>
|
|
||||||
<version>${tencentcloud-sdk-java-sms.version}</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>javax.xml.bind</groupId>
|
|
||||||
<artifactId>jaxb-api</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.squareup.okio</groupId>
|
|
||||||
<artifactId>okio</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package org.apache.shiro;
|
||||||
|
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容处理Online功能使用处理,请勿修改
|
||||||
|
* @author eightmonth@qq.com
|
||||||
|
* @date 2024/4/29 14:05
|
||||||
|
*/
|
||||||
|
public class SecurityUtils {
|
||||||
|
|
||||||
|
|
||||||
|
public static Subject getSubject() {
|
||||||
|
return new Subject() {
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return Subject.super.getPrincipal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package org.apache.shiro.subject;
|
||||||
|
|
||||||
|
import org.jeecg.config.security.utils.SecureUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容处理Online功能使用处理,请勿修改
|
||||||
|
* @author eightmonth@qq.com
|
||||||
|
* @date 2024/4/29 14:18
|
||||||
|
*/
|
||||||
|
public interface Subject {
|
||||||
|
default Object getPrincipal() {
|
||||||
|
return SecureUtil.currentUser();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package org.jeecg.common.api;
|
package org.jeecg.common.api;
|
||||||
|
|
||||||
import org.jeecg.common.api.dto.AiragFlowDTO;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import org.jeecg.common.system.vo.*;
|
import org.jeecg.common.system.vo.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,21 +19,14 @@ public interface CommonAPI {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Set<String> queryUserRoles(String username);
|
Set<String> queryUserRoles(String username);
|
||||||
|
|
||||||
/**
|
|
||||||
* 1查询用户角色信息
|
|
||||||
* @param userId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Set<String> queryUserRolesById(String userId);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 2查询用户权限信息
|
* 2查询用户权限信息
|
||||||
* @param userId
|
* @param username
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Set<String> queryUserAuths(String userId);
|
Set<String> queryUserAuths(String username);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 3根据 id 查询数据库中存储的 DynamicDataSourceModel
|
* 3根据 id 查询数据库中存储的 DynamicDataSourceModel
|
||||||
@ -57,13 +50,13 @@ public interface CommonAPI {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public LoginUser getUserByName(String username);
|
public LoginUser getUserByName(String username);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 5根据用户账号查询用户Id
|
* 5根据用户手机号查询用户信息
|
||||||
* @param username
|
* @param username
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String getUserIdByName(String username);
|
public LoginUser getUserByPhone(String phone);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,20 +131,35 @@ public interface CommonAPI {
|
|||||||
* @param text
|
* @param text
|
||||||
* @param code
|
* @param code
|
||||||
* @param keys 多个用逗号分割
|
* @param keys 多个用逗号分割
|
||||||
* @param dataSource 数据源
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys, String dataSource);
|
List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 16 运行AIRag流程
|
* 登录加载系统字典
|
||||||
* for [QQYUN-13634]在baseapi里面封装方法,方便其他模块调用
|
* @return
|
||||||
*
|
|
||||||
* @param airagFlowDTO
|
|
||||||
* @return 流程执行结果,可能是String或者Map
|
|
||||||
* @author chenrui
|
|
||||||
* @date 2025/9/2 11:43
|
|
||||||
*/
|
*/
|
||||||
Object runAiragFlow(AiragFlowDTO airagFlowDTO);
|
Map<String,List<DictModel>> queryAllDictItems();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询SysDepart集合
|
||||||
|
* @param userId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<SysDepartModel> queryUserDeparts(String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户名设置部门ID
|
||||||
|
* @param username
|
||||||
|
* @param orgCode
|
||||||
|
*/
|
||||||
|
void updateUserDepart(String username,String orgCode,Integer loginTenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置登录租户
|
||||||
|
* @param username
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
JSONObject setLoginTenant(String username);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -17,8 +17,6 @@ public class DataLogDTO {
|
|||||||
|
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
private String createName;
|
|
||||||
|
|
||||||
public DataLogDTO(){
|
public DataLogDTO(){
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jeecg.common.api.dto;
|
package org.jeecg.common.api.dto;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.jeecg.common.aspect.annotation.Dict;
|
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -56,11 +55,6 @@ public class LogDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Integer tenantId;
|
private Integer tenantId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 客户终端类型 pc:电脑端 app:手机端 h5:移动网页端
|
|
||||||
*/
|
|
||||||
private String clientType;
|
|
||||||
|
|
||||||
public LogDTO(){
|
public LogDTO(){
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -30,11 +30,6 @@ public class OnlineAuthDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String onlineFormUrl;
|
private String onlineFormUrl;
|
||||||
|
|
||||||
/**
|
|
||||||
* online工单的地址
|
|
||||||
*/
|
|
||||||
private String onlineWorkOrderUrl;
|
|
||||||
|
|
||||||
public OnlineAuthDTO(){
|
public OnlineAuthDTO(){
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -84,19 +84,7 @@ public class MessageDTO implements Serializable {
|
|||||||
* 邮件抄送地址
|
* 邮件抄送地址
|
||||||
*/
|
*/
|
||||||
protected Set<String> ccEmailList;
|
protected Set<String> ccEmailList;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为定时任务推送email
|
|
||||||
*/
|
|
||||||
private Boolean isTimeJob = false;
|
|
||||||
|
|
||||||
//---【邮件相关参数】-------------------------------------------------------------
|
//---【邮件相关参数】-------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* 枚举:org.jeecg.common.constant.enums.NoticeTypeEnum
|
|
||||||
* 通知类型(system:系统消息、file:知识库、flow:流程、plan:日程计划、meeting:会议)
|
|
||||||
*/
|
|
||||||
private String noticeType;
|
|
||||||
|
|
||||||
public MessageDTO(){
|
public MessageDTO(){
|
||||||
}
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package org.jeecg.common.api.vo;
|
package org.jeecg.common.api.vo;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package org.jeecg.common.aspect;
|
package org.jeecg.common.aspect;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.serializer.PropertyFilter;
|
import com.alibaba.fastjson.serializer.PropertyFilter;
|
||||||
import org.apache.shiro.SecurityUtils;
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
@ -15,12 +15,14 @@ import org.jeecg.common.aspect.annotation.AutoLog;
|
|||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.enums.ModuleType;
|
import org.jeecg.common.constant.enums.ModuleType;
|
||||||
import org.jeecg.common.constant.enums.OperateTypeEnum;
|
import org.jeecg.common.constant.enums.OperateTypeEnum;
|
||||||
|
import org.jeecg.config.security.utils.SecureUtil;
|
||||||
import org.jeecg.modules.base.service.BaseCommonService;
|
import org.jeecg.modules.base.service.BaseCommonService;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.IpUtils;
|
import org.jeecg.common.util.IpUtils;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
|
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -100,7 +102,7 @@ public class AutoLogAspect {
|
|||||||
//设置IP地址
|
//设置IP地址
|
||||||
dto.setIp(IpUtils.getIpAddr(request));
|
dto.setIp(IpUtils.getIpAddr(request));
|
||||||
//获取登录用户信息
|
//获取登录用户信息
|
||||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
LoginUser sysUser = SecureUtil.currentUser();
|
||||||
if(sysUser!=null){
|
if(sysUser!=null){
|
||||||
dto.setUserid(sysUser.getUsername());
|
dto.setUserid(sysUser.getUsername());
|
||||||
dto.setUsername(sysUser.getRealname());
|
dto.setUsername(sysUser.getRealname());
|
||||||
@ -121,8 +123,9 @@ public class AutoLogAspect {
|
|||||||
if (operateType > 0) {
|
if (operateType > 0) {
|
||||||
return operateType;
|
return operateType;
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 阿里云代码扫描规范(不允许任何魔法值出现在代码中)------------
|
//update-begin---author:wangshuai ---date:20220331 for:阿里云代码扫描规范(不允许任何魔法值出现在代码中)------------
|
||||||
return OperateTypeEnum.getTypeByMethodName(methodName);
|
return OperateTypeEnum.getTypeByMethodName(methodName);
|
||||||
|
//update-end---author:wangshuai ---date:20220331 for:阿里云代码扫描规范(不允许任何魔法值出现在代码中)------------
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,15 +145,14 @@ public class AutoLogAspect {
|
|||||||
// https://my.oschina.net/mengzhang6/blog/2395893
|
// https://my.oschina.net/mengzhang6/blog/2395893
|
||||||
Object[] arguments = new Object[paramsArray.length];
|
Object[] arguments = new Object[paramsArray.length];
|
||||||
for (int i = 0; i < paramsArray.length; i++) {
|
for (int i = 0; i < paramsArray.length; i++) {
|
||||||
if (paramsArray[i] instanceof BindingResult || paramsArray[i] instanceof ServletRequest || paramsArray[i] instanceof ServletResponse || paramsArray[i] instanceof MultipartFile || paramsArray[i] instanceof MultipartFile[]) {
|
if (paramsArray[i] instanceof BindingResult || paramsArray[i] instanceof ServletRequest || paramsArray[i] instanceof ServletResponse || paramsArray[i] instanceof MultipartFile) {
|
||||||
//ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
|
//ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
|
||||||
//ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
|
//ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
|
||||||
//MultipartFile和MultipartFile[]不能序列化,从入参里排除
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
arguments[i] = paramsArray[i];
|
arguments[i] = paramsArray[i];
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 日志数据太长的直接过滤掉
|
//update-begin-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
|
||||||
PropertyFilter profilter = new PropertyFilter() {
|
PropertyFilter profilter = new PropertyFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Object o, String name, Object value) {
|
public boolean apply(Object o, String name, Object value) {
|
||||||
@ -165,13 +167,14 @@ public class AutoLogAspect {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
params = JSONObject.toJSONString(arguments, profilter);
|
params = JSONObject.toJSONString(arguments, profilter);
|
||||||
|
//update-end-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
|
||||||
} else {
|
} else {
|
||||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
Method method = signature.getMethod();
|
Method method = signature.getMethod();
|
||||||
// 请求的方法参数值
|
// 请求的方法参数值
|
||||||
Object[] args = joinPoint.getArgs();
|
Object[] args = joinPoint.getArgs();
|
||||||
// 请求的方法参数名称
|
// 请求的方法参数名称
|
||||||
StandardReflectionParameterNameDiscoverer u= new StandardReflectionParameterNameDiscoverer();
|
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
|
||||||
String[] paramNames = u.getParameterNames(method);
|
String[] paramNames = u.getParameterNames(method);
|
||||||
if (args != null && paramNames != null) {
|
if (args != null && paramNames != null) {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
@ -52,9 +52,7 @@ public class DictAspect {
|
|||||||
/**
|
/**
|
||||||
* 定义切点Pointcut
|
* 定义切点Pointcut
|
||||||
*/
|
*/
|
||||||
@Pointcut("(@within(org.springframework.web.bind.annotation.RestController) || " +
|
@Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..)) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)")
|
||||||
"@within(org.springframework.stereotype.Controller) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)) " +
|
|
||||||
"&& execution(public org.jeecg.common.api.vo.Result org.jeecg..*.*(..))")
|
|
||||||
public void excudeService() {
|
public void excudeService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +92,7 @@ public class DictAspect {
|
|||||||
* @param result
|
* @param result
|
||||||
*/
|
*/
|
||||||
private Object parseDictText(Object result) {
|
private Object parseDictText(Object result) {
|
||||||
//if (result instanceof Result) {
|
if (result instanceof Result) {
|
||||||
if (true) {
|
|
||||||
if (((Result) result).getResult() instanceof IPage) {
|
if (((Result) result).getResult() instanceof IPage) {
|
||||||
List<JSONObject> items = new ArrayList<>();
|
List<JSONObject> items = new ArrayList<>();
|
||||||
|
|
||||||
@ -105,24 +102,29 @@ public class DictAspect {
|
|||||||
Map<String, List<String>> dataListMap = new HashMap<>(5);
|
Map<String, List<String>> dataListMap = new HashMap<>(5);
|
||||||
//取出结果集
|
//取出结果集
|
||||||
List<Object> records=((IPage) ((Result) result).getResult()).getRecords();
|
List<Object> records=((IPage) ((Result) result).getResult()).getRecords();
|
||||||
// 代码逻辑说明: 【VUEN-1230】 判断是否含有字典注解,没有注解返回-----
|
//update-begin--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----
|
||||||
Boolean hasDict= checkHasDict(records);
|
Boolean hasDict= checkHasDict(records);
|
||||||
if(!hasDict){
|
if(!hasDict){
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug(" __ 进入字典翻译切面 DictAspect —— " );
|
log.debug(" __ 进入字典翻译切面 DictAspect —— " );
|
||||||
|
//update-end--Author:zyf -- Date:20220606 ----for:【VUEN-1230】 判断是否含有字典注解,没有注解返回-----
|
||||||
for (Object record : records) {
|
for (Object record : records) {
|
||||||
String json="{}";
|
String json="{}";
|
||||||
try {
|
try {
|
||||||
|
//update-begin--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----
|
||||||
//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
|
//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
|
||||||
json = objectMapper.writeValueAsString(record);
|
json = objectMapper.writeValueAsString(record);
|
||||||
|
//update-end--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
log.error("json解析失败"+e.getMessage(),e);
|
log.error("json解析失败"+e.getMessage(),e);
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
//update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
||||||
JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
|
JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
|
||||||
|
//update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
|
||||||
|
|
||||||
|
//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
|
||||||
//for (Field field : record.getClass().getDeclaredFields()) {
|
//for (Field field : record.getClass().getDeclaredFields()) {
|
||||||
// 遍历所有字段,把字典Code取出来,放到 map 里
|
// 遍历所有字段,把字典Code取出来,放到 map 里
|
||||||
for (Field field : oConvertUtils.getAllFields(record)) {
|
for (Field field : oConvertUtils.getAllFields(record)) {
|
||||||
@ -130,6 +132,7 @@ public class DictAspect {
|
|||||||
if (oConvertUtils.isEmpty(value)) {
|
if (oConvertUtils.isEmpty(value)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
|
||||||
if (field.getAnnotation(Dict.class) != null) {
|
if (field.getAnnotation(Dict.class) != null) {
|
||||||
if (!dictFieldList.contains(field)) {
|
if (!dictFieldList.contains(field)) {
|
||||||
dictFieldList.add(field);
|
dictFieldList.add(field);
|
||||||
@ -137,22 +140,22 @@ public class DictAspect {
|
|||||||
String code = field.getAnnotation(Dict.class).dicCode();
|
String code = field.getAnnotation(Dict.class).dicCode();
|
||||||
String text = field.getAnnotation(Dict.class).dicText();
|
String text = field.getAnnotation(Dict.class).dicText();
|
||||||
String table = field.getAnnotation(Dict.class).dictTable();
|
String table = field.getAnnotation(Dict.class).dictTable();
|
||||||
// 代码逻辑说明: [issues/#5643]解决分布式下表字典跨库无法查询问题------------
|
|
||||||
String dataSource = field.getAnnotation(Dict.class).ds();
|
|
||||||
List<String> dataList;
|
List<String> dataList;
|
||||||
String dictCode = code;
|
String dictCode = code;
|
||||||
if (!StringUtils.isEmpty(table)) {
|
if (!StringUtils.isEmpty(table)) {
|
||||||
// 代码逻辑说明: [issues/#5643]解决分布式下表字典跨库无法查询问题------------
|
dictCode = String.format("%s,%s,%s", table, text, code);
|
||||||
dictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);
|
|
||||||
}
|
}
|
||||||
dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||||
this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));
|
this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));
|
||||||
}
|
}
|
||||||
//date类型默认转换string格式化日期
|
//date类型默认转换string格式化日期
|
||||||
|
//update-begin--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----
|
||||||
//if (JAVA_UTIL_DATE.equals(field.getType().getName())&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){
|
//if (JAVA_UTIL_DATE.equals(field.getType().getName())&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){
|
||||||
//SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
//SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
// item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
|
// item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
|
||||||
//}
|
//}
|
||||||
|
//update-end--Author:zyf -- Date:20220531 ----for:【issues/#3629】 DictAspect Jackson序列化报错-----
|
||||||
}
|
}
|
||||||
items.add(item);
|
items.add(item);
|
||||||
}
|
}
|
||||||
@ -166,12 +169,10 @@ public class DictAspect {
|
|||||||
String code = field.getAnnotation(Dict.class).dicCode();
|
String code = field.getAnnotation(Dict.class).dicCode();
|
||||||
String text = field.getAnnotation(Dict.class).dicText();
|
String text = field.getAnnotation(Dict.class).dicText();
|
||||||
String table = field.getAnnotation(Dict.class).dictTable();
|
String table = field.getAnnotation(Dict.class).dictTable();
|
||||||
// 自定义的字典表数据源
|
|
||||||
String dataSource = field.getAnnotation(Dict.class).ds();
|
|
||||||
String fieldDictCode = code;
|
String fieldDictCode = code;
|
||||||
if (!StringUtils.isEmpty(table)) {
|
if (!StringUtils.isEmpty(table)) {
|
||||||
// 代码逻辑说明: [issues/#5643]解决分布式下表字典跨库无法查询问题------------
|
fieldDictCode = String.format("%s,%s,%s", table, text, code);
|
||||||
fieldDictCode = String.format("%s,%s,%s,%s", table, text, code, dataSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = record.getString(field.getName());
|
String value = record.getString(field.getName());
|
||||||
@ -273,20 +274,9 @@ public class DictAspect {
|
|||||||
String[] arr = dictCode.split(",");
|
String[] arr = dictCode.split(",");
|
||||||
String table = arr[0], text = arr[1], code = arr[2];
|
String table = arr[0], text = arr[1], code = arr[2];
|
||||||
String values = String.join(",", needTranslDataTable);
|
String values = String.join(",", needTranslDataTable);
|
||||||
// 自定义的数据源
|
|
||||||
String dataSource = null;
|
|
||||||
if (arr.length > 3) {
|
|
||||||
dataSource = arr[3];
|
|
||||||
}
|
|
||||||
log.debug("translateDictFromTableByKeys.dictCode:" + dictCode);
|
log.debug("translateDictFromTableByKeys.dictCode:" + dictCode);
|
||||||
log.debug("translateDictFromTableByKeys.values:" + values);
|
log.debug("translateDictFromTableByKeys.values:" + values);
|
||||||
|
List<DictModel> texts = commonApi.translateDictFromTableByKeys(table, text, code, values);
|
||||||
// 代码逻辑说明: 微服务下为空报错没有参数需要传递空字符串---
|
|
||||||
if(null == dataSource){
|
|
||||||
dataSource = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DictModel> texts = commonApi.translateDictFromTableByKeys(table, text, code, values, dataSource);
|
|
||||||
log.debug("translateDictFromTableByKeys.result:" + texts);
|
log.debug("translateDictFromTableByKeys.result:" + texts);
|
||||||
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
|
||||||
list.addAll(texts);
|
list.addAll(texts);
|
||||||
@ -295,8 +285,10 @@ public class DictAspect {
|
|||||||
for (DictModel dict : texts) {
|
for (DictModel dict : texts) {
|
||||||
String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());
|
String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());
|
||||||
try {
|
try {
|
||||||
|
// update-begin-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
|
||||||
// 保留5分钟
|
// 保留5分钟
|
||||||
redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);
|
redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);
|
||||||
|
// update-end-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn(e.getMessage(), e);
|
log.warn(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@ -380,7 +372,7 @@ public class DictAspect {
|
|||||||
if (k.trim().length() == 0) {
|
if (k.trim().length() == 0) {
|
||||||
continue; //跳过循环
|
continue; //跳过循环
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----
|
//update-begin--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----
|
||||||
if (!StringUtils.isEmpty(table)){
|
if (!StringUtils.isEmpty(table)){
|
||||||
log.debug("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);
|
log.debug("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);
|
||||||
String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s,%s,%s]",table,text,code,k.trim());
|
String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s,%s,%s]",table,text,code,k.trim());
|
||||||
@ -405,6 +397,7 @@ public class DictAspect {
|
|||||||
tmpValue = commonApi.translateDict(code, k.trim());
|
tmpValue = commonApi.translateDict(code, k.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-end--Author:scott -- Date:20210531 ----for: !56 优化微服务应用下存在表字段需要字典翻译时加载缓慢问题-----
|
||||||
|
|
||||||
if (tmpValue != null) {
|
if (tmpValue != null) {
|
||||||
if (!"".equals(textValue.toString())) {
|
if (!"".equals(textValue.toString())) {
|
||||||
@ -57,6 +57,7 @@ public class PermissionDataAspect {
|
|||||||
String requestMethod = request.getMethod();
|
String requestMethod = request.getMethod();
|
||||||
String requestPath = request.getRequestURI().substring(request.getContextPath().length());
|
String requestPath = request.getRequestURI().substring(request.getContextPath().length());
|
||||||
requestPath = filterUrl(requestPath);
|
requestPath = filterUrl(requestPath);
|
||||||
|
//update-begin-author:taoyan date:20211027 for:JTC-132【online报表权限】online报表带参数的菜单配置数据权限无效
|
||||||
//先判断是否online报表请求
|
//先判断是否online报表请求
|
||||||
if(requestPath.indexOf(UrlMatchEnum.CGREPORT_DATA.getMatchUrl())>=0 || requestPath.indexOf(UrlMatchEnum.CGREPORT_ONLY_DATA.getMatchUrl())>=0){
|
if(requestPath.indexOf(UrlMatchEnum.CGREPORT_DATA.getMatchUrl())>=0 || requestPath.indexOf(UrlMatchEnum.CGREPORT_ONLY_DATA.getMatchUrl())>=0){
|
||||||
// 获取地址栏参数
|
// 获取地址栏参数
|
||||||
@ -65,6 +66,7 @@ public class PermissionDataAspect {
|
|||||||
requestPath+="?"+urlParamString;
|
requestPath+="?"+urlParamString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20211027 for:JTC-132【online报表权限】online报表带参数的菜单配置数据权限无效
|
||||||
log.debug("拦截请求 >> {} ; 请求类型 >> {} . ", requestPath, requestMethod);
|
log.debug("拦截请求 >> {} ; 请求类型 >> {} . ", requestPath, requestMethod);
|
||||||
String username = JwtUtil.getUserNameByToken(request);
|
String username = JwtUtil.getUserNameByToken(request);
|
||||||
//查询数据权限信息
|
//查询数据权限信息
|
||||||
@ -39,14 +39,4 @@ public @interface Dict {
|
|||||||
* @return 返回类型: String
|
* @return 返回类型: String
|
||||||
*/
|
*/
|
||||||
String dictTable() default "";
|
String dictTable() default "";
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 方法描述: 数据字典表所在数据源名称
|
|
||||||
* 作 者: chenrui
|
|
||||||
* 日 期: 2023年12月20日-下午4:58
|
|
||||||
*
|
|
||||||
* @return 返回类型: String
|
|
||||||
*/
|
|
||||||
String ds() default "";
|
|
||||||
}
|
}
|
||||||
@ -36,16 +36,6 @@ public interface CommonConstant {
|
|||||||
*/
|
*/
|
||||||
int LOG_TYPE_2 = 2;
|
int LOG_TYPE_2 = 2;
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统日志类型: 租户操作日志
|
|
||||||
*/
|
|
||||||
int LOG_TYPE_3 = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统日志类型: 异常
|
|
||||||
*/
|
|
||||||
int LOG_TYPE_4 = 4;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作日志类型: 查询
|
* 操作日志类型: 查询
|
||||||
*/
|
*/
|
||||||
@ -79,8 +69,6 @@ public interface CommonConstant {
|
|||||||
|
|
||||||
/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
|
/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
|
||||||
Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
|
Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
|
||||||
/** {@code 404 Not Found} (HTTP/1.0 - RFC 1945) */
|
|
||||||
Integer SC_INTERNAL_NOT_FOUND_404 = 404;
|
|
||||||
/** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
|
/** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
|
||||||
Integer SC_OK_200 = 200;
|
Integer SC_OK_200 = 200;
|
||||||
|
|
||||||
@ -90,24 +78,7 @@ public interface CommonConstant {
|
|||||||
/** 登录用户Shiro权限缓存KEY前缀 */
|
/** 登录用户Shiro权限缓存KEY前缀 */
|
||||||
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
||||||
/** 登录用户Token令牌缓存KEY前缀 */
|
/** 登录用户Token令牌缓存KEY前缀 */
|
||||||
String PREFIX_USER_TOKEN = "prefix_user_token:";
|
String PREFIX_USER_TOKEN = "token::jeecg-client::";
|
||||||
/** 登录用户Token令牌作废提示信息,比如 “不允许同一账号多地同时登录,会往这个变量存提示信息” */
|
|
||||||
String PREFIX_USER_TOKEN_ERROR_MSG = "prefix_user_token:error:msg_";
|
|
||||||
|
|
||||||
/**============================== 【是否允许同一账号多地同时登录】登录客户端类型常量 ==============================*/
|
|
||||||
/** 客户端类型:PC端 */
|
|
||||||
String CLIENT_TYPE_PC = "PC";
|
|
||||||
/** 客户端类型:APP端 */
|
|
||||||
String CLIENT_TYPE_APP = "APP";
|
|
||||||
/** 客户端类型:手机号登录 */
|
|
||||||
String CLIENT_TYPE_PHONE = "PHONE";
|
|
||||||
String PREFIX_USER_TOKEN_PC = "prefix_user_token:single_login:pc:";
|
|
||||||
/** 单点登录:用户在APP端的Token缓存KEY前缀 (username -> token) */
|
|
||||||
String PREFIX_USER_TOKEN_APP = "prefix_user_token:single_login:app:";
|
|
||||||
/** 单点登录:用户在手机号登录的Token缓存KEY前缀 (username -> token) */
|
|
||||||
String PREFIX_USER_TOKEN_PHONE = "prefix_user_token:single_login:phone:";
|
|
||||||
/**============================== 【是否允许同一账号多地同时登录】登录客户端类型常量 ==============================*/
|
|
||||||
|
|
||||||
// /** Token缓存时间:3600秒即一小时 */
|
// /** Token缓存时间:3600秒即一小时 */
|
||||||
// int TOKEN_EXPIRE_TIME = 3600;
|
// int TOKEN_EXPIRE_TIME = 3600;
|
||||||
|
|
||||||
@ -161,9 +132,7 @@ public interface CommonConstant {
|
|||||||
*/
|
*/
|
||||||
String STATUS_0 = "0";
|
String STATUS_0 = "0";
|
||||||
String STATUS_1 = "1";
|
String STATUS_1 = "1";
|
||||||
Integer STATUS_0_INT = 0;
|
|
||||||
Integer STATUS_1_INT = 1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步工作流引擎1同步0不同步
|
* 同步工作流引擎1同步0不同步
|
||||||
*/
|
*/
|
||||||
@ -315,20 +284,7 @@ public interface CommonConstant {
|
|||||||
* 在线聊天 用户好友缓存前缀
|
* 在线聊天 用户好友缓存前缀
|
||||||
*/
|
*/
|
||||||
String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
|
String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_";
|
||||||
/**
|
|
||||||
* 缓存用户id与用户名关系
|
|
||||||
*/
|
|
||||||
String SYS_USER_ID_MAPPING_CACHE = "sys:cache:user:id_mapping";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统角色管理员编码
|
|
||||||
*/
|
|
||||||
String SYS_ROLE_ADMIN = "admin";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 考勤补卡业务状态 (0:处理中)
|
|
||||||
*/
|
|
||||||
String SIGN_PATCH_BIZ_STATUS_0 = "0";
|
|
||||||
/**
|
/**
|
||||||
* 考勤补卡业务状态 (1:同意 2:不同意)
|
* 考勤补卡业务状态 (1:同意 2:不同意)
|
||||||
*/
|
*/
|
||||||
@ -419,8 +375,6 @@ public interface CommonConstant {
|
|||||||
/**前端vue3版本Header参数名*/
|
/**前端vue3版本Header参数名*/
|
||||||
String VERSION="X-Version";
|
String VERSION="X-Version";
|
||||||
|
|
||||||
String VERSION_V3 = "v3";
|
|
||||||
|
|
||||||
/**存储在线程变量里的动态表名*/
|
/**存储在线程变量里的动态表名*/
|
||||||
String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME";
|
String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME";
|
||||||
/**
|
/**
|
||||||
@ -454,11 +408,6 @@ public interface CommonConstant {
|
|||||||
*/
|
*/
|
||||||
String NOTICE_MSG_BUS_TYPE = "NOTICE_MSG_BUS_TYPE";
|
String NOTICE_MSG_BUS_TYPE = "NOTICE_MSG_BUS_TYPE";
|
||||||
|
|
||||||
/**
|
|
||||||
* 通知类型,用于区分来源 file 知识 flow 流程 plan 日程 system 系统消息
|
|
||||||
*/
|
|
||||||
String NOTICE_TYPE = "noticeType";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮箱消息中地址登录时地址后携带的token,需要替换成真实的token值
|
* 邮箱消息中地址登录时地址后携带的token,需要替换成真实的token值
|
||||||
*/
|
*/
|
||||||
@ -508,11 +457,6 @@ public interface CommonConstant {
|
|||||||
*/
|
*/
|
||||||
String FILE_EDITABLE = "editable";
|
String FILE_EDITABLE = "editable";
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件 只读
|
|
||||||
*/
|
|
||||||
String FILE_READONLY = "readonly";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录失败,用于记录失败次数的key
|
* 登录失败,用于记录失败次数的key
|
||||||
*/
|
*/
|
||||||
@ -612,6 +556,7 @@ public interface CommonConstant {
|
|||||||
String ORDER_TYPE_DESC = "DESC";
|
String ORDER_TYPE_DESC = "DESC";
|
||||||
|
|
||||||
|
|
||||||
|
//update-begin---author:scott ---date:2023-09-10 for:积木报表常量----
|
||||||
/**
|
/**
|
||||||
* 报表允许设计开发的角色
|
* 报表允许设计开发的角色
|
||||||
*/
|
*/
|
||||||
@ -626,119 +571,6 @@ public interface CommonConstant {
|
|||||||
* 数据隔离模式: 按照租户隔离
|
* 数据隔离模式: 按照租户隔离
|
||||||
*/
|
*/
|
||||||
public static final String SAAS_MODE_TENANT = "tenant";
|
public static final String SAAS_MODE_TENANT = "tenant";
|
||||||
|
//update-end---author:scott ---date::2023-09-10 for:积木报表常量----
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改手机号短信验证码redis-key的前缀
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
String CACHE_KEY_USER_LAST_ANNOUNT_TIME_1HOUR = "sys:cache:userinfo:user_last_annount_time::%s";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证原手机号
|
|
||||||
*/
|
|
||||||
String VERIFY_ORIGINAL_PHONE = "verifyOriginalPhone";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改手机号
|
|
||||||
*/
|
|
||||||
String UPDATE_PHONE = "updatePhone";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改手机号验证码请求次数超出
|
|
||||||
*/
|
|
||||||
Integer PHONE_SMS_FAIL_CODE = 40002;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义首页关联关系(ROLE:表示角色 USER:表示用户 DEFAULT:默认首页)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
String HOME_RELATION_ROLE = "ROLE";
|
|
||||||
String HOME_RELATION_USER = "USER";
|
|
||||||
String HOME_RELATION_DEFAULT = "DEFAULT";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否置顶(0否 1是)
|
|
||||||
*/
|
|
||||||
Integer IZ_TOP_1 = 1;
|
|
||||||
Integer IZ_TOP_0 = 0;
|
|
||||||
|
|
||||||
|
|
||||||
//关注流程缓存前缀
|
|
||||||
String FLOW_FOCUS_NOTICE_PREFIX = "flow:runtimeData:focus:notice:";
|
|
||||||
//任务缓办时间缓存前缀
|
|
||||||
String FLOW_TASK_DELAY_PREFIX = "flow:runtimeData:task:delay:";
|
|
||||||
/**
|
|
||||||
* 用户代理类型:离职:quit 代理:agent
|
|
||||||
*/
|
|
||||||
String USER_AGENT_TYPE_QUIT = "quit";
|
|
||||||
String USER_AGENT_TYPE_AGENT = "agent";
|
|
||||||
/**
|
|
||||||
* 督办流程首节点任务taskKey
|
|
||||||
*/
|
|
||||||
String SUPERVISE_FIRST_TASK_KEY = "Task_1bhxpt0";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* wps模板预览数据缓存前缀
|
|
||||||
*/
|
|
||||||
String EOA_WPS_TEMPLATE_VIEW_DATA ="eoa:wps:templateViewData:";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* wps模板预览版本号缓存前缀
|
|
||||||
*/
|
|
||||||
String EOA_WPS_TEMPLATE_VIEW_VERSION ="eoa:wps:templateViewVersion:";
|
|
||||||
/**
|
|
||||||
* 表单设计器oa新增字段
|
|
||||||
* x_oa_timeout_date:逾期时间
|
|
||||||
* x_oa_archive_status:归档状态
|
|
||||||
*/
|
|
||||||
String X_OA_TIMEOUT_DATE ="x_oa_timeout_date";
|
|
||||||
String X_OA_ARCHIVE_STATUS ="x_oa_archive_status";
|
|
||||||
/**
|
|
||||||
* 流程状态
|
|
||||||
* 待提交: 1
|
|
||||||
* 处理中: 2
|
|
||||||
* 已完成: 3
|
|
||||||
* 已作废: 4
|
|
||||||
* 已挂起: 5
|
|
||||||
*/
|
|
||||||
String BPM_STATUS_1 ="1";
|
|
||||||
String BPM_STATUS_2 ="2";
|
|
||||||
String BPM_STATUS_3 ="3";
|
|
||||||
String BPM_STATUS_4 ="4";
|
|
||||||
String BPM_STATUS_5 ="5";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认租户产品包
|
|
||||||
*/
|
|
||||||
String TENANT_PACK_DEFAULT = "default";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门名称redisKey(全路径)
|
|
||||||
*/
|
|
||||||
String DEPART_NAME_REDIS_KEY_PRE = "sys:cache:departPathName:";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认用户排序值
|
|
||||||
*/
|
|
||||||
Integer DEFAULT_USER_SORT = 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送短信方式:腾讯
|
|
||||||
*/
|
|
||||||
String SMS_SEND_TYPE_TENCENT = "tencent";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送短信方式:阿里云
|
|
||||||
*/
|
|
||||||
String SMS_SEND_TYPE_ALI_YUN = "aliyun";
|
|
||||||
}
|
}
|
||||||
@ -4,20 +4,6 @@ package org.jeecg.common.constant;
|
|||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
public interface DataBaseConstant {
|
public interface DataBaseConstant {
|
||||||
|
|
||||||
/**
|
|
||||||
* 内置的系统变量键列表
|
|
||||||
*/
|
|
||||||
public static final String[] SYSTEM_KEYS = {
|
|
||||||
DataBaseConstant.SYS_ORG_CODE, DataBaseConstant.SYS_ORG_CODE_TABLE, DataBaseConstant.SYS_MULTI_ORG_CODE,
|
|
||||||
DataBaseConstant.SYS_MULTI_ORG_CODE_TABLE, DataBaseConstant.SYS_ORG_ID, DataBaseConstant.SYS_ORG_ID_TABLE,
|
|
||||||
DataBaseConstant.SYS_ROLE_CODE, DataBaseConstant.SYS_ROLE_CODE_TABLE, DataBaseConstant.SYS_USER_CODE,
|
|
||||||
DataBaseConstant.SYS_USER_CODE_TABLE, DataBaseConstant.SYS_USER_ID, DataBaseConstant.SYS_USER_ID_TABLE,
|
|
||||||
DataBaseConstant.SYS_USER_NAME, DataBaseConstant.SYS_USER_NAME_TABLE, DataBaseConstant.SYS_DATE,
|
|
||||||
DataBaseConstant.SYS_DATE_TABLE, DataBaseConstant.SYS_TIME, DataBaseConstant.SYS_TIME_TABLE,
|
|
||||||
DataBaseConstant.SYS_BASE_PATH
|
|
||||||
};
|
|
||||||
|
|
||||||
//*********数据库类型****************************************
|
//*********数据库类型****************************************
|
||||||
|
|
||||||
/**MYSQL数据库*/
|
/**MYSQL数据库*/
|
||||||
@ -31,9 +17,6 @@ public interface DataBaseConstant {
|
|||||||
|
|
||||||
/**postgreSQL达梦数据库*/
|
/**postgreSQL达梦数据库*/
|
||||||
public static final String DB_TYPE_POSTGRESQL = "POSTGRESQL";
|
public static final String DB_TYPE_POSTGRESQL = "POSTGRESQL";
|
||||||
|
|
||||||
/**人大金仓数据库*/
|
|
||||||
public static final String DB_TYPE_KINGBASEES = "KINGBASEES";
|
|
||||||
|
|
||||||
/**sqlserver数据库*/
|
/**sqlserver数据库*/
|
||||||
public static final String DB_TYPE_SQLSERVER = "SQLSERVER";
|
public static final String DB_TYPE_SQLSERVER = "SQLSERVER";
|
||||||
@ -72,22 +55,6 @@ public interface DataBaseConstant {
|
|||||||
* 数据-所属机构编码
|
* 数据-所属机构编码
|
||||||
*/
|
*/
|
||||||
public static final String SYS_MULTI_ORG_CODE_TABLE = "sys_multi_org_code";
|
public static final String SYS_MULTI_ORG_CODE_TABLE = "sys_multi_org_code";
|
||||||
/**
|
|
||||||
* 数据-所属机构ID
|
|
||||||
*/
|
|
||||||
public static final String SYS_ORG_ID = "sysOrgId";
|
|
||||||
/**
|
|
||||||
* 数据-所属机构ID
|
|
||||||
*/
|
|
||||||
public static final String SYS_ORG_ID_TABLE = "sys_org_id";
|
|
||||||
/**
|
|
||||||
* 数据-所属角色code(多个逗号分割)
|
|
||||||
*/
|
|
||||||
public static final String SYS_ROLE_CODE = "sysRoleCode";
|
|
||||||
/**
|
|
||||||
* 数据-所属角色code(多个逗号分割)
|
|
||||||
*/
|
|
||||||
public static final String SYS_ROLE_CODE_TABLE = "sys_role_code";
|
|
||||||
/**
|
/**
|
||||||
* 数据-系统用户编码(对应登录用户账号)
|
* 数据-系统用户编码(对应登录用户账号)
|
||||||
*/
|
*/
|
||||||
@ -96,14 +63,7 @@ public interface DataBaseConstant {
|
|||||||
* 数据-系统用户编码(对应登录用户账号)
|
* 数据-系统用户编码(对应登录用户账号)
|
||||||
*/
|
*/
|
||||||
public static final String SYS_USER_CODE_TABLE = "sys_user_code";
|
public static final String SYS_USER_CODE_TABLE = "sys_user_code";
|
||||||
/**
|
|
||||||
* 登录用户ID
|
|
||||||
*/
|
|
||||||
public static final String SYS_USER_ID = "sysUserId";
|
|
||||||
/**
|
|
||||||
* 登录用户ID
|
|
||||||
*/
|
|
||||||
public static final String SYS_USER_ID_TABLE = "sys_user_id";
|
|
||||||
/**
|
/**
|
||||||
* 登录用户真实姓名
|
* 登录用户真实姓名
|
||||||
*/
|
*/
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package org.jeecg.common.constant;
|
package org.jeecg.common.constant;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@ -23,34 +22,32 @@ public class ProvinceCityArea {
|
|||||||
List<Area> areaList;
|
List<Area> areaList;
|
||||||
|
|
||||||
public String getText(String code){
|
public String getText(String code){
|
||||||
if(StringUtils.isNotBlank(code)){
|
this.initAreaList();
|
||||||
this.initAreaList();
|
if(this.areaList!=null || this.areaList.size()>0){
|
||||||
if(this.areaList!=null || this.areaList.size()>0){
|
List<String> ls = new ArrayList<String>();
|
||||||
List<String> ls = new ArrayList<String>();
|
getAreaByCode(code,ls);
|
||||||
getAreaByCode(code,ls);
|
return String.join("/",ls);
|
||||||
return String.join("/",ls);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCode(String text){
|
public String getCode(String text){
|
||||||
if(StringUtils.isNotBlank(text)){
|
this.initAreaList();
|
||||||
this.initAreaList();
|
if(areaList!=null && areaList.size()>0){
|
||||||
if(areaList!=null && areaList.size()>0){
|
for(int i=areaList.size()-1;i>=0;i--){
|
||||||
for(int i=areaList.size()-1;i>=0;i--){
|
//update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
// 代码逻辑说明: VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
String areaText = areaList.get(i).getText();
|
||||||
String areaText = areaList.get(i).getText();
|
String cityText = areaList.get(i).getAheadText();
|
||||||
String cityText = areaList.get(i).getAheadText();
|
if(text.indexOf(areaText)>=0 && (cityText!=null && text.indexOf(cityText)>=0)){
|
||||||
if(text.indexOf(areaText)>=0 && (cityText!=null && text.indexOf(cityText)>=0)){
|
return areaList.get(i).getId();
|
||||||
return areaList.get(i).getId();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update-begin-author:sunjianlei date:20220121 for:【JTC-704】数据导入错误 省市区组件,文件中为北京市,导入后,导为了山西省
|
||||||
/**
|
/**
|
||||||
* 获取省市区code,精准匹配
|
* 获取省市区code,精准匹配
|
||||||
* @param texts 文本数组,省,市,区
|
* @param texts 文本数组,省,市,区
|
||||||
@ -115,10 +112,11 @@ public class ProvinceCityArea {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// update-end-author:sunjianlei date:20220121 for:【JTC-704】数据导入错误 省市区组件,文件中为北京市,导入后,导为了山西省
|
||||||
|
|
||||||
public void getAreaByCode(String code,List<String> ls){
|
public void getAreaByCode(String code,List<String> ls){
|
||||||
for(Area area: areaList){
|
for(Area area: areaList){
|
||||||
if(null != area && area.getId().equals(code)){
|
if(area.getId().equals(code)){
|
||||||
String pid = area.getPid();
|
String pid = area.getPid();
|
||||||
ls.add(0,area.getText());
|
ls.add(0,area.getText());
|
||||||
getAreaByCode(pid,ls);
|
getAreaByCode(pid,ls);
|
||||||
@ -151,8 +149,9 @@ public class ProvinceCityArea {
|
|||||||
for(String areaKey:areaJson.keySet()){
|
for(String areaKey:areaJson.keySet()){
|
||||||
//System.out.println("········"+areaKey);
|
//System.out.println("········"+areaKey);
|
||||||
Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey);
|
Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey);
|
||||||
// 代码逻辑说明: VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
//update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
area.setAheadText(cityJson.getString(cityKey));
|
area.setAheadText(cityJson.getString(cityKey));
|
||||||
|
//update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区
|
||||||
this.areaList.add(area);
|
this.areaList.add(area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,22 +34,17 @@ public interface ServiceNameConstants {
|
|||||||
*/
|
*/
|
||||||
String SERVICE_DEMO = "jeecg-demo";
|
String SERVICE_DEMO = "jeecg-demo";
|
||||||
/**
|
/**
|
||||||
* 微服务名:joa模块
|
* 微服务名:online在线模块
|
||||||
*/
|
*/
|
||||||
String SERVICE_JOA = "jeecg-joa";
|
String SERVICE_ONLINE = "jeecg-online";
|
||||||
|
/**
|
||||||
// /**
|
* 微服务名:OA模块
|
||||||
// * 微服务名:online在线模块
|
*/
|
||||||
// */
|
String SERVICE_EOA = "jeecg-eoa";
|
||||||
// String SERVICE_ONLINE = "jeecg-online";
|
/**
|
||||||
// /**
|
* 微服务名:表单设计模块
|
||||||
// * 微服务名:OA模块
|
*/
|
||||||
// */
|
String SERVICE_FORM = "jeecg-desform";
|
||||||
// String SERVICE_EOA = "jeecg-eoa";
|
|
||||||
// /**
|
|
||||||
// * 微服务名:表单设计模块
|
|
||||||
// */
|
|
||||||
// String SERVICE_FORM = "jeecg-desform";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gateway通过header传递根路径 basePath
|
* gateway通过header传递根路径 basePath
|
||||||
@ -23,7 +23,7 @@ public enum CgformEnum {
|
|||||||
/**
|
/**
|
||||||
* 多表(jvxe风格)
|
* 多表(jvxe风格)
|
||||||
* */
|
* */
|
||||||
JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "默认风格" ,new String[]{"vue3","vue","vue3Native"}),
|
JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格" ,new String[]{"vue3","vue","vue3Native"}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 多表 (erp风格)
|
* 多表 (erp风格)
|
||||||
@ -9,14 +9,20 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
public enum DySmsEnum {
|
public enum DySmsEnum {
|
||||||
|
|
||||||
/**登录短信模板编码*/
|
/**登录短信模板编码*/
|
||||||
LOGIN_TEMPLATE_CODE("SMS_175435174","敲敲云","code"),
|
LOGIN_TEMPLATE_CODE("SMS_175435174","敲敲云","code"),
|
||||||
/**忘记密码短信模板编码*/
|
/**忘记密码短信模板编码*/
|
||||||
FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","敲敲云","code"),
|
FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","敲敲云","code"),
|
||||||
/**修改密码短信模板编码*/
|
/**注册账号短信模板编码*/
|
||||||
CHANGE_PASSWORD_TEMPLATE_CODE("SMS_465391221","敲敲云","code"),
|
REGISTER_TEMPLATE_CODE("SMS_175430166","敲敲云","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");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信模板编码
|
* 短信模板编码
|
||||||
*/
|
*/
|
||||||
@ -13,10 +13,6 @@ public enum EmailTemplateEnum {
|
|||||||
* 流程催办
|
* 流程催办
|
||||||
*/
|
*/
|
||||||
BPM_CUIBAN_EMAIL("bpm_cuiban_email", "/templates/email/bpm_cuiban_email.ftl"),
|
BPM_CUIBAN_EMAIL("bpm_cuiban_email", "/templates/email/bpm_cuiban_email.ftl"),
|
||||||
/**
|
|
||||||
* 流程抄送
|
|
||||||
*/
|
|
||||||
BPM_CC_EMAIL("bpm_cc_email", "/templates/email/bpm_cc_email.ftl"),
|
|
||||||
/**
|
/**
|
||||||
* 流程新任务
|
* 流程新任务
|
||||||
*/
|
*/
|
||||||
@ -8,30 +8,21 @@ import java.util.List;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息类型
|
* 消息类型
|
||||||
*
|
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
*/
|
*/
|
||||||
@EnumDict("messageType")
|
@EnumDict("messageType")
|
||||||
public enum MessageTypeEnum {
|
public enum MessageTypeEnum {
|
||||||
|
|
||||||
/**
|
/** 系统消息 */
|
||||||
* 系统消息
|
XT("system", "系统消息"),
|
||||||
*/
|
/** 邮件消息 */
|
||||||
XT("system", "系统消息"),
|
YJ("email", "邮件消息"),
|
||||||
/**
|
/** 钉钉消息 */
|
||||||
* 邮件消息
|
|
||||||
*/
|
|
||||||
YJ("email", "邮件消息"),
|
|
||||||
/**
|
|
||||||
* 钉钉消息
|
|
||||||
*/
|
|
||||||
DD("dingtalk", "钉钉消息"),
|
DD("dingtalk", "钉钉消息"),
|
||||||
/**
|
/** 企业微信 */
|
||||||
* 企业微信
|
|
||||||
*/
|
|
||||||
QYWX("wechat_enterprise", "企业微信");
|
QYWX("wechat_enterprise", "企业微信");
|
||||||
|
|
||||||
MessageTypeEnum(String type, String note) {
|
MessageTypeEnum(String type, String note){
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.note = note;
|
this.note = note;
|
||||||
}
|
}
|
||||||
@ -65,13 +56,12 @@ public enum MessageTypeEnum {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取字典数据
|
* 获取字典数据
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static List<DictModel> getDictList() {
|
public static List<DictModel> getDictList(){
|
||||||
List<DictModel> list = new ArrayList<>();
|
List<DictModel> list = new ArrayList<>();
|
||||||
DictModel dictModel = null;
|
DictModel dictModel = null;
|
||||||
for (MessageTypeEnum e : MessageTypeEnum.values()) {
|
for(MessageTypeEnum e: MessageTypeEnum.values()){
|
||||||
dictModel = new DictModel();
|
dictModel = new DictModel();
|
||||||
dictModel.setValue(e.getType());
|
dictModel.setValue(e.getType());
|
||||||
dictModel.setText(e.getNote());
|
dictModel.setText(e.getNote());
|
||||||
@ -13,16 +13,12 @@ import java.util.List;
|
|||||||
public enum RoleIndexConfigEnum {
|
public enum RoleIndexConfigEnum {
|
||||||
|
|
||||||
/**首页自定义 admin*/
|
/**首页自定义 admin*/
|
||||||
// ADMIN("admin", "dashboard/Analysis"),
|
ADMIN("admin", "dashboard/Analysis"),
|
||||||
//TEST("test", "dashboard/IndexChart"),
|
//TEST("test", "dashboard/IndexChart"),
|
||||||
/**首页自定义 hr*/
|
/**首页自定义 hr*/
|
||||||
// HR("hr", "dashboard/IndexBdc");
|
HR("hr", "dashboard/IndexBdc");
|
||||||
|
|
||||||
//DM("dm", "dashboard/IndexTask"),
|
//DM("dm", "dashboard/IndexTask"),
|
||||||
|
|
||||||
// 注:此值仅为防止报错,无任何实际意义
|
|
||||||
ROLE_INDEX_CONFIG_ENUM("RoleIndexConfigEnumDefault", "dashboard/Analysis");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色编码
|
* 角色编码
|
||||||
*/
|
*/
|
||||||
@ -23,25 +23,7 @@ public enum SysAnnmentTypeEnum {
|
|||||||
/**
|
/**
|
||||||
* 邀请用户跳转到个人设置
|
* 邀请用户跳转到个人设置
|
||||||
*/
|
*/
|
||||||
TENANT_INVITE("tenant_invite", "url", "/system/usersetting"),
|
TENANT_INVITE("tenant_invite", "url", "/system/usersetting");
|
||||||
/**
|
|
||||||
* 协同工作-待办通知
|
|
||||||
* for [JHHB-136]【vue3】协同工作系统消息需要添加一个类型
|
|
||||||
*/
|
|
||||||
EOA_CO_NOTIFY("eoa_co_notify", "url", "/collaboration/pending"),
|
|
||||||
/**
|
|
||||||
* 协同工作-催办通知
|
|
||||||
* for [JHHB-136]【vue3】协同工作系统消息需要添加一个类型
|
|
||||||
*/
|
|
||||||
EOA_CO_REMIND("eoa_co_remind", "url", "/collaboration/pending"),
|
|
||||||
/**
|
|
||||||
* 督办管理-催办
|
|
||||||
*/
|
|
||||||
EOA_SUP_REMIND("eoa_sup_remind", "url", "/superivse/list"),
|
|
||||||
/**
|
|
||||||
* 督办管理-通知
|
|
||||||
*/
|
|
||||||
EOA_SUP_NOTIFY("eoa_sup_notify", "url", "/superivse/list");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务类型(email:邮件 bpm:流程)
|
* 业务类型(email:邮件 bpm:流程)
|
||||||
@ -73,7 +73,7 @@ public class SensitiveDataAspect {
|
|||||||
SensitiveInfoUtil.handleNestedObject(result, entity, isEncode);
|
SensitiveInfoUtil.handleNestedObject(result, entity, isEncode);
|
||||||
}
|
}
|
||||||
long endTime=System.currentTimeMillis();
|
long endTime=System.currentTimeMillis();
|
||||||
log.debug((isEncode ? "加密操作," : "解密操作,") + "Aspect程序耗时:" + (endTime - startTime) + "ms");
|
log.info((isEncode ? "加密操作," : "解密操作,") + "Aspect程序耗时:" + (endTime - startTime) + "ms");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param fullName 全名
|
* @param fullName 全名
|
||||||
* @return <例子:李**>
|
* @return <例子:李**>
|
||||||
*/
|
*/
|
||||||
public static String chineseName(String fullName) {
|
private static String chineseName(String fullName) {
|
||||||
if (oConvertUtils.isEmpty(fullName)) {
|
if (oConvertUtils.isEmpty(fullName)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param firstName 名
|
* @param firstName 名
|
||||||
* @return <例子:李**>
|
* @return <例子:李**>
|
||||||
*/
|
*/
|
||||||
public static String chineseName(String familyName, String firstName) {
|
private static String chineseName(String familyName, String firstName) {
|
||||||
if (oConvertUtils.isEmpty(familyName) || oConvertUtils.isEmpty(firstName)) {
|
if (oConvertUtils.isEmpty(familyName) || oConvertUtils.isEmpty(firstName)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -223,7 +223,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param id 身份证号
|
* @param id 身份证号
|
||||||
* @return <例子:*************5762>
|
* @return <例子:*************5762>
|
||||||
*/
|
*/
|
||||||
public static String idCardNum(String id) {
|
private static String idCardNum(String id) {
|
||||||
if (oConvertUtils.isEmpty(id)) {
|
if (oConvertUtils.isEmpty(id)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param num 固定电话
|
* @param num 固定电话
|
||||||
* @return <例子:****1234>
|
* @return <例子:****1234>
|
||||||
*/
|
*/
|
||||||
public static String fixedPhone(String num) {
|
private static String fixedPhone(String num) {
|
||||||
if (oConvertUtils.isEmpty(num)) {
|
if (oConvertUtils.isEmpty(num)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -248,7 +248,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param num 手机号码
|
* @param num 手机号码
|
||||||
* @return <例子:138******1234>
|
* @return <例子:138******1234>
|
||||||
*/
|
*/
|
||||||
public static String mobilePhone(String num) {
|
private static String mobilePhone(String num) {
|
||||||
if (oConvertUtils.isEmpty(num)) {
|
if (oConvertUtils.isEmpty(num)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param sensitiveSize 敏感信息长度
|
* @param sensitiveSize 敏感信息长度
|
||||||
* @return <例子:北京市海淀区****>
|
* @return <例子:北京市海淀区****>
|
||||||
*/
|
*/
|
||||||
public static String address(String address, int sensitiveSize) {
|
private static String address(String address, int sensitiveSize) {
|
||||||
if (oConvertUtils.isEmpty(address)) {
|
if (oConvertUtils.isEmpty(address)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param email 电子邮箱
|
* @param email 电子邮箱
|
||||||
* @return <例子:g**@163.com>
|
* @return <例子:g**@163.com>
|
||||||
*/
|
*/
|
||||||
public static String email(String email) {
|
private static String email(String email) {
|
||||||
if (oConvertUtils.isEmpty(email)) {
|
if (oConvertUtils.isEmpty(email)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -300,7 +300,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param cardNum 银行卡号
|
* @param cardNum 银行卡号
|
||||||
* @return <例子:6222600**********1234>
|
* @return <例子:6222600**********1234>
|
||||||
*/
|
*/
|
||||||
public static String bankCard(String cardNum) {
|
private static String bankCard(String cardNum) {
|
||||||
if (oConvertUtils.isEmpty(cardNum)) {
|
if (oConvertUtils.isEmpty(cardNum)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -312,7 +312,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param code 公司开户银行联号
|
* @param code 公司开户银行联号
|
||||||
* @return <例子:12********>
|
* @return <例子:12********>
|
||||||
*/
|
*/
|
||||||
public static String cnapsCode(String code) {
|
private static String cnapsCode(String code) {
|
||||||
if (oConvertUtils.isEmpty(code)) {
|
if (oConvertUtils.isEmpty(code)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -326,7 +326,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param reservedLength 保留长度
|
* @param reservedLength 保留长度
|
||||||
* @return 格式化后的字符串
|
* @return 格式化后的字符串
|
||||||
*/
|
*/
|
||||||
public static String formatRight(String str, int reservedLength){
|
private static String formatRight(String str, int reservedLength){
|
||||||
String name = str.substring(0, reservedLength);
|
String name = str.substring(0, reservedLength);
|
||||||
String stars = String.join("", Collections.nCopies(str.length()-reservedLength, "*"));
|
String stars = String.join("", Collections.nCopies(str.length()-reservedLength, "*"));
|
||||||
return name + stars;
|
return name + stars;
|
||||||
@ -338,7 +338,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param reservedLength 保留长度
|
* @param reservedLength 保留长度
|
||||||
* @return 格式化后的字符串
|
* @return 格式化后的字符串
|
||||||
*/
|
*/
|
||||||
public static String formatLeft(String str, int reservedLength){
|
private static String formatLeft(String str, int reservedLength){
|
||||||
int len = str.length();
|
int len = str.length();
|
||||||
String show = str.substring(len-reservedLength);
|
String show = str.substring(len-reservedLength);
|
||||||
String stars = String.join("", Collections.nCopies(len-reservedLength, "*"));
|
String stars = String.join("", Collections.nCopies(len-reservedLength, "*"));
|
||||||
@ -352,7 +352,7 @@ public class SensitiveInfoUtil {
|
|||||||
* @param endLen 结尾保留长度
|
* @param endLen 结尾保留长度
|
||||||
* @return 格式化后的字符串
|
* @return 格式化后的字符串
|
||||||
*/
|
*/
|
||||||
public static String formatBetween(String str, int beginLen, int endLen){
|
private static String formatBetween(String str, int beginLen, int endLen){
|
||||||
int len = str.length();
|
int len = str.length();
|
||||||
String begin = str.substring(0, beginLen);
|
String begin = str.substring(0, beginLen);
|
||||||
String end = str.substring(len-endLen);
|
String end = str.substring(len-endLen);
|
||||||
@ -387,7 +387,7 @@ public class JeecgElasticsearchTemplate {
|
|||||||
data.remove("id");
|
data.remove("id");
|
||||||
bodySb.append(data.toJSONString()).append("\n");
|
bodySb.append(data.toJSONString()).append("\n");
|
||||||
}
|
}
|
||||||
//System.out.println("+-+-+-: bodySb.toString(): " + bodySb.toString());
|
System.out.println("+-+-+-: bodySb.toString(): " + bodySb.toString());
|
||||||
HttpHeaders headers = RestUtil.getHeaderApplicationJson();
|
HttpHeaders headers = RestUtil.getHeaderApplicationJson();
|
||||||
RestUtil.request(url, HttpMethod.PUT, headers, null, bodySb, JSONObject.class);
|
RestUtil.request(url, HttpMethod.PUT, headers, null, bodySb, JSONObject.class);
|
||||||
return true;
|
return true;
|
||||||
@ -1,7 +1,5 @@
|
|||||||
package org.jeecg.common.exception;
|
package org.jeecg.common.exception;
|
||||||
|
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: jeecg-boot自定义异常
|
* @Description: jeecg-boot自定义异常
|
||||||
* @author: jeecg-boot
|
* @author: jeecg-boot
|
||||||
@ -9,24 +7,10 @@ import org.jeecg.common.constant.CommonConstant;
|
|||||||
public class JeecgBootException extends RuntimeException {
|
public class JeecgBootException extends RuntimeException {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回给前端的错误code
|
|
||||||
*/
|
|
||||||
private int errCode = CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
|
|
||||||
|
|
||||||
public JeecgBootException(String message){
|
public JeecgBootException(String message){
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JeecgBootException(String message, int errCode){
|
|
||||||
super(message);
|
|
||||||
this.errCode = errCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getErrCode() {
|
|
||||||
return errCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JeecgBootException(Throwable cause)
|
public JeecgBootException(Throwable cause)
|
||||||
{
|
{
|
||||||
super(cause);
|
super(cause);
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
package org.jeecg.common.exception;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.enums.SentinelErrorInfoEnum;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
import org.springframework.data.redis.connection.PoolException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常处理器
|
||||||
|
*
|
||||||
|
* @Author scott
|
||||||
|
* @Date 2019
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class JeecgBootExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码错误异常
|
||||||
|
*/
|
||||||
|
|
||||||
|
@ExceptionHandler(JeecgCaptchaException.class)
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public Result<?> handleJeecgCaptchaException(JeecgCaptchaException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error(e.getCode(), e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(AuthenticationException.class)
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public Result<?> handleJeecgCaptchaException(AuthenticationException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error(401, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理自定义异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(JeecgBootException.class)
|
||||||
|
public Result<?> handleJeecgBootException(JeecgBootException e){
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理自定义微服务异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(JeecgCloudException.class)
|
||||||
|
public Result<?> handleJeecgCloudException(JeecgCloudException e){
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理自定义异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(JeecgBoot401Exception.class)
|
||||||
|
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||||
|
public Result<?> handleJeecgBoot401Exception(JeecgBoot401Exception e){
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return new Result(401,e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(NoHandlerFoundException.class)
|
||||||
|
public Result<?> handlerNoFoundException(Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error(404, "路径不存在,请检查路径是否正确");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(DuplicateKeyException.class)
|
||||||
|
public Result<?> handleDuplicateKeyException(DuplicateKeyException e){
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error("数据库中已存在该记录");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(AccessDeniedException.class)
|
||||||
|
public Result<?> handleAuthorizationException(AccessDeniedException e){
|
||||||
|
return Result.noauth("没有权限,请联系管理员授权");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public Result<?> handleException(Exception e){
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
//update-begin---author:zyf ---date:20220411 for:处理Sentinel限流自定义异常
|
||||||
|
Throwable throwable = e.getCause();
|
||||||
|
SentinelErrorInfoEnum errorInfoEnum = SentinelErrorInfoEnum.getErrorByException(throwable);
|
||||||
|
if (ObjectUtil.isNotEmpty(errorInfoEnum)) {
|
||||||
|
return Result.error(errorInfoEnum.getError());
|
||||||
|
}
|
||||||
|
//update-end---author:zyf ---date:20220411 for:处理Sentinel限流自定义异常
|
||||||
|
return Result.error("操作失败,"+e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author 政辉
|
||||||
|
* @param e
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||||
|
public Result<?> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e){
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append("不支持");
|
||||||
|
sb.append(e.getMethod());
|
||||||
|
sb.append("请求方法,");
|
||||||
|
sb.append("支持以下");
|
||||||
|
String [] methods = e.getSupportedMethods();
|
||||||
|
if(methods!=null){
|
||||||
|
for(String str:methods){
|
||||||
|
sb.append(str);
|
||||||
|
sb.append("、");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.error(sb.toString(), e);
|
||||||
|
//return Result.error("没有权限,请联系管理员授权");
|
||||||
|
return Result.error(405,sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring默认上传大小100MB 超出大小捕获异常MaxUploadSizeExceededException
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||||
|
public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(DataIntegrityViolationException.class)
|
||||||
|
public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
//【issues/3624】数据库执行异常handleDataIntegrityViolationException提示有误 #3624
|
||||||
|
return Result.error("执行数据库异常,违反了完整性例如:违反惟一约束、违反非空限制、字段内容超出长度等");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(PoolException.class)
|
||||||
|
public Result<?> handlePoolException(PoolException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error("Redis 连接异常!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL注入风险,全局异常处理
|
||||||
|
*
|
||||||
|
* @param exception
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(JeecgSqlInjectionException.class)
|
||||||
|
public Result<?> handleSQLException(Exception exception) {
|
||||||
|
String msg = exception.getMessage().toLowerCase();
|
||||||
|
final String extractvalue = "extractvalue";
|
||||||
|
final String updatexml = "updatexml";
|
||||||
|
boolean hasSensitiveInformation = msg.indexOf(extractvalue) >= 0 || msg.indexOf(updatexml) >= 0;
|
||||||
|
if (msg != null && hasSensitiveInformation) {
|
||||||
|
log.error("校验失败,存在SQL注入风险!{}", msg);
|
||||||
|
return Result.error("校验失败,存在SQL注入风险!");
|
||||||
|
}
|
||||||
|
return Result.error("校验失败,存在SQL注入风险!" + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package org.jeecg.common.exception;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kezhijie@wuhandsj.com
|
||||||
|
* @date 2024/1/2 11:38
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class JeecgCaptchaException extends RuntimeException{
|
||||||
|
|
||||||
|
private Integer code;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -9093410345065209053L;
|
||||||
|
|
||||||
|
public JeecgCaptchaException(Integer code, String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JeecgCaptchaException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JeecgCaptchaException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,11 +4,6 @@ import java.lang.annotation.*;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 将枚举类转化成字典数据
|
* 将枚举类转化成字典数据
|
||||||
*
|
|
||||||
* <<使用说明>>
|
|
||||||
* 1. 枚举类需以 `Enum` 结尾,并且在类上添加 `@EnumDict` 注解。
|
|
||||||
* 2. 需要手动将枚举类所在包路径** 添加到 `org.jeecg.common.system.util.ResourceUtil.BASE_SCAN_PACKAGES` 配置数组中。
|
|
||||||
*
|
|
||||||
* @Author taoYan
|
* @Author taoYan
|
||||||
* @Date 2022/7/8 10:34
|
* @Date 2022/7/8 10:34
|
||||||
**/
|
**/
|
||||||
@ -1,25 +1,26 @@
|
|||||||
package org.jeecg.common.system.base.controller;
|
package org.jeecg.common.system.base.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.beanutils.PropertyUtils;
|
import org.apache.commons.beanutils.PropertyUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
|
import org.jeecg.config.security.utils.SecureUtil;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
||||||
import org.jeecgframework.poi.excel.entity.ExportParams;
|
import org.jeecgframework.poi.excel.entity.ExportParams;
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||||
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
|
||||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
||||||
import org.jeecgframework.poi.handler.inter.IExcelExportServer;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
@ -52,7 +53,7 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
protected ModelAndView exportXls(HttpServletRequest request, T object, Class<T> clazz, String title) {
|
protected ModelAndView exportXls(HttpServletRequest request, T object, Class<T> clazz, String title) {
|
||||||
// Step.1 组装查询条件
|
// Step.1 组装查询条件
|
||||||
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
||||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
LoginUser sysUser = SecureUtil.currentUser();
|
||||||
|
|
||||||
// 过滤选中数据
|
// 过滤选中数据
|
||||||
String selections = request.getParameter("selections");
|
String selections = request.getParameter("selections");
|
||||||
@ -68,16 +69,12 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
//此处设置的filename无效 ,前端会重更新设置一下
|
//此处设置的filename无效 ,前端会重更新设置一下
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, title);
|
mv.addObject(NormalExcelConstants.FILE_NAME, title);
|
||||||
mv.addObject(NormalExcelConstants.CLASS, clazz);
|
mv.addObject(NormalExcelConstants.CLASS, clazz);
|
||||||
// 代码逻辑说明: 【QQYUN-13930】统一改成导出xlsx格式---
|
//update-begin--Author:liusq Date:20210126 for:图片导出报错,ImageBasePath未设置--------------------
|
||||||
ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title, ExcelType.XSSF);
|
ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title);
|
||||||
exportParams.setImageBasePath(jeecgBaseConfig.getPath().getUpload());
|
exportParams.setImageBasePath(jeecgBaseConfig.getPath().getUpload());
|
||||||
|
//update-end--Author:liusq Date:20210126 for:图片导出报错,ImageBasePath未设置----------------------
|
||||||
mv.addObject(NormalExcelConstants.PARAMS,exportParams);
|
mv.addObject(NormalExcelConstants.PARAMS,exportParams);
|
||||||
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
|
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
|
||||||
// 代码逻辑说明: 【issues/9052】BasicTable列表页导出excel可以指定列---
|
|
||||||
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
|
|
||||||
if(oConvertUtils.isNotEmpty(exportFields)){
|
|
||||||
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
|
|
||||||
}
|
|
||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -94,16 +91,18 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
protected ModelAndView exportXlsSheet(HttpServletRequest request, T object, Class<T> clazz, String title,String exportFields,Integer pageNum) {
|
protected ModelAndView exportXlsSheet(HttpServletRequest request, T object, Class<T> clazz, String title,String exportFields,Integer pageNum) {
|
||||||
// Step.1 组装查询条件
|
// Step.1 组装查询条件
|
||||||
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
||||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
LoginUser sysUser = SecureUtil.currentUser();
|
||||||
// Step.2 计算分页sheet数据
|
// Step.2 计算分页sheet数据
|
||||||
double total = service.count();
|
double total = service.count();
|
||||||
int count = (int)Math.ceil(total/pageNum);
|
int count = (int)Math.ceil(total/pageNum);
|
||||||
|
//update-begin-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 ---
|
||||||
// Step.3 过滤选中数据
|
// Step.3 过滤选中数据
|
||||||
String selections = request.getParameter("selections");
|
String selections = request.getParameter("selections");
|
||||||
if (oConvertUtils.isNotEmpty(selections)) {
|
if (oConvertUtils.isNotEmpty(selections)) {
|
||||||
List<String> selectionList = Arrays.asList(selections.split(","));
|
List<String> selectionList = Arrays.asList(selections.split(","));
|
||||||
queryWrapper.in("id",selectionList);
|
queryWrapper.in("id",selectionList);
|
||||||
}
|
}
|
||||||
|
//update-end-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 ---
|
||||||
// Step.4 多sheet处理
|
// Step.4 多sheet处理
|
||||||
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
|
List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
|
||||||
for (int i = 1; i <=count ; i++) {
|
for (int i = 1; i <=count ; i++) {
|
||||||
@ -130,53 +129,6 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
return mv;
|
return mv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 大数据导出
|
|
||||||
* @param request
|
|
||||||
* @param object
|
|
||||||
* @param clazz
|
|
||||||
* @param title
|
|
||||||
* @param pageSize 每次查询的数据量
|
|
||||||
* @return
|
|
||||||
* @author chenrui
|
|
||||||
* @date 2025/8/11 16:11
|
|
||||||
*/
|
|
||||||
protected ModelAndView exportXlsForBigData(HttpServletRequest request, T object, Class<T> clazz, String title,Integer pageSize) {
|
|
||||||
// 组装查询条件
|
|
||||||
QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap());
|
|
||||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
|
||||||
// 计算分页数
|
|
||||||
double total = service.count();
|
|
||||||
int count = (int) Math.ceil(total / pageSize);
|
|
||||||
// 过滤选中数据
|
|
||||||
String selections = request.getParameter("selections");
|
|
||||||
if (oConvertUtils.isNotEmpty(selections)) {
|
|
||||||
List<String> selectionList = Arrays.asList(selections.split(","));
|
|
||||||
queryWrapper.in("id", selectionList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义IExcelExportServer
|
|
||||||
IExcelExportServer excelExportServer = (queryParams, pageNum) -> {
|
|
||||||
if (pageNum > count) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Page<T> page = new Page<T>(pageNum, pageSize);
|
|
||||||
IPage<T> pageList = service.page(page, (QueryWrapper<T>) queryParams);
|
|
||||||
return new ArrayList<>(pageList.getRecords());
|
|
||||||
};
|
|
||||||
|
|
||||||
// AutoPoi 导出Excel
|
|
||||||
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
|
|
||||||
//此处设置的filename无效 ,前端会重更新设置一下
|
|
||||||
mv.addObject(NormalExcelConstants.FILE_NAME, title);
|
|
||||||
mv.addObject(NormalExcelConstants.CLASS, clazz);
|
|
||||||
ExportParams exportParams = new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title, jeecgBaseConfig.getPath().getUpload());
|
|
||||||
mv.addObject(NormalExcelConstants.PARAMS, exportParams);
|
|
||||||
mv.addObject(NormalExcelConstants.EXPORT_SERVER, excelExportServer);
|
|
||||||
mv.addObject(NormalExcelConstants.QUERY_PARAMS, queryWrapper);
|
|
||||||
return mv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据权限导出excel,传入导出字段参数
|
* 根据权限导出excel,传入导出字段参数
|
||||||
@ -222,15 +174,16 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
params.setNeedSave(true);
|
params.setNeedSave(true);
|
||||||
try {
|
try {
|
||||||
List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
|
List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
|
||||||
// 代码逻辑说明: 批量插入数据
|
//update-begin-author:taoyan date:20190528 for:批量插入数据
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
service.saveBatch(list);
|
service.saveBatch(list);
|
||||||
//400条 saveBatch消耗时间1592毫秒 循环插入消耗时间1947毫秒
|
//400条 saveBatch消耗时间1592毫秒 循环插入消耗时间1947毫秒
|
||||||
//1200条 saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
|
//1200条 saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
|
||||||
log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
|
log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
|
||||||
|
//update-end-author:taoyan date:20190528 for:批量插入数据
|
||||||
return Result.ok("文件导入成功!数据行数:" + list.size());
|
return Result.ok("文件导入成功!数据行数:" + list.size());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 代码逻辑说明: 导入数据重复增加提示
|
//update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示
|
||||||
String msg = e.getMessage();
|
String msg = e.getMessage();
|
||||||
log.error(msg, e);
|
log.error(msg, e);
|
||||||
if(msg!=null && msg.indexOf("Duplicate entry")>=0){
|
if(msg!=null && msg.indexOf("Duplicate entry")>=0){
|
||||||
@ -238,6 +191,7 @@ public class JeecgController<T, S extends IService<T>> {
|
|||||||
}else{
|
}else{
|
||||||
return Result.error("文件导入失败:" + e.getMessage());
|
return Result.error("文件导入失败:" + e.getMessage());
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20211124 for: 导入数据重复增加提示
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
file.getInputStream().close();
|
file.getInputStream().close();
|
||||||
@ -9,10 +9,10 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: Entity基类
|
* @Description: Entity基类
|
||||||
@ -2,6 +2,7 @@ package org.jeecg.common.system.query;
|
|||||||
|
|
||||||
import java.beans.PropertyDescriptor;
|
import java.beans.PropertyDescriptor;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@ -11,10 +12,10 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
|
||||||
import org.apache.commons.beanutils.PropertyUtils;
|
import org.apache.commons.beanutils.PropertyUtils;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.system.util.JeecgDataAutorUtils;
|
import org.jeecg.common.system.util.JeecgDataAutorUtils;
|
||||||
import org.jeecg.common.system.util.JwtUtil;
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
@ -24,6 +25,7 @@ import org.jeecg.common.util.*;
|
|||||||
import org.springframework.util.NumberUtils;
|
import org.springframework.util.NumberUtils;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -92,22 +94,7 @@ public class QueryGenerator {
|
|||||||
public static <T> QueryWrapper<T> initQueryWrapper(T searchObj,Map<String, String[]> parameterMap){
|
public static <T> QueryWrapper<T> initQueryWrapper(T searchObj,Map<String, String[]> parameterMap){
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
|
QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
|
||||||
installMplus(queryWrapper, searchObj, parameterMap, null);
|
installMplus(queryWrapper, searchObj, parameterMap);
|
||||||
log.debug("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
|
|
||||||
return queryWrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取查询条件构造器QueryWrapper实例 通用查询条件已被封装完成
|
|
||||||
* @param searchObj 查询实体
|
|
||||||
* @param parameterMap request.getParameterMap()
|
|
||||||
* @param customRuleMap 自定义字段查询规则 {field:QueryRuleEnum}
|
|
||||||
* @return QueryWrapper实例
|
|
||||||
*/
|
|
||||||
public static <T> QueryWrapper<T> initQueryWrapper(T searchObj,Map<String, String[]> parameterMap, Map<String, QueryRuleEnum> customRuleMap){
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
|
|
||||||
installMplus(queryWrapper, searchObj, parameterMap, customRuleMap);
|
|
||||||
log.debug("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
|
log.debug("---查询条件构造器初始化完成,耗时:"+(System.currentTimeMillis()-start)+"毫秒----");
|
||||||
return queryWrapper;
|
return queryWrapper;
|
||||||
}
|
}
|
||||||
@ -121,7 +108,8 @@ public class QueryGenerator {
|
|||||||
* <br>正确示例:QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>();
|
* <br>正确示例:QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>();
|
||||||
* <br>3.也可以不使用这个方法直接调用 {@link #initQueryWrapper}直接获取实例
|
* <br>3.也可以不使用这个方法直接调用 {@link #initQueryWrapper}直接获取实例
|
||||||
*/
|
*/
|
||||||
private static void installMplus(QueryWrapper<?> queryWrapper, Object searchObj, Map<String, String[]> parameterMap, Map<String, QueryRuleEnum> customRuleMap) {
|
private static void installMplus(QueryWrapper<?> queryWrapper,Object searchObj,Map<String, String[]> parameterMap) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 注意:权限查询由前端配置数据规则 当一个人有多个所属部门时候 可以在规则配置包含条件 orgCode 包含 #{sys_org_code}
|
* 注意:权限查询由前端配置数据规则 当一个人有多个所属部门时候 可以在规则配置包含条件 orgCode 包含 #{sys_org_code}
|
||||||
但是不支持在自定义SQL中写orgCode in #{sys_org_code}
|
但是不支持在自定义SQL中写orgCode in #{sys_org_code}
|
||||||
@ -140,6 +128,7 @@ public class QueryGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String name, type, column;
|
String name, type, column;
|
||||||
|
// update-begin--Author:taoyan Date:20200923 for:issues/1671 如果字段加注解了@TableField(exist = false),不走DB查询-------
|
||||||
//定义实体字段和数据库字段名称的映射 高级查询中 只能获取实体字段 如果设置TableField注解 那么查询条件会出问题
|
//定义实体字段和数据库字段名称的映射 高级查询中 只能获取实体字段 如果设置TableField注解 那么查询条件会出问题
|
||||||
Map<String,String> fieldColumnMap = new HashMap<>(5);
|
Map<String,String> fieldColumnMap = new HashMap<>(5);
|
||||||
for (int i = 0; i < origDescriptors.length; i++) {
|
for (int i = 0; i < origDescriptors.length; i++) {
|
||||||
@ -185,15 +174,8 @@ public class QueryGenerator {
|
|||||||
queryWrapper.and(j -> j.like(field,vals[0]));
|
queryWrapper.and(j -> j.like(field,vals[0]));
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
// 代码逻辑说明: [TV360X-378]增加自定义字段查询规则功能------------
|
//根据参数值带什么关键字符串判断走什么类型的查询
|
||||||
QueryRuleEnum rule;
|
QueryRuleEnum rule = convert2Rule(value);
|
||||||
if(null != customRuleMap && customRuleMap.containsKey(name)) {
|
|
||||||
// 有自定义规则,使用自定义规则.
|
|
||||||
rule = customRuleMap.get(name);
|
|
||||||
}else {
|
|
||||||
//根据参数值带什么关键字符串判断走什么类型的查询
|
|
||||||
rule = convert2Rule(value);
|
|
||||||
}
|
|
||||||
value = replaceValue(rule,value);
|
value = replaceValue(rule,value);
|
||||||
// add -begin 添加判断为字符串时设为全模糊查询
|
// add -begin 添加判断为字符串时设为全模糊查询
|
||||||
//if( (rule==null || QueryRuleEnum.EQ.equals(rule)) && "class java.lang.String".equals(type)) {
|
//if( (rule==null || QueryRuleEnum.EQ.equals(rule)) && "class java.lang.String".equals(type)) {
|
||||||
@ -213,6 +195,7 @@ public class QueryGenerator {
|
|||||||
|
|
||||||
//高级查询
|
//高级查询
|
||||||
doSuperQuery(queryWrapper, parameterMap, fieldColumnMap);
|
doSuperQuery(queryWrapper, parameterMap, fieldColumnMap);
|
||||||
|
// update-end--Author:taoyan Date:20200923 for:issues/1671 如果字段加注解了@TableField(exist = false),不走DB查询-------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,74 +236,15 @@ public class QueryGenerator {
|
|||||||
if(parameterMap!=null&& parameterMap.containsKey(ORDER_TYPE)) {
|
if(parameterMap!=null&& parameterMap.containsKey(ORDER_TYPE)) {
|
||||||
order = parameterMap.get(ORDER_TYPE)[0];
|
order = parameterMap.get(ORDER_TYPE)[0];
|
||||||
}
|
}
|
||||||
|
log.debug("排序规则>>列:" + column + ",排序方式:" + order);
|
||||||
if(oConvertUtils.isNotEmpty(column)){
|
|
||||||
log.debug("单字段排序规则>> column:" + column + ",排序方式:" + order);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 列表多字段排序优先
|
//update-begin-author:scott date:2022-11-07 for:避免用户自定义表无默认字段{创建时间},导致排序报错
|
||||||
if(parameterMap!=null&& parameterMap.containsKey("sortInfoString")) {
|
|
||||||
// 多字段排序
|
|
||||||
String sortInfoString = parameterMap.get("sortInfoString")[0];
|
|
||||||
log.debug("多字段排序规则>> sortInfoString:" + sortInfoString);
|
|
||||||
List<OrderItem> orderItemList = SqlConcatUtil.getQueryConditionOrders(column, order, sortInfoString);
|
|
||||||
log.debug(orderItemList.toString());
|
|
||||||
if (orderItemList != null && !orderItemList.isEmpty()) {
|
|
||||||
for (OrderItem item : orderItemList) {
|
|
||||||
// 一、获取排序数据库字段
|
|
||||||
String columnName = item.getColumn();
|
|
||||||
// 1.字典字段,去掉字典翻译文本后缀
|
|
||||||
if(columnName.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
|
|
||||||
columnName = columnName.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
|
|
||||||
}
|
|
||||||
// 2.实体驼峰字段转为数据库字段
|
|
||||||
columnName = SqlInjectionUtil.getSqlInjectSortField(columnName);
|
|
||||||
|
|
||||||
// 二、设置字段排序规则
|
|
||||||
if (item.isAsc()) {
|
|
||||||
queryWrapper.orderByAsc(columnName);
|
|
||||||
} else {
|
|
||||||
queryWrapper.orderByDesc(columnName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 列表单字段默认排序
|
|
||||||
if(oConvertUtils.isEmpty(column) && parameterMap!=null&& parameterMap.containsKey("defSortString")) {
|
|
||||||
// 多字段排序
|
|
||||||
String sortInfoString = parameterMap.get("defSortString")[0];
|
|
||||||
log.info("默认多字段排序规则>> defSortString:" + sortInfoString);
|
|
||||||
List<OrderItem> orderItemList = SqlConcatUtil.getQueryConditionOrders(column, order, sortInfoString);
|
|
||||||
log.info(orderItemList.toString());
|
|
||||||
if (orderItemList != null && !orderItemList.isEmpty()) {
|
|
||||||
for (OrderItem item : orderItemList) {
|
|
||||||
// 一、获取排序数据库字段
|
|
||||||
String columnName = item.getColumn();
|
|
||||||
// 1.字典字段,去掉字典翻译文本后缀
|
|
||||||
if(columnName.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
|
|
||||||
columnName = columnName.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
|
|
||||||
}
|
|
||||||
// 2.实体驼峰字段转为数据库字段
|
|
||||||
columnName = SqlInjectionUtil.getSqlInjectSortField(columnName);
|
|
||||||
|
|
||||||
// 二、设置字段排序规则
|
|
||||||
if (item.isAsc()) {
|
|
||||||
queryWrapper.orderByAsc(columnName);
|
|
||||||
} else {
|
|
||||||
queryWrapper.orderByDesc(columnName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO 避免用户自定义表无默认字段创建时间,导致排序报错
|
//TODO 避免用户自定义表无默认字段创建时间,导致排序报错
|
||||||
if(DataBaseConstant.CREATE_TIME.equals(column) && !fieldColumnMap.containsKey(DataBaseConstant.CREATE_TIME)){
|
if(DataBaseConstant.CREATE_TIME.equals(column) && !fieldColumnMap.containsKey(DataBaseConstant.CREATE_TIME)){
|
||||||
column = "id";
|
column = "id";
|
||||||
log.warn("检测到实体里没有字段createTime,改成采用ID排序!");
|
log.warn("检测到实体里没有字段createTime,改成采用ID排序!");
|
||||||
}
|
}
|
||||||
|
//update-end-author:scott date:2022-11-07 for:避免用户自定义表无默认字段{创建时间},导致排序报错
|
||||||
|
|
||||||
if (oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
|
if (oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
|
||||||
//字典字段,去掉字典翻译文本后缀
|
//字典字段,去掉字典翻译文本后缀
|
||||||
@ -328,12 +252,15 @@ public class QueryGenerator {
|
|||||||
column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
|
column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
//判断column是不是当前实体的
|
//判断column是不是当前实体的
|
||||||
log.debug("当前字段有:"+ allFields);
|
log.debug("当前字段有:"+ allFields);
|
||||||
if (!allColumnExist(column, allFields)) {
|
if (!allColumnExist(column, allFields)) {
|
||||||
throw new JeecgBootException("请注意,将要排序的列字段不存在:" + column);
|
throw new JeecgBootException("请注意,将要排序的列字段不存在:" + column);
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
|
|
||||||
|
//update-begin-author:scott date:2022-10-10 for:【jeecg-boot/issues/I5FJU6】doMultiFieldsOrder() 多字段排序方法存在问题
|
||||||
//多字段排序方法没有读取 MybatisPlus 注解 @TableField 里 value 的值
|
//多字段排序方法没有读取 MybatisPlus 注解 @TableField 里 value 的值
|
||||||
if (column.contains(",")) {
|
if (column.contains(",")) {
|
||||||
List<String> columnList = Arrays.asList(column.split(","));
|
List<String> columnList = Arrays.asList(column.split(","));
|
||||||
@ -344,10 +271,12 @@ public class QueryGenerator {
|
|||||||
}else{
|
}else{
|
||||||
column = fieldColumnMap.get(column);
|
column = fieldColumnMap.get(column);
|
||||||
}
|
}
|
||||||
|
//update-end-author:scott date:2022-10-10 for:【jeecg-boot/issues/I5FJU6】doMultiFieldsOrder() 多字段排序方法存在问题
|
||||||
|
|
||||||
//SQL注入check
|
//SQL注入check
|
||||||
SqlInjectionUtil.filterContentMulti(column);
|
SqlInjectionUtil.filterContent(column);
|
||||||
|
|
||||||
|
//update-begin--Author:scott Date:20210531 for:36 多条件排序无效问题修正-------
|
||||||
// 排序规则修改
|
// 排序规则修改
|
||||||
// 将现有排序 _ 前端传递排序条件{....,column: 'column1,column2',order: 'desc'} 翻译成sql "column1,column2 desc"
|
// 将现有排序 _ 前端传递排序条件{....,column: 'column1,column2',order: 'desc'} 翻译成sql "column1,column2 desc"
|
||||||
// 修改为 _ 前端传递排序条件{....,column: 'column1,column2',order: 'desc'} 翻译成sql "column1 desc,column2 desc"
|
// 修改为 _ 前端传递排序条件{....,column: 'column1,column2',order: 'desc'} 翻译成sql "column1 desc,column2 desc"
|
||||||
@ -356,9 +285,11 @@ public class QueryGenerator {
|
|||||||
} else {
|
} else {
|
||||||
queryWrapper.orderByDesc(SqlInjectionUtil.getSqlInjectSortFields(column.split(",")));
|
queryWrapper.orderByDesc(SqlInjectionUtil.getSqlInjectSortFields(column.split(",")));
|
||||||
}
|
}
|
||||||
|
//update-end--Author:scott Date:20210531 for:36 多条件排序无效问题修正-------
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
/**
|
/**
|
||||||
* 多字段排序 判断所传字段是否存在
|
* 多字段排序 判断所传字段是否存在
|
||||||
* @return
|
* @return
|
||||||
@ -378,6 +309,7 @@ public class QueryGenerator {
|
|||||||
}
|
}
|
||||||
return exist;
|
return exist;
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高级查询
|
* 高级查询
|
||||||
@ -390,46 +322,42 @@ public class QueryGenerator {
|
|||||||
String superQueryParams = parameterMap.get(SUPER_QUERY_PARAMS)[0];
|
String superQueryParams = parameterMap.get(SUPER_QUERY_PARAMS)[0];
|
||||||
String superQueryMatchType = parameterMap.get(SUPER_QUERY_MATCH_TYPE) != null ? parameterMap.get(SUPER_QUERY_MATCH_TYPE)[0] : MatchTypeEnum.AND.getValue();
|
String superQueryMatchType = parameterMap.get(SUPER_QUERY_MATCH_TYPE) != null ? parameterMap.get(SUPER_QUERY_MATCH_TYPE)[0] : MatchTypeEnum.AND.getValue();
|
||||||
MatchTypeEnum matchType = MatchTypeEnum.getByValue(superQueryMatchType);
|
MatchTypeEnum matchType = MatchTypeEnum.getByValue(superQueryMatchType);
|
||||||
// 代码逻辑说明: 高级查询的条件要用括号括起来,防止和用户的其他条件冲突 -------
|
// update-begin--Author:sunjianlei Date:20200325 for:高级查询的条件要用括号括起来,防止和用户的其他条件冲突 -------
|
||||||
try {
|
try {
|
||||||
superQueryParams = URLDecoder.decode(superQueryParams, "UTF-8");
|
superQueryParams = URLDecoder.decode(superQueryParams, "UTF-8");
|
||||||
List<QueryCondition> conditions = JSON.parseArray(superQueryParams, QueryCondition.class);
|
List<QueryCondition> conditions = JSON.parseArray(superQueryParams, QueryCondition.class);
|
||||||
if (conditions == null || conditions.size() == 0) {
|
if (conditions == null || conditions.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
|
// update-begin-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
|
||||||
List<QueryCondition> filterConditions = conditions.stream().filter(
|
List<QueryCondition> filterConditions = conditions.stream().filter(
|
||||||
rule -> (oConvertUtils.isNotEmpty(rule.getField())
|
rule -> oConvertUtils.isNotEmpty(rule.getField())
|
||||||
&& oConvertUtils.isNotEmpty(rule.getRule())
|
&& oConvertUtils.isNotEmpty(rule.getRule())
|
||||||
&& oConvertUtils.isNotEmpty(rule.getVal())
|
&& oConvertUtils.isNotEmpty(rule.getVal())
|
||||||
)
|
|
||||||
|| "empty".equals(rule.getRule())
|
|
||||||
).collect(Collectors.toList());
|
).collect(Collectors.toList());
|
||||||
if (filterConditions.size() == 0) {
|
if (filterConditions.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// update-end-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
|
||||||
log.debug("---高级查询参数-->" + filterConditions);
|
log.debug("---高级查询参数-->" + filterConditions);
|
||||||
|
|
||||||
queryWrapper.and(andWrapper -> {
|
queryWrapper.and(andWrapper -> {
|
||||||
for (int i = 0; i < filterConditions.size(); i++) {
|
for (int i = 0; i < filterConditions.size(); i++) {
|
||||||
QueryCondition rule = filterConditions.get(i);
|
QueryCondition rule = filterConditions.get(i);
|
||||||
if (
|
if (oConvertUtils.isNotEmpty(rule.getField())
|
||||||
(
|
&& oConvertUtils.isNotEmpty(rule.getRule())
|
||||||
oConvertUtils.isNotEmpty(rule.getField()) && oConvertUtils.isNotEmpty(rule.getRule()) && oConvertUtils.isNotEmpty(rule.getVal())
|
&& oConvertUtils.isNotEmpty(rule.getVal())) {
|
||||||
)
|
|
||||||
|| "empty".equals(rule.getRule())
|
|
||||||
) {
|
|
||||||
|
|
||||||
log.debug("SuperQuery ==> " + rule.toString());
|
log.debug("SuperQuery ==> " + rule.toString());
|
||||||
|
|
||||||
// 代码逻辑说明: 【高级查询】 oracle 日期等于查询报错
|
//update-begin-author:taoyan date:20201228 for: 【高级查询】 oracle 日期等于查询报错
|
||||||
Object queryValue = rule.getVal();
|
Object queryValue = rule.getVal();
|
||||||
if("date".equals(rule.getType())){
|
if("date".equals(rule.getType())){
|
||||||
queryValue = DateUtils.str2Date(rule.getVal(),DateUtils.date_sdf.get());
|
queryValue = DateUtils.str2Date(rule.getVal(),DateUtils.date_sdf.get());
|
||||||
}else if("datetime".equals(rule.getType())){
|
}else if("datetime".equals(rule.getType())){
|
||||||
queryValue = DateUtils.str2Date(rule.getVal(), DateUtils.datetimeFormat.get());
|
queryValue = DateUtils.str2Date(rule.getVal(), DateUtils.datetimeFormat.get());
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 【/issues/I3VR8E】高级查询没有类型转换,查询参数都是字符串类型 ----
|
// update-begin--author:sunjianlei date:20210702 for:【/issues/I3VR8E】高级查询没有类型转换,查询参数都是字符串类型 ----
|
||||||
String dbType = rule.getDbType();
|
String dbType = rule.getDbType();
|
||||||
if (oConvertUtils.isNotEmpty(dbType)) {
|
if (oConvertUtils.isNotEmpty(dbType)) {
|
||||||
try {
|
try {
|
||||||
@ -462,8 +390,9 @@ public class QueryGenerator {
|
|||||||
log.error("高级查询值转换失败:", e);
|
log.error("高级查询值转换失败:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 【/issues/I3VR8E】高级查询没有类型转换,查询参数都是字符串类型 ----
|
// update-begin--author:sunjianlei date:20210702 for:【/issues/I3VR8E】高级查询没有类型转换,查询参数都是字符串类型 ----
|
||||||
addEasyQuery(andWrapper, fieldColumnMap.get(rule.getField()), QueryRuleEnum.getByValue(rule.getRule()), queryValue);
|
addEasyQuery(andWrapper, fieldColumnMap.get(rule.getField()), QueryRuleEnum.getByValue(rule.getRule()), queryValue);
|
||||||
|
//update-end-author:taoyan date:20201228 for: 【高级查询】 oracle 日期等于查询报错
|
||||||
|
|
||||||
// 如果拼接方式是OR,就拼接OR
|
// 如果拼接方式是OR,就拼接OR
|
||||||
if (MatchTypeEnum.OR == matchType && i < (filterConditions.size() - 1)) {
|
if (MatchTypeEnum.OR == matchType && i < (filterConditions.size() - 1)) {
|
||||||
@ -479,6 +408,7 @@ public class QueryGenerator {
|
|||||||
log.error("--高级查询拼接失败:" + e.getMessage());
|
log.error("--高级查询拼接失败:" + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
// update-end--Author:sunjianlei Date:20200325 for:高级查询的条件要用括号括起来,防止和用户的其他条件冲突 -------
|
||||||
}
|
}
|
||||||
//log.info(" superQuery getCustomSqlSegment: "+ queryWrapper.getCustomSqlSegment());
|
//log.info(" superQuery getCustomSqlSegment: "+ queryWrapper.getCustomSqlSegment());
|
||||||
}
|
}
|
||||||
@ -490,7 +420,7 @@ public class QueryGenerator {
|
|||||||
*/
|
*/
|
||||||
public static QueryRuleEnum convert2Rule(Object value) {
|
public static QueryRuleEnum convert2Rule(Object value) {
|
||||||
// 避免空数据
|
// 避免空数据
|
||||||
// 代码逻辑说明: 查询条件输入空格导致return null后续判断导致抛出null异常
|
// update-begin-author:taoyan date:20210629 for: 查询条件输入空格导致return null后续判断导致抛出null异常
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return QueryRuleEnum.EQ;
|
return QueryRuleEnum.EQ;
|
||||||
}
|
}
|
||||||
@ -498,8 +428,10 @@ public class QueryGenerator {
|
|||||||
if (val.length() == 0) {
|
if (val.length() == 0) {
|
||||||
return QueryRuleEnum.EQ;
|
return QueryRuleEnum.EQ;
|
||||||
}
|
}
|
||||||
|
// update-end-author:taoyan date:20210629 for: 查询条件输入空格导致return null后续判断导致抛出null异常
|
||||||
QueryRuleEnum rule =null;
|
QueryRuleEnum rule =null;
|
||||||
|
|
||||||
|
//update-begin--Author:scott Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284-------------------
|
||||||
//TODO 此处规则,只适用于 le lt ge gt
|
//TODO 此处规则,只适用于 le lt ge gt
|
||||||
// step 2 .>= =<
|
// step 2 .>= =<
|
||||||
int length2 = 2;
|
int length2 = 2;
|
||||||
@ -515,12 +447,14 @@ public class QueryGenerator {
|
|||||||
rule = QueryRuleEnum.getByValue(val.substring(0, 1));
|
rule = QueryRuleEnum.getByValue(val.substring(0, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-end--Author:scott Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284---------------------
|
||||||
|
|
||||||
// step 3 like
|
// step 3 like
|
||||||
// 代码逻辑说明: /issues/3382 默认带*就走模糊,但是如果只有一个*,那么走等于查询
|
//update-begin-author:taoyan for: /issues/3382 默认带*就走模糊,但是如果只有一个*,那么走等于查询
|
||||||
if(rule == null && val.equals(STAR)){
|
if(rule == null && val.equals(STAR)){
|
||||||
rule = QueryRuleEnum.EQ;
|
rule = QueryRuleEnum.EQ;
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan for: /issues/3382 默认带*就走模糊,但是如果只有一个*,那么走等于查询
|
||||||
if (rule == null && val.contains(STAR)) {
|
if (rule == null && val.contains(STAR)) {
|
||||||
if (val.startsWith(STAR) && val.endsWith(STAR)) {
|
if (val.startsWith(STAR) && val.endsWith(STAR)) {
|
||||||
rule = QueryRuleEnum.LIKE;
|
rule = QueryRuleEnum.LIKE;
|
||||||
@ -545,10 +479,12 @@ public class QueryGenerator {
|
|||||||
rule = QueryRuleEnum.EQ_WITH_ADD;
|
rule = QueryRuleEnum.EQ_WITH_ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin--Author:taoyan Date:20201229 for:initQueryWrapper组装sql查询条件错误 #284---------------------
|
||||||
//特殊处理:Oracle的表达式to_date('xxx','yyyy-MM-dd')含有逗号,会被识别为in查询,转为等于查询
|
//特殊处理:Oracle的表达式to_date('xxx','yyyy-MM-dd')含有逗号,会被识别为in查询,转为等于查询
|
||||||
if(rule == QueryRuleEnum.IN && val.indexOf(YYYY_MM_DD)>=0 && val.indexOf(TO_DATE)>=0){
|
if(rule == QueryRuleEnum.IN && val.indexOf(YYYY_MM_DD)>=0 && val.indexOf(TO_DATE)>=0){
|
||||||
rule = QueryRuleEnum.EQ;
|
rule = QueryRuleEnum.EQ;
|
||||||
}
|
}
|
||||||
|
//update-end--Author:taoyan Date:20201229 for:initQueryWrapper组装sql查询条件错误 #284---------------------
|
||||||
|
|
||||||
return rule != null ? rule : QueryRuleEnum.EQ;
|
return rule != null ? rule : QueryRuleEnum.EQ;
|
||||||
}
|
}
|
||||||
@ -568,10 +504,11 @@ public class QueryGenerator {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
String val = (value + "").toString().trim();
|
String val = (value + "").toString().trim();
|
||||||
// 代码逻辑说明: 查询条件的值为等号(=)bug #3443
|
//update-begin-author:taoyan date:20220302 for: 查询条件的值为等号(=)bug #3443
|
||||||
if(QueryRuleEnum.EQ.getValue().equals(val)){
|
if(QueryRuleEnum.EQ.getValue().equals(val)){
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20220302 for: 查询条件的值为等号(=)bug #3443
|
||||||
if (rule == QueryRuleEnum.LIKE) {
|
if (rule == QueryRuleEnum.LIKE) {
|
||||||
value = val.substring(1, val.length() - 1);
|
value = val.substring(1, val.length() - 1);
|
||||||
//mysql 模糊查询之特殊字符下划线 (_、\)
|
//mysql 模糊查询之特殊字符下划线 (_、\)
|
||||||
@ -589,19 +526,21 @@ public class QueryGenerator {
|
|||||||
} else if (rule == QueryRuleEnum.EQ_WITH_ADD) {
|
} else if (rule == QueryRuleEnum.EQ_WITH_ADD) {
|
||||||
value = val.replaceAll("\\+\\+", COMMA);
|
value = val.replaceAll("\\+\\+", COMMA);
|
||||||
}else {
|
}else {
|
||||||
// 代码逻辑说明: initQueryWrapper组装sql查询条件错误 #284-------------------
|
//update-begin--Author:scott Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284-------------------
|
||||||
if(val.startsWith(rule.getValue())){
|
if(val.startsWith(rule.getValue())){
|
||||||
//TODO 此处逻辑应该注释掉-> 如果查询内容中带有查询匹配规则符号,就会被截取的(比如:>=您好)
|
//TODO 此处逻辑应该注释掉-> 如果查询内容中带有查询匹配规则符号,就会被截取的(比如:>=您好)
|
||||||
value = val.replaceFirst(rule.getValue(),"");
|
value = val.replaceFirst(rule.getValue(),"");
|
||||||
}else if(val.startsWith(rule.getCondition()+QUERY_SEPARATE_KEYWORD)){
|
}else if(val.startsWith(rule.getCondition()+QUERY_SEPARATE_KEYWORD)){
|
||||||
value = val.replaceFirst(rule.getCondition()+QUERY_SEPARATE_KEYWORD,"").trim();
|
value = val.replaceFirst(rule.getCondition()+QUERY_SEPARATE_KEYWORD,"").trim();
|
||||||
}
|
}
|
||||||
|
//update-end--Author:scott Date:20190724 for:initQueryWrapper组装sql查询条件错误 #284-------------------
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addQueryByRule(QueryWrapper<?> queryWrapper,String name,String type,String value,QueryRuleEnum rule) throws ParseException {
|
private static void addQueryByRule(QueryWrapper<?> queryWrapper,String name,String type,String value,QueryRuleEnum rule) throws ParseException {
|
||||||
if(oConvertUtils.isNotEmpty(value)) {
|
if(oConvertUtils.isNotEmpty(value)) {
|
||||||
|
//update-begin--Author:sunjianlei Date:20220104 for:【JTC-409】修复逗号分割情况下没有转换类型,导致类型严格的数据库查询报错 -------------------
|
||||||
// 针对数字类型字段,多值查询
|
// 针对数字类型字段,多值查询
|
||||||
if(value.contains(COMMA)){
|
if(value.contains(COMMA)){
|
||||||
Object[] temp = Arrays.stream(value.split(COMMA)).map(v -> {
|
Object[] temp = Arrays.stream(value.split(COMMA)).map(v -> {
|
||||||
@ -617,6 +556,7 @@ public class QueryGenerator {
|
|||||||
}
|
}
|
||||||
Object temp = QueryGenerator.parseByType(value, type, rule);
|
Object temp = QueryGenerator.parseByType(value, type, rule);
|
||||||
addEasyQuery(queryWrapper, name, rule, temp);
|
addEasyQuery(queryWrapper, name, rule, temp);
|
||||||
|
//update-end--Author:sunjianlei Date:20220104 for:【JTC-409】修复逗号分割情况下没有转换类型,导致类型严格的数据库查询报错 -------------------
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,11 +633,7 @@ public class QueryGenerator {
|
|||||||
* @param value 查询条件值
|
* @param value 查询条件值
|
||||||
*/
|
*/
|
||||||
public static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
|
public static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
|
||||||
if (
|
if (name==null || value == null || rule == null || oConvertUtils.isEmpty(value)) {
|
||||||
(
|
|
||||||
name==null || value == null || rule == null || oConvertUtils.isEmpty(value)
|
|
||||||
)
|
|
||||||
&& !QueryRuleEnum.EMPTY.equals(rule)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
name = oConvertUtils.camelToUnderline(name);
|
name = oConvertUtils.camelToUnderline(name);
|
||||||
@ -709,9 +645,6 @@ public class QueryGenerator {
|
|||||||
case GE:
|
case GE:
|
||||||
queryWrapper.ge(name, value);
|
queryWrapper.ge(name, value);
|
||||||
break;
|
break;
|
||||||
case EMPTY:
|
|
||||||
queryWrapper.isNull(name);
|
|
||||||
break;
|
|
||||||
case LT:
|
case LT:
|
||||||
queryWrapper.lt(name, value);
|
queryWrapper.lt(name, value);
|
||||||
break;
|
break;
|
||||||
@ -731,12 +664,13 @@ public class QueryGenerator {
|
|||||||
}else if(value instanceof String[]) {
|
}else if(value instanceof String[]) {
|
||||||
queryWrapper.in(name, (Object[]) value);
|
queryWrapper.in(name, (Object[]) value);
|
||||||
}
|
}
|
||||||
// 代码逻辑说明: 【bug】in 类型多值查询 不适配postgresql #1671
|
//update-begin-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
|
||||||
else if(value.getClass().isArray()) {
|
else if(value.getClass().isArray()) {
|
||||||
queryWrapper.in(name, (Object[])value);
|
queryWrapper.in(name, (Object[])value);
|
||||||
}else {
|
}else {
|
||||||
queryWrapper.in(name, value);
|
queryWrapper.in(name, value);
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
|
||||||
break;
|
break;
|
||||||
case LIKE:
|
case LIKE:
|
||||||
queryWrapper.like(name, value);
|
queryWrapper.like(name, value);
|
||||||
@ -744,39 +678,9 @@ public class QueryGenerator {
|
|||||||
case LEFT_LIKE:
|
case LEFT_LIKE:
|
||||||
queryWrapper.likeLeft(name, value);
|
queryWrapper.likeLeft(name, value);
|
||||||
break;
|
break;
|
||||||
case NOT_LEFT_LIKE:
|
|
||||||
queryWrapper.notLikeLeft(name, value);
|
|
||||||
break;
|
|
||||||
case RIGHT_LIKE:
|
case RIGHT_LIKE:
|
||||||
queryWrapper.likeRight(name, value);
|
queryWrapper.likeRight(name, value);
|
||||||
break;
|
break;
|
||||||
case NOT_RIGHT_LIKE:
|
|
||||||
queryWrapper.notLikeRight(name, value);
|
|
||||||
break;
|
|
||||||
// 代码逻辑说明: [TV360X-378]下拉多框根据条件查询不出来:增加自定义字段查询规则功能------------
|
|
||||||
case LIKE_WITH_OR:
|
|
||||||
final String nameFinal = name;
|
|
||||||
Object[] vals;
|
|
||||||
if (value instanceof String) {
|
|
||||||
vals = value.toString().split(COMMA);
|
|
||||||
} else if (value instanceof String[]) {
|
|
||||||
vals = (Object[]) value;
|
|
||||||
}
|
|
||||||
// 代码逻辑说明: 【bug】in 类型多值查询 不适配postgresql #1671
|
|
||||||
else if (value.getClass().isArray()) {
|
|
||||||
vals = (Object[]) value;
|
|
||||||
} else {
|
|
||||||
vals = new Object[]{value};
|
|
||||||
}
|
|
||||||
queryWrapper.and(j -> {
|
|
||||||
log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}", nameFinal, "like", vals[0]);
|
|
||||||
j = j.like(nameFinal, vals[0]);
|
|
||||||
for (int k = 1; k < vals.length; k++) {
|
|
||||||
j = j.or().like(nameFinal, vals[k]);
|
|
||||||
log.info("---查询过滤器,Query规则 .or()---field:{}, rule:{}, value:{}", nameFinal, "like", vals[k]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
log.info("--查询规则未匹配到---");
|
log.info("--查询规则未匹配到---");
|
||||||
break;
|
break;
|
||||||
@ -790,9 +694,7 @@ public class QueryGenerator {
|
|||||||
private static boolean judgedIsUselessField(String name) {
|
private static boolean judgedIsUselessField(String name) {
|
||||||
return "class".equals(name) || "ids".equals(name)
|
return "class".equals(name) || "ids".equals(name)
|
||||||
|| "page".equals(name) || "rows".equals(name)
|
|| "page".equals(name) || "rows".equals(name)
|
||||||
//// https://github.com/jeecgboot/JeecgBoot/issues/6937
|
|| "sort".equals(name) || "order".equals(name);
|
||||||
// || "sort".equals(name) || "order".equals(name)
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -804,12 +706,13 @@ public class QueryGenerator {
|
|||||||
public static Map<String, SysPermissionDataRuleModel> getRuleMap() {
|
public static Map<String, SysPermissionDataRuleModel> getRuleMap() {
|
||||||
Map<String, SysPermissionDataRuleModel> ruleMap = new HashMap<>(5);
|
Map<String, SysPermissionDataRuleModel> ruleMap = new HashMap<>(5);
|
||||||
List<SysPermissionDataRuleModel> list = null;
|
List<SysPermissionDataRuleModel> list = null;
|
||||||
// 代码逻辑说明: QQYUN-5441 【简流】获取多个用户/部门/角色 设置部门查询 报错
|
//update-begin-author:taoyan date:2023-6-1 for:QQYUN-5441 【简流】获取多个用户/部门/角色 设置部门查询 报错
|
||||||
try {
|
try {
|
||||||
list = JeecgDataAutorUtils.loadDataSearchConditon();
|
list = JeecgDataAutorUtils.loadDataSearchConditon();
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
log.error("根据request对象获取权限数据失败,可能是定时任务中执行的。", e);
|
log.error("根据request对象获取权限数据失败,可能是定时任务中执行的。", e);
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2023-6-1 for:QQYUN-5441 【简流】获取多个用户/部门/角色 设置部门查询 报错
|
||||||
if(list != null&&list.size()>0){
|
if(list != null&&list.size()>0){
|
||||||
if(list.get(0)==null){
|
if(list.get(0)==null){
|
||||||
return ruleMap;
|
return ruleMap;
|
||||||
@ -846,8 +749,7 @@ public class QueryGenerator {
|
|||||||
addEasyQuery(queryWrapper, name, rule, DateUtils.str2Date(dateStr,DateUtils.datetimeFormat.get()));
|
addEasyQuery(queryWrapper, name, rule, DateUtils.str2Date(dateStr,DateUtils.datetimeFormat.get()));
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
// 代码逻辑说明: [issues/7481]多租户模式下 数据权限使用变量:#{tenant_id} 报错------------
|
addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(dataRule.getRuleValue(), propertyType));
|
||||||
addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(converRuleValue(dataRule.getRuleValue()), propertyType));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -880,9 +782,6 @@ public class QueryGenerator {
|
|||||||
public static String getSqlRuleValue(String sqlRule){
|
public static String getSqlRuleValue(String sqlRule){
|
||||||
try {
|
try {
|
||||||
Set<String> varParams = getSqlRuleParams(sqlRule);
|
Set<String> varParams = getSqlRuleParams(sqlRule);
|
||||||
if (varParams == null || varParams.isEmpty()) {
|
|
||||||
return sqlRule;
|
|
||||||
}
|
|
||||||
for(String var:varParams){
|
for(String var:varParams){
|
||||||
String tempValue = converRuleValue(var);
|
String tempValue = converRuleValue(var);
|
||||||
sqlRule = sqlRule.replace("#{"+var+"}",tempValue);
|
sqlRule = sqlRule.replace("#{"+var+"}",tempValue);
|
||||||
@ -901,8 +800,7 @@ public class QueryGenerator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Set<String> varParams = new HashSet<String>();
|
Set<String> varParams = new HashSet<String>();
|
||||||
// 代码逻辑说明: [QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
String regex = "\\#\\{\\w+\\}";
|
||||||
String regex = "#\\{\\[*\\w+]*}";
|
|
||||||
|
|
||||||
Pattern p = Pattern.compile(regex);
|
Pattern p = Pattern.compile(regex);
|
||||||
Matcher m = p.matcher(sql);
|
Matcher m = p.matcher(sql);
|
||||||
@ -958,8 +856,7 @@ public class QueryGenerator {
|
|||||||
Class propType = origDescriptors[i].getPropertyType();
|
Class propType = origDescriptors[i].getPropertyType();
|
||||||
boolean isString = propType.equals(String.class);
|
boolean isString = propType.equals(String.class);
|
||||||
Object value;
|
Object value;
|
||||||
// 代码逻辑说明: [TV360X-539]数据权限,配置日期等于条件时后端报转换错误------------
|
if(isString) {
|
||||||
if(isString || Date.class.equals(propType)) {
|
|
||||||
value = converRuleValue(dataRule.getRuleValue());
|
value = converRuleValue(dataRule.getRuleValue());
|
||||||
}else {
|
}else {
|
||||||
value = NumberUtils.parseNumber(dataRule.getRuleValue(),propType);
|
value = NumberUtils.parseNumber(dataRule.getRuleValue(),propType);
|
||||||
@ -33,37 +33,23 @@ public enum QueryRuleEnum {
|
|||||||
RIGHT_LIKE("RIGHT_LIKE","right_like","右模糊"),
|
RIGHT_LIKE("RIGHT_LIKE","right_like","右模糊"),
|
||||||
/**查询规则 带加号等于*/
|
/**查询规则 带加号等于*/
|
||||||
EQ_WITH_ADD("EQWITHADD","eq_with_add","带加号等于"),
|
EQ_WITH_ADD("EQWITHADD","eq_with_add","带加号等于"),
|
||||||
/**查询规则 多词模糊匹配(and)*/
|
/**查询规则 多词模糊匹配*/
|
||||||
LIKE_WITH_AND("LIKEWITHAND","like_with_and","多词模糊匹配————暂时未用上"),
|
LIKE_WITH_AND("LIKEWITHAND","like_with_and","多词模糊匹配————暂时未用上"),
|
||||||
/**查询规则 多词模糊匹配(or)*/
|
|
||||||
LIKE_WITH_OR("LIKEWITHOR","like_with_or","多词模糊匹配(or)"),
|
|
||||||
/**查询规则 自定义SQL片段*/
|
/**查询规则 自定义SQL片段*/
|
||||||
SQL_RULES("USE_SQL_RULES","ext","自定义SQL片段"),
|
SQL_RULES("USE_SQL_RULES","ext","自定义SQL片段"),
|
||||||
|
|
||||||
/** 查询工作表 */
|
|
||||||
LINKAGE("LINKAGE","linkage","查询工作表"),
|
|
||||||
|
|
||||||
// ------- 当前表单设计器内专用 -------
|
// ------- 当前表单设计器内专用 -------
|
||||||
/**查询规则 不以…结尾*/
|
|
||||||
NOT_LEFT_LIKE("NOT_LEFT_LIKE","not_left_like","不以…结尾"),
|
|
||||||
/**查询规则 不以…开头*/
|
|
||||||
NOT_RIGHT_LIKE("NOT_RIGHT_LIKE","not_right_like","不以…开头"),
|
|
||||||
/** 值为空 */
|
/** 值为空 */
|
||||||
EMPTY("EMPTY","empty","值为空"),
|
EMPTY("EMPTY","empty","值为空"),
|
||||||
/** 值不为空 */
|
/** 值不为空 */
|
||||||
NOT_EMPTY("NOT_EMPTY","not_empty","值不为空"),
|
NOT_EMPTY("NOT_EMPTY","not_empty","值不为空"),
|
||||||
/**查询规则 不包含*/
|
/**查询规则 不包含*/
|
||||||
NOT_IN("NOT_IN","not_in","不包含"),
|
NOT_IN("NOT_IN","not_in","不包含"),
|
||||||
/**查询规则 多词精确匹配*/
|
/**查询规则 多词匹配*/
|
||||||
ELE_MATCH("ELE_MATCH","elemMatch","多词匹配"),
|
ELE_MATCH("ELE_MATCH","elemMatch","多词匹配"),
|
||||||
/**查询规则 多词精确不匹配*/
|
|
||||||
ELE_NOT_MATCH("ELE_NOT_MATCH","elemNotMatch","多词精确不匹配"),
|
|
||||||
/**查询规则 范围查询*/
|
/**查询规则 范围查询*/
|
||||||
RANGE("RANGE","range","范围查询"),
|
RANGE("RANGE","range","范围查询"),
|
||||||
/**查询规则 不在范围内查询*/
|
NOT_RANGE("NOT_RANGE","not_range","不在范围查询");
|
||||||
NOT_RANGE("NOT_RANGE","not_range","不在范围查询"),
|
|
||||||
/** 自定义mongodb查询语句 */
|
|
||||||
CUSTOM_MONGODB("CUSTOM_MONGODB","custom_mongodb","自定义mongodb查询语句");
|
|
||||||
// ------- 当前表单设计器内专用 -------
|
// ------- 当前表单设计器内专用 -------
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package org.jeecg.common.system.util;
|
package org.jeecg.common.system.util;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.auth0.jwt.JWT;
|
import com.auth0.jwt.JWT;
|
||||||
import com.auth0.jwt.JWTVerifier;
|
import com.auth0.jwt.JWTVerifier;
|
||||||
import com.auth0.jwt.algorithms.Algorithm;
|
import com.auth0.jwt.algorithms.Algorithm;
|
||||||
@ -10,9 +12,9 @@ import com.google.common.base.Joiner;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Date;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -20,7 +22,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
@ -32,6 +34,22 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
|
|||||||
import org.jeecg.common.util.DateUtils;
|
import org.jeecg.common.util.DateUtils;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.config.security.self.SelfAuthenticationProvider;
|
||||||
|
import org.jeecg.config.security.self.SelfAuthenticationToken;
|
||||||
|
import org.jeecg.config.security.utils.SecureUtil;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.oauth2.core.*;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author Scott
|
* @Author Scott
|
||||||
@ -41,36 +59,36 @@ import org.jeecg.common.util.oConvertUtils;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class JwtUtil {
|
public class JwtUtil {
|
||||||
|
|
||||||
/**PC端,Token有效期为7天(Token在reids中缓存时间为两倍)*/
|
/**Token有效期为7天(Token在reids中缓存时间为两倍)*/
|
||||||
public static final long EXPIRE_TIME = (7 * 12) * 60 * 60 * 1000L;
|
public static final long EXPIRE_TIME = (7 * 12) * 60 * 60 * 1000;
|
||||||
/**APP端,Token有效期为30天(Token在reids中缓存时间为两倍)*/
|
|
||||||
public static final long APP_EXPIRE_TIME = (30 * 12) * 60 * 60 * 1000L;
|
|
||||||
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
|
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
|
||||||
|
|
||||||
|
public static final String DEFAULT_CLIENT = "jeecg-client";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param response
|
* @param response
|
||||||
* @param code
|
* @param code
|
||||||
* @param errorMsg
|
* @param errorMsg
|
||||||
*/
|
*/
|
||||||
public static void responseError(HttpServletResponse response, Integer code, String errorMsg) {
|
public static void responseError(ServletResponse response, Integer code, String errorMsg) {
|
||||||
try {
|
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||||
Result jsonResult = new Result(code, errorMsg);
|
// issues/I4YH95浏览器显示乱码问题
|
||||||
jsonResult.setSuccess(false);
|
httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
|
||||||
|
Result jsonResult = new Result(code, errorMsg);
|
||||||
// 设置响应头和内容类型
|
jsonResult.setSuccess(false);
|
||||||
response.setStatus(code);
|
OutputStream os = null;
|
||||||
response.setHeader("Content-type", "text/html;charset=UTF-8");
|
try {
|
||||||
response.setContentType("application/json;charset=UTF-8");
|
os = httpServletResponse.getOutputStream();
|
||||||
// 使用 ObjectMapper 序列化为 JSON 字符串
|
httpServletResponse.setCharacterEncoding("UTF-8");
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
httpServletResponse.setStatus(code);
|
||||||
String json = objectMapper.writeValueAsString(jsonResult);
|
os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
|
||||||
response.getWriter().write(json);
|
os.flush();
|
||||||
response.getWriter().flush();
|
os.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e.getMessage(), e);
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验token是否正确
|
* 校验token是否正确
|
||||||
@ -82,13 +100,11 @@ public class JwtUtil {
|
|||||||
public static boolean verify(String token, String username, String secret) {
|
public static boolean verify(String token, String username, String secret) {
|
||||||
try {
|
try {
|
||||||
// 根据密码生成JWT效验器
|
// 根据密码生成JWT效验器
|
||||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
JwtDecoder jwtDecoder = SpringContextUtils.getBean(JwtDecoder.class);
|
||||||
JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
|
|
||||||
// 效验TOKEN
|
// 效验TOKEN
|
||||||
DecodedJWT jwt = verifier.verify(token);
|
jwtDecoder.decode(token);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception exception) {
|
||||||
log.warn("Token验证失败:" + e.getMessage(),e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,90 +117,34 @@ public class JwtUtil {
|
|||||||
public static String getUsername(String token) {
|
public static String getUsername(String token) {
|
||||||
try {
|
try {
|
||||||
DecodedJWT jwt = JWT.decode(token);
|
DecodedJWT jwt = JWT.decode(token);
|
||||||
return jwt.getClaim("username").asString();
|
LoginUser loginUser = JSONObject.parseObject(jwt.getClaim("sub").asString(), LoginUser.class);
|
||||||
|
return loginUser.getUsername();
|
||||||
} catch (JWTDecodeException e) {
|
} catch (JWTDecodeException e) {
|
||||||
log.error(e.getMessage(), e);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成签名,5min后过期
|
* 生成token
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @param secret 用户的密码
|
* @param secret 用户的密码
|
||||||
* @return 加密的token
|
* @return 加密的token
|
||||||
* @deprecated 请使用sign(String username, String secret, String clientType)方法代替
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static String sign(String username, String secret) {
|
public static String sign(String username, String secret) {
|
||||||
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
|
Map<String, Object> additionalParameter = new HashMap<>();
|
||||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
additionalParameter.put("username", username);
|
||||||
// 附带username信息
|
|
||||||
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
|
|
||||||
|
|
||||||
}
|
RegisteredClientRepository registeredClientRepository = SpringContextUtils.getBean(RegisteredClientRepository.class);
|
||||||
|
SelfAuthenticationProvider selfAuthenticationProvider = SpringContextUtils.getBean(SelfAuthenticationProvider.class);
|
||||||
|
|
||||||
|
OAuth2ClientAuthenticationToken client = new OAuth2ClientAuthenticationToken(Objects.requireNonNull(registeredClientRepository.findByClientId("jeecg-client")), ClientAuthenticationMethod.CLIENT_SECRET_BASIC, null);
|
||||||
|
client.setAuthenticated(true);
|
||||||
|
SelfAuthenticationToken selfAuthenticationToken = new SelfAuthenticationToken(client, additionalParameter);
|
||||||
|
selfAuthenticationToken.setAuthenticated(true);
|
||||||
|
OAuth2AccessTokenAuthenticationToken accessToken = (OAuth2AccessTokenAuthenticationToken) selfAuthenticationProvider.authenticate(selfAuthenticationToken);
|
||||||
|
return accessToken.getAccessToken().getTokenValue();
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成签名,5min后过期
|
|
||||||
*
|
|
||||||
* @param username 用户名
|
|
||||||
* @param secret 用户的密码
|
|
||||||
* @param expireTime 过期时间
|
|
||||||
* @return 加密的token
|
|
||||||
* @deprecated 请使用sign(String username, String secret, String clientType)方法代替
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static String sign(String username, String secret, Long expireTime) {
|
|
||||||
Date date = new Date(System.currentTimeMillis() + expireTime);
|
|
||||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
|
||||||
// 附带username信息
|
|
||||||
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成签名,根据客户端类型自动选择过期时间
|
|
||||||
* for [JHHB-1030]【鉴权】移动端用户token到期后续期时间变成pc端时长
|
|
||||||
*
|
|
||||||
* @param username 用户名
|
|
||||||
* @param secret 用户的密码
|
|
||||||
* @param clientType 客户端类型(PC或APP)
|
|
||||||
* @return 加密的token
|
|
||||||
*/
|
|
||||||
public static String sign(String username, String secret, String clientType) {
|
|
||||||
// 根据客户端类型选择对应的过期时间
|
|
||||||
long expireTime = CommonConstant.CLIENT_TYPE_APP.equalsIgnoreCase(clientType)
|
|
||||||
? APP_EXPIRE_TIME
|
|
||||||
: EXPIRE_TIME;
|
|
||||||
Date date = new Date(System.currentTimeMillis() + expireTime);
|
|
||||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
|
||||||
// 附带username和clientType信息
|
|
||||||
return JWT.create()
|
|
||||||
.withClaim("username", username)
|
|
||||||
.withClaim("clientType", clientType)
|
|
||||||
.withExpiresAt(date)
|
|
||||||
.sign(algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从token中获取客户端类型
|
|
||||||
* for [JHHB-1030]【鉴权】移动端用户token到期后续期时间变成pc端时长
|
|
||||||
*
|
|
||||||
* @param token JWT token
|
|
||||||
* @return 客户端类型,如果不存在则返回PC(兼容旧token)
|
|
||||||
*/
|
|
||||||
public static String getClientType(String token) {
|
|
||||||
try {
|
|
||||||
DecodedJWT jwt = JWT.decode(token);
|
|
||||||
String clientType = jwt.getClaim("clientType").asString();
|
|
||||||
// 如果clientType为空,返回默认值PC(兼容旧token)
|
|
||||||
return oConvertUtils.isNotEmpty(clientType) ? clientType : CommonConstant.CLIENT_TYPE_PC;
|
|
||||||
} catch (JWTDecodeException e) {
|
|
||||||
log.warn("解析token中的clientType失败,使用默认值PC:" + e.getMessage());
|
|
||||||
return CommonConstant.CLIENT_TYPE_PC;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,7 +208,7 @@ public class JwtUtil {
|
|||||||
//2.通过shiro获取登录用户信息
|
//2.通过shiro获取登录用户信息
|
||||||
LoginUser sysUser = null;
|
LoginUser sysUser = null;
|
||||||
try {
|
try {
|
||||||
sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
sysUser = SecureUtil.currentUser();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("SecurityUtils.getSubject() 获取用户信息异常:" + e.getMessage());
|
log.warn("SecurityUtils.getSubject() 获取用户信息异常:" + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -266,14 +226,6 @@ public class JwtUtil {
|
|||||||
} else {
|
} else {
|
||||||
key = key;
|
key = key;
|
||||||
}
|
}
|
||||||
// 是否存在字符串标志
|
|
||||||
boolean multiStr;
|
|
||||||
if(oConvertUtils.isNotEmpty(key) && key.trim().matches("^\\[\\w+]$")){
|
|
||||||
key = key.substring(1,key.length()-1);
|
|
||||||
multiStr = true;
|
|
||||||
} else {
|
|
||||||
multiStr = false;
|
|
||||||
}
|
|
||||||
//替换为当前系统时间(年月日)
|
//替换为当前系统时间(年月日)
|
||||||
if (key.equals(DataBaseConstant.SYS_DATE)|| key.toLowerCase().equals(DataBaseConstant.SYS_DATE_TABLE)) {
|
if (key.equals(DataBaseConstant.SYS_DATE)|| key.toLowerCase().equals(DataBaseConstant.SYS_DATE_TABLE)) {
|
||||||
returnValue = DateUtils.formatDate();
|
returnValue = DateUtils.formatDate();
|
||||||
@ -300,16 +252,6 @@ public class JwtUtil {
|
|||||||
returnValue = user.getSysUserCode();
|
returnValue = user.getSysUserCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换为系统登录用户ID
|
|
||||||
else if (key.equals(DataBaseConstant.SYS_USER_ID) || key.equalsIgnoreCase(DataBaseConstant.SYS_USER_ID_TABLE)) {
|
|
||||||
if(user==null) {
|
|
||||||
returnValue = sysUser.getId();
|
|
||||||
}else {
|
|
||||||
returnValue = user.getSysUserId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//替换为系统登录用户真实名字
|
//替换为系统登录用户真实名字
|
||||||
else if (key.equals(DataBaseConstant.SYS_USER_NAME)|| key.toLowerCase().equals(DataBaseConstant.SYS_USER_NAME_TABLE)) {
|
else if (key.equals(DataBaseConstant.SYS_USER_NAME)|| key.toLowerCase().equals(DataBaseConstant.SYS_USER_NAME_TABLE)) {
|
||||||
if(user==null) {
|
if(user==null) {
|
||||||
@ -327,54 +269,20 @@ public class JwtUtil {
|
|||||||
returnValue = user.getSysOrgCode();
|
returnValue = user.getSysOrgCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换为系统用户登录所使用的机构ID
|
|
||||||
else if (key.equals(DataBaseConstant.SYS_ORG_ID) || key.equalsIgnoreCase(DataBaseConstant.SYS_ORG_ID_TABLE)) {
|
|
||||||
if (user == null) {
|
|
||||||
returnValue = sysUser.getOrgId();
|
|
||||||
} else {
|
|
||||||
returnValue = user.getSysOrgId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//替换为系统用户所拥有的所有机构编码
|
//替换为系统用户所拥有的所有机构编码
|
||||||
else if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_MULTI_ORG_CODE_TABLE)) {
|
else if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_MULTI_ORG_CODE_TABLE)) {
|
||||||
if(user==null){
|
if(user==null){
|
||||||
//TODO 暂时使用用户登录部门,存在逻辑缺陷,不是用户所拥有的部门
|
//TODO 暂时使用用户登录部门,存在逻辑缺陷,不是用户所拥有的部门
|
||||||
returnValue = sysUser.getOrgCode();
|
returnValue = sysUser.getOrgCode();
|
||||||
// 代码逻辑说明: [QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
|
||||||
returnValue = multiStr ? "'" + returnValue + "'" : returnValue;
|
|
||||||
}else{
|
}else{
|
||||||
if(user.isOneDepart()) {
|
if(user.isOneDepart()) {
|
||||||
returnValue = user.getSysMultiOrgCode().get(0);
|
returnValue = user.getSysMultiOrgCode().get(0);
|
||||||
// 代码逻辑说明: [QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
|
||||||
returnValue = multiStr ? "'" + returnValue + "'" : returnValue;
|
|
||||||
}else {
|
}else {
|
||||||
// 代码逻辑说明: [QQYUN-10785]数据权限,查看自己拥有部门的权限中存在问题 #7288------------
|
returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
|
||||||
returnValue = user.getSysMultiOrgCode().stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.map(orgCode -> {
|
|
||||||
if (multiStr) {
|
|
||||||
return "'" + orgCode + "'";
|
|
||||||
} else {
|
|
||||||
return orgCode;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(Collectors.joining(", "));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-begin-author:taoyan date:20210330 for:多租户ID作为系统变量
|
||||||
// 替换为当前登录用户的角色code(多个逗号分割)
|
|
||||||
else if (key.equals(DataBaseConstant.SYS_ROLE_CODE) || key.equalsIgnoreCase(DataBaseConstant.SYS_ROLE_CODE_TABLE)) {
|
|
||||||
if (user == null) {
|
|
||||||
returnValue = sysUser.getRoleCode();
|
|
||||||
} else {
|
|
||||||
returnValue = user.getSysRoleCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 代码逻辑说明: 多租户ID作为系统变量
|
|
||||||
else if (key.equals(TenantConstant.TENANT_ID) || key.toLowerCase().equals(TenantConstant.TENANT_ID_TABLE)){
|
else if (key.equals(TenantConstant.TENANT_ID) || key.toLowerCase().equals(TenantConstant.TENANT_ID_TABLE)){
|
||||||
try {
|
try {
|
||||||
returnValue = SpringContextUtils.getHttpServletRequest().getHeader(CommonConstant.TENANT_ID);
|
returnValue = SpringContextUtils.getHttpServletRequest().getHeader(CommonConstant.TENANT_ID);
|
||||||
@ -382,6 +290,7 @@ public class JwtUtil {
|
|||||||
log.warn("获取系统租户异常:" + e.getMessage());
|
log.warn("获取系统租户异常:" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20210330 for:多租户ID作为系统变量
|
||||||
if(returnValue!=null){returnValue = returnValue + moshi;}
|
if(returnValue!=null){returnValue = returnValue + moshi;}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package org.jeecg.common.system.util;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.system.annotation.EnumDict;
|
||||||
|
import org.jeecg.common.system.vo.DictModel;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
|
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源加载工具类
|
||||||
|
* @Author taoYan
|
||||||
|
* @Date 2022/7/8 10:40
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class ResourceUtil {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枚举字典数据
|
||||||
|
*/
|
||||||
|
private final static Map<String, List<DictModel>> enumDictData = new HashMap<>(5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有java类
|
||||||
|
*/
|
||||||
|
private final static String CLASS_PATTERN="/**/*.class";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有枚举java类
|
||||||
|
*/
|
||||||
|
|
||||||
|
private final static String CLASS_ENUM_PATTERN="/**/*Enum.class";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包路径 org.jeecg
|
||||||
|
*/
|
||||||
|
private final static String BASE_PACKAGE = "org.jeecg";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枚举类中获取字典数据的方法名
|
||||||
|
*/
|
||||||
|
private final static String METHOD_NAME = "getDictList";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取枚举类对应的字典数据 SysDictServiceImpl#queryAllDictItems()
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Map<String, List<DictModel>> getEnumDictData(){
|
||||||
|
if(enumDictData.keySet().size()>0){
|
||||||
|
return enumDictData;
|
||||||
|
}
|
||||||
|
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||||
|
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + CLASS_ENUM_PATTERN;
|
||||||
|
try {
|
||||||
|
Resource[] resources = resourcePatternResolver.getResources(pattern);
|
||||||
|
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
|
||||||
|
for (Resource resource : resources) {
|
||||||
|
MetadataReader reader = readerFactory.getMetadataReader(resource);
|
||||||
|
String classname = reader.getClassMetadata().getClassName();
|
||||||
|
Class<?> clazz = Class.forName(classname);
|
||||||
|
EnumDict enumDict = clazz.getAnnotation(EnumDict.class);
|
||||||
|
if (enumDict != null) {
|
||||||
|
EnumDict annotation = clazz.getAnnotation(EnumDict.class);
|
||||||
|
String key = annotation.value();
|
||||||
|
if(oConvertUtils.isNotEmpty(key)){
|
||||||
|
List<DictModel> list = (List<DictModel>) clazz.getDeclaredMethod(METHOD_NAME).invoke(null);
|
||||||
|
enumDictData.put(key, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("获取枚举类字典数据异常", e.getMessage());
|
||||||
|
// e.printStackTrace();
|
||||||
|
}
|
||||||
|
return enumDictData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于后端字典翻译 SysDictServiceImpl#queryManyDictByKeys(java.util.List, java.util.List)
|
||||||
|
* @param dictCodeList
|
||||||
|
* @param keys
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys){
|
||||||
|
if(enumDictData.keySet().size()==0){
|
||||||
|
getEnumDictData();
|
||||||
|
}
|
||||||
|
Map<String, List<DictModel>> map = new HashMap<>();
|
||||||
|
for (String code : enumDictData.keySet()) {
|
||||||
|
if(dictCodeList.indexOf(code)>=0){
|
||||||
|
List<DictModel> dictItemList = enumDictData.get(code);
|
||||||
|
for(DictModel dm: dictItemList){
|
||||||
|
String value = dm.getValue();
|
||||||
|
if(keys.indexOf(value)>=0){
|
||||||
|
List<DictModel> list = new ArrayList<>();
|
||||||
|
list.add(new DictModel(value, dm.getText()));
|
||||||
|
map.put(code,list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +1,13 @@
|
|||||||
package org.jeecg.common.system.util;
|
package org.jeecg.common.system.util;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.system.query.QueryRuleEnum;
|
import org.jeecg.common.system.query.QueryRuleEnum;
|
||||||
import org.jeecg.common.util.CommonUtils;
|
import org.jeecg.common.util.CommonUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,7 +141,7 @@ public class SqlConcatUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String getInConditionValue(Object value,boolean isString) {
|
private static String getInConditionValue(Object value,boolean isString) {
|
||||||
// 代码逻辑说明: 查询条件如果输入,导致sql报错
|
//update-begin-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错
|
||||||
String[] temp = value.toString().split(",");
|
String[] temp = value.toString().split(",");
|
||||||
if(temp.length==0){
|
if(temp.length==0){
|
||||||
return "('')";
|
return "('')";
|
||||||
@ -168,6 +159,7 @@ public class SqlConcatUtil {
|
|||||||
}else {
|
}else {
|
||||||
return "("+value.toString()+")";
|
return "("+value.toString()+")";
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -214,6 +206,7 @@ public class SqlConcatUtil {
|
|||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题
|
||||||
// 走到这里说明 value不带有任何模糊查询的标识(*或者%)
|
// 走到这里说明 value不带有任何模糊查询的标识(*或者%)
|
||||||
if (ruleEnum == QueryRuleEnum.LEFT_LIKE) {
|
if (ruleEnum == QueryRuleEnum.LEFT_LIKE) {
|
||||||
if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
|
if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) {
|
||||||
@ -234,6 +227,7 @@ public class SqlConcatUtil {
|
|||||||
return "'%" + str + "%'";
|
return "'%" + str + "%'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,47 +239,5 @@ public class SqlConcatUtil {
|
|||||||
private static String getDbType() {
|
private static String getDbType() {
|
||||||
return CommonUtils.getDatabaseType();
|
return CommonUtils.getDatabaseType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取前端传过来的 "多字段排序信息: sortInfoString"
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static List<OrderItem> getQueryConditionOrders(String column, String order, String queryInfoString){
|
|
||||||
List<OrderItem> list = new ArrayList<>();
|
|
||||||
if(oConvertUtils.isEmpty(queryInfoString)){
|
|
||||||
//默认以创建时间倒序查询
|
|
||||||
if(CommonConstant.ORDER_TYPE_DESC.equalsIgnoreCase(order)){
|
|
||||||
list.add(OrderItem.desc(column));
|
|
||||||
}else{
|
|
||||||
list.add(OrderItem.asc(column));
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
// 【TV360X-967】URL解码(微服务下需要)
|
|
||||||
if (queryInfoString.contains("%22column%22")) {
|
|
||||||
log.info("queryInfoString 原生 = {}", queryInfoString);
|
|
||||||
try {
|
|
||||||
queryInfoString = URLDecoder.decode(queryInfoString, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new JeecgBootException(e);
|
|
||||||
}
|
|
||||||
log.info("queryInfoString 解码 = {}", queryInfoString);
|
|
||||||
}
|
|
||||||
JSONArray array = JSONArray.parseArray(queryInfoString);
|
|
||||||
Iterator it = array.iterator();
|
|
||||||
while(it.hasNext()){
|
|
||||||
JSONObject json = (JSONObject)it.next();
|
|
||||||
String tempColumn = json.getString("column");
|
|
||||||
if(oConvertUtils.isNotEmpty(tempColumn)){
|
|
||||||
String tempOrder = json.getString("order");
|
|
||||||
if(CommonConstant.ORDER_TYPE_DESC.equalsIgnoreCase(tempOrder)){
|
|
||||||
list.add(OrderItem.desc(tempColumn));
|
|
||||||
}else{
|
|
||||||
list.add(OrderItem.asc(tempColumn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user