!46 Spring Boot升级至4.0.1

Merge pull request !46 from 太空眼睛/master-upgrade-springboot4
This commit is contained in:
Ray.Hao
2026-01-11 16:22:26 +00:00
committed by Gitee
11 changed files with 48 additions and 52 deletions

22
pom.xml
View File

@@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version> <!-- lookup parent from repository --> <version>4.0.1</version> <!-- lookup parent from repository -->
<relativePath/> <relativePath/>
</parent> </parent>
@@ -24,7 +24,8 @@
<mysql-connector-j.version>9.1.0</mysql-connector-j.version> <mysql-connector-j.version>9.1.0</mysql-connector-j.version>
<druid.version>1.2.24</druid.version> <druid.version>1.2.24</druid.version>
<mybatis-plus.version>3.5.5</mybatis-plus.version> <!-- Spring Boot 4.x 必须使用更新的版本 -->
<mybatis-plus.version>3.5.15</mybatis-plus.version>
<dynamic-datasource.version>4.3.1</dynamic-datasource.version> <dynamic-datasource.version>4.3.1</dynamic-datasource.version>
<knife4j.version>4.5.0</knife4j.version> <knife4j.version>4.5.0</knife4j.version>
@@ -43,7 +44,8 @@
<aliyun-sdk-oss.version>3.16.3</aliyun-sdk-oss.version> <aliyun-sdk-oss.version>3.16.3</aliyun-sdk-oss.version>
<!-- redisson 分布式锁 --> <!-- redisson 分布式锁 -->
<redisson.version>3.51.0</redisson.version> <!-- Spring Boot 4.x 必须使用更新的版本 -->
<redisson.version>4.1.0</redisson.version>
<!-- 自动代码生成 --> <!-- 自动代码生成 -->
<mybatis-plus-generator.version>3.5.6</mybatis-plus-generator.version> <mybatis-plus-generator.version>3.5.6</mybatis-plus-generator.version>
@@ -63,7 +65,8 @@
<!-- 阿里 TransmittableThreadLocal (支持异步场景的ThreadLocal传递) --> <!-- 阿里 TransmittableThreadLocal (支持异步场景的ThreadLocal传递) -->
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version> <transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
<spring-ai-openai.version>1.1.2</spring-ai-openai.version> <!-- Spring Boot 4.x 必须使用更新的版本 -->
<spring-ai-openai.version>2.0.0-M1</spring-ai-openai.version>
</properties> </properties>
<dependencies> <dependencies>
@@ -121,9 +124,10 @@
<artifactId>spring-boot-starter-cache</artifactId> <artifactId>spring-boot-starter-cache</artifactId>
</dependency> </dependency>
<!-- Spring Boot 4.x 已改名 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>spring-boot-starter-aspectj</artifactId>
</dependency> </dependency>
<dependency> <dependency>
@@ -154,9 +158,15 @@
<version>${druid.version}</version> <version>${druid.version}</version>
</dependency> </dependency>
<!-- Spring Boot 4.x 必须使用boot4版本 -->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId> <artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
<version>${mybatis-plus.version}</version> <version>${mybatis-plus.version}</version>
</dependency> </dependency>

View File

@@ -1,7 +1,7 @@
package com.youlai.boot.config; package com.youlai.boot.config;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.cache.autoconfigure.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;

View File

