升级日期:2026-10-19
分支:feature/spring-boot-4(基于 develop 的 147bbe6,即已升到 3.5.16 的提交)
| 组件 | 升级前 | 升级后 |
|---|---|---|
| Spring Boot | 3.2.5 | 4.1.1 |
| Spring Framework | 6.1.x | 7.0.9(Boot 传递) |
| Spring Security (crypto) | 6.2.x | 7.0.x |
| Jakarta EE 基线 | 10(Servlet 6.0 / Tomcat 10.1) | 11(Servlet 6.1 / Tomcat 11.0.24) |
| Jackson | 2.15 | 3.1.5(tools.jackson.*) |
| MyBatis-Plus | 3.5.5 / spring-boot3-starter | 3.5.17 / spring-boot4-starter |
| JDK | 21 | 21(不变,Boot 4 基线为 17) |
升级前先单独落了一版 3.5.16(提交 147bbe6),确认零改动即可通过全部回归,再进 4.x,避免跨两个大版本混在一起排错。
com.fasterxml.jackson.databind|core → tools.jackson.databind|core。
注解不动:@JsonProperty / @JsonIgnore / @JsonInclude / @JsonView 仍在
com.fasterxml.jackson.annotation(Jackson 3 为向后兼容刻意保留),涉及 63 个文件一行未改。
批量脚本:tools/migrate_jackson3.py(可重复执行,--dry 只统计不写)。
Jackson 3 把 JsonSerializer 更名 ValueSerializer,第三个参数换成 SerializationContext,
异常由受检的 IOException 改为非受检的 JacksonException:
// 旧
public class PhpFloatSerializer extends JsonSerializer<Double> {
public void serialize(Double v, JsonGenerator gen, SerializerProvider p) throws IOException
// 新
public class PhpFloatSerializer extends ValueSerializer<Double> {
public void serialize(Double v, JsonGenerator gen, SerializationContext ctxt) throws JacksonException
common/util/PhpFloatSerializer.javacommon/util/UserLiteSerializer.java(另:new ObjectMapper().setSerializationInclusion(..)
不可用,改为 JsonMapper.builder().build();默认包含策略本就是 ALWAYS)这两个类被 8 处 @JsonSerialize(using = ...) 引用,改完实体侧无需改动。
config/RedisConfig.java:
new ObjectMapper() + setVisibility(..) + enableDefaultTyping(NON_FINAL) 全部不可用
(Jackson 3 的 mapper 不可变,这些方法已移除)。改用 Spring Data Redis 4 新增的 GenericJacksonJsonRedisSerializer:
GenericJacksonJsonRedisSerializer.builder().enableUnsafeDefaultTyping().build()
语义等价于原 GenericJackson2JsonRedisSerializer / default typing(写 @class 类型信息),
RedisTemplate<String,Object> 与 RedisCacheManager 共用同一个工厂方法。
config/RedisConfigCacheManager.java 的 DEFAULT_PAIR 同步换成 RedisConfig.jsonSerializer()。
注:项目内
@Cacheable用量为 0,缓存管理器实际未被业务使用,因此即便有旧缓存格式差异也不影响业务。
PaginationInnerInterceptor 移到独立模块,需显式引入
com.baomidou:mybatis-plus-jsqlparser(版本随 mybatis-plus.version)。
不加会报 cannot find symbol: class PaginationInnerInterceptor。Goods.deliveryType 原来用 JacksonTypeHandler(Jackson 2 实现),
Boot 4 不再带 Jackson 2,启动时会 NoClassDefFoundError: com/fasterxml/jackson/core/JacksonException。
改为 MP 3.5.17 提供的 Jackson3TypeHandler。Boot 4 的 maven-compiler-plugin 3.15.0 不再从 classpath 自动发现注解处理器,
只配 <parameters>true</parameters> 时 @Data 完全不生成方法(一开始报了 200 个
"cannot find symbol: getXxx")。pom 里补:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Boot 4 把 spring-boot-starter-web 标为废弃,pom 描述原文:
Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container (deprecated in favor of spring-boot-starter-webmvc)
所以 pom 换成 spring-boot-starter-webmvc。两者在 4.1.1 中解析出的依赖集合完全等价:
| 项 | starter-web | starter-webmvc |
|---|---|---|
| starter-jackson | ✓ | ✓ |
| starter-tomcat | ✓ | ✓ |
| spring-boot-http-converter | ✓ | ✓ |
| spring-boot-webmvc | ✓ | ✓ |
| spring-boot-starter | ✗(靠 starter-validation 传递) | ✓(直接声明) |
实测 mvn dependency:tree 前后各 100 个构件,唯一差异就是 starter 自身坐标;
换名后回归 390 项仍全过。早先版本(3.x)没有 starter-webmvc 这个坐标,
只有在 Boot 4 上才能换。
Integer 时间戳 + getCreateTimeText() 手工 TimeUtil.format,
不走 Jackson 日期序列化。Jackson 3 把 WRITE_DATES_AS_TIMESTAMPS 默认改为 ISO-8601 的变化
对本项目出参零影响,spring.jackson.date-format 保留即可。@JsonView:spring.jackson.mapper.default-view-inclusion: true 在 Boot 4 仍有效
(已实测 goods/list 不含 content、goods/detail 含 content)。spring.jackson.date-format / time-zone / mapper.*:配置项在 4.1.1 中均仍存在。ObjectNode.remove(Collection) / createObjectNode() / valueToTree():签名未变,ApiView 只改了 import。WebMvcConfig / StoreAuthInterceptor / AdminAuthInterceptor / ApiAuthInterceptor 未改。$2y$ 口令:Spring Security 7 的 BCryptPasswordEncoder 仍能校验
(用 PHP 8.2 password_hash 生成 $2y$ 哈希实测登录成功)。Jackson 3 默认开启 SORT_PROPERTIES_ALPHABETICALLY,实体经 valueToTree 后字段顺序变为字母序
(如 goodsId 之前排在 goodsName 前,现在 aloneGradeEquity 开头)。字段名与值不变,
前端按名取值不受影响;手工 put 的 ObjectNode 仍保持插入顺序。
旧的 compare_*.py 若按字节比 JSON 会误报,这些脚本已随驼峰改造废弃。
| 脚本 | 内容 | 结果 |
|---|---|---|
test_api_batch1.py |
api 只读接口 | 52 / 0 |
test_api_batch2.py |
购物车/结算/订单/地址 | 97 / 0 |
test_api_batch3.py |
用户中心/售后/充值/上传 | 99 / 0 |
test_api_batch4.py |
登录/验证码/收银台/支付回调 | 77 / 0 |
test_admin_api.py |
平台后台 | 45 / 0 |
test_token_user.py |
store 登录态(Redis) | 20 / 0 |
smoke_camel.py |
驼峰冒烟 | 全部通过 |
合计 390 项断言,0 失败。
git checkout develop # Boot 3.5.16,随时可发布
# 或
git checkout feature/spring-boot-4
spring-boot-jackson2 模块(spring.jackson2.* 属性),
万一某个第三方库只支持 Jackson 2,可用它过渡,但属废弃路径,不建议长期依赖。@Cacheable,注意 Boot 4 + Jackson 3 的缓存值格式与 Jackson 2 的
GenericJackson2JsonRedisSerializer 不完全一致(@class vs 数组式 typing),切流时先清缓存。