当前位置: 首页 > news >正文

redis 序列化 支持 PageImpl

既然 Redis 序列化器配置了activateDefaultTyping,且不能修改,那就只能PageImpl具备被 Jackson 反序列化的能力


一、核心思路

text

Jackson 反序列化 PageImpl 失败的原因: ↓ PageImpl 没有无参构造器 ↓ 解决方案:为 PageImpl 添加反序列化支持(不修改 Redis 配置) ↓ 方式1:Jackson Mixin(推荐) 方式2:自定义反序列化器并注册到 Redis 的 ObjectMapper 方式3:在 Redis 配置中注入自定义 ObjectMapper

二、方案一:Jackson Mixin(推荐,最简洁)

通过 Mixin 为PageImpl提供@JsonCreator注解,告诉 Jackson 如何构造PageImpl对象。

1. 创建 Mixin 类

java

import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import java.util.List; /** * PageImpl 的 Jackson Mixin,用于提供反序列化支持 */ public abstract class PageImplMixin<T> { @JsonCreator public PageImplMixin( @JsonProperty("content") List<T> content, @JsonProperty("page") int page, @JsonProperty("size") int size, @JsonProperty("total") long total) { // Mixin 方法不需要实现,只用于注解 } // 如果 pageable 是完整对象,也可以支持 @JsonCreator public PageImplMixin( @JsonProperty("content") List<T> content, @JsonProperty("pageable") Pageable pageable, @JsonProperty("total") long total) { // 另一个构造方法签名 } }

2. 在 Redis 配置中注册 Mixin

找到 Redis 序列化器配置的地方,添加 Mixin:

java

@Configuration public class RedisConfig { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory factory) { // 1. 创建 ObjectMapper ObjectMapper mapper = new ObjectMapper(); // 2. 注册 PageImpl 的 Mixin mapper.addMixIn(PageImpl.class, PageImplMixin.class); // 3. 注册 JavaTimeModule(支持 LocalDate/LocalDateTime) mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 4. 保留原有的 DefaultTyping 配置 mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); // 5. 创建序列化器 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); serializer.setObjectMapper(mapper); // 6. 配置 RedisCacheManager RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .entryTtl(Duration.ofHours(1)); return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); } }

三、方案二:自定义反序列化器(更精细控制)

如果 Mixin 方式不生效,可以编写一个完整的PageImpl反序列化器。

1. 创建反序列化器

java

import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import java.io.IOException; import java.util.List; public class PageImplDeserializer extends StdDeserializer<PageImpl<?>> { public PageImplDeserializer() { super(PageImpl.class); } @Override public PageImpl<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); // 1. 解析 content JsonNode contentNode = node.get("content"); List<?> content = p.getCodec().treeToValue(contentNode, List.class); // 2. 解析 total JsonNode totalNode = node.get("total"); long total = totalNode != null ? totalNode.asLong() : 0L; // 3. 解析 pageable JsonNode pageableNode = node.get("pageable"); Pageable pageable; if (pageableNode == null || pageableNode.isNull()) { // 如果 pageable 不存在,从 page/size 构建 int page = node.has("page") ? node.get("page").asInt() : 0; int size = node.has("size") ? node.get("size").asInt() : 20; pageable = PageRequest.of(page, size); } else if (pageableNode.isTextual() && "INSTANCE".equals(pageableNode.asText())) { // 处理 Unpaged.INSTANCE pageable = Pageable.unpaged(); } else { // 从 pageable 对象解析 int page = pageableNode.has("pageNumber") ? pageableNode.get("pageNumber").asInt() : 0; int size = pageableNode.has("pageSize") ? pageableNode.get("pageSize").asInt() : 20; pageable = PageRequest.of(page, size); } return new PageImpl<>(content, pageable, total); } }

2. 注册到 Redis ObjectMapper

java

@Configuration public class RedisConfig { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory factory) { ObjectMapper mapper = new ObjectMapper(); // 注册 PageImpl 反序列化器 SimpleModule module = new SimpleModule(); module.addDeserializer(PageImpl.class, new PageImplDeserializer()); mapper.registerModule(module); // 其他配置... mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); serializer.setObjectMapper(mapper); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .entryTtl(Duration.ofHours(1)); return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); } }

四、方案三:直接修改 Redis 配置类(如果可访问)

如果 Redis 配置类是可访问的,直接在你现有的RedisConfig中添加 Mixin:

java

@Configuration public class RedisConfig { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory factory) { // 获取现有的 ObjectMapper ObjectMapper mapper = new ObjectMapper(); // ✅ 添加这一行:注册 PageImpl 的 Mixin mapper.addMixIn(PageImpl.class, PageImplMixin.class); // 保留原有配置 mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); // ... 其他配置 } }

五、方案对比

方案改动量复杂度推荐度
Mixin小(新增1个类+1行配置)⭐⭐⭐⭐⭐
自定义反序列化器中(新增1个类+注册逻辑)⭐⭐⭐⭐
修改现有 Redis 配置最小(只加1行)最低⭐⭐⭐⭐⭐

六、最终推荐

使用 Mixin 方案,这是最简洁、最优雅的方式:

java

// 1. 创建 Mixin 类(只需要注解,不需要实现) public abstract class PageImplMixin<T> { @JsonCreator public PageImplMixin( @JsonProperty("content") List<T> content, @JsonProperty("page") int page, @JsonProperty("size") int size, @JsonProperty("total") long total) {} } // 2. 在 Redis 配置中注册 mapper.addMixIn(PageImpl.class, PageImplMixin.class);

这样:

  • ✅ 不需要修改 Redis 序列化器的activateDefaultTyping配置

  • ✅ 支持PageImpl的反序列化

  • ✅ 不影响其他类型

  • ✅ 改动量最小

http://www.jsqmd.com/news/1362129/

相关文章:

  • 整理销售谈判记录太慢还写不清?2026自动生成方案帮你梳理
  • Windows 11任务栏崩溃终极修复指南:ExplorerPatcher 23H2兼容性解决方案
  • 2026年常熟记账报税公司推荐:月度申报、报表与账套交付验收指南 - 企业服务研究所
  • Angular-Async-Local-Storage快速上手:5分钟集成高性能存储服务
  • 如何用biliTickerBuy轻松抢到B站会员购热门商品:完整指南
  • 10分钟掌握LunaTranslator:免费游戏实时翻译工具的终极指南
  • 腾讯云大额优惠券在哪领?认准这个**特惠入口,先领券再买服务器,直接省几十到几百 - 172号卡
  • 3步搞定老旧电脑升级:Rufus终极Windows 11安装绕过指南
  • 玉米绿豆混合物浓度图像数据集:21类浓度分析监督学习数据
  • 5分钟快速上手:Reloaded-II游戏Mod管理终极指南
  • 【NeurIPS 2018】World Models:世界模型,让智能体在梦境中学会驾驶与躲避|从世界模型与演化计算视角
  • openapi-backend在AWS Lambda中的应用:构建无服务器API
  • Pickerview非弹窗场景应用:从入门到精通
  • 如何从零开始搭建高转化率网站?一份保姆级个人网站建设策划书助你避坑指南
  • 【实时Linux核心技术:从概念到实战】06:编写你的第一个实时线程:API详解与注意事项
  • DHCP实训方案:从拓扑设计到故障排查全流程
  • 2026年河北沧州市政设施厂家推荐:河北市政井盖、成品排水沟、市政配重构件、市政配套设施优选指南 - 海棠依旧大
  • 如何实现2倍加速:TeaCache视频扩散模型优化技术深度解析
  • 选购超载超限检测仪注意事项,靠谱品牌浙江润鑫,一站式提供整套计量解决方案 - 品牌速递
  • Python 异常处理进阶——自定义异常、断言、finally
  • 3步掌握Rosetta国际化库:打造全球化的JavaScript应用
  • 如何在VS Code中高效管理Azure DevOps工作项?Azure Repos扩展实战指南
  • 开源电池修复终极指南:如何用Open Battery Information拯救误锁电池
  • 本地AI视频剪辑终极指南:FunClip从零到精通的完整教程
  • Word批量转PDF技术方案与实战优化
  • 免费AI音乐创作终极指南:ACE-Step UI带你开启无限音乐之旅
  • GoB终极指南:深度解析Blender与ZBrush双向数据桥接的5大核心技术优势
  • 面向高维向量检索的近似索引设计与评估7
  • 蚌埠大建设及棚户区改造官方网站深度解析:老城的涅槃与新城的崛起
  • WinForm类间数据传递的7种实现方式与实战技巧