Skip to content

Commit d0293ea

Browse files
committed
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-dependencies/pom.xml
2 parents 136be0a + 0eed2fa commit d0293ea

21 files changed

Lines changed: 1552 additions & 1386 deletions

File tree

sql/postgresql/ruoyi-vue-pro.sql

Lines changed: 1257 additions & 1335 deletions
Large diffs are not rendered by default.

yudao-dependencies/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
<jimureport.version>2.1.3</jimureport.version>
7878
<jimubi.version>2.3.0</jimubi.version>
7979
<weixin-java.version>4.7.9-20251224.161447</weixin-java.version>
80+
<alipay-sdk-java.version>4.40.607.ALL</alipay-sdk-java.version>
8081
<!-- 专属于 JDK8 安全漏洞升级 -->
8182
<logback.version>1.2.13</logback.version> <!-- 无法使用 1.3.X 版本,启动会报错 -->
8283
</properties>
@@ -596,6 +597,18 @@
596597
</exclusions>
597598
</dependency>
598599

600+
<dependency>
601+
<groupId>com.alipay.sdk</groupId>
602+
<artifactId>alipay-sdk-java</artifactId>
603+
<version>${alipay-sdk-java.version}</version>
604+
<exclusions>
605+
<exclusion>
606+
<groupId>org.bouncycastle</groupId>
607+
<artifactId>bcprov-jdk15on</artifactId>
608+
</exclusion>
609+
</exclusions>
610+
</dependency>
611+
599612
<dependency>
600613
<groupId>com.github.binarywang</groupId>
601614
<artifactId>weixin-java-pay</artifactId>

yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959

6060
import java.time.LocalDateTime;
6161
import java.util.*;
62+
import java.util.concurrent.atomic.AtomicBoolean;
63+
import java.util.concurrent.atomic.AtomicReference;
6264
import java.util.stream.Collectors;
6365

