Skip to content

Commit baac4fc

Browse files
committed
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-dependencies/pom.xml # yudao-module-report/pom.xml
2 parents a52a357 + a9a6bff commit baac4fc

22 files changed

Lines changed: 749 additions & 341 deletions

File tree

yudao-dependencies/pom.xml

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@
2525
<knife4j.version>4.5.0</knife4j.version>
2626
<servlet.versoin>2.5</servlet.versoin>
2727
<!-- DB 相关 -->
28-
<druid.version>1.2.27</druid.version>
28+
<druid.version>1.2.28</druid.version>
2929
<mybatis.version>3.5.19</mybatis.version>
30-
<mybatis-plus.version>3.5.15</mybatis-plus.version>
31-
<mybatis-plus-join.version>1.5.5</mybatis-plus-join.version>
30+
<mybatis-plus.version>3.5.16</mybatis-plus.version>
31+
<mybatis-plus-join.version>1.5.7</mybatis-plus-join.version>
3232
<dynamic-datasource.version>4.5.0</dynamic-datasource.version>
3333
<easy-trans.version>3.0.6</easy-trans.version>
3434
<redisson.version>3.52.0</redisson.version>
3535
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
36-
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
37-
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
38-
<taos.version>3.7.9</taos.version>
36+
<kingbase.jdbc.version>9.0.1.jre7</kingbase.jdbc.version>
37+
<opengauss.jdbc.version>7.0.0-RC3-og</opengauss.jdbc.version>
38+
<taos.version>3.8.3</taos.version>
3939
<!-- 消息队列 -->
4040
<rocketmq-spring.version>2.3.5</rocketmq-spring.version>
4141
<!-- 服务保障相关 -->
@@ -52,33 +52,33 @@
5252
<flowable.version>6.8.1</flowable.version>
5353
<!-- 工具类相关 -->
5454
<anji-plus-captcha.version>1.4.0</anji-plus-captcha.version>
55-
<jsoup.version>1.21.2</jsoup.version>
56-
<lombok.version>1.18.42</lombok.version>
55+
<jsoup.version>1.22.2</jsoup.version>
56+
<lombok.version>1.18.46</lombok.version>
5757
<mapstruct.version>1.6.3</mapstruct.version>
58-
<hutool-5.version>5.8.42</hutool-5.version>
58+
<hutool-5.version>5.8.44</hutool-5.version>
5959
<fastexcel.version>1.3.0</fastexcel.version>
6060
<velocity.version>2.4</velocity.version> <!-- JDK8 不能从 2.4 升级到 2.4.1,会报包不存在!!!! -->
6161
<fastjson.version>1.2.83</fastjson.version>
62-
<guava.version>33.5.0-jre</guava.version>
62+
<guava.version>33.6.0-jre</guava.version>
6363
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
64-
<commons-net.version>3.12.0</commons-net.version>
64+
<commons-net.version>3.13.0</commons-net.version>
6565
<commons-lang3.version>3.20.0</commons-lang3.version>
66-
<jsch.version>2.27.7</jsch.version>
66+
<jsch.version>2.28.2</jsch.version>
6767
<tika-core.version>2.9.3</tika-core.version> <!-- JDK8 不能从 2.9.3 升级到 3.X,会报 JDK8 不支持 -->
6868
<ip2region.version>2.7.0</ip2region.version>
6969
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
70-
<netty.version>4.2.9.Final</netty.version>
70+
<netty.version>4.2.12.Final</netty.version>
7171
<mqtt.version>1.2.5</mqtt.version>
72-
<vertx.version>4.5.22</vertx.version>
72+
<vertx.version>4.5.26</vertx.version>
7373
<okhttp.version>4.12.0</okhttp.version>
74-
<californium.version>3.12.0</californium.version>
75-
<j2mod.version>3.2.1</j2mod.version>
74+
<californium.version>3.14.0</californium.version>
75+
<j2mod.version>3.3.0</j2mod.version>
7676
<!-- 三方云服务相关 -->
77-
<awssdk.version>2.40.15</awssdk.version>
77+
<awssdk.version>2.44.0</awssdk.version>
7878
<justauth.version>1.16.7</justauth.version>
7979
<justauth-starter.version>1.4.0</justauth-starter.version>
80-
<jimureport.version>2.1.3</jimureport.version>
81-
<jimubi.version>2.3.0</jimubi.version>
80+
<jimureport.version>2.3.2</jimureport.version>
81+
<jimubi.version>2.3.2</jimubi.version>
8282
<weixin-java.version>4.7.9-20251224.161447</weixin-java.version>
8383
<alipay-sdk-java.version>4.40.607.ALL</alipay-sdk-java.version>
8484
<!-- 专属于 JDK8 安全漏洞升级 -->

yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package cn.iocoder.yudao.framework.common.util.http;
22

33
import cn.hutool.core.codec.Base64;
4-
import cn.hutool.core.map.TableMap;
54
import cn.hutool.core.net.url.UrlBuilder;
6-
import cn.hutool.core.util.ReflectUtil;
75
import cn.hutool.core.util.StrUtil;
86
import cn.hutool.http.HttpRequest;
97
import cn.hutool.http.HttpResponse;
@@ -66,14 +64,10 @@ public static String decodeUrlPath(String path) {
6664
return URLDecoder.decode(encoded, StandardCharsets.UTF_8.name());
6765
}
6866

69-
@SuppressWarnings("unchecked")
7067
public static String replaceUrlQuery(String url, String key, String value) {
7168
UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
72-
// 先移除
73-
TableMap<CharSequence, CharSequence> query = (TableMap<CharSequence, CharSequence>)
74-
ReflectUtil.getFieldValue(builder.getQuery(), "query");
75-
query.remove(key);
76-
// 后添加
69+
// 先移除;再添加
70+
builder.getQuery().remove(key);
7771
builder.addQuery(key, value);
7872
return builder.build();
7973
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package cn.iocoder.yudao.framework.common.util.http;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
7+
/**
8+
* {@link HttpUtils} 的单元测试
9+
*/
10+
public class HttpUtilsTest {
11+
12+
@Test
13+
public void testReplaceUrlQuery_replace() {
14+
// 准备参数
15+
String url = "https://www.iocoder.cn/path?a=1&b=2";
16+
// 调用
17+
String result = HttpUtils.replaceUrlQuery(url, "a", "3");
18+
// 断言:被替换的 key 会移到末尾,原顺序的其它参数保留
19+
assertEquals("https://www.iocoder.cn/path?b=2&a=3", result);
20+
}
21+
22+
@Test
23+
public void testReplaceUrlQuery_add() {
24+
// 准备参数
25+
String url = "https://www.iocoder.cn/path?a=1";
26+
// 调用
27+
String result = HttpUtils.replaceUrlQuery(url, "b", "2");
28+
// 断言
29+
assertEquals("https://www.iocoder.cn/path?a=1&b=2", result);
30+
}
31+
32+
@Test
33+
public void testReplaceUrlQuery_noQuery() {
34+
// 准备参数:原 URL 没有 query
35+
String url = "https://www.iocoder.cn/path";
36+
// 调用
37+
String result = HttpUtils.replaceUrlQuery(url, "a", "1");
38+
// 断言
39+
assertEquals("https://www.iocoder.cn/path?a=1", result);
40+
}
41+
42+
@Test
43+
public void testReplaceUrlQuery_emptyValue() {
44+
// 准备参数:value 为空字符串
45+
String url = "https://www.iocoder.cn/path?a=1";
46+
// 调用
47+
String result = HttpUtils.replaceUrlQuery(url, "a", "");
48+
// 断言:保留 key,value 为空
49+
assertEquals("https://www.iocoder.cn/path?a=", result);
50+
}
51+
52+
}

yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeSegmentController.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ public CommonResult<Boolean> updateKnowledgeSegmentStatus(
8383
return success(true);
8484
}
8585

86+
@DeleteMapping("/delete")
87+
@Operation(summary = "删除段落")
88+
@Parameter(name = "id", description = "段落编号", required = true, example = "1024")
89+
@PreAuthorize("@ss.hasPermission('ai:knowledge:delete')")
90+
public CommonResult<Boolean> deleteKnowledgeSegment(@RequestParam("id") Long id) {
91+
segmentService.deleteKnowledgeSegment(id);
92+
return success(true);
93+
}
94+
8695
@GetMapping("/split")
8796
@Operation(summary = "切片内容")
8897
@Parameters({

yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public Long drawImage(Long userId, AiImageDrawReqVO drawReqVO) {
109109
}
110110

111111
@Async
112+
@SuppressWarnings("ConstantValue")
112113
public void executeDrawImage(AiImageDO image, AiImageDrawReqVO reqVO, AiModelDO model) {
113114
try {
114115
// 1.1 构建请求
@@ -164,8 +165,8 @@ private static ImageOptions buildImageOptions(AiImageDrawReqVO draw, AiModelDO m
164165
.build();
165166
} else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.TONG_YI.getPlatform())) {
166167
return DashScopeImageOptions.builder()
167-
.withModel(model.getModel()).withN(1)
168-
.withHeight(draw.getHeight()).withWidth(draw.getWidth())
168+
.model(model.getModel()).n(1)
169+
.height(draw.getHeight()).width(draw.getWidth())
169170
.build();
170171
} else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.YI_YAN.getPlatform())) {
171172
return QianFanImageOptions.builder()

yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ default void createKnowledgeSegmentBySplitContentAsync(Long documentId, String c
9898
*/
9999
void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO);
100100

101+
/**
102+
* 删除知识库段落
103+
*
104+
* @param id 段落编号
105+
*/
106+
void deleteKnowledgeSegment(Long id);
107+
101108
/**
102109
* 重新索引知识库下的所有文档段落
103110
*

yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ public void updateKnowledgeSegment(AiKnowledgeSegmentSaveReqVO reqVO) {
141141
}
142142
}
143143

144+
@Override
145+
public void deleteKnowledgeSegment(Long id) {
146+
// 1. 校验段落存在
147+
AiKnowledgeSegmentDO segment = validateKnowledgeSegmentExists(id);
148+
149+
// 2. 删除向量
150+
VectorStore vectorStore = getVectorStoreById(segment.getKnowledgeId());
151+
deleteVectorStore(vectorStore, segment);
152+
153+
// 3. 删除段落记录
154+
segmentMapper.deleteById(id);
155+
}
156+
144157
@Override
145158
public void deleteKnowledgeSegmentByDocumentId(Long documentId) {
146159
// 1. 查询需要删除的段落

yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cn.iocoder.yudao.module.ai.util;
22

3+
import cn.hutool.core.map.MapUtil;
34
import cn.hutool.core.util.ObjUtil;
45
import cn.hutool.core.util.StrUtil;
6+
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
57
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
68
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
79
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
@@ -33,6 +35,28 @@ public class AiUtils {
3335
public static final String TOOL_CONTEXT_LOGIN_USER = "LOGIN_USER";
3436
public static final String TOOL_CONTEXT_TENANT_ID = "TENANT_ID";
3537

38+
/**
39+
* 通义千问支持多模态的模型
40+
*
41+
* @see <a href="https://bailian.console.aliyun.com/cn-beijing/?tab=model#/model-market/all?providers=qwen&capabilities=VU">模型广场</a>
42+
* @see <a href="https://help.aliyun.com/zh/model-studio/error-code#error-url">必须开启 withMultiModel 参数</a>
43+
*/
44+
public static final Set<String> TONG_YI_MULTI_MODELS = SetUtils.asSet(
45+
// qwen3.5 / 3.6 系列(统一多模态主干)
46+
"qwen3.6-plus", "qwen3.6-flash",
47+
"qwen3.5-plus", "qwen3.5-flash",
48+
// qwen-vl 视觉理解
49+
"qwen3-vl-plus", "qwen3-vl-flash",
50+
"qwen-vl-max", "qwen-vl-plus",
51+
"qwen2.5-vl-72b-instruct", "qwen2.5-vl-32b-instruct",
52+
"qwen2.5-vl-7b-instruct", "qwen2.5-vl-3b-instruct",
53+
// qvq 视觉推理
54+
"qvq-max", "qvq-plus",
55+
// qwen-omni 全模态
56+
"qwen3.5-omni-plus", "qwen3.5-omni-flash",
57+
"qwen3-omni-flash", "qwen-omni-turbo"
58+
);
59+
3660
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens) {
3761
return buildChatOptions(platform, model, temperature, maxTokens, null, null);
3862
}
@@ -44,9 +68,10 @@ public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model
4468
// noinspection EnhancedSwitchMigration
4569
switch (platform) {
4670
case TONG_YI:
47-
return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens)
48-
.withEnableThinking(true) // TODO 芋艿:默认都开启 thinking 模式,后续可以让用户配置
49-
.withToolCallbacks(toolCallbacks).withToolContext(toolContext).build();
71+
return DashScopeChatOptions.builder().model(model).temperature(temperature).maxToken(maxTokens)
72+
.enableThinking(true) // TODO 芋艿:默认都开启 thinking 模式,后续可以让用户配置
73+
.multiModel(TONG_YI_MULTI_MODELS.contains(model)) // 是否多模态模型
74+
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
5075
case YI_YAN:
5176
return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
5277
case DEEP_SEEK:
@@ -125,10 +150,13 @@ public static String getChatResponseReasoningContent(ChatResponse response) {
125150
|| response.getResult().getOutput() == null) {
126151
return null;
127152
}
128-
if (response.getResult().getOutput() instanceof DeepSeekAssistantMessage) {
129-
return ((DeepSeekAssistantMessage) (response.getResult().getOutput())).getReasoningContent();
153+
AssistantMessage output = response.getResult().getOutput();
154+
// DeepSeek 通过专属 AssistantMessage 暴露 reasoningContent
155+
if (output instanceof DeepSeekAssistantMessage) {
156+
return ((DeepSeekAssistantMessage) output).getReasoningContent();
130157
}
131-
return null;
158+
// 通义千问等通过 metadata 透传 reasoningContent
159+
return MapUtil.getStr(output.getMetadata(), "reasoningContent");
132160
}
133161

134162
}

yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ public class TongYiChatModelTests {
3434

3535
private final DashScopeChatModel chatModel = DashScopeChatModel.builder()
3636
.dashScopeApi(DashScopeApi.builder()
37-
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
37+
.apiKey("sk-cd9f39e99ea54840bd1888282325f55a") // https://bailian.console.aliyun.com/cn-beijing/?tab=model#/api-key 获取密钥
3838
.build())
3939
.defaultOptions(DashScopeChatOptions.builder()
40-
// .withModel("qwen1.5-72b-chat") // 模型
41-
.withModel("qwen3-235b-a22b-thinking-2507") // 模型
42-
// .withModel("deepseek-r1") // 模型(deepseek-r1)
43-
// .withModel("deepseek-v3") // 模型(deepseek-v3)
44-
// .withModel("deepseek-r1-distill-qwen-1.5b") // 模型(deepseek-r1-distill-qwen-1.5b)
45-
// .withEnableThinking(true)
40+
.multiModel(true) // 注意:当使用 qwen3.6-plus 等多模态模型,需要设置为 true,可见 https://help.aliyun.com/zh/model-studio/error-code#error-url 链接
41+
.model("qwen3.6-plus") // 模型
42+
// .model("deepseek-r1") // 模型(deepseek-r1)
43+
// .model("deepseek-v3") // 模型(deepseek-v3)
44+
// .model("deepseek-r1-distill-qwen-1.5b") // 模型(deepseek-r1-distill-qwen-1.5b)
45+
// .enableThinking(true)
4646
.build())
4747
.build();
4848

@@ -85,9 +85,9 @@ public void testStream_thinking() {
8585
List<Message> messages = new ArrayList<>();
8686
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
8787
DashScopeChatOptions options = DashScopeChatOptions.builder()
88-
.withModel("qwen3-235b-a22b-thinking-2507")
88+
.model("qwen3.6-plus").multiModel(true)
8989
// .withModel("qwen-max-2025-01-25")
90-
.withEnableThinking(true) // 必须设置,否则会报错
90+
.enableThinking(true) // 必须设置,否则会报错
9191
.build();
9292

9393
// 调用
@@ -112,8 +112,8 @@ public void testRerank() {
112112
Document document01 = new Document("abc");
113113
Document document02 = new Document("sapring");
114114
RerankOptions options = DashScopeRerankOptions.builder()
115-
.withTopN(1)
116-
.withModel("gte-rerank-v2")
115+
.topN(1)
116+
.model("gte-rerank-v2")
117117
.build();
118118
RerankRequest rerankRequest = new RerankRequest(
119119
query,

yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,34 @@
1212
/**
1313
* {@link DashScopeImageModel} 集成测试类
1414
*
15+
* TODO @芋艿:注:spring-ai-alibaba-dashscope(1.1.2.2)的 {@code DashScopeImageApi#resolveImagePath} 未给 {@code wan2.7-image} 加路由分支,
16+
* 会落到默认的 {@code text2image/image-synthesis} 异步端点 + 旧版 {@code prompt} 入参,
17+
* 而该模型实际要求 {@code multimodal-generation/generation} 同步端点 + {@code messages} 入参,
18+
* 端点、异步头、入参结构全部对不上,所以走 SDK 直接调用必失败。
19+
*
20+
* 临时方案:改用 SDK 已支持的 {@code wan2.6-image}(异步)或 {@code qwen-image}(同步);
21+
* 或在项目内同包同名覆盖 {@code DashScopeImageApi},把 {@code wan2.7*} 也路由到 {@code wan2.6-image} 那条 {@code image-generation/generation} 异步分支。
22+
*
1523
* @author fansili
1624
*/
1725
public class TongYiImagesModelTest {
1826

1927
private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
2028
.dashScopeApi(DashScopeImageApi.builder()
21-
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
29+
.apiKey("sk-cd9f39e99ea54840bd1888282325f55a") // https://bailian.console.aliyun.com/cn-beijing/?tab=model#/api-key 获取密钥
2230
.build())
2331
.build();
2432

33+
// TODO @芋艿:
2534
@Test
2635
@Disabled
2736
public void imageCallTest() {
2837
// 准备参数
2938
ImageOptions options = DashScopeImageOptions.builder()
30-
.withModel("wanx-v1")
31-
.withHeight(256).withWidth(256)
39+
.model("wan2.7-image")
40+
// .withSize("2k")
41+
.height(768).width(768)
42+
.n(1)
3243
.build();
3344
ImagePrompt prompt = new ImagePrompt("中国长城!", options);
3445

0 commit comments

Comments
 (0)