@@ -1,12 +1,5 @@
package com.youlai.boot.config; package com.youlai.boot.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import jakarta.validation.Validation; import jakarta.validation.Validation;
import jakarta.validation.Validator; import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory; import jakarta.validation.ValidatorFactory;
@@ -15,16 +8,18 @@ import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverters;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory; import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import tools.jackson.databind.cfg.DateTimeFeature;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.module.SimpleModule;
import tools.jackson.databind.ser.std.ToStringSerializer;
import java.math.BigInteger; import java.math.BigInteger;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
@@ -40,36 +35,27 @@ public class WebMvcConfig implements WebMvcConfigurer {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/** /**
* 配置消息转换器 * Spring Boot 4.x 已经使用Jackson 3.x
* Jackson 3.x已经自带JavaTimeModule不再需要手工注册
* *
* @param converters 消息转换器列表 * @param converterBuilder the builder to configure
*/ */
@Override @Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { public void configureMessageConverters(HttpMessageConverters.ServerBuilder converterBuilder) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); JsonMapper.Builder builder = JsonMapper.builder();
ObjectMapper objectMapper = new ObjectMapper();
// 注册 JavaTimeModule替代手动注册 LocalDateTimeSerializer
JavaTimeModule javaTimeModule = new JavaTimeModule();
// 返回指定字符串格式
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
// 反序列化,接受前端传来的格式
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
objectMapper.registerModule(javaTimeModule);
// 配置全局日期格式和时区 // 配置全局日期格式和时区
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); builder.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); builder.defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); builder.defaultTimeZone(TimeZone.getTimeZone("GMT+8"));
// 处理 Long/BigInteger 的精度问题 // 处理 Long/BigInteger 的精度问题
SimpleModule simpleModule = new SimpleModule(); SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance); simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule); builder.addModule(simpleModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper); converterBuilder.addCustomConverter(new JacksonJsonHttpMessageConverter(builder));
converters.add(1, jackson2HttpMessageConverter);
} }
/** /**

View File

@@ -1,7 +1,7 @@
package com.youlai.boot.core.exception; package com.youlai.boot.core.exception;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException; import tools.jackson.core.JacksonException;
import com.youlai.boot.core.web.Result; import com.youlai.boot.core.web.Result;
import com.youlai.boot.core.web.ResultCode; import com.youlai.boot.core.web.ResultCode;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
@@ -143,11 +143,11 @@ public class GlobalExceptionHandler {
/** /**
* 处理 JSON 处理异常 * 处理 JSON 处理异常
* <p> * <p>
* 当处理 JSON 数据时发生错误,会抛出 JsonProcessingException 异常。 * 当处理 JSON 数据时发生错误,会抛出 JacksonException 异常。
*/ */
@ExceptionHandler(JsonProcessingException.class) @ExceptionHandler(JacksonException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public <T> Result<T> handleJsonProcessingException(JsonProcessingException e) { public <T> Result<T> handleJacksonException(JacksonException e) {
log.error("Json转换异常异常原因{}", e.getMessage(), e); log.error("Json转换异常异常原因{}", e.getMessage(), e);
return Result.failed(e.getMessage()); return Result.failed(e.getMessage());
} }

View File

@@ -1,12 +1,12 @@
package com.youlai.boot.platform.websocket.publisher; package com.youlai.boot.platform.websocket.publisher;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import tools.jackson.core.JacksonException;
import tools.jackson.databind.ObjectMapper;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -49,7 +49,7 @@ public class WebSocketPublisher {
} }
} }
private Object serializeIfNeeded(Object payload) throws JsonProcessingException { private Object serializeIfNeeded(Object payload) throws JacksonException {
if (payload == null) { if (payload == null) {
return null; return null;
} }

View File

@@ -13,7 +13,7 @@ import java.util.List;
/** /**
* WebSocket 服务实现类 * WebSocket 服务实现类
* *
* 核心功能: * 核心功能:
* - 用户在线状态管理(支持多设备登录) * - 用户在线状态管理(支持多设备登录)
* - 消息推送(广播、点对点) * - 消息推送(广播、点对点)
@@ -145,7 +145,7 @@ public class WebSocketServiceImpl implements WebSocketService {
/** /**
* 手动触发在线用户数量广播 * 手动触发在线用户数量广播
* *
* 供外部服务(如定时任务)调用 * 供外部服务(如定时任务)调用
*/ */
public void notifyOnlineUsersChange() { public void notifyOnlineUsersChange() {

View File

@@ -66,7 +66,7 @@ public class CaptchaValidationFilter extends OncePerRequestFilter {
} }
// 包装请求,确保下游还能读取 body // 包装请求,确保下游还能读取 body
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request, -1);
byte[] bodyBytes = StreamUtils.copyToByteArray(requestWrapper.getInputStream()); byte[] bodyBytes = StreamUtils.copyToByteArray(requestWrapper.getInputStream());
String body = new String(bodyBytes, StandardCharsets.UTF_8); String body = new String(bodyBytes, StandardCharsets.UTF_8);

View File

@@ -33,7 +33,7 @@ public class SmsAuthenticationToken extends AbstractAuthenticationToken {
*/ */
public SmsAuthenticationToken(Object principal, Object credentials) { public SmsAuthenticationToken(Object principal, Object credentials) {
// 没有授权信息时,设置为 null // 没有授权信息时,设置为 null
super(null); super((Collection<? extends GrantedAuthority>) null);
this.principal = principal; this.principal = principal;
this.credentials = credentials; this.credentials = credentials;
// 默认未认证 // 默认未认证

View File

@@ -24,7 +24,7 @@ public class WxMiniAppCodeAuthenticationToken extends AbstractAuthenticationToke
*/ */
public WxMiniAppCodeAuthenticationToken(Object principal) { public WxMiniAppCodeAuthenticationToken(Object principal) {
// 没有授权信息时,设置为 null // 没有授权信息时,设置为 null
super(null); super((Collection<? extends GrantedAuthority>) null);
this.principal = principal; this.principal = principal;
// 默认未认证 // 默认未认证
this.setAuthenticated(false); this.setAuthenticated(false);

View File

@@ -28,7 +28,7 @@ public class WxMiniAppPhoneAuthenticationToken extends AbstractAuthenticationTok
* @param iv 初始向量 * @param iv 初始向量
*/ */
public WxMiniAppPhoneAuthenticationToken(String code, String encryptedData, String iv) { public WxMiniAppPhoneAuthenticationToken(String code, String encryptedData, String iv) {
super(null); super((Collection<? extends GrantedAuthority>) null);
this.principal = code; this.principal = code;
this.encryptedData = encryptedData; this.encryptedData = encryptedData;
this.iv = iv; this.iv = iv;

View File

@@ -8,8 +8,8 @@ import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference; import tools.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import tools.jackson.databind.ObjectMapper;
import com.youlai.boot.platform.codegen.model.entity.GenTable; import com.youlai.boot.platform.codegen.model.entity.GenTable;
import com.youlai.boot.security.util.SecurityUtils; import com.youlai.boot.security.util.SecurityUtils;
import com.youlai.boot.system.converter.MenuConverter; import com.youlai.boot.system.converter.MenuConverter;