6466
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -231,20 +233,24 @@ public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatM
231233
// 4.3 流式返回
232234
StringBuffer contentBuffer = new StringBuffer();
233235
StringBuffer reasoningContentBuffer = new StringBuffer();
236+
237+
// 防止执行多次知识库和联网搜索
238+
AtomicBoolean firstExecuteFlag = new AtomicBoolean(true);
239+
AtomicReference<List<AiChatMessageRespVO.KnowledgeSegment>> cacheSegments = new AtomicReference<>();
240+
AtomicReference<List<AiWebSearchResponse.WebPage>> cacheWebSearchPages = new AtomicReference<>();
234241
return streamResponse.map(chunk -> {
235242
// 仅首次:返回知识库、联网搜索
236-
List<AiChatMessageRespVO.KnowledgeSegment> segments = null;
237-
List<AiWebSearchResponse.WebPage> webSearchPages = null;
238243
if (StrUtil.isEmpty(contentBuffer)) {
239-
Map<Long, AiKnowledgeDocumentDO> documentMap = TenantUtils.executeIgnore(() ->
240-
knowledgeDocumentService.getKnowledgeDocumentMap(
241-
convertSet(knowledgeSegments, AiKnowledgeSegmentSearchRespBO::getDocumentId)));
242-
segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, segment -> {
243-
AiKnowledgeDocumentDO document = documentMap.get(segment.getDocumentId());
244-
segment.setDocumentName(document != null ? document.getName() : null);
245-
});
246-
if (webSearchResponse != null) {
247-
webSearchPages = webSearchResponse.getLists();
244+
if (firstExecuteFlag.compareAndSet(true, false)) { // CAS 操作,确保仅执行一次
245+
Map<Long, AiKnowledgeDocumentDO> documentMap = TenantUtils.executeIgnore(() -> knowledgeDocumentService.getKnowledgeDocumentMap(
246+
convertSet(knowledgeSegments, AiKnowledgeSegmentSearchRespBO::getDocumentId)));
247+
cacheSegments.set(BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, segment -> {
248+
AiKnowledgeDocumentDO document = documentMap.get(segment.getDocumentId());
249+
segment.setDocumentName(document != null ? document.getName() : null);
250+
}));
251+
if (webSearchResponse != null) {
252+
cacheWebSearchPages.set(webSearchResponse.getLists());
253+
}
248254
}
249255
}
250256
// 响应结果
@@ -261,7 +267,7 @@ public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatM
261267
.setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class)
262268
.setContent(StrUtil.nullToDefault(newContent, "")) // 避免 null 的 情况
263269
.setReasoningContent(StrUtil.nullToDefault(newReasoningContent, "")) // 避免 null 的 情况
264-
.setSegments(segments).setWebSearchPages(webSearchPages))); // 知识库 + 联网搜索
270+
.setSegments(cacheSegments.get()).setWebSearchPages(cacheWebSearchPages.get()))); // 知识库 + 联网搜索
265271
}).doOnComplete(() -> {
266272
// 忽略租户,因为 Flux 异步无法透传租户
267273
TenantUtils.executeIgnore(() -> chatMessageMapper.updateById(

yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,24 @@
44
import cn.hutool.core.util.StrUtil;
55
import cn.iocoder.yudao.framework.common.pojo.PageResult;
66
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7+
import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
78
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
89
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
910
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
1011
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
1112
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
1213
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
14+
import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
1315
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
1416
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
1517
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
1618
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
1719
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
1820
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
1921
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
22+
import cn.iocoder.yudao.module.infra.service.db.DataSourceConfigService;
2023
import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
24+
import com.baomidou.mybatisplus.annotation.DbType;
2125
import com.baomidou.mybatisplus.generator.config.po.TableField;
2226
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
2327
import com.google.common.annotations.VisibleForTesting;
@@ -45,6 +49,8 @@ public class CodegenServiceImpl implements CodegenService {
4549

4650
@Resource
4751
private DatabaseTableService databaseTableService;
52+
@Resource
53+
private DataSourceConfigService dataSourceConfigService;
4854

4955
@Resource
5056
private CodegenTableMapper codegenTableMapper;
@@ -284,8 +290,11 @@ public Map<String, String> generationCodes(Long tableId) {
284290
}
285291
}
286292

293+
// 获取数据源对应的数据库类型
294+
DataSourceConfigDO dataSourceConfig = dataSourceConfigService.getDataSourceConfig(table.getDataSourceConfigId());
295+
DbType dbType = JdbcUtils.getDbType(dataSourceConfig.getUrl());
287296
// 执行生成
288-
return codegenEngine.execute(table, columns, subTables, subColumnsList);
297+
return codegenEngine.execute(dbType, table, columns, subTables, subColumnsList);
289298
}
290299

291300
@Override

yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
3434
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenVOTypeEnum;
3535
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
36+
import com.baomidou.mybatisplus.annotation.DbType;
3637
import com.google.common.annotations.VisibleForTesting;
3738
import com.google.common.collect.ImmutableTable;
3839
import com.google.common.collect.Maps;
@@ -310,16 +311,17 @@ void initGlobalBindingMap() {
310311
/**
311312
* 生成代码
312313
*
314+
* @param dbType 数据库类型
313315
* @param table 表定义
314316
* @param columns table 的字段定义数组
315317
* @param subTables 子表数组,当且仅当主子表时使用
316318
* @param subColumnsList subTables 的字段定义数组
317319
* @return 生成的代码,key 是路径,value 是对应代码
318320
*/
319-
public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns,
321+
public Map<String, String> execute(DbType dbType, CodegenTableDO table, List<CodegenColumnDO> columns,
320322
List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
321323
// 1.1 初始化 bindMap 上下文
322-
Map<String, Object> bindingMap = initBindingMap(table, columns, subTables, subColumnsList);
324+
Map<String, Object> bindingMap = initBindingMap(dbType, table, columns, subTables, subColumnsList);
323325
// 1.2 获得模版
324326
Map<String, String> templates = getTemplates(table.getFrontType());
325327

@@ -425,10 +427,11 @@ private String prettyCode(String content, String vmPath) {
425427
return content;
426428
}
427429

428-
private Map<String, Object> initBindingMap(CodegenTableDO table, List<CodegenColumnDO> columns,
430+
private Map<String, Object> initBindingMap(DbType dbType, CodegenTableDO table, List<CodegenColumnDO> columns,
429431
List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
430432
// 创建 bindingMap
431433
Map<String, Object> bindingMap = new HashMap<>(globalBindingMap);
434+
bindingMap.put("dbType", dbType);
432435
bindingMap.put("table", table);
433436
bindingMap.put("columns", columns);
434437
bindingMap.put("primaryColumn", CollectionUtils.findFirst(columns, CodegenColumnDO::getPrimaryKey)); // 主键字段

yudao-module-infra/src/main/resources/codegen/sql/sql.vm

Lines changed: 157 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
## 通用变量定义
2+
#set ($functionNames = ['查询', '创建', '更新', '删除', '导出'])
3+
#set ($functionOps = ['query', 'create', 'update', 'delete', 'export'])
4+
##
5+
## 宏定义:生成按钮 SQL(通用部分)
6+
#macro(insertButtonSql $parentIdVar)
7+
#foreach ($functionName in $functionNames)
8+
#set ($index = $foreach.count - 1)
9+
INSERT INTO system_menu(
10+
name, permission, type, sort, parent_id,
11+
path, icon, component, status
12+
)
13+
VALUES (
14+
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, ${parentIdVar},
15+
'', '', '', 0
16+
);
17+
#end
18+
#end
19+
##
20+
## ======================= MySQL / OceanBase =======================
21+
#if ($dbType.name() == 'MYSQL' || $dbType.name() == 'OCEAN_BASE')
122
-- 菜单 SQL
223
INSERT INTO system_menu(
324
name, permission, type, sort, parent_id,
@@ -9,12 +30,9 @@ VALUES (
930
);
1031

1132
-- 按钮父菜单ID
12-
-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
1333
SELECT @parentId := LAST_INSERT_ID();
1434

1535
-- 按钮 SQL
16-
#set ($functionNames = ['查询', '创建', '更新', '删除', '导出'])
17-
#set ($functionOps = ['query', 'create', 'update', 'delete', 'export'])
1836
#foreach ($functionName in $functionNames)
1937
#set ($index = $foreach.count - 1)
2038
INSERT INTO system_menu(
@@ -25,4 +43,139 @@ VALUES (
2543
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
2644
'', '', '', 0
2745
);
28-
#end
46+
#end
47+
##
48+
## ======================= Oracle / 达梦 DM =======================
49+
#elseif ($dbType.name() == 'ORACLE' || $dbType.name() == 'DM')
50+
-- 菜单 SQL
51+
INSERT INTO system_menu(
52+
name, permission, type, sort, parent_id,
53+
path, icon, component, status, component_name
54+
)
55+
VALUES (
56+
'${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
57+
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
58+
);
59+
60+
-- 按钮父菜单ID
61+
-- 说明:Oracle/达梦 使用序列获取上一个插入的 ID
62+
DECLARE
63+
v_parent_id NUMBER;
64+
BEGIN
65+
SELECT system_menu_seq.CURRVAL INTO v_parent_id FROM DUAL;
66+
-- 按钮 SQL
67+
#foreach ($functionName in $functionNames)
68+
#set ($index = $foreach.count - 1)
69+
INSERT INTO system_menu(
70+
name, permission, type, sort, parent_id,
71+
path, icon, component, status
72+
)
73+
VALUES (
74+
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, v_parent_id,
75+
'', '', '', 0
76+
);
77+
#end
78+
END;
79+
/
80+
##
81+
## ======================= PostgreSQL / 人大金仓 KingbaseES =======================
82+
#elseif ($dbType.name() == 'POSTGRE_SQL' || $dbType.name() == 'KINGBASE_ES')
83+
-- 菜单 SQL
84+
INSERT INTO system_menu(
85+
name, permission, type, sort, parent_id,
86+
path, icon, component, status, component_name
87+
)
88+
VALUES (
89+
'${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
90+
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
91+
);
92+
93+
-- 按钮父菜单ID
94+
-- 说明:PostgreSQL/KingbaseES 使用 lastval() 获取上一个插入的序列值
95+
DO $$
96+
DECLARE
97+
v_parent_id BIGINT;
98+
BEGIN
99+
v_parent_id := lastval();
100+
-- 按钮 SQL
101+
#foreach ($functionName in $functionNames)
102+
#set ($index = $foreach.count - 1)
103+
INSERT INTO system_menu(
104+
name, permission, type, sort, parent_id,
105+
path, icon, component, status
106+
)
107+
VALUES (
108+
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, v_parent_id,
109+
'', '', '', 0
110+
);
111+
#end
112+
END $$;
113+
##
114+
## ======================= SQL Server =======================
115+
#elseif ($dbType.name() == 'SQL_SERVER' || $dbType.name() == 'SQL_SERVER2005')
116+
-- 菜单 SQL
117+
INSERT INTO system_menu(
118+
name, permission, type, sort, parent_id,
119+
path, icon, component, status, component_name
120+
)
121+
VALUES (
122+
'${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
123+
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
124+
);
125+
126+
-- 按钮父菜单ID
127+
-- 说明:SQL Server 使用 SCOPE_IDENTITY() 获取上一个插入的自增 ID
128+
DECLARE @parentId BIGINT;
129+
SET @parentId = SCOPE_IDENTITY();
130+
131+
-- 按钮 SQL
132+
#foreach ($functionName in $functionNames)
133+
#set ($index = $foreach.count - 1)
134+
INSERT INTO system_menu(
135+
name, permission, type, sort, parent_id,
136+
path, icon, component, status
137+
)
138+
VALUES (
139+
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
140+
'', '', '', 0
141+
);
142+
#end
143+
##
144+
## ======================= 不支持的数据库类型 =======================
145+
#else
146+
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
147+
-- 注意:当前数据库类型 ${dbType.name()} 暂不支持自动生成菜单 SQL
148+
-- 请参考以下 MySQL 语法,手动修改为您的数据库对应的语法
149+
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
150+
151+
-- 菜单 SQL
152+
INSERT INTO system_menu(
153+
name, permission, type, sort, parent_id,
154+
path, icon, component, status, component_name
155+
)
156+
VALUES (
157+
'${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
158+
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
159+
);
160+
161+
-- 按钮父菜单ID
162+
-- TODO: 请根据您的数据库类型,修改获取上一个插入 ID 的方式
163+
-- MySQL: SELECT @parentId := LAST_INSERT_ID();
164+
-- Oracle: SELECT system_menu_seq.CURRVAL INTO v_parent_id FROM DUAL;
165+
-- PostgreSQL: SELECT lastval() INTO v_parent_id;
166+
-- SQL Server: SET @parentId = SCOPE_IDENTITY();
167+
SELECT @parentId := LAST_INSERT_ID();
168+
169+
-- 按钮 SQL
170+
#foreach ($functionName in $functionNames)
171+
#set ($index = $foreach.count - 1)
172+
INSERT INTO system_menu(
173+
name, permission, type, sort, parent_id,
174+
path, icon, component, status
175+
)
176+
VALUES (
177+
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
178+
'', '', '', 0
179+
);
180+
#end
181+
#end

0 commit comments

Comments
 (0)