Compare commits

..

1 Commits

Author SHA1 Message Date
83edfa9090 版本发布日期更新 2025-09-24 13:18:16 +08:00
269 changed files with 2957 additions and 109349 deletions

View File

@ -10,9 +10,6 @@ assignees: getActivity
##### 版本号:
##### 分支:
##### 问题描述:

View File

@ -6,12 +6,10 @@ assignees: getActivity
---
##### 版本号:
##### 分支:
##### 问题描述:

2
.gitignore vendored
View File

@ -13,5 +13,3 @@ os_del.cmd
os_del_doc.cmd
.svn
derby.log
.cursor
.history

View File

@ -12,7 +12,7 @@ Current version: 3.8.3 (Release date: 2025-10-09)
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
[![](https://img.shields.io/badge/Author-guojusoft-orange.svg)](http://www.jeecg.com)
[![](https://img.shields.io/badge/version-3.8.2-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![](https://img.shields.io/badge/version-3.8.3-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)

View File

@ -19,18 +19,16 @@ JeecgBoot AI低代码平台
<h3 align="center">企业级AI低代码平台</h3>
JeecgBoot 是一款基于BPM流程和代码生成的AI低代码平台助力企业快速实现低代码开发和构建AI应用。
采用前后端分离架构Ant Design&Vue3SpringBoot3SpringCloud AlibabaMybatis-plus,强大代码生成器实现前后端一键生成,无需手写代码。
平台引领AI低代码开发模式AI生成→在线编码→代码生成→手工合并,解决Java项目80%重复工作,提升效率节省成本,兼顾灵活性。
具备强大且颗粒化的权限控制支持按钮权限和数据权限设置满足大型业务系统需求。功能涵盖在线表单、表单设计、流程设计、门户设计、报表与大屏设计、OA办公、AI应用、AI知识库、大模型管理、AI流程编排、AI聊天支持ChatGPT、DeepSeek、Ollama等多种AI大模型。
JeecgBoot是一款企业级低代码平台集成了AI应用平台功能旨在帮助开发者快速实现低代码开发和构建、部署个性化的 AI 应用。
前后端分离架构Ant Design4、Vue3SpringBoot2/3SpringCloud AlibabaMybatis-plusShiro/SpringAuthorizationServer,强大代码生成器前后端代码一键生成,无需写任何代码;提供强大的报表和大屏工具,满足企业级数据产品需求!
引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE 帮助Java项目解决80%重复工作,让开发更多关注业务,提高效率节省成本,同时又不失灵活性低代码能力Online表单、表单设计、流程设计、Online报表、大屏/仪表盘设计、报表设计; AI应用平台功能AI知识库问答、AI模型管理、AI流程编排、AI聊天等支持含ChatGPT、DeepSeek、Ollama等多种AI大模型
`AI赋能报表:` 积木报表是一款自主研发的强大开源企业级Web报表与大屏工具。它通过零编码的拖拽式操作赋能用户如同搭积木般轻松构建各类复杂报表和数据大屏全面满足企业数据可视化与分析需求助力企业级数据产品的高效打造与应用。
`AI赋能低代码:` 提供完善成熟AI应用平台,涵盖AI应用管理、AI模型管理、智能对话助手、知识库问答、流程编排设计器AI建表等多项功能。平台兼容多种主流大模型,包括ChatGPT、DeepSeek、Ollama、智普、千问等助力企业高效构建智能化应用推动低代码开发与AI深度融合。
`AI赋能低代码:` 提供一套成熟AI应用平台功能:包含AI应用管理、AI模型管理、AI对话助手、AI知识库问答、AI流程编排、AI流程设计器AI建表等功能; 支持各种AI大模型ChatGPT、DeepSeek、Ollama、智普、千问等.
`JEECG宗旨是:` JEECG旨在通过OnlineCoding平台实现简单功能的零代码快速搭建,同时针对复杂功能采用代码生成器生成代码并手工合并,打造智能且灵活的低代码开发模式,有效解决了当前低代码产品普遍缺乏灵活性的问题,提升开发效率的同时兼顾系统的扩展性和定制化能力。
`JEECG宗旨是:` 简单功能由OnlineCoding零代码搭建做到`零代码开发`复杂功能代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`,解决了当前低代码产品普遍不灵活的弊端!
`JEECG业务流程:` JEECG业务流程采用BPM工作流引擎实现业务审批扩展任务接口供开发人员编写业务逻辑,表单提供表单设计器、在线配置表单编码表单等多种解决方案。通过流程与表单的分离设计(松耦合)任务节点灵活配置,既保障了企业流程的安全性与保密性,又大幅降低了开发人员的工作量。
`JEECG业务流程:` 采用工作流来实现、扩展任务接口供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单编码表单。同时实现了流程与表单的分离设计(松耦合)、并支持任务节点灵活配置,既保证了公司流程的保密性,又减少了开发人员的工作量。
@ -38,8 +36,8 @@ JeecgBoot 是一款基于BPM流程和代码生成的AI低代码平台助力
适用项目
-----------------------------------
JeecgBoot低代码平台兼容所有J2EE项目开发支持信创国产化,特别适用于SAAS、企业信息管理系统MIS、内部办公系统OA、企业资源计划系统ERP、客户关系管理系统CRMAI知识库等场景。其半智能手工Merge开发式,可显著提升70%以上的开发效率极大降低开发成本。同时JeecgBoot还是一款全栈式AI开发平台助力企业快速构建和部署个性化AI应用。
JeecgBoot低代码平台,可以应用在任何J2EE项目开发,支持信创国产化。尤其适合SAAS项目、企业信息管理系统MIS、内部办公系统OA、企业资源计划系统ERP、客户关系管理系统CRMAI知识库等其半智能手工Merge开发式,可显著提高开发效率70%以上,极大降低开发成本
又是一个全栈式 AI 开发平台,快速帮助企业构建和部署个性化的 AI 应用。
**信创兼容说明**
- 操作系统:国产麒麟、银河麒麟等国产系统几乎都是基于 Linux 内核,因此它们具有良好的兼容性。
@ -50,16 +48,15 @@ JeecgBoot低代码平台兼容所有J2EE项目开发支持信创国产化
版本说明
-----------------------------------
|下载 | SpringBoot3.5 + Shiro |SpringBoot3.5+ SpringAuthorizationServer | SpringBoot3.5 + Sa-Token | SpringBoot2.7(JDK17/JDK8) |
|------|----------------|----------------------------|-------------------|--------------------------------------------|
| Github | [`springboot3`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3) | [`springboot3_sas`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3_sas) 分支 | [`springboot3-satoken`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3-satoken) 分支|[`master`](https://github.com/jeecgboot/JeecgBoot) 分支|
| Gitee | [`springboot3`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3/) | [`springboot3_sas`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3_sas) 分支| [`springboot3-satoken`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3-satoken) 分支|[`master`](https://gitee.com/jeecg/JeecgBoot) 分支 |
|下载 | JDK17 + SpringBoot3.3 + Shiro |JDK17 + SpringBoot3.3+ SpringAuthorizationServer | JDK17/JDK8 + SpringBoot2.7 |
|------|----------------------------------------------------|-----------------------------------------------------------------------------|--------------------------------------------|
| Github | [`springboot3`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3) | [`springboot3_sas`](https://github.com/jeecgboot/JeecgBoot/tree/springboot3_sas) 分支 |[`master`](https://github.com/jeecgboot/JeecgBoot) 分支|
| Gitee | [`springboot3`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3/) | [`springboot3_sas`](https://gitee.com/jeecg/JeecgBoot/tree/springboot3_sas) 分支 |[`master`](https://gitee.com/jeecg/JeecgBoot) 分支 |
- `jeecg-boot` 是后端JAVA源码项目Springboot3+SpringCloudAlibaba(支持单体和微服务切换).
- `jeecg-boot` 是后端JAVA源码项目支持单体和微服务切换.
- `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制作一个精简版本
@ -84,7 +81,6 @@ JeecgBoot低代码平台兼容所有J2EE项目开发支持信创国产化
- 官方网站: [http://www.jeecg.com](http://www.jeecg.com)
- 在线演示: [平台演示](https://boot3.jeecg.com) | [APP演示](https://jeecg.com/appIndex)
- 入门指南: [快速入门](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)
- 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)
- QQ交流群 964611995、⑩716488839(满)、⑨808791225(满)、其他(满)
@ -106,7 +102,7 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块是一套类
为什么选择JeecgBoot?
-----------------------------------
- 1.采用最新主流前后分离框架Spring Boot3 + MyBatis + Shiro/SpringAuthorizationServer + Ant Design4 + Vue3容易上手代码生成器依赖性低灵活的扩展能力可快速实现二次开发。
- 1.采用最新主流前后分离框架Spring Boot3 + MyBatis + Shiro//SpringAuthorizationServer + Ant Design4 + Vue3容易上手代码生成器依赖性低灵活的扩展能力可快速实现二次开发。
- 2.前端大版本换代,最新版采用 Vue3.0 + TypeScript + Vite6 + Ant Design Vue4 等新技术方案。
- 3.支持微服务Spring Cloud AlibabaNacos、Gateway、Sentinel、Skywalking提供简易机制支持单体和微服务自由切换这样可以满足各类项目需求
- 4.开发效率高支持在线建表和AI建表提供强大代码生成器单表、树列表、一对多、一对一等数据模型增删改查功能一键生成菜单配置直接使用。
@ -159,9 +155,6 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块是一套类
#### 前端
- 前端环境要求Node.js要求`Node 20+` 版本以上、pnpm 要求`9+` 版本以上
` ( Vite 不再支持已结束生命周期EOL的 Node.js 18。现在需要使用 Node.js 20.19+ 或 22.12+)`
- 依赖管理node、npm、pnpm
- 前端IDE建议IDEA、WebStorm、Vscode
- 采用 Vue3.0+TypeScript+Vite6+Ant-Design-Vue4等新技术方案包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
@ -171,16 +164,16 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块是一套类
#### 后端
- IDE建议 IDEA (必须安装lombok插件 )
- 语言Java 默认jdk17(jdk21、jdk24)
- 语言Java 默认jdk17(支持jdk8、jdk21)
- 依赖管理Maven
- 基础框架Spring Boot 3.5.5
- 微服务框架: Spring Cloud Alibaba 2023.0.3.3
- 持久层框架MybatisPlus 3.5.12
- 基础框架Spring Boot 3.5.5/2.7.18
- 微服务框架: Spring Cloud Alibaba 2021.0.6.2
- 持久层框架MybatisPlus 3.5.3.2
- 报表工具: JimuReport 2.1.3
- 安全框架Apache Shiro 2.0.4Jwt 4.5.0
- 安全框架Apache Shiro/SpringAuthorizationServerJwt 4.5.0
- 微服务技术栈Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
- 数据库连接池阿里巴巴Druid 1.2.24
- AI大模型支持 `ChatGPT` `DeepSeek` `千问`等各种常规模式
- 数据库连接池阿里巴巴Druid 1.1.24
- AI大模型支持 `ChatGPT` `DeepSeek`切换
- 日志打印logback
- 缓存Redis
- 其他autopoi, fastjsonpoiSwagger-uiquartz, lombok简化代码等。

View File

@ -109,33 +109,28 @@ services:
# environment:
# RABBITMQ_DEFAULT_USER: guest
# RABBITMQ_DEFAULT_PASS: guest
# jeecg-boot-sentinel:
# restart: on-failure
# build:
# context: ./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
#
# jeecg-boot-xxljob:
# build:
# context: ./jeecg-visual/jeecg-cloud-xxljob
# ports:
# - 9080:9080
# container_name: jeecg-boot-xxljob
# hostname: jeecg-boot-xxljob
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

View File

@ -2,7 +2,7 @@
JeecgBoot 低代码开发平台
===============
当前最新版本: 3.8.3发布日期2025-10-09
当前最新版本: 3.8.3发布日期2025-09-22
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
@ -16,127 +16,43 @@ JeecgBoot 低代码开发平台
项目介绍
-----------------------------------
<h3 align="center">企业级AI低代码平台</h3>
JeecgBoot 是一款基于BPM流程和代码生成的AI低代码平台助力企业快速实现低代码开发和构建AI应用。
采用前后端分离架构Ant Design&Vue3SpringBoot3SpringCloud AlibabaMybatis-plus强大代码生成器实现前后端一键生成无需手写代码。
平台引领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工作流引擎实现业务审批扩展任务接口供开发人员编写业务逻辑表单提供表单设计器、在线配置表单和编码表单等多种解决方案。通过流程与表单的分离设计松耦合及任务节点的灵活配置既保障了企业流程的安全性与保密性又大幅降低了开发人员的工作量。
适用项目
-----------------------------------
JeecgBoot低代码平台兼容所有J2EE项目开发支持信创国产化特别适用于SAAS、企业信息管理系统MIS、内部办公系统OA、企业资源计划系统ERP、客户关系管理系统CRM及AI知识库等场景。其半智能手工Merge开发模式可显著提升70%以上的开发效率极大降低开发成本。同时JeecgBoot还是一款全栈式AI开发平台助力企业快速构建和部署个性化AI应用。。
**信创兼容说明**
- 操作系统:国产麒麟、银河麒麟等国产系统几乎都是基于 Linux 内核,因此它们具有良好的兼容性。
- 数据库达梦、人大金仓、TiDB
- 中间件:东方通 TongWeb、TongRDS宝兰德 AppServer、CacheDB, [信创配置文档](https://help.jeecg.com/java/tongweb-deploy/)
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
JeecgBoot 是一款基于代码生成器的`低代码开发平台`!前后端分离架构 SpringBoot2.x和3.xSpringCloudAnt Design Vue3Mybatis-plusShiroJWT支持微服务。强大的代码生成器让前后端代码一键生成实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE) 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
#### 项目说明
| 项目名 | 说明 |
|--------------------|------------------------------------|
| `jeecg-boot` | 后端源码JAVASpringBoot3微服务架构) |
| `jeecgboot-vue3` | 前端源码VUE3vue3+vite6+antd4+ts最新技术栈 |
| 项目名 | 说明 |
|--------------------|------------------------|
| `jeecg-boot` | 后端源码JAVASpringBoot微服务架构 |
| `jeecgboot-vue3` | 前端源码VUE3vue3+vite5+ts最新技术栈 |
启动项目
-----------------------------------
> 默认账号密码: admin/123456
- [开发环境搭建](https://help.jeecg.com/java/setup/tools)
- [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)
- 在线演示 [平台演示](https://boot3.jeecg.com) | [APP演示](https://jeecg.com/appIndex)
- 入门指南: [快速入门](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)
- 技术支持: [反馈问题](https://github.com/jeecgboot/JeecgBoot/issues/new?template=bug_report.md) | [低代码体验一分钟](https://jeecg.blog.csdn.net/article/details/106079007)
- 新手指南 [快速入门](http://www.jeecg.com/doc/quickstart)
- QQ交流群 964611995、⑩716488839(满)、⑨808791225(满)、其他(满)
- 在线演示 [在线演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
> 演示系统的登录账号密码,请点击 [获取账号密码](http://jeecg.com/doc/demo) 获取
AI 应用平台介绍
启动项目
-----------------------------------
一个全栈式 AI 开发平台,旨在帮助开发者快速构建和部署个性化的 AI 应用。
JeecgBoot平台提供了一套完善的AI应用管理系统模块是一套类似`Dify``AIGC应用开发平台`+`知识库问答`是一款基于LLM大语言模型AI应用平台和 RAG 的知识库问答系统。
其直观的界面结合了 AI 流程编排、RAG 管道、知识库管理、模型管理、对接向量库、实时运行可观察等让您可以快速从原型到生产拥有AI服务能力。
- [详细专题介绍,请点击查看](README-AI.md)
- AI视频介绍
[![](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/jeecg_aivideo.png)](https://www.bilibili.com/video/BV1zmd7YFE4w)
- [IDEA启动前后端项目](https://help.jeecg.com/java/setup/idea/startup)
- [Docker一键启动前后端](https://help.jeecg.com/java/docker/quick)
为什么选择JeecgBoot?
微服务启动
-----------------------------------
- 1.采用最新主流前后分离框架Spring Boot3 + MyBatis + Shiro/SpringAuthorizationServer + Ant Design4 + Vue3容易上手代码生成器依赖性低灵活的扩展能力可快速实现二次开发。
- 2.前端大版本换代,最新版采用 Vue3.0 + TypeScript + Vite6 + Ant Design Vue4 等新技术方案。
- 3.支持微服务Spring Cloud AlibabaNacos、Gateway、Sentinel、Skywalking提供简易机制支持单体和微服务自由切换这样可以满足各类项目需求
- 4.开发效率高支持在线建表和AI建表提供强大代码生成器单表、树列表、一对多、一对一等数据模型增删改查功能一键生成菜单配置直接使用。
- 5.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)。
- 6.提供强大的报表和大屏可视化工具,支持丰富的数据源连接,能够通过拖拉拽方式快速制作报表、大屏和门户设计;支持多种图表类型:柱形图、折线图、散点图、饼图、环形图、面积图、漏斗图、进度图、仪表盘、雷达图、地图等。
- 7.低代码能力在线表单无需编码通过在线配置表单实现表单的增删改查支持单表、树、一对多、一对一等模型实现人人皆可编码在线配置零代码开发、所见即所得支持23种类控件。
- 8.低代码能力:在线报表、在线图表(无需编码,通过在线配置方式,实现数据报表和图形报表,可以快速抽取数据,减轻开发压力,实现人人皆可编码)。
- 9.Online支持在线增强开发提供在线代码编辑器支持代码高亮、代码提示等功能支持多种语言Java、SQL、JavaScript等
- 10.封装完善的用户、角色、菜单、组织机构、数据字典、在线定时任务等基础功能,支持访问授权、按钮权限、数据权限等功能。
- 11.前端UI提供丰富的组件库支持各种常用组件如表格、树形控件、下拉框、日期选择器等满足各种复杂的业务需求 [UI组件库文档](https://help.jeecg.com/category/ui%E7%BB%84%E4%BB%B6%E5%BA%93)。
- 12.提供APP配套框架一份多代码多终端适配一份代码多终端适配小程序、H5、安卓、iOS、鸿蒙Next。
- 13.新版APP框架采用Uniapp、Vue3.0、Vite、Wot-design-uni、TypeScript等最新技术栈包括二次封装组件、路由拦截、请求拦截等功能。实现了与JeecgBoot完美对接目前已经实现登录、用户信息、通讯录、公告、移动首页、九宫格、聊天、Online表单、仪表盘等功能提供了丰富的组件。
- 14.提供了一套成熟的AI应用平台功能从AI模型、知识库到AI应用搭建助力企业快速落地AI服务加速智能化升级。
- 15.AI能力目前JeecgBoot支持AI大模型chatgpt和deepseek现在最新版默认使用deepseek速度更快质量更高。目前提供了AI对话助手、AI知识库、AI应用、AI建表、AI报表等功能。
- 16.提供新行编辑表格JVXETable轻松满足各种复杂ERP布局拥有更高的性能、更灵活的扩展、更强大的功能。
- 17.平台首页风格,提供多种组合模式,支持自定义风格;支持门户设计,支持自定义首页。
- 18.常用共通封装各种工具类定时任务、短信接口、邮件发送、Excel导入导出等基本满足80%项目需求。
- 19.简易Excel导入导出支持单表导出和一对多表模式导出生成的代码自带导入导出功能。
- 20.集成智能报表工具报表打印、图像报表和数据导出非常方便可极其方便地生成PDF、Excel、Word等报表。
- 21.采用前后分离技术页面UI风格精美针对常用组件做了封装时间、行表格控件、截取显示控件、报表组件、编辑器等。
- 22.查询过滤器查询功能自动生成后台动态拼SQL追加查询条件支持多种匹配方式全匹配/模糊查询/包含查询/不匹配查询)。
- 23.数据权限(精细化数据权限控制,控制到行级、列表级、表单字段级,实现不同人看不同数据,不同人对同一个页面操作不同字段)。
- 24.接口安全机制可细化控制接口授权非常简便实现不同客户端只看自己数据等控制也提供了基于AK和SK认证鉴权的OpenAPI功能。
- 25.活跃的社区支持;近年来,随着网络威胁的日益增加,团队在安全和漏洞管理方面积累了丰富的经验,能够为企业提供全面的安全解决方案。
- 26.权限控制采用RBACRole-Based Access Control基于角色的访问控制
- 27.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等)。
- 28.支持SaaS服务模式提供SaaS多租户架构方案。
- 29.分布式文件服务集成MinIO、阿里OSS等优秀的第三方提供便捷的文件上传与管理同时也支持本地存储。
- 30.主流数据库兼容一套代码完全兼容MySQL、PostgreSQL、Oracle、SQL Server、MariaDB、达梦、人大金仓等主流数据库。
- 31.集成工作流Flowable并实现了只需在页面配置流程转向可极大简化BPM工作流的开发用BPM的流程设计器画出了流程走向一个工作流基本就完成了只需写很少量的Java代码。
- 32.低代码能力在线流程设计采用开源Flowable流程引擎实现在线画流程、自定义表单、表单挂靠、业务流转。
- 33.多数据源:极其简易的使用方式,在线配置数据源配置,便捷地从其他数据抓取数据。
- 34.提供单点登录CAS集成方案项目中已经提供完善的对接代码。
- 35.低代码能力表单设计器支持用户自定义表单布局支持单表、一对多表单支持select、radio、checkbox、textarea、date、popup、列表、宏等控件。
- 36.专业接口对接机制统一采用RESTful接口方式集成Swagger-UI在线接口文档JWT token安全验证方便客户端对接。
- 37.高级组合查询功能,在线配置支持主子表关联查询,可保存查询历史。
- 38.提供各种系统监控实时跟踪系统运行情况监控Redis、Tomcat、JVM、服务器信息、请求追踪、SQL监控
- 39.消息中心支持短信、邮件、微信推送等集成WebSocket消息通知机制。
- 40.支持多语言,提供国际化方案。
- 41.数据变更记录日志,可记录数据每次变更内容,通过版本对比功能查看历史变化。
- 42.提供简单易用的打印插件支持谷歌、火狐、IE11+等各种浏览器。
- 43.后端采用Maven分模块开发方式前端支持菜单动态路由。
- 44.提供丰富的示例代码,涵盖了常用的业务场景,便于学习和参考。
- [单体快速切换微服务](https://help.jeecg.com/java/springcloud/switchcloud/monomer)
- [Docker启动微服务后台](https://help.jeecg.com/java/docker/springcloud)
技术架构:
@ -145,33 +61,28 @@ JeecgBoot平台提供了一套完善的AI应用管理系统模块是一套类
#### 后端
- IDE建议 IDEA (必须安装lombok插件 )
- 语言Java 默认jdk17(jdk21、jdk24)
- 语言Java 8+ (支持17)
- 依赖管理Maven
- 基础框架Spring Boot 3.5.5
- 微服务框架: Spring Cloud Alibaba 2023.0.3.3
- 持久层框架MybatisPlus 3.5.12
- 报表工具: JimuReport 2.1.3
- 安全框架Apache Shiro 2.0.4Jwt 4.5.0
- 基础框架Spring Boot 2.7.18
- 微服务框架: Spring Cloud Alibaba 2021.0.1.0
- 持久层框架MybatisPlus 3.5.3.2
- 报表工具: JimuReport 1.9.4
- 安全框架Apache Shiro 1.12.0Jwt 3.11.0
- 微服务技术栈Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
- 数据库连接池阿里巴巴Druid 1.2.24
- AI大模型支持 `ChatGPT` `DeepSeek` `千问`等各种常规模式
- 数据库连接池阿里巴巴Druid 1.1.24
- 日志打印logback
- 缓存Redis
- 其他autopoi, fastjsonpoiSwagger-uiquartz, lombok简化代码等。
- 默认提供MySQL5.7+数据库脚本
- 默认数据库脚本:MySQL5.7+
- [其他数据库,需要自己转](https://my.oschina.net/jeecg/blog/4905722)
#### 前端
- 前端环境要求Node.js要求`Node 20+` 版本以上、pnpm 要求`9+` 版本以上
` ( Vite 不再支持已结束生命周期EOL的 Node.js 18。现在需要使用 Node.js 20.19+ 或 22.12+)`
- 前端IDE建议WebStorm、Vscode
- 采用 Vue3.0+TypeScript+Vite+Ant-Design-Vue等新技术方案包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
- 最新技术栈Vue3.0 + TypeScript + Vite5 + ant-design-vue4 + pinia + echarts + unocss + vxe-table + qiankun + es6
- 依赖管理node、npm、pnpm
- 前端IDE建议IDEA、WebStorm、Vscode
- 采用 Vue3.0+TypeScript+Vite6+Ant-Design-Vue4等新技术方案包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能
- 最新技术栈Vue3.0 + TypeScript + Vite6 + ant-design-vue4 + pinia + echarts + unocss + vxe-table + qiankun + es6

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,6 @@
> JeecgBoot属于平台级产品每次升级改动较大目前做不到平滑升级。
### 增量升级方案
#### 1.代码合并
本地通过svn或git做好主干在分支上做业务开发jeecg每次版本发布可以手工覆盖主干的代码对比合并代码
@ -12,12 +11,5 @@
- 其他库请手工执行SQL, 目录: `jeecg-module-system\jeecg-system-start\src\main\resources\flyway\sql\mysql`
> 注意: 升级sql只提供mysql版本如果有权限升级, 还需要手工角色授权,退出重新登录才好使。
#### 3.其他数据库脚本说明
原先官方默认提供oracle和SqlServer的脚本但是维护成本太高未提供脚本的数据库可以参考下面的文档自己转
https://my.oschina.net/jeecg/blog/4905722
注意定时任务的表qrtz_*,需要删掉用原始的脚本重新执行一下)
quartz-2.2.3-distribution.tar.gz放到百度网盘中大家自己下载执行所需数据库脚本
https://pan.baidu.com/s/1WrmZdUuAPg3iBwJ-LoHWyg?pwd=8mdz
#### 4.兼容问题
#### 3.兼容问题
每次发版,会针对不兼容地方重点说明。

View File

@ -2,7 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-parent</artifactId>
<version>3.8.3</version>
</parent>
@ -42,7 +42,7 @@
<dependencies>
<!--jeecg-tools-->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-common</artifactId>
</dependency>
<!--集成springmvc框架并实现自动配置 -->
@ -98,7 +98,7 @@
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
@ -107,22 +107,22 @@
<version>${mybatis-plus.version}</version>
</dependency>
<!-- minidao -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework</groupId>
<artifactId>minidao-spring-boot-starter-jsqlparser-4.9</artifactId>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-datasource-spring-boot-starter.version}</version>
</dependency>
@ -191,50 +191,7 @@
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
<!-- 排除仍使用了javax.servlet的依赖 -->
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入适配jakarta的依赖包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<classifier>jakarta</classifier>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- shiro-redis -->
<dependency>
@ -253,23 +210,12 @@
</exclusions>
</dependency>
<!-- <dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j-spring-boot-starter.version}</version>
</dependency>-->
<!-- knife4j 升级springboot3.4.5报错 -->
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-ui</artifactId>
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
<version>${knife4j-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!-- 代码生成器 -->
<!-- 如下载失败,请参考此文档 https://help.jeecg.com/java/setup/maven.html -->
@ -291,7 +237,7 @@
<!-- AutoPoi Excel工具类-->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework</groupId>
<artifactId>autopoi-web</artifactId>
</dependency>
<dependency>
@ -329,16 +275,6 @@
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
@ -364,8 +300,8 @@
</dependency>
<!-- chatgpt -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-starter-chatgpt</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@ -2,7 +2,7 @@ package org.jeecg.common.api.dto;
import lombok.Data;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
/**

View File

@ -20,14 +20,14 @@ import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.IpUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
@ -172,7 +172,7 @@ public class AutoLogAspect {
// 请求的方法参数值
Object[] args = joinPoint.getArgs();
// 请求的方法参数名称
StandardReflectionParameterNameDiscoverer u=new StandardReflectionParameterNameDiscoverer();
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null) {
for (int i = 0; i < args.length; i++) {

View File

@ -21,7 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;

View File

@ -1,8 +1,6 @@
package org.jeecg.common.exception;
import cn.hutool.core.util.ObjectUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.shiro.SecurityUtils;
@ -35,6 +33,8 @@ import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.stream.Collectors;

View File

@ -24,9 +24,9 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

View File

@ -13,7 +13,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* @Description: Entity基类

View File

@ -5,7 +5,7 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
import org.jeecg.common.util.SpringContextUtils;
import org.springframework.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

View File

@ -6,18 +6,16 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Objects;
import java.util.stream.Collectors;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;

View File

@ -5,7 +5,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
*

View File

@ -19,7 +19,7 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.io.File;
@ -153,9 +153,9 @@ public class CommonUtils {
*/
public static String uploadLocal(MultipartFile mf,String bizPath,String uploadpath){
try {
// 文件安全校验,防止上传漏洞文件
SsrfFileTypeFilter.checkUploadFileType(mf, bizPath);
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
SsrfFileTypeFilter.checkUploadFileType(mf);
//update-end-author:liusq date:20210809 for: 过滤上传文件类型
String fileName = null;
File file = new File(uploadpath + File.separator + bizPath + File.separator );
if (!file.exists()) {

View File

@ -1,6 +1,5 @@
package org.jeecg.common.util;
import jakarta.servlet.http.HttpServletResponse;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
@ -11,6 +10,7 @@ import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

View File

@ -4,13 +4,13 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.common.system.query.QueryGenerator;
import javax.servlet.http.HttpServletRequest;
/**

View File

@ -1,6 +1,6 @@
package org.jeecg.common.util;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CommonConstant;

View File

@ -55,11 +55,13 @@ public class MinioUtil {
*/
public static String upload(MultipartFile file, String bizPath, String customBucket) throws Exception {
String fileUrl = "";
// 业务路径过滤,防止攻击
//update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
bizPath = StrAttackFilter.filter(bizPath);
//update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
// 文件安全校验,防止上传漏洞文件
SsrfFileTypeFilter.checkUploadFileType(file, bizPath);
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
SsrfFileTypeFilter.checkUploadFileType(file);
//update-end-author:liusq date:20210809 for: 过滤上传文件类型
String newBucket = bucketName;
if(oConvertUtils.isNotEmpty(customBucket)){

View File

@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
@ -56,22 +56,12 @@ public class RestUtil {
private final static RestTemplate RT;
static {
//update-begin---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
// 使用 Apache HttpClient 避免 JDK HttpURLConnection 的 too many bytes written 问题
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
//update-end---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(30000);
requestFactory.setReadTimeout(30000);
RT = new RestTemplate(requestFactory);
//update-begin---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
// 解决乱码问题(替换 StringHttpMessageConverter 为 UTF-8
for (int i = 0; i < RT.getMessageConverters().size(); i++) {
if (RT.getMessageConverters().get(i) instanceof StringHttpMessageConverter) {
RT.getMessageConverters().set(i, new StringHttpMessageConverter(StandardCharsets.UTF_8));
break;
}
}
//update-end---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
// 解决乱码问题
RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
}
public static RestTemplate getRestTemplate() {
@ -260,21 +250,12 @@ public class RestUtil {
// 创建自定义RestTemplate如果需要设置超时
RestTemplate restTemplate = RT;
if (timeout > 0) {
//update-begin---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
//update-end---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(timeout);
requestFactory.setReadTimeout(timeout);
restTemplate = new RestTemplate(requestFactory);
//update-begin---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
// 解决乱码问题(替换 StringHttpMessageConverter 为 UTF-8
for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
if (restTemplate.getMessageConverters().get(i) instanceof StringHttpMessageConverter) {
restTemplate.getMessageConverters().set(i, new StringHttpMessageConverter(StandardCharsets.UTF_8));
break;
}
}
//update-end---author:chenrui ---date:20251011 for[issues/8859]online表单java增强失效------------
// 解决乱码问题
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
}
// 请求体

View File

@ -1,7 +1,7 @@
package org.jeecg.common.util;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.ServiceNameConstants;

View File

@ -11,7 +11,7 @@ import org.jeecg.common.exception.JeecgBoot401Exception;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* @Author scott

View File

@ -1,6 +1,7 @@
package org.jeecg.common.util.encryption;
import org.apache.shiro.lang.codec.Base64;
import org.apache.shiro.codec.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

View File

@ -2,7 +2,6 @@ package org.jeecg.common.util.filter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@ -150,38 +149,29 @@ public class SsrfFileTypeFilter {
public static void checkDownloadFileType(String filePath) throws IOException {
//文件后缀
String suffix = getFileTypeBySuffix(filePath);
log.debug(" 【文件下载校验】文件后缀 suffix: {}", suffix);
log.info("suffix:{}", suffix);
boolean isAllowExtension = FILE_TYPE_WHITE_LIST.contains(suffix.toLowerCase());
//是否允许下载的文件
if (!isAllowExtension) {
throw new JeecgBootException("下载失败,存在非法文件类型:" + suffix);
throw new IOException("下载失败,存在非法文件类型:" + suffix);
}
}
/**
* 上传文件类型过滤
*
* @param file
*/
public static void checkUploadFileType(MultipartFile file) throws Exception {
checkUploadFileType(file, null);
}
/**
* 上传文件类型过滤
*
* @param file
*/
public static void checkUploadFileType(MultipartFile file, String customPath) throws Exception {
//1. 路径安全校验
validatePathSecurity(customPath);
//2. 校验文件后缀和头
String suffix = getFileType(file, customPath);
log.info("【文件上传校验】文件后缀 suffix: {}customPath{}", suffix, customPath);
//获取文件真是后缀
String suffix = getFileType(file);
log.info("suffix:{}", suffix);
boolean isAllowExtension = FILE_TYPE_WHITE_LIST.contains(suffix.toLowerCase());
//是否允许下载的文件
if (!isAllowExtension) {
throw new JeecgBootException("上传失败,存在非法文件类型:" + suffix);
throw new Exception("上传失败,存在非法文件类型:" + suffix);
}
}
@ -193,7 +183,7 @@ public class SsrfFileTypeFilter {
* @throws Exception
*/
private static String getFileType(MultipartFile file, String customPath) throws Exception {
private static String getFileType(MultipartFile file) throws Exception {
//update-begin-author:liusq date:20230404 for: [issue/4672]方法造成的文件被占用注释掉此方法tomcat就能自动清理掉临时文件
String fileExtendName = null;
InputStream is = null;
@ -213,7 +203,7 @@ public class SsrfFileTypeFilter {
break;
}
}
log.debug("-----获取到的指定文件类型------"+fileExtendName);
log.info("-----获取到的指定文件类型------"+fileExtendName);
// 如果不是上述类型,则判断扩展名
if (StringUtils.isBlank(fileExtendName)) {
String fileName = file.getOriginalFilename();
@ -224,6 +214,7 @@ public class SsrfFileTypeFilter {
// 如果有扩展名,则返回扩展名
return getFileTypeBySuffix(fileName);
}
log.info("-----最終的文件类型------"+fileExtendName);
is.close();
return fileExtendName;
} catch (Exception e) {
@ -258,34 +249,4 @@ public class SsrfFileTypeFilter {
}
return stringBuilder.toString();
}
/**
* 路径安全校验
*/
private static void validatePathSecurity(String customPath) throws JeecgBootException {
if (customPath == null || customPath.trim().isEmpty()) {
return;
}
// 统一分隔符为 /
String normalized = customPath.replace("\\", "/");
// 1. 防止路径遍历攻击
if (normalized.contains("..") || normalized.contains("~")) {
throw new JeecgBootException("上传业务路径包含非法字符!");
}
// 2. 限制路径深度
int depth = normalized.split("/").length;
if (depth > 5) {
throw new JeecgBootException("上传业务路径深度超出限制!");
}
// 3. 限制字符集(只允许字母、数字、下划线、横线、斜杠)
if (!normalized.matches("^[a-zA-Z0-9/_-]+$")) {
throw new JeecgBootException("上传业务路径包含非法字符!");
}
}
}

View File

@ -10,7 +10,7 @@ import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.springframework.beans.BeanUtils;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

View File

@ -97,8 +97,9 @@ public class OssBootUtil {
* @return oss 中的相对文件路径
*/
public static String upload(MultipartFile file, String fileDir,String customBucket) throws Exception {
// 文件安全校验,防止上传漏洞文件
//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
SsrfFileTypeFilter.checkUploadFileType(file);
//update-end-author:liusq date:20210809 for: 过滤上传文件类型
String filePath = null;
initOss(endPoint, accessKeyId, accessKeySecret);

View File

@ -3,7 +3,7 @@ package org.jeecg.config;
import java.util.ArrayList;
import java.util.List;
import jakarta.annotation.Resource;
import javax.annotation.Resource;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.system.vo.DictModel;

View File

@ -2,9 +2,7 @@ package org.jeecg.config;
import java.io.IOException;
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import jakarta.servlet.*;
import javax.servlet.*;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -13,6 +11,8 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
/**

View File

@ -12,7 +12,6 @@ import java.util.HashMap;
import java.util.Map;
/**
* @author eightmonth@qq.com
* 启动程序修改DruidWallConfig配置
* 允许SELECT语句的WHERE子句是一个永真条件
* @author eightmonth

View File

@ -1,10 +1,7 @@
package org.jeecg.config;
import org.jeecg.config.vo.*;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Component;
@ -14,7 +11,6 @@ import org.springframework.stereotype.Component;
*/
@Component("jeecgBaseConfig")
@ConfigurationProperties(prefix = "jeecg")
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class JeecgBaseConfig {
/**
* 签名密钥串(字典等敏感接口)

View File

@ -10,13 +10,11 @@ import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springdoc.core.filters.GlobalOpenApiMethodFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -63,55 +61,28 @@ public class Swagger3Config implements WebMvcConfigurer {
}
@Bean
public OperationCustomizer operationCustomizer() {
return (operation, handlerMethod) -> {
String path = getFullPath(handlerMethod);
if (!isExcludedPath(path)) {
operation.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN));
}else{
log.info("忽略加入 X_ACCESS_TOKEN 的 PATH:" + path);
public GlobalOpenApiCustomizer globalOpenApiCustomizer() {
return openApi -> {
// 全局添加鉴权参数
if (openApi.getPaths() != null) {
openApi.getPaths().forEach((path, pathItem) -> {
//log.debug("path: {}", path);
// 检查当前路径是否在排除列表中
boolean isExcluded = excludedPaths.stream().anyMatch(
excludedPath -> excludedPath.equals(path) || (excludedPath.endsWith("**") && path.startsWith(excludedPath.substring(0, excludedPath.length() - 2)))
);
if (!isExcluded) {
// 接口添加鉴权参数
pathItem.readOperations().forEach(operation ->
operation.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN))
);
}
});
}
return operation;
};
}
private String getFullPath(HandlerMethod handlerMethod) {
StringBuilder fullPath = new StringBuilder();
// 获取类级别的路径
RequestMapping classMapping = handlerMethod.getBeanType().getAnnotation(RequestMapping.class);
if (classMapping != null && classMapping.value().length > 0) {
fullPath.append(classMapping.value()[0]);
}
// 获取方法级别的路径
RequestMapping methodMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
if (methodMapping != null && methodMapping.value().length > 0) {
String methodPath = methodMapping.value()[0];
// 确保路径正确拼接,处理斜杠
if (!fullPath.toString().endsWith("/") && !methodPath.startsWith("/")) {
fullPath.append("/");
}
fullPath.append(methodPath);
}
return fullPath.toString();
}
private boolean isExcludedPath(String path) {
return excludedPaths.stream()
.anyMatch(pattern -> {
if (pattern.endsWith("/**")) {
// 处理通配符匹配
String basePath = pattern.substring(0, pattern.length() - 3);
return path.startsWith(basePath);
}
// 精确匹配
return pattern.equals(path);
});
}
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
@ -119,15 +90,11 @@ public class Swagger3Config implements WebMvcConfigurer {
.title("JeecgBoot 后台服务API接口文档")
.version("3.8.3")
.contact(new Contact().name("北京国炬信息技术有限公司").url("www.jeccg.com").email("jeecgos@163.com"))
.description("后台API接口")
.description( "后台API接口")
.termsOfService("NO terms of service")
.license(new License().name("Apache 2.0").url("http://www.apache.org/licenses/LICENSE-2.0.html")))
.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN))
.components(new Components().addSecuritySchemes(CommonConstant.X_ACCESS_TOKEN,
new SecurityScheme()
.name(CommonConstant.X_ACCESS_TOKEN)
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER) // 关键:指定为 header
));
new SecurityScheme().name(CommonConstant.X_ACCESS_TOKEN).type(SecurityScheme.Type.HTTP)));
}
}

View File

@ -1,19 +0,0 @@
//package org.jeecg.config;
//
//import io.undertow.server.DefaultByteBufferPool;
//import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
//import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
//import org.springframework.boot.web.server.WebServerFactoryCustomizer;
//import org.springframework.stereotype.Component;
//
//@Component
//public class UndertowCustomizer implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
// @Override
// public void customize(UndertowServletWebServerFactory factory) {
// factory.addDeploymentInfoCustomizers(deploymentInfo -> {
// WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
// webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(false, 1024));
// deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
// });
// }
//}

View File

@ -10,18 +10,17 @@ import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.EventListener;
import org.springframework.http.CacheControl;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@ -33,6 +32,7 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -47,7 +47,6 @@ import java.util.concurrent.TimeUnit;
* @Author qinfeng
*
*/
@Slf4j
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@ -155,17 +154,16 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
/**
* 在Bean初始化完成后立即配置PrometheusMeterRegistry避免在Meter注册后才配置MeterFilter
* 监听应用启动完成事件,确保 PrometheusMeterRegistry 已经初始化
* for [QQYUN-12558]【监控】系统监控的头两个tab不好使接口404
* @param event
* @author chenrui
* @date 2025/5/26 16:46
*/
@PostConstruct
public void initPrometheusMeterRegistry() {
// 确保在应用启动早期就配置MeterFilter避免警告
if (null != meterRegistryPostProcessor && null != prometheusMeterRegistry) {
meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, "prometheusMeterRegistry");
log.info("PrometheusMeterRegistry配置完成");
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
if(null != meterRegistryPostProcessor){
meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, "");
}
}

View File

@ -3,8 +3,8 @@ package org.jeecg.config.filter;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**

View File

@ -7,9 +7,9 @@ import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**

View File

@ -14,9 +14,9 @@ import org.jeecg.config.JeecgBaseConfig;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;

View File

@ -11,7 +11,7 @@ import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.config.mybatis.ThreadLocalDataHelper;
import org.springframework.stereotype.Component;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**

View File

@ -6,8 +6,8 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 动态数据源切换拦截器

View File

@ -1,6 +1,5 @@
package org.jeecg.config.oss;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
@ -29,7 +28,7 @@ public class MinioConfig {
@Value(value = "${jeecg.minio.bucketName}")
private String bucketName;
@PostConstruct
@Bean
public void initMinio(){
if(!minioUrl.startsWith(CommonConstant.STR_HTTP)){
minioUrl = "http://" + minioUrl;

View File

@ -1,6 +1,5 @@
package org.jeecg.config.oss;
import jakarta.annotation.PostConstruct;
import org.jeecg.common.util.oss.OssBootUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -29,7 +28,7 @@ public class OssConfiguration {
private String staticDomain;
@PostConstruct
@Bean
public void initOssBootConfiguration() {
OssBootUtil.setEndPoint(endpoint);
OssBootUtil.setAccessKeyId(accessKeyId);

View File

@ -1,8 +1,5 @@
package org.jeecg.config.shiro;
import jakarta.annotation.Resource;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
@ -11,7 +8,6 @@ import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.ShiroUrlPathHelper;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.*;
import org.jeecg.common.constant.CommonConstant;
@ -21,20 +17,25 @@ import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
import org.jeecg.config.shiro.filters.JwtFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import javax.annotation.Resource;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.lang.reflect.Method;
import java.util.*;
/**
@ -45,7 +46,6 @@ import java.util.*;
@Slf4j
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ShiroConfig {
@Resource
@ -158,7 +158,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getTotalDataByCompId", "anon");
filterChainDefinitionMap.put("/drag/mock/json/**", "anon");
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/getDictByCodes", "anon");
filterChainDefinitionMap.put("/drag/onlDragDatasetHead/queryAllById", "anon");
filterChainDefinitionMap.put("/jimubi/view", "anon");
filterChainDefinitionMap.put("/jimubi/share/view/**", "anon");
@ -364,18 +364,6 @@ public class ShiroConfig {
return manager;
}
/**
* 解决 ShiroRequestMappingConfig 获取 requestMappingHandlerMapping Bean 冲突
* spring-boot-autoconfigure:3.4.5 和 spring-boot-actuator-autoconfigure:3.4.5
*/
@Primary
@Bean
public RequestMappingHandlerMapping overridedRequestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
mapping.setUrlPathHelper(new ShiroUrlPathHelper());
return mapping;
}
private List<String> rebuildUrl(String[] bases, String[] uris) {
List<String> urls = new ArrayList<>();
for (String base : bases) {

View File

@ -20,13 +20,11 @@ import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Set;
/**
@ -37,7 +35,6 @@ import java.util.Set;
*/
@Component
@Slf4j
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ShiroRealm extends AuthorizingRealm {
@Lazy
@Resource
@ -110,8 +107,8 @@ public class ShiroRealm extends AuthorizingRealm {
loginUser = this.checkUserTokenIsEffect(token);
} catch (AuthenticationException e) {
log.error("—————校验 check token 失败——————————"+ e.getMessage(), e);
// 重新抛出异常让JwtFilter统一处理避免返回两次错误响应
throw e;
JwtUtil.responseError(SpringContextUtils.getHttpServletResponse(),401,e.getMessage());
return null;
}
return new SimpleAuthenticationInfo(loginUser, token, getName());
}

View File

@ -12,7 +12,7 @@ import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.beans.factory.BeanInitializationException;
import jakarta.servlet.Filter;
import javax.servlet.Filter;
import java.util.Map;
/**

View File

@ -13,10 +13,10 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: 鉴权登录拦截器

View File

@ -1,9 +1,9 @@
package org.jeecg.config.shiro.filters;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import lombok.extern.slf4j.Slf4j;

View File

@ -10,7 +10,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import jakarta.annotation.Resource;
import javax.annotation.Resource;
/**
* 签名 拦截器配置

View File

@ -4,8 +4,8 @@ package org.jeecg.config.sign.interceptor;
import java.io.PrintWriter;
import java.util.SortedMap;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;

View File

@ -1,10 +1,10 @@
package org.jeecg.config.sign.util;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;

View File

@ -10,7 +10,7 @@ import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.SymbolConstant;

View File

@ -14,8 +14,8 @@ import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-module</artifactId>
<version>3.8.3</version>
</parent>
@ -31,49 +31,31 @@
</repositories>
<properties>
<langchain4j.version>0.35.0</langchain4j.version>
<apache-tika.version>2.9.1</apache-tika.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId>
<version>1.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-bom</artifactId>
<version>1.3.0-beta9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- system单体 api-->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
<!-- 微服务starter和system微服务 api
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-starter-cloud</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-cloud-api</artifactId>
</dependency>-->
<!-- aiflow依赖 -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-aiflow</artifactId>
<version>3.8.3.1</version>
<version>1.2.0</version>
</dependency>
<!-- beigin 这两个依赖太多每个包50M左右如果你发布需要使用请把<scope>provided</scope>删掉 -->
@ -90,6 +72,7 @@
<scope>provided</scope>
</dependency>
<!-- end 这两个依赖太多每个包50M左右如果你发布需要使用请把<scope>provided</scope>删掉 -->
<!-- aiflow 脚本依赖 -->
<dependency>
<groupId>com.yomahub</groupId>
@ -122,19 +105,17 @@
</exclusions>
</dependency>
<!-- aiflow 脚本依赖 -->
<!-- langChain4j model support -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-zhipu-ai</artifactId>
<artifactId>langchain4j-zhipu-ai</artifactId>
<version>${langchain4j.version}</version>
<exclusions>
<exclusion>
<artifactId>checker-qual</artifactId>
@ -148,11 +129,13 @@
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-qianfan</artifactId>
<artifactId>langchain4j-qianfan</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope</artifactId>
<artifactId>langchain4j-dashscope</artifactId>
<version>${langchain4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
@ -168,7 +151,7 @@
<dependency>
<groupId>org.jeecgframework</groupId>
<artifactId>langchain4j-pgvector</artifactId>
<version>1.3.0-beta9</version>
<version>${langchain4j.version}</version>
</dependency>
<!-- langChain4j Document Parser -->
<dependency>

View File

@ -21,8 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
/**
* @Description: AI应用

View File

@ -1,7 +1,5 @@
package org.jeecg.modules.airag.app.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
@ -17,6 +15,8 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**

View File

@ -71,7 +71,7 @@ public class AiragAppServiceImpl extends ServiceImpl<AiragAppMapper, AiragApp> i
AtomicBoolean isThinking = new AtomicBoolean(false);
String requestId = UUIDGenerator.generate();
// ai聊天响应逻辑
tokenStream.onPartialResponse((String resMessage) -> {
tokenStream.onNext((String resMessage) -> {
// 兼容推理模型
if ("<think>".equals(resMessage)) {
isThinking.set(true);
@ -99,9 +99,9 @@ public class AiragAppServiceImpl extends ServiceImpl<AiragAppMapper, AiragApp> i
throw new RuntimeException(e);
}
})
.onCompleteResponse((responseMessage) -> {
.onComplete((responseMessage) -> {
// 记录ai的回复
AiMessage aiMessage = responseMessage.aiMessage();
AiMessage aiMessage = responseMessage.content();
FinishReason finishReason = responseMessage.finishReason();
String respText = aiMessage.text();
if (FinishReason.STOP.equals(finishReason) || null == finishReason) {
@ -114,6 +114,9 @@ public class AiragAppServiceImpl extends ServiceImpl<AiragAppMapper, AiragApp> i
throw new RuntimeException(e);
}
closeSSE(emitter, eventData);
} else if (FinishReason.TOOL_EXECUTION.equals(finishReason)) {
// 需要执行工具
// TODO author: chenrui for: date:2025/3/7
} else {
// 异常结束
log.error("调用模型异常:" + respText);

View File

@ -40,7 +40,7 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
@ -860,7 +860,7 @@ public class AiragChatServiceImpl implements IAiragChatService {
*/
AtomicBoolean isThinking = new AtomicBoolean(false);
// ai聊天响应逻辑
chatStream.onPartialResponse((String resMessage) -> {
chatStream.onNext((String resMessage) -> {
// 兼容推理模型
if ("<think>".equals(resMessage)) {
isThinking.set(true);
@ -886,12 +886,12 @@ public class AiragChatServiceImpl implements IAiragChatService {
return;
}
sendMessage2Client(emitter, eventData);
}).onCompleteResponse((responseMessage) -> {
}).onComplete((responseMessage) -> {
// 打印流程耗时日志
printChatDuration(requestId, "LLM输出消息完成");
AiragLocalCache.remove(AiragConsts.CACHE_TYPE_SSE_SEND_TIME, requestId);
// 记录ai的回复
AiMessage aiMessage = responseMessage.aiMessage();
AiMessage aiMessage = responseMessage.content();
FinishReason finishReason = responseMessage.finishReason();
String respText = aiMessage.text();
// sse

View File

@ -22,7 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

View File

@ -26,8 +26,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Collections;

View File

@ -105,14 +105,14 @@ public class AIChatHandler implements IAIChatHandler {
// langchain4j 异常友好提示
String errMsg = "调用大模型接口失败,详情请查看后台日志。";
if (oConvertUtils.isNotEmpty(e.getMessage())) {
// 根据常见异常关键字做细致翻译
for (Map.Entry<String, String> entry : MODEL_ERROR_MAP.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (errMsg.contains(key)) {
errMsg = value;
}
}
// // 根据常见异常关键字做细致翻译
// for (Map.Entry<String, String> entry : MODEL_ERROR_MAP.entrySet()) {
// String key = entry.getKey();
// String value = entry.getValue();
// if (errMsg.contains(key)) {
// errMsg = value;
// }
// }
}
log.error("AI模型调用异常: {}", errMsg, e);
throw new JeecgBootException(errMsg);

View File

@ -9,6 +9,7 @@ import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiTokenizer;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.rag.query.router.DefaultQueryRouter;
@ -166,7 +167,7 @@ public class EmbeddingHandler implements IEmbeddingHandler {
// 删除旧数据
embeddingStore.removeAll(metadataKey(EMBED_STORE_METADATA_DOCID).isEqualTo(doc.getId()));
// 分段器
DocumentSplitter splitter = DocumentSplitters.recursive(DEFAULT_SEGMENT_SIZE, DEFAULT_OVERLAP_SIZE);
DocumentSplitter splitter = DocumentSplitters.recursive(DEFAULT_SEGMENT_SIZE, DEFAULT_OVERLAP_SIZE, new OpenAiTokenizer());
// 分段并存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(splitter)

View File

@ -27,7 +27,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-boot-module</artifactId>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -13,7 +13,7 @@
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-core</artifactId>
</dependency>
</dependencies>

View File

@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import javax.annotation.Resource;
/**
* 服务端提供方——feign接口

View File

@ -6,8 +6,8 @@ import org.apache.commons.io.IOUtils;
import org.jeecg.common.api.vo.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.io.IOException;

View File

@ -18,7 +18,7 @@ import org.jeecg.modules.demo.mock.vxe.entity.MockEntity;
import org.jeecg.modules.demo.mock.vxe.websocket.VxeSocket;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;

View File

@ -6,12 +6,12 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.VxeSocketConst;
import org.springframework.stereotype.Component;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

View File

@ -29,8 +29,8 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import reactor.core.publisher.Mono;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

View File

@ -10,10 +10,7 @@ import org.jeecg.modules.demo.test.entity.JeecgDemo;
import org.jeecg.modules.demo.test.service.IJeecgDemoService;
import org.jeecg.modules.demo.test.service.IJeecgDynamicDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;

View File

@ -17,7 +17,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**

View File

@ -5,8 +5,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;

View File

@ -7,8 +7,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;

View File

@ -18,7 +18,7 @@ import org.jeecg.modules.demo.mock.vxe.websocket.VxeSocket;
import org.jeecg.modules.dlglong.entity.MockEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-system-api</artifactId>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
//import java.util.List;
//import java.util.SortedMap;
//
//import jakarta.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletRequest;
//
//import org.jeecg.common.config.mqtoken.UserTokenContext;
//import org.jeecg.common.constant.CommonConstant;

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-system-api</artifactId>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-module-system</artifactId>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<version>3.8.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -19,7 +19,7 @@
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-core</artifactId>
</dependency>
</dependencies>

View File

@ -2,7 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-module-system</artifactId>
<version>3.8.3</version>
</parent>
@ -12,7 +12,7 @@
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
<dependency>
@ -20,13 +20,13 @@
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>hibernate-re</artifactId>
</dependency>
<!-- AI大模型管理 -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-module-airag</artifactId>
<version>${jeecgboot.version}</version>
</dependency>
@ -38,13 +38,7 @@
<!-- 积木报表 -->
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot3-starter</artifactId>
<exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
<artifactId>jimureport-spring-boot-starter</artifactId>
</dependency>
<!-- mongo、redis和文件数据集支持包按需引入 -->
<dependency>
@ -59,19 +53,7 @@
<!-- 积木BI -->
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimubi-spring-boot3-starter</artifactId>
<exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- AI大模型管理 -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<artifactId>jeecg-boot-module-airag</artifactId>
<version>${jeecgboot.version}</version>
<artifactId>jimubi-spring-boot-starter</artifactId>
</dependency>
</dependencies>

View File

@ -12,7 +12,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@ -36,7 +36,11 @@ public class JimuReportTokenService implements JmReportTokenServiceI {
@Override
public String getToken(HttpServletRequest request) {
return TokenUtils.getTokenByRequest(request);
try {
return TokenUtils.getTokenByRequest(request);
} catch (Exception e) {
return null;
}
}
@Override

View File

@ -5,11 +5,13 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import dev.langchain4j.agent.tool.JsonSchemaProperty;
import dev.langchain4j.agent.tool.ToolSpecification;
import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
import dev.langchain4j.service.tool.ToolExecutor;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.airag.llm.handler.JeecgToolsProvider;
@ -83,17 +85,12 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
"\n\n - 提前使用用户名查询用户是否存在,如果存在则不能添加." +
"\n\n - 添加成功后返回成功消息,如果失败则返回失败原因." +
"\n\n - 用户名,工号,邮箱,手机号均要求唯一,提前通过查询用户工具确认唯一性." )
.parameters(
JsonObjectSchema.builder()
.addStringProperty("username", "用户名,必填,只允许使用字母、数字、下划线,且必须以字母开头,唯一")
.addStringProperty("password", "用户密码,必填")
.addStringProperty("realname", "真实姓名,必填")
.addStringProperty("workNo", "号,必填,唯一")
.addStringProperty("email", "邮箱,必填,唯一")
.addStringProperty("phone", "手机号,必填,唯一")
.required("username","password","realname","workNo","email","phone")
.build()
)
.addParameter("username", JsonSchemaProperty.STRING, JsonSchemaProperty.description("用户名,必填,只允许使用字母、数字、下划线,且必须以字母开头,唯一"))
.addParameter("password", JsonSchemaProperty.STRING, JsonSchemaProperty.description("用户密码,必填"))
.addParameter("realname", JsonSchemaProperty.STRING, JsonSchemaProperty.description("真实姓名,必填"))
.addParameter("workNo", JsonSchemaProperty.STRING, JsonSchemaProperty.description("工号,必填,唯一"))
.addParameter("email", JsonSchemaProperty.STRING, JsonSchemaProperty.description("邮箱,必填,唯一"))
.addParameter("phone", JsonSchemaProperty.STRING, JsonSchemaProperty.description("手机号,必填,唯一"))
.build();
ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
JSONObject arguments = JSONObject.parseObject(toolExecutionRequest.arguments());
@ -141,15 +138,11 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
ToolSpecification toolSpecification = ToolSpecification.builder()
.name("query_user_by_name")
.description("查询用户详细信息返回json数组。支持用户名、真实姓名、邮箱、手机号、工号多字段组合查询用户名、真实姓名、邮箱、手机号均为模糊查询工号为精确查询。无条件则返回全部用户。")
.parameters(
JsonObjectSchema.builder()
.addStringProperty("username", "用户名")
.addStringProperty("realname", "真实姓名")
.addStringProperty("email", "电子邮件")
.addStringProperty("phone", "手机号")
.addStringProperty("workNo", "工号")
.build()
)
.addParameter("username", JsonSchemaProperty.STRING, JsonSchemaProperty.description("用户名"))
.addParameter("realname", JsonSchemaProperty.STRING, JsonSchemaProperty.description("真实姓名"))
.addParameter("email", JsonSchemaProperty.STRING, JsonSchemaProperty.description("电子邮件"))
.addParameter("phone", JsonSchemaProperty.STRING, JsonSchemaProperty.description("手机号"))
.addParameter("workNo", JsonSchemaProperty.STRING, JsonSchemaProperty.description("工号"))
.build();
ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
SysUser args = JSONObject.parseObject(toolExecutionRequest.arguments(), SysUser.class);
@ -187,12 +180,8 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
ToolSpecification spec = ToolSpecification.builder()
.name("query_all_roles")
.description("查询所有角色返回json数组。包含字段id、roleName、roleCode默认按创建时间/排序号规则由后端决定。")
.parameters(
JsonObjectSchema.builder()
.addStringProperty("roleName", "角色姓名")
.addStringProperty("roleCode", "角色编码")
.build()
)
.addParameter("roleName", JsonSchemaProperty.STRING, JsonSchemaProperty.description("角色姓名"))
.addParameter("roleCode", JsonSchemaProperty.STRING, JsonSchemaProperty.description("角色编码"))
.build();
ToolExecutor exec = (toolExecutionRequest, memoryId) -> {
// 做租户隔离查询(若开启)
@ -205,10 +194,10 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
qw.like("role_code", sysRole.getRoleCode());
}
// 未删除
List<SysRole> roles = sysRoleService.list(qw);
List<org.jeecg.modules.system.entity.SysRole> roles = sysRoleService.list(qw);
// 仅返回核心字段
JSONArray arr = new JSONArray();
for (SysRole r : roles) {
for (org.jeecg.modules.system.entity.SysRole r : roles) {
JSONObject o = new JSONObject();
o.put("id", r.getId());
o.put("roleName", r.getRoleName());
@ -230,22 +219,17 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
ToolSpecification spec = ToolSpecification.builder()
.name("grant_user_roles")
.description("给用户授予角色,支持一次授予多个角色;如果关系已存在则跳过。返回授予结果统计。")
.parameters(
JsonObjectSchema.builder()
.addStringProperty("userId", "用户ID必填")
.addStringProperty("roleIds", "角色ID列表必填使用英文逗号分隔")
.required("userId","roleIds")
.build()
)
.addParameter("userId", JsonSchemaProperty.STRING, JsonSchemaProperty.description("用户ID必填"))
.addParameter("roleIds", JsonSchemaProperty.STRING, JsonSchemaProperty.description("角色ID列表必填使用英文逗号分隔"))
.build();
ToolExecutor exec = (toolExecutionRequest, memoryId) -> {
JSONObject args = JSONObject.parseObject(toolExecutionRequest.arguments());
String userId = args.getString("userId");
String roleIdsStr = args.getString("roleIds");
if (StringUtils.isAnyBlank(userId, roleIdsStr)) {
if (org.apache.commons.lang3.StringUtils.isAnyBlank(userId, roleIdsStr)) {
return "参数缺失userId 或 roleIds";
}
SysUser user = sysUserService.getById(userId);
org.jeecg.modules.system.entity.SysUser user = sysUserService.getById(userId);
if (user == null) {
return "用户不存在:" + userId;
}
@ -254,9 +238,9 @@ public class JeecgBizToolsProvider implements JeecgToolsProvider {
for (String roleId : roleIds) {
roleId = roleId.trim();
if (roleId.isEmpty()) continue;
SysRole role = sysRoleService.getById(roleId);
org.jeecg.modules.system.entity.SysRole role = sysRoleService.getById(roleId);
if (role == null) { invalid++; continue; }
QueryWrapper<org.jeecg.modules.system.entity.SysUserRole> q = new QueryWrapper<>();
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<org.jeecg.modules.system.entity.SysUserRole> q = new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>();
q.eq("role_id", roleId).eq("user_id", userId);
org.jeecg.modules.system.entity.SysUserRole one = sysUserRoleService.getOne(q);
if (one == null) {

View File

@ -15,7 +15,7 @@ import org.jeecg.modules.system.entity.SysTenantPack;
import org.jeecg.modules.system.entity.SysTenantPackUser;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;

View File

@ -2,8 +2,8 @@ package org.jeecg.modules.cas.controller;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;

View File

@ -2,8 +2,8 @@ package org.jeecg.modules.message.controller;
import java.util.Arrays;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;

View File

@ -3,8 +3,8 @@ package org.jeecg.modules.message.controller;
import java.util.Arrays;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.api.vo.Result;

View File

@ -21,8 +21,8 @@ import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;

View File

@ -20,7 +20,7 @@ import org.jeecg.modules.system.mapper.SysAnnouncementSendMapper;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

View File

@ -2,9 +2,9 @@ package org.jeecg.modules.message.websocket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.base.BaseMap;

View File

@ -1,9 +1,9 @@
package org.jeecg.modules.monitor.actuator;
import org.jeecg.modules.monitor.actuator.httptrace.CustomInMemoryHttpTraceRepository;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesProperties;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceProperties;
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -18,8 +18,8 @@ import org.springframework.context.annotation.Configuration;
* @Date: 2024/5/13 17:20
*/
@Configuration
@EnableConfigurationProperties(HttpExchangesProperties.class)
@AutoConfigureBefore(HttpExchangesAutoConfiguration.class)
@EnableConfigurationProperties(HttpTraceProperties.class)
@AutoConfigureBefore(HttpTraceAutoConfiguration.class)
public class CustomActuatorConfig {
/**
@ -30,7 +30,7 @@ public class CustomActuatorConfig {
*/
@Bean
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
@ConditionalOnMissingBean(HttpExchangeRepository.class)
@ConditionalOnMissingBean(HttpTraceRepository.class)
public CustomInMemoryHttpTraceRepository traceRepository() {
return new CustomInMemoryHttpTraceRepository();
}

View File

@ -4,7 +4,7 @@ import lombok.Getter;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@ -29,14 +29,14 @@ public class CustomHttpTraceEndpoint{
@ReadOperation
public HttpTraceDescriptor traces(@Selector(match = ALL_REMAINING) String query) {
return new HttpTraceDescriptor(this.repository.findAll(query));
return new CustomHttpTraceEndpoint.HttpTraceDescriptor(this.repository.findAll(query));
}
@Getter
public static final class HttpTraceDescriptor {
private final List<HttpExchange> traces;
private final List<HttpTrace> traces;
private HttpTraceDescriptor(List<HttpExchange> traces) {
private HttpTraceDescriptor(List<HttpTrace> traces) {
this.traces = traces;
}

View File

@ -1,7 +1,7 @@
package org.jeecg.modules.monitor.actuator.httptrace;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
import java.util.List;
import java.util.stream.Collectors;
@ -12,10 +12,10 @@ import java.util.stream.Stream;
* @Author: chenrui
* @Date: 2024/5/13 17:02
*/
public class CustomInMemoryHttpTraceRepository extends InMemoryHttpExchangeRepository {
public class CustomInMemoryHttpTraceRepository extends InMemoryHttpTraceRepository {
@Override
public List<HttpExchange> findAll() {
public List<HttpTrace> findAll() {
return super.findAll();
}
@ -26,7 +26,7 @@ public class CustomInMemoryHttpTraceRepository extends InMemoryHttpExchangeRepos
* @date 2025/6/4 19:38
*/
@Override
public void add(HttpExchange trace) {
public void add(HttpTrace trace) {
// 只有当请求不是OPTIONS方法并且URI不包含httptrace时才记录数据
if (!"OPTIONS".equals(trace.getRequest().getMethod()) &&
!trace.getRequest().getUri().toString().contains("httptrace")) {
@ -34,10 +34,10 @@ public class CustomInMemoryHttpTraceRepository extends InMemoryHttpExchangeRepos
}
}
public List<HttpExchange> findAll(String query) {
List<HttpExchange> allTrace = super.findAll();
public List<HttpTrace> findAll(String query) {
List<HttpTrace> allTrace = super.findAll();
if (null != allTrace && !allTrace.isEmpty()) {
Stream<HttpExchange> stream = allTrace.stream();
Stream<HttpTrace> stream = allTrace.stream();
String[] params = query.split(",");
stream = filter(params, stream);
stream = sort(params, stream);
@ -46,7 +46,7 @@ public class CustomInMemoryHttpTraceRepository extends InMemoryHttpExchangeRepos
return allTrace;
}
private Stream<HttpExchange> sort(String[] params, Stream<HttpExchange> stream) {
private Stream<HttpTrace> sort(String[] params, Stream<HttpTrace> stream) {
if (params.length < 2) {
return stream;
}
@ -71,7 +71,7 @@ public class CustomInMemoryHttpTraceRepository extends InMemoryHttpExchangeRepos
});
}
private static Stream<HttpExchange> filter(String[] params, Stream<HttpExchange> stream) {
private static Stream<HttpTrace> filter(String[] params, Stream<HttpTrace> stream) {
if (params.length == 0) {
return stream;
}

View File

@ -10,8 +10,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.util.ArrayList;

Some files were not shown because too many files have changed in this diff Show More