diff --git a/pom.xml b/pom.xml
index 366940545..aaf59b512 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,15 +38,15 @@
2026.05-SNAPSHOT
- 17
+ 25
${java.version}
${java.version}
- 3.5.3
+ 3.5.5
3.14.0
1.7.2
1.18.46
- 3.5.15
+ 4.1.0
1.6.3
UTF-8
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index 013853c5e..0224c519c 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -17,11 +17,11 @@
2026.05-SNAPSHOT
1.7.2
- 3.5.15
- 2025.0.1
- 2025.0.0.0
+ 4.1.0
+ 2025.1.2
+ 2025.1.0.0
- 2.8.17
+ 3.0.3
4.5.0
1.2.28
@@ -45,7 +45,7 @@
2.2.7
9.6.0
- 3.5.9
+ 4.1.1
0.33.0
8.0.2.RELEASE
@@ -88,7 +88,7 @@
2.3.4
2.3.2
4.8.4-20260623.211820
- 1.80
+ 1.84
4.40.865.ALL
@@ -159,6 +159,11 @@
spring-boot-configuration-processor
${spring.boot.version}
+
+ org.springframework.boot
+ spring-boot-jackson
+ ${spring.boot.version}
+
cn.iocoder.cloud
@@ -216,7 +221,7 @@
com.alibaba
- druid-spring-boot-3-starter
+ druid-spring-boot-4-starter
${druid.version}
@@ -227,7 +232,7 @@
com.baomidou
- mybatis-plus-spring-boot3-starter
+ mybatis-plus-spring-boot4-starter
${mybatis-plus.version}
@@ -242,7 +247,7 @@
com.baomidou
- dynamic-datasource-spring-boot3-starter
+ dynamic-datasource-spring-boot4-starter
${dynamic-datasource.version}
@@ -287,18 +292,6 @@
org.redisson
redisson-spring-boot-starter
${redisson.version}
-
-
- org.redisson
-
- redisson-spring-data-41
-
-
-
-
- org.redisson
- redisson-spring-data-35
- ${redisson.version}
diff --git a/yudao-framework/yudao-common/pom.xml b/yudao-framework/yudao-common/pom.xml
index 4446762ee..e03f3b173 100644
--- a/yudao-framework/yudao-common/pom.xml
+++ b/yudao-framework/yudao-common/pom.xml
@@ -44,7 +44,6 @@
spring-boot-configuration-processor
true
-
org.springframework
@@ -104,17 +103,17 @@
com.fasterxml.jackson.core
- jackson-databind
+ jackson-annotations
provided
- com.fasterxml.jackson.core
+ tools.jackson.core
jackson-core
provided
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
+ tools.jackson.core
+ jackson-databind
provided
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
index 9452ff442..558c8d293 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
@@ -6,20 +6,18 @@ import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JacksonException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.databind.json.JsonMapper;
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.type.TypeReference;
+import tools.jackson.databind.DeserializationFeature;
+import tools.jackson.databind.JsonNode;
+import tools.jackson.databind.ObjectMapper;
+import tools.jackson.databind.SerializationFeature;
+import tools.jackson.databind.json.JsonMapper;
+import tools.jackson.databind.module.SimpleModule;
-import java.io.IOException;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.ArrayList;
@@ -38,14 +36,14 @@ public class JsonUtils {
private static ObjectMapper objectMapper = buildObjectMapper();
private static ObjectMapper buildObjectMapper() {
- SimpleModule simpleModule = new JavaTimeModule()
+ SimpleModule simpleModule = new SimpleModule()
// 解决 LocalDateTime 的序列化
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
return JsonMapper.builder()
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
- .defaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL))
+ .changeDefaultPropertyInclusion(value -> JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL))
.addModule(simpleModule)
.build();
}
@@ -120,7 +118,7 @@ public class JsonUtils {
}
try {
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
- } catch (IOException e) {
+ } catch (JacksonException e) {
log.error("json parse err,json:{}", text, e);
throw new RuntimeException(e);
}
@@ -148,7 +146,7 @@ public class JsonUtils {
}
try {
return objectMapper.readValue(bytes, clazz);
- } catch (IOException e) {
+ } catch (JacksonException e) {
log.error("json parse err,json:{}", bytes, e);
throw new RuntimeException(e);
}
@@ -251,7 +249,7 @@ public class JsonUtils {
public static JsonNode parseTree(byte[] text) {
try {
return objectMapper.readTree(text);
- } catch (IOException e) {
+ } catch (JacksonException e) {
log.error("json parse err,json:{}", text, e);
throw new RuntimeException(e);
}
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java
index 35fc9f72c..0e7d052b8 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java
@@ -1,10 +1,9 @@
package cn.iocoder.yudao.framework.common.util.json.databind;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
-
-import java.io.IOException;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.annotation.JacksonStdImpl;
/**
* Long 序列化规则
@@ -14,7 +13,7 @@ import java.io.IOException;
* @author 星语
*/
@JacksonStdImpl
-public class NumberSerializer extends com.fasterxml.jackson.databind.ser.std.NumberSerializer {
+public class NumberSerializer extends tools.jackson.databind.ser.jdk.NumberSerializer {
private static final long MAX_SAFE_INTEGER = 9007199254740991L;
private static final long MIN_SAFE_INTEGER = -9007199254740991L;
@@ -26,7 +25,7 @@ public class NumberSerializer extends com.fasterxml.jackson.databind.ser.std.Num
}
@Override
- public void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+ public void serialize(Number value, JsonGenerator gen, SerializationContext serializers) throws JacksonException {
// 超出范围 序列化位字符串
if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
super.serialize(value, gen, serializers);
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeDeserializer.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeDeserializer.java
index 5bf5d6c63..4d639ba8e 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeDeserializer.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeDeserializer.java
@@ -1,25 +1,24 @@
package cn.iocoder.yudao.framework.common.util.json.databind;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-
-import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonParser;
+import tools.jackson.databind.DeserializationContext;
+import tools.jackson.databind.ValueDeserializer;
/**
* 基于时间戳的 LocalDateTime 反序列化器
*
* @author 老五
*/
-public class TimestampLocalDateTimeDeserializer extends JsonDeserializer {
+public class TimestampLocalDateTimeDeserializer extends ValueDeserializer {
public static final TimestampLocalDateTimeDeserializer INSTANCE = new TimestampLocalDateTimeDeserializer();
@Override
- public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException {
// 将 Long 时间戳,转换为 LocalDateTime 对象
return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
}
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java
index 4e422feef..fc49e805e 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeSerializer.java
@@ -5,12 +5,12 @@ import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.extern.slf4j.Slf4j;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdScalarSerializer;
-import java.io.IOException;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -25,18 +25,22 @@ import java.util.concurrent.ConcurrentHashMap;
* @author 老五
*/
@Slf4j
-public class TimestampLocalDateTimeSerializer extends JsonSerializer {
+public class TimestampLocalDateTimeSerializer extends StdScalarSerializer {
public static final TimestampLocalDateTimeSerializer INSTANCE = new TimestampLocalDateTimeSerializer();
private static final Map, Map> FIELD_CACHE = new ConcurrentHashMap<>();
+ public TimestampLocalDateTimeSerializer() {
+ super(LocalDateTime.class);
+ }
+
@Override
- public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+ public void serialize(LocalDateTime value, JsonGenerator gen, SerializationContext serializers) throws JacksonException {
// 情况一:有 JsonFormat 自定义注解,则使用它。https://github.com/YunaiV/ruoyi-vue-pro/pull/1019
- String fieldName = gen.getOutputContext().getCurrentName();
+ String fieldName = gen.streamWriteContext().currentName();
if (fieldName != null) {
- Object currentValue = gen.getOutputContext().getCurrentValue();
+ Object currentValue = gen.currentValue();
if (currentValue != null) {
Class> clazz = currentValue.getClass();
Map fieldMap = FIELD_CACHE.computeIfAbsent(clazz, this::buildFieldMap);
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
index 905f5d541..260eee858 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
@@ -26,10 +26,9 @@ public class ServletUtils {
* @param response 响应
* @param object 对象,会序列化成 JSON 字符串
*/
- @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
public static void writeJSON(HttpServletResponse response, Object object) {
String content = JsonUtils.toJsonString(object);
- JakartaServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
+ JakartaServletUtil.write(response, content, MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8");
}
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
index 0a79468b3..e636624f0 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
@@ -129,6 +129,7 @@ public class YudaoTenantAutoConfiguration {
*
* @return 忽略租户的 URL 集合
*/
+ @SuppressWarnings("removal")
private Set getTenantIgnoreUrls() {
Set ignoreUrls = new HashSet<>();
// 获得接口对应的 HandlerMethod 集合
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java
index 8bf7cc1a8..55f982db2 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/mq/kafka/TenantKafkaEnvironmentPostProcessor.java
@@ -2,8 +2,8 @@ package cn.iocoder.yudao.framework.tenant.core.mq.kafka;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.EnvironmentPostProcessor;
import org.springframework.boot.SpringApplication;
-import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories
index a495842a0..560a54170 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/resources/META-INF/spring.factories
@@ -1,2 +1,2 @@
-org.springframework.boot.env.EnvironmentPostProcessor=\
+org.springframework.boot.EnvironmentPostProcessor=\
cn.iocoder.yudao.framework.tenant.core.mq.kafka.TenantKafkaEnvironmentPostProcessor
diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml b/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml
index de0a0ed74..89a2939eb 100644
--- a/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-monitor/pom.xml
@@ -24,7 +24,7 @@
org.springframework.boot
- spring-boot-starter-aop
+ spring-boot-starter-aspectj
@@ -41,6 +41,11 @@
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
io.opentracing
opentracing-util
diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java
index 9b75d960c..688601f21 100644
--- a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoMetricsAutoConfiguration.java
@@ -2,12 +2,11 @@ package cn.iocoder.yudao.framework.tracer.config;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
/**
* Metrics 配置类
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java
index af1467376..4d6dd1944 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/rabbitmq/config/YudaoRabbitMQAutoConfiguration.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.framework.mq.rabbitmq.config;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
+import org.springframework.amqp.support.converter.JacksonJsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -18,11 +18,11 @@ import org.springframework.context.annotation.Bean;
public class YudaoRabbitMQAutoConfiguration {
/**
- * Jackson2JsonMessageConverter Bean:使用 jackson 序列化消息
+ * JacksonJsonMessageConverter Bean:使用 jackson 序列化消息
*/
@Bean
public MessageConverter createMessageConverter() {
- return new Jackson2JsonMessageConverter();
+ return new JacksonJsonMessageConverter();
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
index cd3f70c2e..12eb52d4a 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -66,11 +66,11 @@
com.alibaba
- druid-spring-boot-3-starter
+ druid-spring-boot-4-starter
com.baomidou
- mybatis-plus-spring-boot3-starter
+ mybatis-plus-spring-boot4-starter
com.baomidou
@@ -78,13 +78,7 @@
com.baomidou
- dynamic-datasource-spring-boot3-starter
-
-
- org.springframework.boot
- spring-boot-starter-undertow
-
-
+ dynamic-datasource-spring-boot4-starter
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java
index 879a19aae..30063d9da 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/config/YudaoDataSourceAutoConfiguration.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.framework.datasource.config;
import cn.iocoder.yudao.framework.datasource.core.filter.DruidAdRemoveFilter;
-import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.spring.boot4.autoconfigure.properties.DruidStatProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java
index 0ea6bf252..cf1797a7f 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessor.java
@@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.EnvironmentPostProcessor;
import org.springframework.boot.SpringApplication;
-import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
index 775447a06..e5fb82eaa 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java
@@ -9,19 +9,19 @@ import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.baomidou.mybatisplus.core.handlers.IJsonTypeHandler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.baomidou.mybatisplus.extension.handlers.Jackson3TypeHandler;
import com.baomidou.mybatisplus.extension.incrementer.*;
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
-import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.ConfigurableEnvironment;
+import tools.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -81,15 +81,15 @@ public class YudaoMybatisAutoConfiguration {
throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType));
}
- @Bean // 特殊:返回结果使用 Object 而不用 JacksonTypeHandler 的原因,避免因为 JacksonTypeHandler 被 mybatis 全局使用!
+ @Bean // 特殊:返回结果使用 Object 而不用 Jackson3TypeHandler 的原因,避免因为 Jackson3TypeHandler 被 mybatis 全局使用!
public Object jacksonTypeHandler(List objectMappers) {
- // 特殊:设置 JacksonTypeHandler 的 ObjectMapper!
+ // 特殊:设置 Jackson3TypeHandler 的 ObjectMapper!
ObjectMapper objectMapper = CollUtil.getFirst(objectMappers);
if (objectMapper == null) {
objectMapper = JsonUtils.getObjectMapper();
}
- JacksonTypeHandler.setObjectMapper(objectMapper);
- return new JacksonTypeHandler(Object.class);
+ Jackson3TypeHandler.setObjectMapper(objectMapper);
+ return new Jackson3TypeHandler(Object.class);
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories
index eb172e4ce..ff83b2a62 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/resources/META-INF/spring.factories
@@ -1,2 +1,2 @@
-org.springframework.boot.env.EnvironmentPostProcessor=\
+org.springframework.boot.EnvironmentPostProcessor=\
cn.iocoder.yudao.framework.mybatis.config.IdTypeEnvironmentPostProcessor
diff --git a/yudao-framework/yudao-spring-boot-starter-redis/pom.xml b/yudao-framework/yudao-spring-boot-starter-redis/pom.xml
index e5d3a9a7c..d1e25c8f9 100644
--- a/yudao-framework/yudao-spring-boot-starter-redis/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-redis/pom.xml
@@ -26,10 +26,6 @@
org.redisson
redisson-spring-boot-starter
-
- org.redisson
- redisson-spring-data-35
-
org.springframework.boot
@@ -37,8 +33,8 @@
- com.fasterxml.jackson.datatype
- jackson-datatype-jsr310
+ org.springframework.boot
+ spring-boot-jackson
diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
index afdb32cc7..cc9409406 100644
--- a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.redis.config;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.cache.CacheProperties;
+import org.springframework.boot.cache.autoconfigure.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
index b6374e9f0..87d0b7214 100644
--- a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
@@ -1,9 +1,6 @@
package cn.iocoder.yudao.framework.redis.config;
-import cn.hutool.core.util.ReflectUtil;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import org.redisson.spring.starter.RedissonAutoConfigurationV2;
+import org.redisson.spring.starter.RedissonAutoConfigurationV4;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -13,7 +10,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
/**
* Redis 配置类
*/
-@AutoConfiguration(before = RedissonAutoConfigurationV2.class) // 目的:使用自己定义的 RedisTemplate Bean
+@AutoConfiguration(before = RedissonAutoConfigurationV4.class) // 目的:使用自己定义的 RedisTemplate Bean
public class YudaoRedisAutoConfiguration {
/**
@@ -35,11 +32,11 @@ public class YudaoRedisAutoConfiguration {
return template;
}
+ @SuppressWarnings("UnnecessaryLocalVariable")
public static RedisSerializer> buildRedisSerializer() {
RedisSerializer
+
+ org.springframework.boot
+ spring-boot-jackson
+
+
+ org.springframework.boot
+ spring-boot-restclient
+
org.springframework.boot
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java
index efaed77f1..cd0b2fabc 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java
@@ -19,7 +19,6 @@ import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
-import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.FilterChain;
@@ -35,6 +34,7 @@ import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import java.util.Map;
+import tools.jackson.databind.JsonNode;
import static cn.iocoder.yudao.framework.apilog.core.interceptor.ApiAccessLogInterceptor.ATTRIBUTE_HANDLER_METHOD;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java
index 1e252c052..a62d7b5e3 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/annotation/DesensitizeBy.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.desensitize.core.base.annotation;
import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler;
import cn.iocoder.yudao.framework.desensitize.core.base.serializer.StringDesensitizeSerializer;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.*;
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java
index 566b0d176..987336606 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/base/serializer/StringDesensitizeSerializer.java
@@ -7,16 +7,15 @@ import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy;
import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.BeanProperty;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.ContextualSerializer;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.Getter;
import lombok.Setter;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.BeanProperty;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ValueSerializer;
+import tools.jackson.databind.ser.std.StdSerializer;
-import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
@@ -28,7 +27,7 @@ import java.lang.reflect.Field;
* @author gaibu
*/
@SuppressWarnings("rawtypes")
-public class StringDesensitizeSerializer extends StdSerializer implements ContextualSerializer {
+public class StringDesensitizeSerializer extends StdSerializer {
@Getter
@Setter
@@ -39,7 +38,7 @@ public class StringDesensitizeSerializer extends StdSerializer implement
}
@Override
- public JsonSerializer> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) {
+ public ValueSerializer> createContextual(SerializationContext serializerProvider, BeanProperty beanProperty) {
DesensitizeBy annotation = beanProperty.getAnnotation(DesensitizeBy.class);
if (annotation == null) {
return this;
@@ -52,7 +51,7 @@ public class StringDesensitizeSerializer extends StdSerializer implement
@Override
@SuppressWarnings("unchecked")
- public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
+ public void serialize(String value, JsonGenerator gen, SerializationContext serializerProvider) throws JacksonException {
if (StrUtil.isBlank(value)) {
gen.writeNull();
return;
@@ -83,7 +82,7 @@ public class StringDesensitizeSerializer extends StdSerializer implement
* @return 字段
*/
private Field getField(JsonGenerator generator) {
- String currentName = generator.getOutputContext().getCurrentName();
+ String currentName = generator.streamWriteContext().currentName();
Object currentValue = generator.currentValue();
Class> currentValueClass = currentValue.getClass();
return ReflectUtil.getField(currentValueClass, currentName);
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
index 280f8da34..3225d4d68 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
@@ -4,18 +4,18 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
-import com.fasterxml.jackson.databind.Module;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
+import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
+import tools.jackson.databind.JacksonModule;
+import tools.jackson.databind.ObjectMapper;
+import tools.jackson.databind.ext.javatime.deser.LocalDateDeserializer;
+import tools.jackson.databind.ext.javatime.deser.LocalTimeDeserializer;
+import tools.jackson.databind.ext.javatime.ser.LocalDateSerializer;
+import tools.jackson.databind.ext.javatime.ser.LocalTimeSerializer;
+import tools.jackson.databind.module.SimpleModule;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -29,26 +29,15 @@ public class YudaoJacksonAutoConfiguration {
* 从 Builder 源头定制(关键:使用 *ByType,避免 handledType 要求)
*/
@Bean
- public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() {
- return builder -> builder
- // Long -> Number
- .serializerByType(Long.class, NumberSerializer.INSTANCE)
- .serializerByType(Long.TYPE, NumberSerializer.INSTANCE)
- // LocalDate / LocalTime
- .serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE)
- .deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE)
- .serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE)
- .deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE)
- // LocalDateTime < - > EpochMillis
- .serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
- .deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
+ public JsonMapperBuilderCustomizer ldtEpochMillisCustomizer(JacksonModule timestampSupportModuleBean) {
+ return builder -> builder.addModule(timestampSupportModuleBean);
}
/**
* 以 Bean 形式暴露 Module(Boot 会自动注册到所有 ObjectMapper)
*/
@Bean
- public Module timestampSupportModuleBean() {
+ public JacksonModule timestampSupportModuleBean() {
SimpleModule m = new SimpleModule("TimestampSupportModule");
// Long -> Number,避免前端精度丢失
m.addSerializer(Long.class, NumberSerializer.INSTANCE);
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
index 745c9775e..a559c80c7 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
@@ -14,11 +14,11 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
-import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.boot.restclient.RestTemplateBuilder;
+import org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
index 91dc38967..8821683b3 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -15,7 +15,6 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
-import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.google.common.util.concurrent.UncheckedExecutionException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
@@ -39,6 +38,7 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;
+import tools.jackson.databind.exc.InvalidFormatException;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java
index fcac987a7..4a983e11e 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/config/YudaoXssAutoConfiguration.java
@@ -5,12 +5,11 @@ import cn.iocoder.yudao.framework.xss.core.clean.JsoupXssCleaner;
import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner;
import cn.iocoder.yudao.framework.xss.core.filter.XssFilter;
import cn.iocoder.yudao.framework.xss.core.json.XssStringJsonDeserializer;
-import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@@ -38,17 +37,17 @@ public class YudaoXssAutoConfiguration implements WebMvcConfigurer {
/**
* 注册 Jackson 的序列化器,用于处理 json 类型参数的 xss 过滤
*
- * @return Jackson2ObjectMapperBuilderCustomizer
+ * @return JsonMapperBuilderCustomizer
*/
@Bean
@ConditionalOnMissingBean(name = "xssJacksonCustomizer")
@ConditionalOnProperty(value = "yudao.xss.enable", havingValue = "true")
- public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssProperties properties,
- PathMatcher pathMatcher,
- XssCleaner xssCleaner) {
+ public JsonMapperBuilderCustomizer xssJacksonCustomizer(XssProperties properties,
+ PathMatcher pathMatcher,
+ XssCleaner xssCleaner) {
// 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer,在序列化时进行处理
- return builder ->
- builder.deserializerByType(String.class, new XssStringJsonDeserializer(properties, pathMatcher, xssCleaner));
+ return builder -> builder.addModule(new tools.jackson.databind.module.SimpleModule("XssStringModule")
+ .addDeserializer(String.class, new XssStringJsonDeserializer(properties, pathMatcher, xssCleaner)));
}
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java
index 047b19d38..4874ebd00 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/xss/core/json/XssStringJsonDeserializer.java
@@ -3,16 +3,15 @@ package cn.iocoder.yudao.framework.xss.core.json;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.xss.config.XssProperties;
import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.PathMatcher;
-
-import java.io.IOException;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonParser;
+import tools.jackson.core.JsonToken;
+import tools.jackson.databind.DeserializationContext;
+import tools.jackson.databind.deser.jdk.StringDeserializer;
/**
* XSS 过滤 jackson 反序列化器。
@@ -36,19 +35,19 @@ public class XssStringJsonDeserializer extends StringDeserializer {
private final XssCleaner xssCleaner;
@Override
- public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ public String deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException {
// 1. 白名单 URL 的处理
HttpServletRequest request = ServletUtils.getRequest();
if (request != null) {
String uri = ServletUtils.getRequest().getRequestURI();
if (properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, uri))) {
- return p.getText();
+ return p.getString();
}
}
// 2. 真正使用 xssCleaner 进行过滤
if (p.hasToken(JsonToken.VALUE_STRING)) {
- return xssCleaner.clean(p.getText());
+ return xssCleaner.clean(p.getString());
}
JsonToken t = p.currentToken();
// [databind#381]
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java
index 9a29f7a36..6e4a1c582 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/logging/AccessLogFilter.java
@@ -107,6 +107,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
}
@Override
+ @SuppressWarnings("removal")
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 将 Request 中可以直接获取到的参数,设置到网关日志
ServerHttpRequest request = exchange.getRequest();
@@ -117,7 +118,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
gatewayLog.setRequestMethod(request.getMethod().name());
gatewayLog.setRequestUrl(request.getURI().getRawPath());
gatewayLog.setQueryParams(request.getQueryParams());
- gatewayLog.setRequestHeaders(request.getHeaders());
+ gatewayLog.setRequestHeaders(request.getHeaders().asMultiValueMap());
gatewayLog.setStartTime(LocalDateTime.now());
gatewayLog.setUserIp(WebFrameworkUtils.getClientIP(exchange));
@@ -192,7 +193,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
// 设置其它字段
gatewayLog.setUserId(SecurityFrameworkUtils.getLoginUserId(exchange));
gatewayLog.setUserType(SecurityFrameworkUtils.getLoginUserType(exchange));
- gatewayLog.setResponseHeaders(response.getHeaders());
+ gatewayLog.setResponseHeaders(response.getHeaders().asMultiValueMap());
gatewayLog.setHttpStatus((HttpStatus) response.getStatusCode());
// 获取响应类型,如果是 json 就打印
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java
index f2e96719c..8daff57c3 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/filter/security/TokenAuthenticationFilter.java
@@ -9,7 +9,7 @@ import cn.iocoder.yudao.gateway.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.gateway.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
-import com.fasterxml.jackson.core.type.TypeReference;
+import tools.jackson.core.type.TypeReference;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction;
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/handler/GlobalExceptionHandler.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/handler/GlobalExceptionHandler.java
index e967cb775..5757352ac 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/handler/GlobalExceptionHandler.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/handler/GlobalExceptionHandler.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.gateway.handler;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.gateway.util.WebFrameworkUtils;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
+import org.springframework.boot.webflux.error.ErrorWebExceptionHandler;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/jackson/GatewayJacksonAutoConfiguration.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/jackson/GatewayJacksonAutoConfiguration.java
index c7ccadf70..7877f157f 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/jackson/GatewayJacksonAutoConfiguration.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/jackson/GatewayJacksonAutoConfiguration.java
@@ -4,20 +4,21 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
-import com.fasterxml.jackson.databind.Module;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.boot.web.codec.CodecCustomizer;
+import org.springframework.boot.http.codec.CodecCustomizer;
+import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
-import org.springframework.http.codec.json.Jackson2JsonDecoder;
-import org.springframework.http.codec.json.Jackson2JsonEncoder;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.codec.json.JacksonJsonDecoder;
+import org.springframework.http.codec.json.JacksonJsonEncoder;
+import tools.jackson.databind.JacksonModule;
+import tools.jackson.databind.ObjectMapper;
+import tools.jackson.databind.ext.javatime.deser.LocalDateDeserializer;
+import tools.jackson.databind.ext.javatime.deser.LocalTimeDeserializer;
+import tools.jackson.databind.ext.javatime.ser.LocalDateSerializer;
+import tools.jackson.databind.ext.javatime.ser.LocalTimeSerializer;
+import tools.jackson.databind.json.JsonMapper;
+import tools.jackson.databind.module.SimpleModule;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -31,26 +32,15 @@ public class GatewayJacksonAutoConfiguration {
* 从 Builder 源头定制(关键:使用 *ByType,避免 handledType 要求)
*/
@Bean
- public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() {
- return builder -> builder
- // Long -> Number
- .serializerByType(Long.class, NumberSerializer.INSTANCE)
- .serializerByType(Long.TYPE, NumberSerializer.INSTANCE)
- // LocalDate / LocalTime
- .serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE)
- .deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE)
- .serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE)
- .deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE)
- // LocalDateTime < - > EpochMillis
- .serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
- .deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
+ public JsonMapperBuilderCustomizer ldtEpochMillisCustomizer(JacksonModule timestampSupportModuleBean) {
+ return builder -> builder.addModule(timestampSupportModuleBean);
}
/**
* 以 Bean 形式暴露 Module(Boot 会自动注册到所有 ObjectMapper)
*/
@Bean
- public Module timestampSupportModuleBean() {
+ public JacksonModule timestampSupportModuleBean() {
SimpleModule m = new SimpleModule("TimestampSupportModule");
// Long -> Number
m.addSerializer(Long.class, NumberSerializer.INSTANCE);
@@ -81,12 +71,12 @@ public class GatewayJacksonAutoConfiguration {
* WebFlux 场景:强制默认编解码器使用同一个 ObjectMapper
*/
@Bean
- public CodecCustomizer unifyJackson(ObjectMapper om) {
+ public CodecCustomizer unifyJackson(JsonMapper om) {
return configurer -> {
- Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(om);
- Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(om);
- configurer.defaultCodecs().jackson2JsonDecoder(decoder);
- configurer.defaultCodecs().jackson2JsonEncoder(encoder);
+ JacksonJsonDecoder decoder = new JacksonJsonDecoder(om);
+ JacksonJsonEncoder encoder = new JacksonJsonEncoder(om);
+ configurer.defaultCodecs().jacksonJsonDecoder(decoder);
+ configurer.defaultCodecs().jacksonJsonEncoder(encoder);
};
}
}
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/SecurityFrameworkUtils.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/SecurityFrameworkUtils.java
index d1c0eeaf0..03fbbdfef 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/SecurityFrameworkUtils.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/SecurityFrameworkUtils.java
@@ -69,7 +69,7 @@ public class SecurityFrameworkUtils {
*/
public static ServerWebExchange removeLoginUser(ServerWebExchange exchange) {
// 如果不包含,直接返回
- if (!exchange.getRequest().getHeaders().containsKey(LOGIN_USER_HEADER)) {
+ if (!exchange.getRequest().getHeaders().containsHeader(LOGIN_USER_HEADER)) {
return exchange;
}
// 如果包含,则移除。参考 RemoveRequestHeaderGatewayFilterFactory 实现
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java
index bc28664bc..001f6fbb8 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/WebFrameworkUtils.java
@@ -54,11 +54,10 @@ public class WebFrameworkUtils {
* @param exchange 响应
* @param object 对象,会序列化成 JSON 字符串
*/
- @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE,否则会乱码
public static Mono writeJSON(ServerWebExchange exchange, Object object) {
// 设置 header
ServerHttpResponse response = exchange.getResponse();
- response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
+ response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
// 设置 body
return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
diff --git a/yudao-gateway/src/main/resources/application.yaml b/yudao-gateway/src/main/resources/application.yaml
index 4b97b5a8c..68dfe1ade 100644
--- a/yudao-gateway/src/main/resources/application.yaml
+++ b/yudao-gateway/src/main/resources/application.yaml
@@ -9,14 +9,6 @@ spring:
codecs:
max-in-memory-size: 10MB # 调整缓冲区大小https://gitee.com/zhijiantianya/yudao-cloud/pulls/176
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
-
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
diff --git a/yudao-module-ai/yudao-module-ai-server/pom.xml b/yudao-module-ai/yudao-module-ai-server/pom.xml
index 0871d8e75..d9613ccf1 100644
--- a/yudao-module-ai/yudao-module-ai-server/pom.xml
+++ b/yudao-module-ai/yudao-module-ai-server/pom.xml
@@ -19,9 +19,9 @@
国外:OpenAI、Ollama、Midjourney、StableDiffusion、Suno
- 1.1.5
+ 2.0.0
- 1.1.2.2
+ 2.0.0-M1.1
1.2.6
@@ -122,11 +122,6 @@
-
- org.springframework.ai
- spring-ai-starter-model-azure-openai
- ${spring-ai.version}
-
org.springframework.ai
spring-ai-starter-model-anthropic
@@ -147,18 +142,6 @@
spring-ai-starter-model-stability-ai
${spring-ai.version}
-
-
- org.springframework.ai
- spring-ai-starter-model-zhipuai
- ${spring-ai.version}
-
-
- org.springframework.ai
- spring-ai-starter-model-minimax
- ${spring-ai.version}
-
-
com.alibaba.cloud.ai
@@ -166,19 +149,6 @@
${alibaba-ai.version}
-
-
- org.springaicommunity
- qianfan-spring-boot-starter
- 1.0.0
-
-
-
- org.springaicommunity
- moonshot-spring-boot-starter
- 1.0.0
-
-
@@ -247,12 +217,22 @@
+
+ org.springframework.ai
+ spring-ai-autoconfigure-mcp-server-common
+ ${spring-ai.version}
+
org.springframework.ai
spring-ai-starter-mcp-client
${spring-ai.version}
+
+ org.springframework.ai
+ spring-ai-autoconfigure-mcp-client-common
+ ${spring-ai.version}
+
@@ -315,4 +295,4 @@
-
\ No newline at end of file
+
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
index 9009cbc8c..61336f148 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
@@ -10,25 +10,38 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel
import cn.iocoder.yudao.module.ai.framework.ai.core.model.grok.GrokChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax.MiniMaxChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot.MoonshotChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan.YiYanChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu.ZhiPuChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient;
import cn.iocoder.yudao.module.ai.tool.method.PersonService;
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
+import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingModel;
+import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingOptions;
+import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
+import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import io.micrometer.observation.ObservationRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
+import org.springframework.ai.document.MetadataMode;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.openai.api.OpenAiApi;
+import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
import org.springframework.ai.tokenizer.TokenCountEstimator;
@@ -40,11 +53,11 @@ import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStorePr
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
-import java.util.Optional;
/**
* 芋道 AI 自动配置
@@ -74,6 +87,73 @@ public class AiAutoConfiguration {
// ========== 各种 AI Client 创建 ==========
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.ai.dashscope.api-key")
+ public DashScopeChatModel dashScopeChatModel(@Value("${spring.ai.dashscope.api-key}") String apiKey,
+ ToolCallingManager toolCallingManager,
+ ObservationRegistry observationRegistry) {
+ return buildTongYiChatModel(apiKey, toolCallingManager, observationRegistry);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.ai.dashscope.api-key")
+ public DashScopeImageModel dashScopeImageModel(@Value("${spring.ai.dashscope.api-key}") String apiKey,
+ ObservationRegistry observationRegistry) {
+ return buildTongYiImagesModel(apiKey, observationRegistry);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.ai.dashscope.api-key")
+ public DashScopeEmbeddingModel dashScopeEmbeddingModel(@Value("${spring.ai.dashscope.api-key}") String apiKey,
+ ObservationRegistry observationRegistry) {
+ return buildTongYiEmbeddingModel(apiKey, null, observationRegistry);
+ }
+
+ public static DashScopeChatModel buildTongYiChatModel(String apiKey) {
+ return buildTongYiChatModel(apiKey, getToolCallingManager(), getObservationRegistry());
+ }
+
+ private static DashScopeChatModel buildTongYiChatModel(String apiKey, ToolCallingManager toolCallingManager,
+ ObservationRegistry observationRegistry) {
+ DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
+ DashScopeChatOptions options = DashScopeChatOptions.builder()
+ .model(DashScopeApi.DEFAULT_CHAT_MODEL)
+ .temperature(0.7)
+ .build();
+ return new DashScopeChatModel(dashScopeApi, options, toolCallingManager, RetryUtils.DEFAULT_RETRY_TEMPLATE,
+ observationRegistry);
+ }
+
+ public static DashScopeImageModel buildTongYiImagesModel(String apiKey) {
+ return buildTongYiImagesModel(apiKey, getObservationRegistry());
+ }
+
+ private static DashScopeImageModel buildTongYiImagesModel(String apiKey, ObservationRegistry observationRegistry) {
+ DashScopeImageApi dashScopeImageApi = DashScopeImageApi.builder().apiKey(apiKey).build();
+ DashScopeImageOptions options = DashScopeImageOptions.builder()
+ .model(DashScopeImageApi.DEFAULT_IMAGE_MODEL)
+ .build();
+ return new DashScopeImageModel(dashScopeImageApi, options, RetryUtils.DEFAULT_RETRY_TEMPLATE,
+ observationRegistry);
+ }
+
+ public static DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) {
+ return buildTongYiEmbeddingModel(apiKey, model, getObservationRegistry());
+ }
+
+ private static DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model,
+ ObservationRegistry observationRegistry) {
+ DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
+ DashScopeEmbeddingOptions options = DashScopeEmbeddingOptions.builder()
+ .model(StrUtil.blankToDefault(model, DashScopeApi.DEFAULT_EMBEDDING_MODEL))
+ .build();
+ return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.EMBED, options, RetryUtils.DEFAULT_RETRY_TEMPLATE,
+ observationRegistry);
+ }
+
@Bean
@ConditionalOnProperty(value = "yudao.ai.gemini.enable", havingValue = "true")
public GeminiChatModel geminiChatModel(YudaoAiProperties yudaoAiProperties) {
@@ -86,18 +166,14 @@ public class AiAutoConfiguration {
properties.setModel(GeminiChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl(GeminiChatModel.BASE_URL)
- .completionsPath(GeminiChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new GeminiChatModel(openAiChatModel);
}
@@ -114,18 +190,14 @@ public class AiAutoConfiguration {
properties.setModel(DouBaoChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl(DouBaoChatModel.BASE_URL)
- .completionsPath(DouBaoChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new DouBaoChatModel(openAiChatModel);
}
@@ -146,13 +218,12 @@ public class AiAutoConfiguration {
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
.apiKey(properties.getApiKey())
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new SiliconFlowChatModel(openAiChatModel);
}
@@ -181,13 +252,12 @@ public class AiAutoConfiguration {
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new HunYuanChatModel(openAiChatModel);
}
@@ -203,23 +273,17 @@ public class AiAutoConfiguration {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(XingHuoChatModel.MODEL_DEFAULT);
}
- OpenAiApi.Builder builder = OpenAiApi.builder()
- .baseUrl(XingHuoChatModel.BASE_URL_V1)
- .apiKey(properties.getAppKey() + ":" + properties.getSecretKey());
- if ("x1".equals(properties.getModel())) {
- builder.baseUrl(XingHuoChatModel.BASE_URL_V2)
- .completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2);
- }
+ String baseUrl = "x1".equals(properties.getModel()) ? XingHuoChatModel.BASE_URL_V2
+ : XingHuoChatModel.BASE_URL_V1;
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(builder.build())
- .defaultOptions(OpenAiChatOptions.builder()
+ .options(OpenAiChatOptions.builder()
+ .baseUrl(baseUrl)
+ .apiKey(properties.getAppKey() + ":" + properties.getSecretKey())
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- // TODO @芋艿:星火的 function call 有 bug,会报 ToolResponseMessage must have an id 错误!!!
- .toolCallingManager(getToolCallingManager())
.build();
return new XingHuoChatModel(openAiChatModel);
}
@@ -236,21 +300,116 @@ public class AiAutoConfiguration {
properties.setModel(BaiChuanChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl(BaiChuanChatModel.BASE_URL)
.apiKey(properties.getApiKey())
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new BaiChuanChatModel(openAiChatModel);
}
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.yiyan.enable", havingValue = "true")
+ public YiYanChatModel yiYanChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.YiYan properties = yudaoAiProperties.getYiyan();
+ return buildYiYanChatClient(properties);
+ }
+
+ public YiYanChatModel buildYiYanChatClient(YudaoAiProperties.YiYan properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(YiYanChatModel.MODEL_DEFAULT);
+ }
+ return new YiYanChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), YiYanChatModel.BASE_URL),
+ null, properties.getApiKey(), properties.getModel(), properties.getTemperature(),
+ properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.zhipu.enable", havingValue = "true")
+ public ZhiPuChatModel zhiPuChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.ZhiPu properties = yudaoAiProperties.getZhipu();
+ return buildZhiPuChatClient(properties);
+ }
+
+ public ZhiPuChatModel buildZhiPuChatClient(YudaoAiProperties.ZhiPu properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(ZhiPuChatModel.MODEL_DEFAULT);
+ }
+ DeepSeekChatModel deepSeekChatModel = DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(StrUtil.blankToDefault(properties.getBaseUrl(), ZhiPuChatModel.BASE_URL))
+ .apiKey(properties.getApiKey())
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(properties.getModel())
+ .temperature(properties.getTemperature())
+ .maxTokens(properties.getMaxTokens())
+ .topP(properties.getTopP())
+ .build())
+ .build();
+ return new ZhiPuChatModel(deepSeekChatModel);
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.minimax.enable", havingValue = "true")
+ public MiniMaxChatModel miniMaxChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.MiniMax properties = yudaoAiProperties.getMinimax();
+ return buildMiniMaxChatClient(properties);
+ }
+
+ public MiniMaxChatModel buildMiniMaxChatClient(YudaoAiProperties.MiniMax properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(MiniMaxChatModel.MODEL_DEFAULT);
+ }
+ return new MiniMaxChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), MiniMaxChatModel.BASE_URL),
+ null, properties.getApiKey(), properties.getModel(), properties.getTemperature(),
+ properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.moonshot.enable", havingValue = "true")
+ public MoonshotChatModel moonshotChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.Moonshot properties = yudaoAiProperties.getMoonshot();
+ return buildMoonshotChatClient(properties);
+ }
+
+ public MoonshotChatModel buildMoonshotChatClient(YudaoAiProperties.Moonshot properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(MoonshotChatModel.MODEL_DEFAULT);
+ }
+ return new MoonshotChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), MoonshotChatModel.BASE_URL),
+ MoonshotChatModel.COMPLETE_PATH, properties.getApiKey(), properties.getModel(),
+ properties.getTemperature(), properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ private static DeepSeekChatModel buildDeepSeekCompatibleChatModel(String baseUrl, String completionsPath,
+ String apiKey, String model,
+ Double temperature, Integer maxTokens,
+ Double topP) {
+ DeepSeekApi.Builder apiBuilder = DeepSeekApi.builder()
+ .baseUrl(baseUrl)
+ .apiKey(apiKey);
+ if (StrUtil.isNotEmpty(completionsPath)) {
+ apiBuilder.completionsPath(completionsPath);
+ }
+ return DeepSeekChatModel.builder()
+ .deepSeekApi(apiBuilder.build())
+ .options(DeepSeekChatOptions.builder()
+ .model(model)
+ .temperature(temperature)
+ .maxTokens(maxTokens)
+ .topP(topP)
+ .build())
+ .build();
+ }
+
@Bean
@ConditionalOnProperty(value = "yudao.ai.midjourney.enable", havingValue = "true")
public MidjourneyApi midjourneyApi(YudaoAiProperties yudaoAiProperties) {
@@ -269,21 +428,16 @@ public class AiAutoConfiguration {
properties.setModel(GrokChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
- .baseUrl(Optional.ofNullable(properties.getBaseUrl())
- .orElse(GrokChatModel.BASE_URL))
- .completionsPath(GrokChatModel.COMPLETE_PATH)
+ .options(OpenAiChatOptions.builder()
+ .baseUrl(StrUtil.blankToDefault(properties.getBaseUrl(), GrokChatModel.BASE_URL))
.apiKey(properties.getApiKey())
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
- return new DouBaoChatModel(openAiChatModel);
+ return new GrokChatModel(openAiChatModel);
}
// ========== RAG 相关 ==========
@@ -302,6 +456,10 @@ public class AiAutoConfiguration {
return SpringUtil.getBean(ToolCallingManager.class);
}
+ private static ObservationRegistry getObservationRegistry() {
+ return SpringUtil.getBean(ObservationRegistry.class);
+ }
+
// ========== Web Search 相关 ==========
@Bean
@@ -320,4 +478,4 @@ public class AiAutoConfiguration {
return List.of(ToolCallbacks.from(personService));
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
index 986c24c18..e750eb0c3 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
@@ -43,6 +43,26 @@ public class YudaoAiProperties {
*/
private BaiChuan baichuan;
+ /**
+ * 文心一言
+ */
+ private YiYan yiyan;
+
+ /**
+ * 智谱
+ */
+ private ZhiPu zhipu;
+
+ /**
+ * MiniMax
+ */
+ private MiniMax minimax;
+
+ /**
+ * 月之暗面
+ */
+ private Moonshot moonshot;
+
/**
* Midjourney 绘图
*/
@@ -140,6 +160,62 @@ public class YudaoAiProperties {
}
+ @Data
+ public static class YiYan {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class ZhiPu {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class MiniMax {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class Moonshot {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
@Data
public static class Midjourney {
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
index f8067dea2..1604d012b 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
@@ -8,7 +8,6 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
-import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration;
import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties;
@@ -17,12 +16,16 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel
import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax.MiniMaxChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot.MoonshotChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan.YiYanChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu.ZhiPuChatModel;
import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration;
import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration;
import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration;
@@ -30,30 +33,14 @@ import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
-import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel;
-import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
+import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingModel;
+import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingOptions;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
-import com.azure.ai.openai.OpenAIClientBuilder;
-import com.azure.core.credential.KeyCredential;
import io.micrometer.observation.ObservationRegistry;
import io.milvus.client.MilvusServiceClient;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import lombok.SneakyThrows;
-import org.springaicommunity.moonshot.MoonshotChatModel;
-import org.springaicommunity.moonshot.MoonshotChatOptions;
-import org.springaicommunity.moonshot.api.MoonshotApi;
-import org.springaicommunity.moonshot.autoconfigure.MoonshotChatAutoConfiguration;
-import org.springaicommunity.qianfan.QianFanChatModel;
-import org.springaicommunity.qianfan.QianFanEmbeddingModel;
-import org.springaicommunity.qianfan.QianFanEmbeddingOptions;
-import org.springaicommunity.qianfan.QianFanImageModel;
-import org.springaicommunity.qianfan.api.QianFanApi;
-import org.springaicommunity.qianfan.api.QianFanImageApi;
-import org.springaicommunity.qianfan.autoconfigure.QianFanChatAutoConfiguration;
-import org.springaicommunity.qianfan.autoconfigure.QianFanEmbeddingAutoConfiguration;
-import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
-import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
@@ -63,27 +50,13 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
import org.springframework.ai.image.ImageModel;
-import org.springframework.ai.minimax.MiniMaxChatModel;
-import org.springframework.ai.minimax.MiniMaxChatOptions;
-import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
-import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
-import org.springframework.ai.minimax.api.MiniMaxApi;
import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
-import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
-import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
-import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
import org.springframework.ai.model.deepseek.autoconfigure.DeepSeekChatAutoConfiguration;
-import org.springframework.ai.model.minimax.autoconfigure.MiniMaxChatAutoConfiguration;
-import org.springframework.ai.model.minimax.autoconfigure.MiniMaxEmbeddingAutoConfiguration;
import org.springframework.ai.model.ollama.autoconfigure.OllamaChatAutoConfiguration;
import org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration;
import org.springframework.ai.model.stabilityai.autoconfigure.StabilityAiImageAutoConfiguration;
-import org.springframework.ai.model.tool.ToolCallingManager;
-import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiChatAutoConfiguration;
-import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiEmbeddingAutoConfiguration;
-import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiImageAutoConfiguration;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.OllamaEmbeddingModel;
import org.springframework.ai.ollama.api.OllamaApi;
@@ -92,11 +65,10 @@ import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingOptions;
import org.springframework.ai.openai.OpenAiImageModel;
-import org.springframework.ai.openai.api.OpenAiApi;
-import org.springframework.ai.openai.api.OpenAiImageApi;
-import org.springframework.ai.openai.api.common.OpenAiApiConstants;
import org.springframework.ai.anthropic.AnthropicChatModel;
-import org.springframework.ai.anthropic.api.AnthropicApi;
+import org.springframework.ai.anthropic.AnthropicChatOptions;
+import org.springframework.ai.openai.OpenAiChatOptions;
+import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.ai.stabilityai.StabilityAiImageModel;
import org.springframework.ai.stabilityai.api.StabilityAiApi;
import org.springframework.ai.vectorstore.SimpleVectorStore;
@@ -114,14 +86,13 @@ import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStore
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration;
import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreProperties;
-import org.springframework.ai.zhipuai.*;
-import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
-import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
-import org.springframework.web.client.RestClient;
-import redis.clients.jedis.JedisPooled;
+import org.springframework.boot.data.redis.autoconfigure.DataRedisProperties;
+import redis.clients.jedis.DefaultJedisClientConfig;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.JedisClientConfig;
+import redis.clients.jedis.RedisClient;
import java.io.File;
import java.time.Duration;
@@ -131,7 +102,6 @@ import java.util.Timer;
import java.util.TimerTask;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
-import static org.springframework.ai.retry.RetryUtils.DEFAULT_RETRY_TEMPLATE;
/**
* AI Model 模型工厂的实现类
@@ -179,7 +149,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
case OLLAMA:
return buildOllamaChatModel(url);
case GROK:
- return buildGrokChatModel(apiKey,url);
+ return buildGrokChatModel(apiKey, url);
default:
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
}
@@ -193,7 +163,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
case TONG_YI:
return SpringUtil.getBean(DashScopeChatModel.class);
case YI_YAN:
- return SpringUtil.getBean(QianFanChatModel.class);
+ return SpringUtil.getBean(YiYanChatModel.class);
case DEEP_SEEK:
return SpringUtil.getBean(DeepSeekChatModel.class);
case DOU_BAO:
@@ -203,7 +173,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
case SILICON_FLOW:
return SpringUtil.getBean(SiliconFlowChatModel.class);
case ZHI_PU:
- return SpringUtil.getBean(ZhiPuAiChatModel.class);
+ return SpringUtil.getBean(ZhiPuChatModel.class);
case MINI_MAX:
return SpringUtil.getBean(MiniMaxChatModel.class);
case MOONSHOT:
@@ -214,8 +184,6 @@ public class AiModelFactoryImpl implements AiModelFactory {
return SpringUtil.getBean(BaiChuanChatModel.class);
case OPENAI:
return SpringUtil.getBean(OpenAiChatModel.class);
- case AZURE_OPENAI:
- return SpringUtil.getBean(AzureOpenAiChatModel.class);
case ANTHROPIC:
return SpringUtil.getBean(AnthropicChatModel.class);
case GEMINI:
@@ -233,10 +201,6 @@ public class AiModelFactoryImpl implements AiModelFactory {
switch (platform) {
case TONG_YI:
return SpringUtil.getBean(DashScopeImageModel.class);
- case YI_YAN:
- return SpringUtil.getBean(QianFanImageModel.class);
- case ZHI_PU:
- return SpringUtil.getBean(ZhiPuAiImageModel.class);
case SILICON_FLOW:
return SpringUtil.getBean(SiliconFlowImageModel.class);
case OPENAI:
@@ -254,10 +218,6 @@ public class AiModelFactoryImpl implements AiModelFactory {
switch (platform) {
case TONG_YI:
return buildTongYiImagesModel(apiKey);
- case YI_YAN:
- return buildQianFanImageModel(apiKey);
- case ZHI_PU:
- return buildZhiPuAiImageModel(apiKey, url);
case OPENAI:
return buildOpenAiImageModel(apiKey, url);
case SILICON_FLOW:
@@ -294,16 +254,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
switch (platform) {
case TONG_YI:
return buildTongYiEmbeddingModel(apiKey, model);
- case YI_YAN:
- return buildYiYanEmbeddingModel(apiKey, model);
- case ZHI_PU:
- return buildZhiPuEmbeddingModel(apiKey, url, model);
- case MINI_MAX:
- return buildMiniMaxEmbeddingModel(apiKey, url, model);
case OPENAI:
return buildOpenAiEmbeddingModel(apiKey, url, model);
- case AZURE_OPENAI:
- return buildAzureOpenAiEmbeddingModel(apiKey, url, model);
case OLLAMA:
return buildOllamaEmbeddingModel(url, model);
default:
@@ -347,50 +299,20 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link DashScopeChatAutoConfiguration} 的 dashscopeChatModel 方法
*/
private static DashScopeChatModel buildTongYiChatModel(String key) {
- DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(key).build();
- DashScopeChatOptions options = DashScopeChatOptions.builder().withModel(DashScopeApi.DEFAULT_CHAT_MODEL)
- .withTemperature(0.7).build();
- return DashScopeChatModel.builder()
- .dashScopeApi(dashScopeApi)
- .defaultOptions(options)
- .toolCallingManager(getToolCallingManager())
- .build();
+ return AiAutoConfiguration.buildTongYiChatModel(key);
}
/**
* 可参考 {@link DashScopeImageAutoConfiguration} 的 dashScopeImageModel 方法
*/
private static DashScopeImageModel buildTongYiImagesModel(String key) {
- DashScopeImageApi dashScopeImageApi = DashScopeImageApi.builder().apiKey(key).build();
- return DashScopeImageModel.builder()
- .dashScopeApi(dashScopeImageApi)
- .build();
+ return AiAutoConfiguration.buildTongYiImagesModel(key);
}
- /**
- * 可参考 {@link QianFanChatAutoConfiguration} 的 qianFanChatModel 方法
- */
- private static QianFanChatModel buildYiYanChatModel(String key) {
- // TODO spring ai qianfan 有 bug,无法使用 https://github.com/spring-ai-community/qianfan/issues/6
- List keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
- String appKey = keys.get(0);
- String secretKey = keys.get(1);
- QianFanApi qianFanApi = new QianFanApi(appKey, secretKey);
- return new QianFanChatModel(qianFanApi);
- }
-
- /**
- * 可参考 {@link QianFanEmbeddingAutoConfiguration} 的 qianFanImageModel 方法
- */
- private QianFanImageModel buildQianFanImageModel(String key) {
- // TODO spring ai qianfan 有 bug,无法使用 https://github.com/spring-ai-community/qianfan/issues/6
- List keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
- String appKey = keys.get(0);
- String secretKey = keys.get(1);
- QianFanImageApi qianFanApi = new QianFanImageApi(appKey, secretKey);
- return new QianFanImageModel(qianFanApi);
+ private ChatModel buildYiYanChatModel(String apiKey) {
+ YudaoAiProperties.YiYan properties = new YudaoAiProperties.YiYan()
+ .setApiKey(apiKey);
+ return new AiAutoConfiguration().buildYiYanChatClient(properties);
}
/**
@@ -402,8 +324,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
.temperature(0.7).build();
return DeepSeekChatModel.builder()
.deepSeekApi(deepSeekApi)
- .defaultOptions(options)
- .toolCallingManager(getToolCallingManager())
+ .options(options)
.build();
}
@@ -435,52 +356,30 @@ public class AiModelFactoryImpl implements AiModelFactory {
}
/**
- * 可参考 {@link ZhiPuAiChatAutoConfiguration} 的 zhiPuAiChatModel 方法
+ * 可参考 {@link AiAutoConfiguration#zhiPuChatClient(YudaoAiProperties)}
*/
- private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
- ZhiPuAiApi.Builder zhiPuAiApiBuilder = ZhiPuAiApi.builder().apiKey(apiKey);
- if (StrUtil.isNotEmpty(url)) {
- zhiPuAiApiBuilder.baseUrl(url);
- }
- ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().model(ZhiPuAiApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
- return new ZhiPuAiChatModel(zhiPuAiApiBuilder.build(), options, getToolCallingManager(), DEFAULT_RETRY_TEMPLATE,
- getObservationRegistry().getIfAvailable());
+ private ZhiPuChatModel buildZhiPuChatModel(String apiKey, String url) {
+ YudaoAiProperties.ZhiPu properties = new YudaoAiProperties.ZhiPu()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildZhiPuChatClient(properties);
}
/**
- * 可参考 {@link ZhiPuAiImageAutoConfiguration} 的 zhiPuAiImageModel 方法
- */
- private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) {
- ZhiPuAiImageApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiImageApi(apiKey)
- : new ZhiPuAiImageApi(url, apiKey, RestClient.builder());
- return new ZhiPuAiImageModel(zhiPuAiApi);
- }
-
- /**
- * 可参考 {@link MiniMaxChatAutoConfiguration} 的 miniMaxChatModel 方法
+ * 可参考 {@link AiAutoConfiguration#miniMaxChatClient(YudaoAiProperties)}
*/
private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
- MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
- : new MiniMaxApi(url, apiKey);
- MiniMaxChatOptions options = MiniMaxChatOptions.builder().model(MiniMaxApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
- return new MiniMaxChatModel(miniMaxApi, options, getToolCallingManager(), DEFAULT_RETRY_TEMPLATE);
+ YudaoAiProperties.MiniMax properties = new YudaoAiProperties.MiniMax()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildMiniMaxChatClient(properties);
}
/**
- * 可参考 {@link MoonshotChatAutoConfiguration} 的 moonshotChatModel 方法
+ * 可参考 {@link AiAutoConfiguration#moonshotChatClient(YudaoAiProperties)}
*/
private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
- MoonshotApi.Builder moonshotApiBuilder = MoonshotApi.builder()
- .apiKey(apiKey);
- if (StrUtil.isNotEmpty(url)) {
- moonshotApiBuilder.baseUrl(url);
- }
- MoonshotChatOptions options = MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build();
- return MoonshotChatModel.builder()
- .moonshotApi(moonshotApiBuilder.build())
- .defaultOptions(options)
- .toolCallingManager(getToolCallingManager())
- .build();
+ YudaoAiProperties.Moonshot properties = new YudaoAiProperties.Moonshot()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildMoonshotChatClient(properties);
}
/**
@@ -507,39 +406,37 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link OpenAiChatAutoConfiguration} 的 openAiChatModel 方法
*/
private static OpenAiChatModel buildOpenAiChatModel(String openAiToken, String url) {
- url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL);
- OpenAiApi openAiApi = OpenAiApi.builder().baseUrl(url).apiKey(openAiToken).build();
return OpenAiChatModel.builder()
- .openAiApi(openAiApi)
- .toolCallingManager(getToolCallingManager())
+ .options(buildOpenAiChatOptions(openAiToken, url).build())
.build();
}
- /**
- * 可参考 {@link AzureOpenAiChatAutoConfiguration}
- */
- private static AzureOpenAiChatModel buildAzureOpenAiChatModel(String apiKey, String url) {
- // TODO @芋艿:使用前,请测试,暂时没密钥!!!
- OpenAIClientBuilder openAIClientBuilder = new OpenAIClientBuilder()
- .endpoint(url).credential(new KeyCredential(apiKey));
- return AzureOpenAiChatModel.builder()
- .openAIClientBuilder(openAIClientBuilder)
- .toolCallingManager(getToolCallingManager())
+ private static OpenAiChatModel buildAzureOpenAiChatModel(String openAiToken, String url) {
+ return OpenAiChatModel.builder()
+ .options(buildOpenAiChatOptions(openAiToken, url)
+ .azure(true)
+ .build())
.build();
}
+ private static OpenAiChatOptions.Builder buildOpenAiChatOptions(String apiKey, String url) {
+ OpenAiChatOptions.Builder optionsBuilder = OpenAiChatOptions.builder().apiKey(apiKey);
+ if (StrUtil.isNotEmpty(url)) {
+ optionsBuilder.baseUrl(url);
+ }
+ return optionsBuilder;
+ }
+
/**
* 可参考 {@link AnthropicChatAutoConfiguration} 的 anthropicApi 方法
*/
private static AnthropicChatModel buildAnthropicChatModel(String apiKey, String url) {
- AnthropicApi.Builder builder = AnthropicApi.builder().apiKey(apiKey);
+ AnthropicChatOptions.Builder optionsBuilder = AnthropicChatOptions.builder().apiKey(apiKey);
if (StrUtil.isNotEmpty(url)) {
- builder.baseUrl(url);
+ optionsBuilder.baseUrl(url);
}
- AnthropicApi anthropicApi = builder.build();
return AnthropicChatModel.builder()
- .anthropicApi(anthropicApi)
- .toolCallingManager(getToolCallingManager())
+ .options(optionsBuilder.build())
.build();
}
@@ -556,9 +453,13 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法
*/
private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) {
- url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL);
- OpenAiImageApi openAiApi = OpenAiImageApi.builder().baseUrl(url).apiKey(openAiToken).build();
- return new OpenAiImageModel(openAiApi);
+ OpenAiImageOptions.Builder optionsBuilder = OpenAiImageOptions.builder().apiKey(openAiToken);
+ if (StrUtil.isNotEmpty(url)) {
+ optionsBuilder.baseUrl(url);
+ }
+ return OpenAiImageModel.builder()
+ .options(optionsBuilder.build())
+ .build();
}
/**
@@ -577,7 +478,6 @@ public class AiModelFactoryImpl implements AiModelFactory {
OllamaApi ollamaApi = OllamaApi.builder().baseUrl(url).build();
return OllamaChatModel.builder()
.ollamaApi(ollamaApi)
- .toolCallingManager(getToolCallingManager())
.build();
}
@@ -600,47 +500,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
// ========== 各种创建 EmbeddingModel 的方法 ==========
/**
- * 可参考 {@link DashScopeEmbeddingAutoConfiguration} 的 dashscopeEmbeddingModel 方法
+ * 可参考 {@link DashScopeEmbeddingAutoConfiguration} 的 DashScopeEmbeddingModel 方法
*/
private DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) {
- DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
- DashScopeEmbeddingOptions dashScopeEmbeddingOptions = DashScopeEmbeddingOptions.builder().withModel(model).build();
- return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.EMBED, dashScopeEmbeddingOptions);
- }
-
- /**
- * 可参考 {@link ZhiPuAiEmbeddingAutoConfiguration} 的 zhiPuAiEmbeddingModel 方法
- */
- private ZhiPuAiEmbeddingModel buildZhiPuEmbeddingModel(String apiKey, String url, String model) {
- ZhiPuAiApi.Builder zhiPuAiApiBuilder = ZhiPuAiApi.builder().apiKey(apiKey);
- if (StrUtil.isNotEmpty(url)) {
- zhiPuAiApiBuilder.baseUrl(url);
- }
- ZhiPuAiEmbeddingOptions zhiPuAiEmbeddingOptions = ZhiPuAiEmbeddingOptions.builder().model(model).build();
- return new ZhiPuAiEmbeddingModel(zhiPuAiApiBuilder.build(), MetadataMode.EMBED, zhiPuAiEmbeddingOptions);
- }
-
- /**
- * 可参考 {@link MiniMaxEmbeddingAutoConfiguration} 的 miniMaxEmbeddingModel 方法
- */
- private EmbeddingModel buildMiniMaxEmbeddingModel(String apiKey, String url, String model) {
- MiniMaxApi miniMaxApi = StrUtil.isEmpty(url)? new MiniMaxApi(apiKey)
- : new MiniMaxApi(url, apiKey);
- MiniMaxEmbeddingOptions miniMaxEmbeddingOptions = MiniMaxEmbeddingOptions.builder().model(model).build();
- return new MiniMaxEmbeddingModel(miniMaxApi, MetadataMode.EMBED, miniMaxEmbeddingOptions);
- }
-
- /**
- * 可参考 {@link QianFanEmbeddingAutoConfiguration} 的 qianFanEmbeddingModel 方法
- */
- private QianFanEmbeddingModel buildYiYanEmbeddingModel(String key, String model) {
- List keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
- String appKey = keys.get(0);
- String secretKey = keys.get(1);
- QianFanApi qianFanApi = new QianFanApi(appKey, secretKey);
- QianFanEmbeddingOptions qianFanEmbeddingOptions = QianFanEmbeddingOptions.builder().model(model).build();
- return new QianFanEmbeddingModel(qianFanApi, MetadataMode.EMBED, qianFanEmbeddingOptions);
+ return AiAutoConfiguration.buildTongYiEmbeddingModel(apiKey, model);
}
private OllamaEmbeddingModel buildOllamaEmbeddingModel(String url, String model) {
@@ -648,7 +511,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
OllamaEmbeddingOptions ollamaOptions = OllamaEmbeddingOptions.builder().model(model).build();
return OllamaEmbeddingModel.builder()
.ollamaApi(ollamaApi)
- .defaultOptions(ollamaOptions)
+ .options(ollamaOptions)
.build();
}
@@ -656,25 +519,16 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link OpenAiEmbeddingAutoConfiguration} 的 openAiEmbeddingModel 方法
*/
private OpenAiEmbeddingModel buildOpenAiEmbeddingModel(String openAiToken, String url, String model) {
- url = StrUtil.blankToDefault(url, OpenAiApiConstants.DEFAULT_BASE_URL);
- OpenAiApi openAiApi = OpenAiApi.builder().baseUrl(url).apiKey(openAiToken).build();
- OpenAiEmbeddingOptions openAiEmbeddingProperties = OpenAiEmbeddingOptions.builder().model(model).build();
- return new OpenAiEmbeddingModel(openAiApi, MetadataMode.EMBED, openAiEmbeddingProperties);
- }
-
- /**
- * 可参考 {@link AzureOpenAiEmbeddingAutoConfiguration} 的 azureOpenAiEmbeddingModel 方法
- */
- private AzureOpenAiEmbeddingModel buildAzureOpenAiEmbeddingModel(String apiKey, String url, String model) {
- // TODO @芋艿:手头暂时没密钥,使用建议再测试下
- AzureOpenAiEmbeddingAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiEmbeddingAutoConfiguration();
- // 创建 OpenAIClientBuilder 对象
- OpenAIClientBuilder openAIClientBuilder = new OpenAIClientBuilder()
- .endpoint(url).credential(new KeyCredential(apiKey));
- // 获取 AzureOpenAiChatProperties 对象
- AzureOpenAiEmbeddingProperties embeddingProperties = SpringUtil.getBean(AzureOpenAiEmbeddingProperties.class);
- return azureOpenAiAutoConfiguration.azureOpenAiEmbeddingModel(openAIClientBuilder, embeddingProperties,
- getObservationRegistry(), getEmbeddingModelObservationConvention());
+ OpenAiEmbeddingOptions.Builder optionsBuilder = OpenAiEmbeddingOptions.builder()
+ .apiKey(openAiToken)
+ .model(model);
+ if (StrUtil.isNotEmpty(url)) {
+ optionsBuilder.baseUrl(url);
+ }
+ return OpenAiEmbeddingModel.builder()
+ .metadataMode(MetadataMode.EMBED)
+ .options(optionsBuilder.build())
+ .build();
}
// ========== 各种创建 VectorStore 的方法 ==========
@@ -737,13 +591,11 @@ public class AiModelFactoryImpl implements AiModelFactory {
*/
private RedisVectorStore buildRedisVectorStore(EmbeddingModel embeddingModel,
Map> metadataFields) {
- // 创建 JedisPooled 对象
- RedisProperties redisProperties = SpringUtils.getBean(RedisProperties.class);
- JedisPooled jedisPooled = new JedisPooled(redisProperties.getHost(), redisProperties.getPort(),
- redisProperties.getUsername(), redisProperties.getPassword());
+ // 创建 RedisClient 对象
+ RedisClient redisClient = buildRedisClient();
// 创建 RedisVectorStoreProperties 对象
RedisVectorStoreProperties properties = SpringUtil.getBean(RedisVectorStoreProperties.class);
- RedisVectorStore redisVectorStore = RedisVectorStore.builder(jedisPooled, embeddingModel)
+ RedisVectorStore redisVectorStore = RedisVectorStore.builder(redisClient, embeddingModel)
.indexName(properties.getIndexName()).prefix(properties.getPrefix())
.initializeSchema(properties.isInitializeSchema())
.metadataFields(convertList(metadataFields.entrySet(), entry -> {
@@ -766,6 +618,43 @@ public class AiModelFactoryImpl implements AiModelFactory {
return redisVectorStore;
}
+ private RedisClient buildRedisClient() {
+ DataRedisProperties redisProperties = SpringUtil.getBean(DataRedisProperties.class);
+ Assert.isNull(redisProperties.getCluster(), "RedisVectorStore 暂不支持 Redis Cluster 模式");
+ Assert.isNull(redisProperties.getSentinel(), "RedisVectorStore 暂不支持 Redis Sentinel 模式");
+ Assert.isNull(redisProperties.getMasterreplica(), "RedisVectorStore 暂不支持 Redis Master-Replica 模式");
+ if (StrUtil.isNotEmpty(redisProperties.getUrl())) {
+ return RedisClient.create(redisProperties.getUrl());
+ }
+ DefaultJedisClientConfig.Builder clientConfigBuilder = DefaultJedisClientConfig.builder()
+ .ssl(redisProperties.getSsl().isEnabled())
+ .database(redisProperties.getDatabase());
+ if (StrUtil.isNotEmpty(redisProperties.getUsername())) {
+ clientConfigBuilder.user(redisProperties.getUsername());
+ }
+ if (StrUtil.isNotEmpty(redisProperties.getPassword())) {
+ clientConfigBuilder.password(redisProperties.getPassword());
+ }
+ if (StrUtil.isNotEmpty(redisProperties.getClientName())) {
+ clientConfigBuilder.clientName(redisProperties.getClientName());
+ }
+ if (redisProperties.getTimeout() != null) {
+ clientConfigBuilder.socketTimeoutMillis(toMillis(redisProperties.getTimeout()));
+ }
+ if (redisProperties.getConnectTimeout() != null) {
+ clientConfigBuilder.connectionTimeoutMillis(toMillis(redisProperties.getConnectTimeout()));
+ }
+ JedisClientConfig clientConfig = clientConfigBuilder.build();
+ return RedisClient.builder()
+ .hostAndPort(new HostAndPort(redisProperties.getHost(), redisProperties.getPort()))
+ .clientConfig(clientConfig)
+ .build();
+ }
+
+ private static int toMillis(Duration duration) {
+ return Math.toIntExact(duration.toMillis());
+ }
+
/**
* 参考 {@link MilvusVectorStoreAutoConfiguration} 的 vectorStore 方法
*/
@@ -827,10 +716,6 @@ public class AiModelFactoryImpl implements AiModelFactory {
return SpringUtil.getBean(BatchingStrategy.class);
}
- private static ToolCallingManager getToolCallingManager() {
- return SpringUtil.getBean(ToolCallingManager.class);
- }
-
private static ObjectProvider getEmbeddingModelObservationConvention() {
return new ObjectProvider<>() {
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
index 5fb71c942..18b53c54b 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
@@ -38,8 +38,15 @@ public class BaiChuanChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
index a542cb372..a049947ca 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
@@ -38,8 +38,15 @@ public class DouBaoChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java
index 378a0af1f..ef887a0be 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java
@@ -39,8 +39,15 @@ public class GeminiChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
index 06eed2504..3a9f5b1f9 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
@@ -37,8 +37,15 @@ public class GrokChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
index 9513c6c5f..4461c5c60 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
@@ -45,8 +45,15 @@ public class HunYuanChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java
new file mode 100644
index 000000000..d464ab86a
--- /dev/null
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * MiniMax {@link ChatModel} 实现类
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MiniMaxChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://api.minimaxi.com/v1";
+
+ public static final String MODEL_DEFAULT = "MiniMax-M3";
+
+ /**
+ * 兼容 OpenAI 接口,复用 DeepSeek 客户端
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java
new file mode 100644
index 000000000..391cec54a
--- /dev/null
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 月之暗面 {@link ChatModel} 实现类
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MoonshotChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://api.moonshot.cn";
+
+ public static final String COMPLETE_PATH = "/v1/chat/completions";
+
+ public static final String MODEL_DEFAULT = "kimi-k2.6";
+
+ /**
+ * 兼容 OpenAI 接口,复用 DeepSeek 客户端
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java
index a910e3403..9d66f25c1 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java
@@ -6,7 +6,6 @@ import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
import reactor.core.publisher.Flux;
/**
@@ -36,8 +35,15 @@ public class SiliconFlowChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java
index f9cd81cb3..006658ea7 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageApi.java
@@ -21,18 +21,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.ai.model.ApiKey;
import org.springframework.ai.model.NoopApiKey;
import org.springframework.ai.model.SimpleApiKey;
-import org.springframework.ai.openai.api.OpenAiImageApi;
import org.springframework.ai.retry.RetryUtils;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
-import java.util.Map;
-
/**
* 硅基流动 Image API
*
@@ -58,15 +54,15 @@ public class SiliconFlowImageApi {
public SiliconFlowImageApi(String baseUrl, String apiKey, RestClient.Builder restClientBuilder,
ResponseErrorHandler responseErrorHandler) {
- this(baseUrl, apiKey, CollectionUtils.toMultiValueMap(Map.of()), restClientBuilder, responseErrorHandler);
+ this(baseUrl, apiKey, new HttpHeaders(), restClientBuilder, responseErrorHandler);
}
- public SiliconFlowImageApi(String baseUrl, String apiKey, MultiValueMap headers,
+ public SiliconFlowImageApi(String baseUrl, String apiKey, HttpHeaders headers,
RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) {
this(baseUrl, new SimpleApiKey(apiKey), headers, restClientBuilder, responseErrorHandler);
}
- public SiliconFlowImageApi(String baseUrl, ApiKey apiKey, MultiValueMap headers,
+ public SiliconFlowImageApi(String baseUrl, ApiKey apiKey, HttpHeaders headers,
RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) {
// @formatter:off
@@ -83,7 +79,7 @@ public class SiliconFlowImageApi {
// @formatter:on
}
- public ResponseEntity createImage(SiliconflowImageRequest siliconflowImageRequest) {
+ public ResponseEntity createImage(SiliconflowImageRequest siliconflowImageRequest) {
Assert.notNull(siliconflowImageRequest, "Image request cannot be null.");
Assert.hasLength(siliconflowImageRequest.prompt(), "Prompt cannot be empty.");
@@ -91,7 +87,7 @@ public class SiliconFlowImageApi {
.uri("v1/images/generations")
.body(siliconflowImageRequest)
.retrieve()
- .toEntity(OpenAiImageApi.OpenAiImageResponse.class);
+ .toEntity(SiliconFlowImageResponse.class);
}
@@ -112,4 +108,15 @@ public class SiliconFlowImageApi {
}
}
+ public record SiliconFlowImageResponse(
+ @JsonProperty("created") Long created,
+ @JsonProperty("data") java.util.List data) {
+
+ public record Entry(
+ @JsonProperty("url") String url,
+ @JsonProperty("b64_json") String b64Json,
+ @JsonProperty("revised_prompt") String revisedPrompt) {
+ }
+ }
+
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
index f205b80fc..d6d5b7be0 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
@@ -27,12 +27,11 @@ import org.springframework.ai.image.observation.ImageModelObservationConvention;
import org.springframework.ai.image.observation.ImageModelObservationDocumentation;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.openai.OpenAiImageModel;
-import org.springframework.ai.openai.api.OpenAiImageApi;
import org.springframework.ai.openai.metadata.OpenAiImageGenerationMetadata;
import org.springframework.ai.retry.RetryUtils;
+import org.springframework.core.retry.RetryTemplate;
import org.springframework.http.ResponseEntity;
-import org.springframework.lang.Nullable;
-import org.springframework.retry.support.RetryTemplate;
+import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import java.util.List;
@@ -46,102 +45,112 @@ import java.util.List;
*/
public class SiliconFlowImageModel implements ImageModel {
- private static final Logger logger = LoggerFactory.getLogger(SiliconFlowImageModel.class);
+ private static final Logger logger = LoggerFactory.getLogger(SiliconFlowImageModel.class);
- private static final ImageModelObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultImageModelObservationConvention();
+ private static final ImageModelObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultImageModelObservationConvention();
- private final SiliconFlowImageOptions defaultOptions;
+ private final SiliconFlowImageOptions defaultOptions;
- private final RetryTemplate retryTemplate;
+ private final RetryTemplate retryTemplate;
- private final SiliconFlowImageApi siliconFlowImageApi;
+ private final SiliconFlowImageApi siliconFlowImageApi;
- private final ObservationRegistry observationRegistry;
+ private final ObservationRegistry observationRegistry;
@Setter
- private ImageModelObservationConvention observationConvention = DEFAULT_OBSERVATION_CONVENTION;
+ private ImageModelObservationConvention observationConvention = DEFAULT_OBSERVATION_CONVENTION;
- public SiliconFlowImageModel(SiliconFlowImageApi siliconFlowImageApi) {
- this(siliconFlowImageApi, SiliconFlowImageOptions.builder().build(), RetryUtils.DEFAULT_RETRY_TEMPLATE);
- }
+ public SiliconFlowImageModel(SiliconFlowImageApi siliconFlowImageApi) {
+ this(siliconFlowImageApi, SiliconFlowImageOptions.builder().build(), RetryUtils.DEFAULT_RETRY_TEMPLATE);
+ }
- public SiliconFlowImageModel(SiliconFlowImageApi siliconFlowImageApi, SiliconFlowImageOptions options, RetryTemplate retryTemplate) {
- this(siliconFlowImageApi, options, retryTemplate, ObservationRegistry.NOOP);
- }
+ public SiliconFlowImageModel(SiliconFlowImageApi siliconFlowImageApi, SiliconFlowImageOptions options, RetryTemplate retryTemplate) {
+ this(siliconFlowImageApi, options, retryTemplate, ObservationRegistry.NOOP);
+ }
- public SiliconFlowImageModel(SiliconFlowImageApi siliconFlowImageApi, SiliconFlowImageOptions options, RetryTemplate retryTemplate,
+ public SiliconFlowImageModel(SiliconFlowImageApi siliconFlowImageApi, SiliconFlowImageOptions options, RetryTemplate retryTemplate,
ObservationRegistry observationRegistry) {
- Assert.notNull(siliconFlowImageApi, "OpenAiImageApi must not be null");
- Assert.notNull(options, "options must not be null");
- Assert.notNull(retryTemplate, "retryTemplate must not be null");
- Assert.notNull(observationRegistry, "observationRegistry must not be null");
- this.siliconFlowImageApi = siliconFlowImageApi;
- this.defaultOptions = options;
- this.retryTemplate = retryTemplate;
- this.observationRegistry = observationRegistry;
- }
+ Assert.notNull(siliconFlowImageApi, "SiliconFlowImageApi must not be null");
+ Assert.notNull(options, "options must not be null");
+ Assert.notNull(retryTemplate, "retryTemplate must not be null");
+ Assert.notNull(observationRegistry, "observationRegistry must not be null");
+ this.siliconFlowImageApi = siliconFlowImageApi;
+ this.defaultOptions = options;
+ this.retryTemplate = retryTemplate;
+ this.observationRegistry = observationRegistry;
+ }
- @Override
- public ImageResponse call(ImagePrompt imagePrompt) {
+ @Override
+ public ImageResponse call(ImagePrompt imagePrompt) {
SiliconFlowImageOptions requestImageOptions = mergeOptions(imagePrompt.getOptions(), this.defaultOptions);
SiliconFlowImageApi.SiliconflowImageRequest imageRequest = createRequest(imagePrompt, requestImageOptions);
- var observationContext = ImageModelObservationContext.builder()
- .imagePrompt(imagePrompt)
- .provider(SiliconFlowApiConstants.PROVIDER_NAME)
- .imagePrompt(imagePrompt)
- .build();
+ var observationContext = ImageModelObservationContext.builder()
+ .imagePrompt(imagePrompt)
+ .provider(SiliconFlowApiConstants.PROVIDER_NAME)
+ .imagePrompt(imagePrompt)
+ .build();
- return ImageModelObservationDocumentation.IMAGE_MODEL_OPERATION
- .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
- this.observationRegistry)
- .observe(() -> {
- ResponseEntity imageResponseEntity = this.retryTemplate
- .execute(ctx -> this.siliconFlowImageApi.createImage(imageRequest));
+ return ImageModelObservationDocumentation.IMAGE_MODEL_OPERATION
+ .observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
+ this.observationRegistry)
+ .observe(() -> {
+ ResponseEntity imageResponseEntity = RetryUtils.execute(
+ this.retryTemplate, () -> this.siliconFlowImageApi.createImage(imageRequest));
- ImageResponse imageResponse = convertResponse(imageResponseEntity, imageRequest);
+ ImageResponse imageResponse = convertResponse(imageResponseEntity, imageRequest);
- observationContext.setResponse(imageResponse);
+ observationContext.setResponse(imageResponse);
- return imageResponse;
- });
- }
+ return imageResponse;
+ });
+ }
- private SiliconFlowImageApi.SiliconflowImageRequest createRequest(ImagePrompt imagePrompt,
+ private SiliconFlowImageApi.SiliconflowImageRequest createRequest(ImagePrompt imagePrompt,
SiliconFlowImageOptions requestImageOptions) {
- String instructions = imagePrompt.getInstructions().get(0).getText();
+ String instructions = imagePrompt.getInstructions().getFirst().getText();
- SiliconFlowImageApi.SiliconflowImageRequest imageRequest = new SiliconFlowImageApi.SiliconflowImageRequest(instructions,
- SiliconFlowApiConstants.DEFAULT_IMAGE_MODEL);
+ return new SiliconFlowImageApi.SiliconflowImageRequest(
+ instructions,
+ ModelOptionsUtils.mergeOption(requestImageOptions.getModel(), SiliconFlowApiConstants.DEFAULT_IMAGE_MODEL),
+ requestImageOptions.getN(),
+ requestImageOptions.getNegativePrompt(),
+ requestImageOptions.getSeed(),
+ requestImageOptions.getNumInferenceSteps(),
+ requestImageOptions.getGuidanceScale(),
+ requestImageOptions.getImage());
+ }
- return ModelOptionsUtils.merge(requestImageOptions, imageRequest, SiliconFlowImageApi.SiliconflowImageRequest.class);
- }
+ private ImageResponse convertResponse(ResponseEntity imageResponseEntity,
+ SiliconFlowImageApi.SiliconflowImageRequest siliconflowImageRequest) {
+ SiliconFlowImageApi.SiliconFlowImageResponse imageApiResponse = imageResponseEntity.getBody();
+ if (imageApiResponse == null) {
+ logger.warn("No image response returned for request: {}", siliconflowImageRequest);
+ return new ImageResponse(List.of());
+ }
- private ImageResponse convertResponse(ResponseEntity imageResponseEntity,
- SiliconFlowImageApi.SiliconflowImageRequest siliconflowImageRequest) {
- OpenAiImageApi.OpenAiImageResponse imageApiResponse = imageResponseEntity.getBody();
- if (imageApiResponse == null) {
- logger.warn("No image response returned for request: {}", siliconflowImageRequest);
- return new ImageResponse(List.of());
- }
+ List imageGenerationList = imageApiResponse.data()
+ .stream()
+ .map(entry -> new ImageGeneration(new Image(entry.url(), entry.b64Json()),
+ new OpenAiImageGenerationMetadata(entry.revisedPrompt())))
+ .toList();
- List imageGenerationList = imageApiResponse.data()
- .stream()
- .map(entry -> new ImageGeneration(new Image(entry.url(), entry.b64Json()),
- new OpenAiImageGenerationMetadata(entry.revisedPrompt())))
- .toList();
-
- ImageResponseMetadata openAiImageResponseMetadata = new ImageResponseMetadata(imageApiResponse.created());
- return new ImageResponse(imageGenerationList, openAiImageResponseMetadata);
- }
+ ImageResponseMetadata openAiImageResponseMetadata = new ImageResponseMetadata(imageApiResponse.created());
+ return new ImageResponse(imageGenerationList, openAiImageResponseMetadata);
+ }
private SiliconFlowImageOptions mergeOptions(@Nullable ImageOptions runtimeOptions, SiliconFlowImageOptions defaultOptions) {
- var runtimeOptionsForProvider = ModelOptionsUtils.copyToTarget(runtimeOptions, ImageOptions.class,
- SiliconFlowImageOptions.class);
-
- if (runtimeOptionsForProvider == null) {
+ if (runtimeOptions == null) {
return defaultOptions;
}
+ SiliconFlowImageOptions runtimeOptionsForProvider = runtimeOptions instanceof SiliconFlowImageOptions siliconFlowImageOptions
+ ? siliconFlowImageOptions
+ : SiliconFlowImageOptions.builder()
+ .model(runtimeOptions.getModel())
+ .batchSize(runtimeOptions.getN())
+ .width(runtimeOptions.getWidth())
+ .height(runtimeOptions.getHeight())
+ .build();
return SiliconFlowImageOptions.builder()
// Handle portable image options
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
index cbac3b6df..e565061b6 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
@@ -43,8 +43,15 @@ public class XingHuoChatModel implements ChatModel {
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModelV1.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModelV1.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java
new file mode 100644
index 000000000..b84316b3d
--- /dev/null
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 文心一言 {@link ChatModel} 实现类
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class YiYanChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://qianfan.baidubce.com/v2";
+
+ public static final String MODEL_DEFAULT = "ernie-4.0-8k-latest";
+
+ /**
+ * 兼容 OpenAI 接口,复用 DeepSeek 客户端
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java
new file mode 100644
index 000000000..f22c77c0c
--- /dev/null
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 智谱 {@link ChatModel} 实现类
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class ZhiPuChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
+
+ public static final String MODEL_DEFAULT = "glm-5.2";
+
+ /**
+ * 兼容 OpenAI 接口,复用 DeepSeek 客户端
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java
index aedd493c3..c7632605f 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java
@@ -1,27 +1,25 @@
package cn.iocoder.yudao.module.ai.framework.security.config;
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
-import cn.iocoder.yudao.module.infra.enums.ApiConstants;
-import jakarta.annotation.Resource;
-import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerSseProperties;
-import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties;
+import cn.hutool.core.util.StrUtil;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
-import java.util.Optional;
-
/**
* AI 模块的 Security 配置
*/
@Configuration(proxyBeanMethods = false, value = "aiSecurityConfiguration")
public class SecurityConfiguration {
- @Resource
- private Optional mcpServerSseProperties;
- @Resource
- private Optional mcpServerStreamableHttpProperties;
+ @Value("${spring.ai.mcp.server.sse-endpoint:/sse}")
+ private String mcpSseEndpoint;
+ @Value("${spring.ai.mcp.server.sse-message-endpoint:/mcp/message}")
+ private String mcpSseMessageEndpoint;
+ @Value("${spring.ai.mcp.server.streamable-http-endpoint:/mcp}")
+ private String mcpStreamableHttpEndpoint;
@Bean("aiAuthorizeRequestsCustomizer")
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
@@ -29,28 +27,15 @@ public class SecurityConfiguration {
@Override
public void customize(AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry registry) {
- // Swagger 接口文档
- registry.requestMatchers("/v3/api-docs/**").permitAll()
- .requestMatchers("/webjars/**").permitAll()
- .requestMatchers("/swagger-ui").permitAll()
- .requestMatchers("/swagger-ui/**").permitAll();
- // Spring Boot Actuator 的安全配置
- registry.requestMatchers("/actuator").permitAll()
- .requestMatchers("/actuator/**").permitAll();
- // Druid 监控
- registry.requestMatchers("/druid/**").permitAll();
-
- // TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案
- // RPC 服务的安全配置
- registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
-
- // MCP Server
- mcpServerSseProperties.ifPresent(properties -> {
- registry.requestMatchers(properties.getSseEndpoint()).permitAll();
- registry.requestMatchers(properties.getSseMessageEndpoint()).permitAll();
- });
- mcpServerStreamableHttpProperties.ifPresent(properties ->
- registry.requestMatchers(properties.getMcpEndpoint()).permitAll());
+ if (StrUtil.isNotBlank(mcpSseEndpoint)) {
+ registry.requestMatchers(mcpSseEndpoint).permitAll();
+ }
+ if (StrUtil.isNotBlank(mcpSseMessageEndpoint)) {
+ registry.requestMatchers(mcpSseMessageEndpoint).permitAll();
+ }
+ if (StrUtil.isNotBlank(mcpStreamableHttpEndpoint)) {
+ registry.requestMatchers(mcpStreamableHttpEndpoint).permitAll();
+ }
}
};
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
index bdd2ba2a1..e211af05b 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
@@ -49,10 +49,10 @@ import org.springframework.ai.chat.model.StreamingChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
-import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
@@ -130,9 +130,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
@Autowired(required = false) // 由于 yudao.ai.mcp.client.enable 配置项,可以关闭 McpSyncClient 的功能,所以这里只能不强制注入
private List mcpClients;
- @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
- @Autowired(required = false) // 由于 yudao.ai.mcp.client.enable 配置项,可以关闭 McpSyncClient 的功能,所以这里只能不强制注入
- private McpClientCommonProperties mcpClientCommonProperties;
+ @Value("${spring.ai.mcp.client.name:mcp}")
+ private String mcpClientName;
@Resource
private ToolCallbackResolver toolCallbackResolver;
@@ -410,13 +409,16 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
if (CollUtil.isNotEmpty(mcpClients) && CollUtil.isNotEmpty(chatRole.getMcpClientNames())) {
chatRole.getMcpClientNames().forEach(mcpClientName -> {
// 2.1 标准化名字,参考 McpClientAutoConfiguration 的 connectedClientName 方法
- String finalMcpClientName = mcpClientCommonProperties.getName() + " - " + mcpClientName;
+ String finalMcpClientName = this.mcpClientName + " - " + mcpClientName;
// 2.2 匹配对应的 McpSyncClient
mcpClients.forEach(mcpClient -> {
if (ObjUtil.notEqual(mcpClient.getClientInfo().name(), finalMcpClientName)) {
return;
}
- ToolCallback[] mcpToolCallBacks = new SyncMcpToolCallbackProvider(mcpClient).getToolCallbacks();
+ ToolCallback[] mcpToolCallBacks = SyncMcpToolCallbackProvider.builder()
+ .mcpClients(mcpClient)
+ .build()
+ .getToolCallbacks();
CollUtil.addAll(toolCallbacks, mcpToolCallBacks);
});
});
@@ -539,7 +541,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
public void deleteChatMessageByConversationId(Long conversationId, Long userId) {
// 1. 校验消息存在
List messages = chatMessageMapper.selectListByConversationId(conversationId);
- if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) {
+ if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.getFirst().getUserId(), userId)) {
throw exception(CHAT_MESSAGE_NOT_EXIST);
}
// 2. 执行删除
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
index 3def2a9c7..0163edbc0 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
@@ -29,14 +29,12 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import org.springaicommunity.qianfan.QianFanImageOptions;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImageOptions;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
-import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -168,15 +166,6 @@ public class AiImageServiceImpl implements AiImageService {
.model(model.getModel()).n(1)
.height(draw.getHeight()).width(draw.getWidth())
.build();
- } else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.YI_YAN.getPlatform())) {
- return QianFanImageOptions.builder()
- .model(model.getModel()).N(1)
- .height(draw.getHeight()).width(draw.getWidth())
- .build();
- } else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.ZHI_PU.getPlatform())) {
- return ZhiPuAiImageOptions.builder()
- .model(model.getModel())
- .build();
}
throw new IllegalArgumentException("不支持的 AI 平台:" + model.getPlatform());
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
index b5038412b..45ef1256d 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
@@ -166,7 +166,7 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
segmentMapper.deleteByIds(convertList(segments, AiKnowledgeSegmentDO::getId));
// 3. 删除向量存储中的段落
- VectorStore vectorStore = getVectorStoreById(segments.get(0).getKnowledgeId());
+ VectorStore vectorStore = getVectorStoreById(segments.getFirst().getKnowledgeId());
vectorStore.delete(convertList(segments, AiKnowledgeSegmentDO::getVectorId));
}
@@ -299,7 +299,7 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
// 2. Rerank 重排序
if (rerankModel != null) {
RerankResponse rerankResponse = rerankModel.call(new RerankRequest(reqBO.getContent(), documents,
- DashScopeRerankOptions.builder().withTopN(topK).build()));
+ DashScopeRerankOptions.builder().topN(topK).build()));
documents = convertList(rerankResponse.getResults(),
documentWithScore -> documentWithScore.getScore() >= similarityThreshold
? documentWithScore.getOutput() : null);
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
index 15185235a..f61d97dc7 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
@@ -8,20 +8,15 @@ import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
-import org.springaicommunity.moonshot.MoonshotChatOptions;
-import org.springaicommunity.qianfan.QianFanChatOptions;
import org.springframework.ai.anthropic.AnthropicChatOptions;
-import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.messages.*;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.deepseek.DeepSeekAssistantMessage;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
-import org.springframework.ai.minimax.MiniMaxChatOptions;
import org.springframework.ai.ollama.api.OllamaChatOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.tool.ToolCallback;
-import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
import java.util.*;
@@ -42,7 +37,8 @@ public class AiUtils {
* @see 必须开启 withMultiModel 参数
*/
public static final Set TONG_YI_MULTI_MODELS = SetUtils.asSet(
- // qwen3.5 / 3.6 系列(统一多模态主干)
+ // qwen3.5 / 3.6 / 3.7 系列(统一多模态主干)
+ "qwen3.7-max", "qwen3.7-plus", "qwen3.7-flash",
"qwen3.6-plus", "qwen3.6-flash",
"qwen3.5-plus", "qwen3.5-flash",
// qwen-vl 视觉理解
@@ -72,24 +68,17 @@ public class AiUtils {
.enableThinking(true) // TODO 芋艿:默认都开启 thinking 模式,后续可以让用户配置
.multiModel(TONG_YI_MULTI_MODELS.contains(model)) // 是否多模态模型
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case YI_YAN:
- return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
case DEEP_SEEK:
case DOU_BAO: // 复用 DeepSeek 客户端
case HUN_YUAN: // 复用 DeepSeek 客户端
case SILICON_FLOW: // 复用 DeepSeek 客户端
case XING_HUO: // 复用 DeepSeek 客户端
+ case YI_YAN: // 复用 DeepSeek 客户端
+ case ZHI_PU: // 复用 DeepSeek 客户端
+ case MINI_MAX: // 复用 DeepSeek 客户端
+ case MOONSHOT: // 复用 DeepSeek 客户端
return DeepSeekChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case ZHI_PU:
- return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case MINI_MAX:
- return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case MOONSHOT:
- return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case OPENAI:
case GEMINI: // 复用 OpenAI 客户端
case BAI_CHUAN: // 复用 OpenAI 客户端
@@ -97,7 +86,8 @@ public class AiUtils {
return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case AZURE_OPENAI:
- return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
+ return OpenAiChatOptions.builder().model(model).deploymentName(model).azure(true)
+ .temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case ANTHROPIC:
return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
@@ -159,4 +149,4 @@ public class AiUtils {
return MapUtil.getStr(output.getMetadata(), "reasoningContent");
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java
new file mode 100644
index 000000000..41f5d06a6
--- /dev/null
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java
@@ -0,0 +1,29 @@
+package org.springframework.ai.model.tool;
+
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+
+import java.lang.reflect.Method;
+
+/**
+ * TODO 芋艿:spring-ai-alibaba 2.0.0-M1.1 仍依赖旧的 Spring AI ToolExecutionEligibilityPredicate,
+ * 临时补齐;升级到兼容 Spring AI 2.0.0 的 spring-ai-alibaba 版本后,删除本包下的 shim。
+ */
+public class DefaultToolExecutionEligibilityPredicate implements ToolExecutionEligibilityPredicate {
+
+ @Override
+ public boolean test(ChatOptions promptOptions, ChatResponse chatResponse) {
+ return isInternalToolExecutionEnabled(promptOptions) && chatResponse != null && chatResponse.hasToolCalls();
+ }
+
+ private static boolean isInternalToolExecutionEnabled(ChatOptions promptOptions) {
+ try {
+ Method method = promptOptions.getClass().getMethod("getInternalToolExecutionEnabled");
+ Object result = method.invoke(promptOptions);
+ return result == null || Boolean.TRUE.equals(result);
+ } catch (ReflectiveOperationException | SecurityException ignored) {
+ return true;
+ }
+ }
+
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java b/yudao-module-ai/yudao-module-ai-server/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java
new file mode 100644
index 000000000..c26781077
--- /dev/null
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java
@@ -0,0 +1,21 @@
+package org.springframework.ai.model.tool;
+
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.util.Assert;
+
+import java.util.function.BiPredicate;
+
+/**
+ * TODO 芋艿:spring-ai-alibaba 2.0.0-M1.1 仍依赖旧的 Spring AI ToolExecutionEligibilityPredicate,
+ * 临时补齐;升级到兼容 Spring AI 2.0.0 的 spring-ai-alibaba 版本后,删除本包下的 shim。
+ */
+public interface ToolExecutionEligibilityPredicate extends BiPredicate {
+
+ default boolean isToolExecutionRequired(ChatOptions promptOptions, ChatResponse chatResponse) {
+ Assert.notNull(promptOptions, "promptOptions cannot be null");
+ Assert.notNull(chatResponse, "chatResponse cannot be null");
+ return test(promptOptions, chatResponse);
+ }
+
+}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-dev.yaml b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-dev.yaml
index d9ca9753b..85e4e343e 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-dev.yaml
@@ -17,11 +17,25 @@ spring:
--- #################### 数据库相关配置 ####################
spring:
- # 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
- org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
+ - org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration # 禁用 AI 模块的 Redis,手动创建
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
+ # TODO 芋艿:spring-ai-alibaba 2.0.0-M1.1 的 DashScope 自动配置暂不兼容 Spring AI 2.0.0
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAgentAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeVideoAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioSpeechAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioTranscriptionAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeRerankAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeMultimodalEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAsyncToolCallingManagerAutoConfiguration
+ # 数据源配置项
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-local.yaml b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-local.yaml
index 5cb4c2e79..a293bc108 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-local.yaml
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application-local.yaml
@@ -17,11 +17,25 @@ spring:
--- #################### 数据库相关配置 ####################
spring:
- # 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
- org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
+ - org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration # 禁用 AI 模块的 Redis,手动创建
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
+ # TODO 芋艿:spring-ai-alibaba 2.0.0-M1.1 的 DashScope 自动配置暂不兼容 Spring AI 2.0.0
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAgentAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeVideoAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioSpeechAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioTranscriptionAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeRerankAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeMultimodalEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAsyncToolCallingManagerAutoConfiguration
+ # 数据源配置项
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
@@ -141,4 +155,4 @@ yudao:
security:
mock-enable: true
access-log: # 访问日志的配置项
- enable: false
\ No newline at end of file
+ enable: false
diff --git a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml
index fd7b0d126..7c05e63cb 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml
+++ b/yudao-module-ai/yudao-module-ai-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
@@ -37,11 +33,6 @@ spring:
server:
port: 48090
- servlet:
- encoding:
- enabled: true
- charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
- force: true
logging:
file:
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
index bbcc055a2..7c1fe4183 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
@@ -4,7 +4,6 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.anthropic.AnthropicChatModel;
import org.springframework.ai.anthropic.AnthropicChatOptions;
-import org.springframework.ai.anthropic.api.AnthropicApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
@@ -23,12 +22,10 @@ import java.util.List;
public class AnthropicChatModelTest {
private final AnthropicChatModel chatModel = AnthropicChatModel.builder()
- .anthropicApi(AnthropicApi.builder()
+ .options(AnthropicChatOptions.builder()
.apiKey("sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942")
.baseUrl("https://aihubmix.com")
- .build())
- .defaultOptions(AnthropicChatOptions.builder()
- .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_5)
+ .model("claude-sonnet-4-5")
.temperature(0.7)
.maxTokens(4096)
.build())
@@ -70,8 +67,7 @@ public class AnthropicChatModelTest {
List messages = new ArrayList<>();
messages.add(new UserMessage("thkinking 下,1+1 为什么等于 2 "));
AnthropicChatOptions options = AnthropicChatOptions.builder()
- .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_5)
- .thinking(AnthropicApi.ThinkingType.ENABLED, 3096)
+ .model("claude-sonnet-4-5")
.temperature(1D)
.build();
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
deleted file mode 100644
index 69776d8e6..000000000
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-
-import com.azure.ai.openai.OpenAIClientBuilder;
-import com.azure.core.credential.AzureKeyCredential;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
-import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
-import org.springframework.ai.chat.messages.Message;
-import org.springframework.ai.chat.messages.SystemMessage;
-import org.springframework.ai.chat.messages.UserMessage;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.prompt.Prompt;
-import reactor.core.publisher.Flux;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatProperties.DEFAULT_DEPLOYMENT_NAME;
-
-/**
- * {@link AzureOpenAiChatModel} 集成测试
- *
- * @author 芋道源码
- */
-public class AzureOpenAIChatModelTests {
-
- // TODO @芋艿:晚点在调整
- private final OpenAIClientBuilder openAiApi = new OpenAIClientBuilder()
- .endpoint("https://eastusprejade.openai.azure.com")
- .credential(new AzureKeyCredential("xxx"));
- private final AzureOpenAiChatModel chatModel = AzureOpenAiChatModel.builder()
- .openAIClientBuilder(openAiApi)
- .defaultOptions(AzureOpenAiChatOptions.builder()
- .deploymentName(DEFAULT_DEPLOYMENT_NAME)
- .build())
- .build();
-
- @Test
- @Disabled
- public void testCall() {
- // 准备参数
- List messages = new ArrayList<>();
- messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
- messages.add(new UserMessage("1 + 1 = ?"));
-
- // 调用
- ChatResponse response = chatModel.call(new Prompt(messages));
- // 打印结果
- System.out.println(response);
- System.out.println(response.getResult().getOutput());
- }
-
- @Test
- @Disabled
- public void testStream() {
- // 准备参数
- List messages = new ArrayList<>();
- messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
- messages.add(new UserMessage("1 + 1 = ?"));
-
- // 调用
- Flux flux = chatModel.stream(new Prompt(messages));
- // 打印结果
- flux.doOnNext(response -> {
-// System.out.println(response);
- System.out.println(response.getResult().getOutput());
- }).then().block();
- }
-
-}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
index 06b0b2565..97c5277fb 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
@@ -10,7 +10,6 @@ import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.openai.api.OpenAiApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -24,11 +23,9 @@ import java.util.List;
public class BaiChuanChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl(BaiChuanChatModel.BASE_URL)
.apiKey("sk-61b6766a94c70786ed02673f5e16af3c") // apiKey
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model("Baichuan4-Turbo") // 模型(https://platform.baichuan-ai.com/docs/api)
.temperature(0.7)
.build())
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java
index 9a9314e99..bc6f4a919 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java
@@ -8,11 +8,12 @@ import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.api.OpenAiApi;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* 基于 {@link OpenAiChatModel} 集成 Coze 测试
@@ -22,7 +23,7 @@ import java.util.List;
public class CozeChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("http://127.0.0.1:3000")
.apiKey("app-4hy2d7fJauSbrKbzTKX1afuP") // apiKey
.build())
@@ -40,7 +41,7 @@ public class CozeChatModelTests {
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@@ -56,7 +57,7 @@ public class CozeChatModelTests {
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
index 2fbe0ee5d..2ca32d60e 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
@@ -26,8 +26,9 @@ public class DeepSeekChatModelTests {
.deepSeekApi(DeepSeekApi.builder()
.apiKey("sk-eaf4172a057344dd9bc64b1f806b6axx") // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
- .model("deepseek-chat") // 模型
+ .options(DeepSeekChatOptions.builder()
+ .model("deepseek-v4-flash") // 模型
+// .model("deepseek-v4-pro") // 模型
.temperature(0.7)
.build())
.build();
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java
index b9feaf532..cde8d6009 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java
@@ -8,11 +8,12 @@ import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.api.OpenAiApi;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* 基于 {@link OpenAiChatModel} 集成 Dify 测试
@@ -22,7 +23,7 @@ import java.util.List;
public class DifyChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("http://127.0.0.1:3000")
.apiKey("app-4hy2d7fJauSbrKbzTKX1afuP") // apiKey
.build())
@@ -40,7 +41,7 @@ public class DifyChatModelTests {
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@@ -56,7 +57,7 @@ public class DifyChatModelTests {
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
index 38c4f0b01..327924e63 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
@@ -32,7 +32,7 @@ public class DouBaoChatModelTests {
.completionsPath(DouBaoChatModel.COMPLETE_PATH)
.apiKey("5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272") // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model("doubao-1-5-lite-32k-250115") // 模型(doubao)
// .model("doubao-seed-1-6-thinking-250715") // 模型(doubao)
// .model("deepseek-r1-250120") // 模型(deepseek)
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java
index 458500a8b..09e5153f6 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java
@@ -8,11 +8,12 @@ import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.api.OpenAiApi;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* 基于 {@link OpenAiChatModel} 集成 FastGPT 测试
@@ -22,7 +23,7 @@ import java.util.List;
public class FastGPTChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("https://cloud.fastgpt.cn/api")
.apiKey("fastgpt-aqcc61kFtF8CeaglnGAfQOCIDWwjGdJVJHv6hIlMo28otFlva2aZNK") // apiKey
.build())
@@ -40,7 +41,7 @@ public class FastGPTChatModelTests {
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@@ -56,7 +57,7 @@ public class FastGPTChatModelTests {
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
index 964a5f3c3..fd66ad725 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
@@ -10,7 +10,6 @@ import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.openai.api.OpenAiApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -24,12 +23,9 @@ import java.util.List;
public class GeminiChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl(GeminiChatModel.BASE_URL)
- .completionsPath(GeminiChatModel.COMPLETE_PATH)
.apiKey("AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ")
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model(GeminiChatModel.MODEL_DEFAULT) // 模型
.temperature(0.7)
.build())
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
index eeafef261..e09622767 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
@@ -29,7 +29,7 @@ public class HunYuanChatModelTests {
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey("sk-abc") // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(HunYuanChatModel.MODEL_DEFAULT) // 模型
.temperature(0.7)
.build())
@@ -91,7 +91,7 @@ public class HunYuanChatModelTests {
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey("sk-abc") // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
// .model(HunYuanChatModel.DEEP_SEEK_MODEL_DEFAULT) // 模型("deepseek-v3")
.model("deepseek-r1") // 模型("deepseek-r1")
.temperature(0.7)
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
index 080146e5a..cafb36023 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
@@ -27,7 +27,7 @@ public class LlamaChatModelTests {
.ollamaApi(OllamaApi.builder()
.baseUrl("http://127.0.0.1:11434") // Ollama 服务地址
.build())
- .defaultOptions(OllamaChatOptions.builder()
+ .options(OllamaChatOptions.builder()
.model(OllamaModel.LLAMA3.getName()) // 模型
.build())
.build();
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
index 8fb133dbb..7a52907f6 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax.MiniMaxChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -7,9 +8,9 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.minimax.MiniMaxChatModel;
-import org.springframework.ai.minimax.MiniMaxChatOptions;
-import org.springframework.ai.minimax.api.MiniMaxApi;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -22,11 +23,15 @@ import java.util.List;
*/
public class MiniMaxChatModelTests {
- private final MiniMaxChatModel chatModel = new MiniMaxChatModel(
- new MiniMaxApi("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLnjovmlofmlowiLCJVc2VyTmFtZSI6IueOi-aWh-aWjCIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxODk3Mjg3MjQ5NDU2ODA4MzQ2IiwiUGhvbmUiOiIxNTYwMTY5MTM5OSIsIkdyb3VwSUQiOiIxODk3Mjg3MjQ5NDQ4NDE5NzM4IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDMtMTEgMTI6NTI6MDIiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.aAuB7gWW_oA4IYhh-CF7c9MfWWxKN49B_HK-DYjXaDwwffhiG-H1571z1WQhp9QytWG-DqgLejneeSxkiq1wQIe3FsEP2wz4BmGBct31LehbJu8ehLxg_vg75Uod1nFAHbm5mZz6JSVLNIlSo87Xr3UtSzJhAXlapEkcqlA4YOzOpKrZ8l5_OJPTORTCmHWZYgJcRS-faNiH62ZnUEHUozesTFhubJHo5GfJCw_edlnmfSUocERV1BjWvenhZ9My-aYXNktcW9WaSj9l6gayV7A0Ium_PL55T9ln1PcI8gayiVUKJGJDoqNyF1AF9_aF9NOKtTnQzwNqnZdlTYH6hw"), // 密钥
- MiniMaxChatOptions.builder()
- .model(MiniMaxApi.ChatModel.ABAB_6_5_G_Chat.getValue()) // 模型
- .build());
+ private final MiniMaxChatModel chatModel = new MiniMaxChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(MiniMaxChatModel.BASE_URL)
+ .apiKey("sk-api-xxx") // 密钥
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(MiniMaxChatModel.MODEL_DEFAULT) // 模型
+ .build())
+ .build());
@Test
@Disabled
public void testCall() {
@@ -59,14 +64,13 @@ public class MiniMaxChatModelTests {
}).then().block();
}
- // TODO @芋艿:暂时没解析 reasoning_content 结果,需要等官方修复
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
- MiniMaxChatOptions options = MiniMaxChatOptions.builder()
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("MiniMax-M1")
.build();
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
index b50ab80f4..bbef36696 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
@@ -1,15 +1,16 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot.MoonshotChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.springaicommunity.moonshot.MoonshotChatModel;
-import org.springaicommunity.moonshot.MoonshotChatOptions;
-import org.springaicommunity.moonshot.api.MoonshotApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -22,14 +23,17 @@ import java.util.List;
*/
public class MoonshotChatModelTests {
- private final MoonshotChatModel chatModel = MoonshotChatModel.builder()
- .moonshotApi(MoonshotApi.builder()
- .apiKey("sk-aHYYV1SARscItye5QQRRNbXij4fy65Ee7pNZlC9gsSQnUKXA") // 密钥
+ private final MoonshotChatModel chatModel = new MoonshotChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(MoonshotChatModel.BASE_URL)
+ .completionsPath(MoonshotChatModel.COMPLETE_PATH)
+ .apiKey("sk-xxx") // 密钥
.build())
- .defaultOptions(MoonshotChatOptions.builder()
- .model("kimi-k2-0711-preview") // 模型
+ .options(DeepSeekChatOptions.builder()
+ .model(MoonshotChatModel.MODEL_DEFAULT) // 模型
+ .temperature(1D)
.build())
- .build();
+ .build());
@Test
@Disabled
@@ -63,16 +67,14 @@ public class MoonshotChatModelTests {
}).then().block();
}
- // TODO @芋艿:暂时没解析 reasoning_content 结果,需要等官方修复
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
- MoonshotChatOptions options = MoonshotChatOptions.builder()
-// .model("kimi-k2-0711-preview")
- .model("kimi-thinking-preview")
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder()
+ .model(MoonshotChatModel.MODEL_DEFAULT)
.build();
// 调用
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
index c03a5de15..119d569b3 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
@@ -26,7 +26,7 @@ public class OllamaChatModelTests {
.ollamaApi(OllamaApi.builder()
.baseUrl("http://127.0.0.1:11434") // Ollama 服务地址
.build())
- .defaultOptions(OllamaChatOptions.builder()
+ .options(OllamaChatOptions.builder()
// .model("qwen") // 模型(https://ollama.com/library/qwen)
.model("deepseek-r1") // 模型(https://ollama.com/library/deepseek-r1)
.build())
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
index 5bae6c694..e3fbedacf 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.azure.ai.openai.models.ReasoningEffortValue;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -10,11 +9,11 @@ import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.openai.api.OpenAiApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* {@link OpenAiChatModel} 集成测试
@@ -24,13 +23,11 @@ import java.util.List;
public class OpenAIChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("https://api.holdai.top")
- .apiKey("sk-z5joyRoV1iFEnh2SAi8QPNrIZTXyQSyxTmD5CoNDQbFixK2l") // apiKey
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
+ .apiKey("sk-xxx") // apiKey
.model("gpt-5-nano-2025-08-07") // 模型
-// .model(OpenAiApi.ChatModel.O1) // 模型
+// .model("o1") // 模型
.temperature(0.7)
.build())
.build();
@@ -47,7 +44,7 @@ public class OpenAIChatModelTests {
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@@ -63,7 +60,7 @@ public class OpenAIChatModelTests {
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
@@ -76,9 +73,9 @@ public class OpenAIChatModelTests {
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model("gpt-5")
-// .model(OpenAiApi.ChatModel.O4_MINI)
+// .model("o4-mini")
// .model("o3-pro")
- .reasoningEffort(ReasoningEffortValue.LOW.getValue())
+ .reasoningEffort("low")
.build();
// 调用
@@ -86,7 +83,7 @@ public class OpenAIChatModelTests {
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
index 3bb58e68e..7578f6e56 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
@@ -29,7 +29,7 @@ public class SiliconFlowChatModelTests {
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
.apiKey("sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz") // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(SiliconFlowApiConstants.MODEL_DEFAULT) // 模型
// .model("deepseek-ai/DeepSeek-R1") // 模型(deepseek-ai/DeepSeek-R1)可用赠费
// .model("Pro/deepseek-ai/DeepSeek-R1") // 模型(Pro/deepseek-ai/DeepSeek-R1)需要付费
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
index 77dbd2bc6..e940b41bf 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
@@ -29,7 +29,7 @@ public class XingHuoChatModelTests {
.completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2)
.apiKey("75b161ed2aef4719b275d6e7f2a4d4cd:YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz") // appKey:secretKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
// .model("generalv3.5") // 模型
.model("x1") // 模型
.temperature(0.7)
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
index cb7be2a29..fd06b1aef 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
@@ -1,41 +1,42 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan.YiYanChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.springaicommunity.qianfan.QianFanChatModel;
-import org.springaicommunity.qianfan.QianFanChatOptions;
-import org.springaicommunity.qianfan.api.QianFanApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
-// TODO @芋艿:百度千帆 API 提供了 V2 版本,目前 Spring AI 不兼容,可关键 进展
/**
- * {@link QianFanChatModel} 的集成测试
+ * {@link YiYanChatModel} 的集成测试
*
* @author fansili
*/
public class YiYanChatModelTests {
- private final QianFanChatModel chatModel = new QianFanChatModel(
- new QianFanApi("DGnyzREuaY7av7c38bOM9Ji2", "9aR8myflEOPDrEeLhoXv0FdqANOAyIZW"), // 密钥
- QianFanChatOptions.builder()
- .model("ERNIE-4.5-8K-Preview")
- .build()
- );
+ private final YiYanChatModel chatModel = new YiYanChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(YiYanChatModel.BASE_URL)
+ .apiKey("bce-v3/xxx") // 密钥
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(YiYanChatModel.MODEL_DEFAULT)
+ .build())
+ .build());
@Test
@Disabled
public void testCall() {
// 准备参数
List messages = new ArrayList<>();
- // TODO @芋艿:文心一言,只要带上 system message 就报错,已经各种测试,很莫名!
-// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
@@ -49,8 +50,6 @@ public class YiYanChatModelTests {
public void testStream() {
// 准备参数
List messages = new ArrayList<>();
- // TODO @芋艿:文心一言,只要带上 system message 就报错,已经各种测试,很莫名!
-// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = ?"));
// 调用
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
index 18c317989..eb6dad05e 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu.ZhiPuChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -7,27 +8,30 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
-import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
-import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
/**
- * {@link ZhiPuAiChatModel} 的集成测试
+ * {@link ZhiPuChatModel} 的集成测试
*
* @author 芋道源码
*/
public class ZhiPuAiChatModelTests {
- private final ZhiPuAiChatModel chatModel = new ZhiPuAiChatModel(
- ZhiPuAiApi.builder().apiKey("2f35fb6ca4ea41fab898729b7fac086c.6ESSfPcCkxaKEUlR").build(), // 密钥
- ZhiPuAiChatOptions.builder()
- .model(ZhiPuAiApi.ChatModel.GLM_4.getName()) // 模型
+ private final ZhiPuChatModel chatModel = new ZhiPuChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(ZhiPuChatModel.BASE_URL)
+ .apiKey("sk-xxx") // 密钥
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(ZhiPuChatModel.MODEL_DEFAULT) // 模型
.build()
- );
+ ).build());
@Test
@Disabled
@@ -61,15 +65,14 @@ public class ZhiPuAiChatModelTests {
}).then().block();
}
- // TODO @芋艿:暂时没解析 reasoning_content 结果,需要等官方修复
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
- ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder()
- .model("GLM-4.5")
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder()
+ .model(ZhiPuChatModel.MODEL_DEFAULT)
.build();
// 调用
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
index 1b124529d..a30e7cfb6 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
@@ -7,7 +7,6 @@ import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.OpenAiImageOptions;
-import org.springframework.ai.openai.api.OpenAiImageApi;
/**
* {@link OpenAiImageModel} 集成测试类
@@ -16,17 +15,19 @@ import org.springframework.ai.openai.api.OpenAiImageApi;
*/
public class OpenAiImageModelTests {
- private final OpenAiImageModel imageModel = new OpenAiImageModel(OpenAiImageApi.builder()
- .baseUrl("https://api.holdai.top") // apiKey
- .apiKey("sk-PytRecQlmjEteoa2RRN6cGnwslo72UUPLQVNEMS6K9yjbmpD")
- .build());
+ private final OpenAiImageModel imageModel = OpenAiImageModel.builder()
+ .options(OpenAiImageOptions.builder()
+ .baseUrl("https://api.holdai.top") // apiKey
+ .apiKey("sk-xxx")
+ .build())
+ .build();
@Test
@Disabled
public void testCall() {
// 准备参数
ImageOptions options = OpenAiImageOptions.builder()
- .model(OpenAiImageApi.ImageModel.DALL_E_2.getValue()) // 这个模型比较便宜
+ .model("dall-e-2") // 这个模型比较便宜
.height(256).width(256)
.build();
ImagePrompt prompt = new ImagePrompt("中国长城!", options);
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
deleted file mode 100644
index 156360f25..000000000
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.springaicommunity.qianfan.QianFanImageModel;
-import org.springaicommunity.qianfan.QianFanImageOptions;
-import org.springaicommunity.qianfan.api.QianFanImageApi;
-import org.springframework.ai.image.ImagePrompt;
-import org.springframework.ai.image.ImageResponse;
-
-import static cn.iocoder.yudao.module.ai.framework.ai.core.model.image.StabilityAiImageModelTests.viewImage;
-
-// TODO @芋艿:百度千帆 API 提供了 V2 版本,目前 Spring AI 不兼容,可关键 进展
-
-/**
- * {@link QianFanImageModel} 集成测试类
- */
-public class QianFanImageTests {
-
- private final QianFanImageModel imageModel = new QianFanImageModel(
- new QianFanImageApi("qS8k8dYr2nXunagK4SSU8Xjj", "pHGbx51ql2f0hOyabQvSZezahVC3hh3e")); // 密钥
-
- @Test
- @Disabled
- public void testCall() {
- // 准备参数
- // 只支持 1024x1024、768x768、768x1024、1024x768、576x1024、1024x576
- QianFanImageOptions imageOptions = QianFanImageOptions.builder()
- .model(QianFanImageApi.ImageModel.Stable_Diffusion_XL.getValue())
- .width(1024).height(1024)
- .N(1)
- .build();
- ImagePrompt prompt = new ImagePrompt("good", imageOptions);
-
- // 方法调用
- ImageResponse response = imageModel.call(prompt);
- // 打印结果
- String b64Json = response.getResult().getOutput().getB64Json();
- System.out.println(response);
- viewImage(b64Json);
- }
-
-}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java
deleted file mode 100644
index bb16aac90..000000000
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.springframework.ai.image.ImagePrompt;
-import org.springframework.ai.image.ImageResponse;
-import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
-import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
-import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
-
-/**
- * {@link ZhiPuAiImageModel} 集成测试
- */
-public class ZhiPuAiImageModelTests {
-
- private final ZhiPuAiImageModel imageModel = new ZhiPuAiImageModel(
- new ZhiPuAiImageApi("78d3228c1d9e5e342a3e1ab349e2dd7b.VXLoq5vrwK2ofboy") // 密钥
- );
-
- @Test
- @Disabled
- public void testCall() {
- // 准备参数
- ZhiPuAiImageOptions imageOptions = ZhiPuAiImageOptions.builder()
- .model(ZhiPuAiImageApi.ImageModel.CogView_3.getValue())
- .build();
- ImagePrompt prompt = new ImagePrompt("万里长城", imageOptions);
-
- // 方法调用
- ImageResponse response = imageModel.call(prompt);
- // 打印结果
- System.out.println(response);
- }
-
-}
diff --git a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
index b50caef5e..d38313cb5 100644
--- a/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
+++ b/yudao-module-ai/yudao-module-ai-server/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
@@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
-import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
@@ -14,11 +13,9 @@ import org.springframework.ai.tool.method.MethodToolCallbackProvider;
public class DouBaoMcpTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiApi(OpenAiApi.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl(DouBaoChatModel.BASE_URL)
.apiKey("5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272") // apiKey
- .build())
- .defaultOptions(OpenAiChatOptions.builder()
.model("doubao-1-5-lite-32k-250115") // 模型(doubao)
.temperature(0.7)
.build())
@@ -36,44 +33,47 @@ public class DouBaoMcpTests {
@Test
public void testMcpGetUserInfo() {
-
// 打印结果
System.out.println(chatClient.prompt()
.user("目前有哪些工具可以使用")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的年龄是多少")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("获取小新的基本信息")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新是什么职业的")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的教育背景")
.call()
.content());
System.out.println("====================================");
+
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的兴趣爱好是什么")
.call()
.content());
System.out.println("====================================");
-
}
@@ -121,4 +121,4 @@ public class DouBaoMcpTests {
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
index 6de7f9dfa..3aa0a9951 100644
--- a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
+++ b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
@@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmHttpRequestParamTypeEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
-import com.fasterxml.jackson.core.type.TypeReference;
+import tools.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.http.*;
@@ -45,7 +45,7 @@ public class BpmHttpRequestUtils {
BpmProcessInstanceService processInstanceService = SpringUtils.getBean(BpmProcessInstanceService.class);
// 1.1 设置请求头
- MultiValueMap headers = buildHttpHeaders(processInstance, headerParams);
+ HttpHeaders headers = buildHttpHeaders(processInstance, headerParams);
// 1.2 设置请求体
MultiValueMap body = buildHttpBody(processInstance, bodyParams);
@@ -113,7 +113,7 @@ public class BpmHttpRequestUtils {
}
public static ResponseEntity sendHttpRequest(String url,
- MultiValueMap headers,
+ HttpHeaders headers,
Object body,
RestTemplate restTemplate) {
HttpEntity
+
+ org.springframework.boot
+ spring-boot-kafka
+ true
+
@@ -69,4 +74,4 @@
-
\ No newline at end of file
+
diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
index 4f14057eb..39f59f303 100644
--- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
+++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
@@ -19,11 +19,11 @@ import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.kafka.autoconfigure.KafkaProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java
index d859f6734..6644dcb28 100644
--- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java
+++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java
@@ -11,7 +11,7 @@ import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
-import org.springframework.boot.autoconfigure.kafka.KafkaProperties;
+import org.springframework.boot.kafka.autoconfigure.KafkaProperties;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
diff --git a/yudao-module-iot/yudao-module-iot-gateway/pom.xml b/yudao-module-iot/yudao-module-iot-gateway/pom.xml
index 46668895c..8843edbab 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-gateway/pom.xml
@@ -27,6 +27,10 @@
org.springframework
spring-web
+
+ org.springframework.boot
+ spring-boot-restclient
+
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/handler/upstream/IotHttpAbstractHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/handler/upstream/IotHttpAbstractHandler.java
index c403ee973..f7fef40fd 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/handler/upstream/IotHttpAbstractHandler.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/handler/upstream/IotHttpAbstractHandler.java
@@ -115,7 +115,7 @@ public abstract class IotHttpAbstractHandler implements Handler
public static void writeResponse(RoutingContext context, CommonResult> data) {
context.response()
.setStatusCode(200)
- .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
+ .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.end(serializeResponse(data));
}
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java
index ed46a9afb..788ad9e89 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java
@@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
@@ -41,7 +41,7 @@ public class IotDeviceApiImpl implements IotDeviceCommonApi {
public void init() {
IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc();
restTemplate = new RestTemplateBuilder()
- .rootUri(rpc.getUrl())
+ .baseUri(rpc.getUrl())
.readTimeout(rpc.getReadTimeout())
.connectTimeout(rpc.getConnectTimeout())
.build();
diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java b/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java
index 3f4b8eb02..7d385d1e8 100644
--- a/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java
+++ b/yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java
@@ -70,7 +70,7 @@ public class IotHttpDataSinkAction implements IotDataRuleAction {
requestBody = new HashMap<>();
}
requestBody.put("message", message);
- headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
+ headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers);
}
@@ -89,4 +89,4 @@ public class IotHttpDataSinkAction implements IotDataRuleAction {
}
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml
index 3129314b3..dfab06ba6 100644
--- a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml
index 8ae2df864..b91abd9a1 100644
--- a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml
+++ b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml
index 8e2036988..51edd54c8 100644
--- a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml
+++ b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-mall/yudao-module-product-server/src/main/resources/application-dev.yaml b/yudao-module-mall/yudao-module-product-server/src/main/resources/application-dev.yaml
index 6dffa16b5..f45b72fa4 100644
--- a/yudao-module-mall/yudao-module-product-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-mall/yudao-module-product-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-product-server/src/main/resources/application-local.yaml b/yudao-module-mall/yudao-module-product-server/src/main/resources/application-local.yaml
index 2557d8fe9..c04f3aa3d 100644
--- a/yudao-module-mall/yudao-module-product-server/src/main/resources/application-local.yaml
+++ b/yudao-module-mall/yudao-module-product-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-product-server/src/main/resources/application.yaml b/yudao-module-mall/yudao-module-product-server/src/main/resources/application.yaml
index 53556bad5..f6984010f 100644
--- a/yudao-module-mall/yudao-module-product-server/src/main/resources/application.yaml
+++ b/yudao-module-mall/yudao-module-product-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-dev.yaml b/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-dev.yaml
index 6dffa16b5..f45b72fa4 100644
--- a/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-local.yaml b/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-local.yaml
index 1c63522a8..b7b0cac76 100644
--- a/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-local.yaml
+++ b/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application.yaml b/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application.yaml
index 429ab9ec4..6b0661c8c 100644
--- a/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application.yaml
+++ b/yudao-module-mall/yudao-module-promotion-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-dev.yaml b/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-dev.yaml
index 6dffa16b5..f45b72fa4 100644
--- a/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-local.yaml b/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-local.yaml
index 0450915d8..ace2e65c2 100644
--- a/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-local.yaml
+++ b/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application.yaml b/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application.yaml
index 40fd663fb..a7a5603db 100644
--- a/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application.yaml
+++ b/yudao-module-mall/yudao-module-statistics-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java
index 37a1a9fad..d055d47ab 100644
--- a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java
+++ b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kd100/Kd100ExpressQueryRespDTO.java
@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kd100;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import lombok.Data;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.ext.javatime.deser.LocalDateTimeDeserializer;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java
index 04a7c1431..0470e81f8 100644
--- a/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java
+++ b/yudao-module-mall/yudao-module-trade-server/src/main/java/cn/iocoder/yudao/module/trade/framework/delivery/core/client/dto/kdniao/KdNiaoExpressQueryRespDTO.java
@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.kdniao;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import lombok.Data;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.ext.javatime.deser.LocalDateTimeDeserializer;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-dev.yaml b/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-dev.yaml
index c0dcf916c..79971794f 100644
--- a/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-local.yaml b/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-local.yaml
index 4fccd3f11..f35471178 100644
--- a/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-local.yaml
+++ b/yudao-module-mall/yudao-module-trade-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mall/yudao-module-trade-server/src/main/resources/application.yaml b/yudao-module-mall/yudao-module-trade-server/src/main/resources/application.yaml
index 291586cdf..43fd16c39 100644
--- a/yudao-module-mall/yudao-module-trade-server/src/main/resources/application.yaml
+++ b/yudao-module-mall/yudao-module-trade-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-member/yudao-module-member-server/src/main/resources/application-dev.yaml b/yudao-module-member/yudao-module-member-server/src/main/resources/application-dev.yaml
index 52ad3f857..0711e732b 100644
--- a/yudao-module-member/yudao-module-member-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-member/yudao-module-member-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-member/yudao-module-member-server/src/main/resources/application-local.yaml b/yudao-module-member/yudao-module-member-server/src/main/resources/application-local.yaml
index 322b1baf7..593fc65f2 100644
--- a/yudao-module-member/yudao-module-member-server/src/main/resources/application-local.yaml
+++ b/yudao-module-member/yudao-module-member-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-member/yudao-module-member-server/src/main/resources/application.yaml b/yudao-module-member/yudao-module-member-server/src/main/resources/application.yaml
index d96acfca6..0dca3c983 100644
--- a/yudao-module-member/yudao-module-member-server/src/main/resources/application.yaml
+++ b/yudao-module-member/yudao-module-member-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-dev.yaml b/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-dev.yaml
index 522c0145e..fc2830742 100644
--- a/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-local.yaml b/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-local.yaml
index bc7958160..2510b671d 100644
--- a/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-local.yaml
+++ b/yudao-module-mes/yudao-module-mes-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mes/yudao-module-mes-server/src/main/resources/application.yaml b/yudao-module-mes/yudao-module-mes-server/src/main/resources/application.yaml
index 4e4328edb..bbe3517d8 100644
--- a/yudao-module-mes/yudao-module-mes-server/src/main/resources/application.yaml
+++ b/yudao-module-mes/yudao-module-mes-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/YudaoWxMpConfiguration.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/YudaoWxMpConfiguration.java
index f3692a0a1..200e6d8a8 100644
--- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/YudaoWxMpConfiguration.java
+++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/config/YudaoWxMpConfiguration.java
@@ -34,11 +34,21 @@ import org.springframework.data.redis.core.StringRedisTemplate;
@Slf4j
public class YudaoWxMpConfiguration {
+ @Bean
+ @ConditionalOnProperty(prefix = WxMpProperties.PREFIX + ".config-storage", name = "type",
+ havingValue = "memory", matchIfMissing = true)
+ @ConditionalOnMissingBean(WxMpConfigStorage.class)
+ public WxMpConfigStorage wxMpMemoryConfigStorage(WxMpProperties properties) {
+ WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
+ applyWxMpConfig(config, properties);
+ return config;
+ }
+
@Bean
@ConditionalOnProperty(prefix = WxMpProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate")
@ConditionalOnClass(StringRedisTemplate.class)
@ConditionalOnMissingBean(WxMpConfigStorage.class)
- public WxMpConfigStorage wxMpConfigStorage(WxMpProperties properties, ApplicationContext applicationContext) {
+ public WxMpConfigStorage wxMpRedisTemplateConfigStorage(WxMpProperties properties, ApplicationContext applicationContext) {
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
WxRedisOps redisOps = new RedisTemplateWxRedisOps(redisTemplate);
WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(redisOps, properties.getConfigStorage().getKeyPrefix());
diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-dev.yaml b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-dev.yaml
index 311a0c1b4..cdae1af12 100644
--- a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-local.yaml b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-local.yaml
index c37c20cd8..30bf35c1d 100644
--- a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-local.yaml
+++ b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml
index 09e77d09b..31f987f86 100644
--- a/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml
+++ b/yudao-module-mp/yudao-module-mp-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java
index 00397863c..86f71520e 100644
--- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java
+++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/channel/PayChannelDO.java
@@ -8,15 +8,13 @@ import cn.iocoder.yudao.module.pay.framework.pay.core.client.PayClientConfig;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
import cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.NonePayClientConfig;
-import cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.alipay.AlipayAppPayClient;
import cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
import cn.iocoder.yudao.module.pay.framework.pay.core.client.impl.weixin.WxPayClientConfig;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
-import com.fasterxml.jackson.core.type.TypeReference;
+import tools.jackson.core.type.TypeReference;
import lombok.*;
import java.lang.reflect.Field;
diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-dev.yaml b/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-dev.yaml
index e9bb6e9b9..67ba0518e 100644
--- a/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-local.yaml b/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-local.yaml
index 0fa0c1b66..75e6a9d64 100644
--- a/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-local.yaml
+++ b/yudao-module-pay/yudao-module-pay-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/resources/application.yaml b/yudao-module-pay/yudao-module-pay-server/src/main/resources/application.yaml
index 08e604694..17665c3d5 100644
--- a/yudao-module-pay/yudao-module-pay-server/src/main/resources/application.yaml
+++ b/yudao-module-pay/yudao-module-pay-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-report/yudao-module-report-server/src/main/resources/application-dev.yaml b/yudao-module-report/yudao-module-report-server/src/main/resources/application-dev.yaml
index 6d6c51a86..e92a3d441 100644
--- a/yudao-module-report/yudao-module-report-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-report/yudao-module-report-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-report/yudao-module-report-server/src/main/resources/application-local.yaml b/yudao-module-report/yudao-module-report-server/src/main/resources/application-local.yaml
index 763128de8..ae1e3754e 100644
--- a/yudao-module-report/yudao-module-report-server/src/main/resources/application-local.yaml
+++ b/yudao-module-report/yudao-module-report-server/src/main/resources/application-local.yaml
@@ -20,7 +20,9 @@ spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-report/yudao-module-report-server/src/main/resources/application.yaml b/yudao-module-report/yudao-module-report-server/src/main/resources/application.yaml
index 90b417921..f5f0ba61b 100644
--- a/yudao-module-report/yudao-module-report-server/src/main/resources/application.yaml
+++ b/yudao-module-report/yudao-module-report-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-system/yudao-module-system-server/src/main/resources/application-dev.yaml b/yudao-module-system/yudao-module-system-server/src/main/resources/application-dev.yaml
index 28b362e6b..311018796 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-system/yudao-module-system-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-system/yudao-module-system-server/src/main/resources/application-local.yaml b/yudao-module-system/yudao-module-system-server/src/main/resources/application-local.yaml
index 31c55ece9..0a1a2ef1f 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/resources/application-local.yaml
+++ b/yudao-module-system/yudao-module-system-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml b/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml
index 1c1e27d2e..cfa8acd28 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml
+++ b/yudao-module-system/yudao-module-system-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-dev.yaml b/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-dev.yaml
index 522c0145e..fc2830742 100644
--- a/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-dev.yaml
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-dev.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-local.yaml b/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-local.yaml
index ece61d357..32156d3c2 100644
--- a/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-local.yaml
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/resources/application-local.yaml
@@ -19,7 +19,9 @@ spring:
spring:
# 数据源配置项
autoconfigure:
+ # noinspection SpringBootApplicationYaml
exclude:
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/resources/application.yaml b/yudao-module-wms/yudao-module-wms-server/src/main/resources/application.yaml
index 82dfb4e4a..ed7f0b473 100644
--- a/yudao-module-wms/yudao-module-wms-server/src/main/resources/application.yaml
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/resources/application.yaml
@@ -20,14 +20,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml
index 4113d93df..8c35b726d 100644
--- a/yudao-server/src/main/resources/application-dev.yaml
+++ b/yudao-server/src/main/resources/application-dev.yaml
@@ -9,6 +9,7 @@ spring:
exclude:
- org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
# 数据源配置项
datasource:
druid: # Druid 【监控】相关的全局配置
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index e2e24fb72..17fedfe9b 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -8,6 +8,7 @@ spring:
exclude:
- org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
+ - org.dromara.trans.config.TransServiceConfig # TODO 芋艿:easy-trans 兼容 Spring Boot 4 后移除(TransServiceConfig 引用了已移除的 RestTemplateBuilder)
# 数据源配置项
datasource:
druid: # Druid 【监控】相关的全局配置
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index f02cbf706..79452f27c 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -15,14 +15,10 @@ spring:
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
-
- # Jackson 配置项
- jackson:
- serialization:
- write-dates-as-timestamps: true # 设置 Date 的格式,使用时间戳
- write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
- write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
- fail-on-empty-beans: false # 允许序列化无属性的 Bean
+ encoding:
+ enabled: true
+ charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
+ force: true
# Cache 配置项
cache:
@@ -30,13 +26,6 @@ spring:
redis:
time-to-live: 1h # 设置过期时间为 1 小时
-server:
- servlet:
- encoding:
- enabled: true
- charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
- force: true
-
--- #################### Spring Cloud 禁用配置 ####################
spring:
@@ -375,4 +364,4 @@ yudao:
message-bus:
type: redis # 消息总线的类型
-debug: false
\ No newline at end of file
+debug: false