基于Jackson注解的JSON工具封装与Redis集成实战

基于Jackson注解的JSON工具封装与Redis集成实战

一、深度整合Jackson注解的领域对象

1.1 完整商品类示例

java 复制代码
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@JsonInclude(JsonInclude.Include.NON_NULL) // 空值字段不序列化
public class Product {
    @JsonProperty("product_id") // 自定义JSON字段名
    private Long id;

    @JsonProperty("product_name")
    private String name;

    @JsonFormat(shape = JsonFormat.Shape.STRING) // 精确序列化BigDecimal
    private BigDecimal price;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
    private LocalDateTime createTime;

    @JsonSerialize(using = CustomListSerializer.class) // 自定义列表序列化
    private List<String> tags;

    @JsonIgnore // 忽略敏感字段
    private String internalCode;

    // 构造方法、getter、setter省略
}

二、增强型JsonUtil工具类

2.1 支持注解的配置

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class JsonUtil {
    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        // 基础配置
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        
        // 支持注解的配置
        mapper.enable(SerializationFeature.INDENT_OUTPUT); // 美化输出
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    // 序列化方法
    public static String toJson(Object obj) {
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException("序列化失败", e);
        }
    }

    // 反序列化方法(支持泛型)
    public static <T> T fromJson(String json, Class<T> clazz) {
        try {
            return mapper.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeException("反序列化失败", e);
        }
    }
}

2.2 自定义序列化器示例

java 复制代码
// 处理标签列表的紧凑格式
public class CustomListSerializer extends JsonSerializer<List<String>> {
    @Override
    public void serialize(List<String> value, JsonGenerator gen, 
                         SerializerProvider serializers) throws IOException {
        gen.writeString(String.join(",", value));
    }
}

三、Redis集成与验证

3.1 Redis配置类增强

java 复制代码
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        
        // 启用事务支持
        template.setEnableTransactionSupport(true);
        return template;
    }
}

3.2 存储与读取验证

java 复制代码
// 测试用例
@Test
void testProductSerialization() {
    Product product = new Product();
    product.setId(1001L);
    product.setName("iPad Pro");
    product.setPrice(new BigDecimal("7999.00"));
    product.setCreateTime(LocalDateTime.now());
    product.setTags(List.of("平板", "旗舰"));
    
    // 序列化
    String json = JsonUtil.toJson(product);
    System.out.println("序列化结果:\n" + json);
    
    // 存储到Redis
    redisTemplate.opsForValue().set("product:1001", json);
    
    // 从Redis读取并反序列化
    String storedJson = redisTemplate.opsForValue().get("product:1001");
    Product parsedProduct = JsonUtil.fromJson(storedJson, Product.class);
    
    assertNotNull(parsedProduct);
    assertEquals("iPad Pro", parsedProduct.getName());
}

序列化输出示例

json 复制代码
{
  "product_id" : 1001,
  "product_name" : "iPad Pro",
  "price" : "7999.00",
  "createTime" : "2023-08-20 14:30:45",
  "tags" : "平板,旗舰"
}

四、注解应用场景详解

4.1 日期格式控制矩阵

需求场景 注解配置 输出示例
日期+时间 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") "2023-08-20 14:30:45"
仅日期 @JsonFormat(pattern="yyyy-MM-dd") "2023-08-20"
时间戳格式 不添加注解(默认配置) 1692592245
ISO8601格式 @JsonFormat(shape=JsonFormat.Shape.STRING) "2023-08-20T14:30:45.123+08:00"

4.2 字段重命名策略

java 复制代码
// 全局配置驼峰转下划线
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

// 配合字段级注解
public class User {
    @JsonProperty("user_name") // 优先级高于全局策略
    private String userName;
    
    private String emailAddress; // 自动转为email_address
}

五、生产环境最佳实践

5.1 安全防护方案

java 复制代码
// 防止Jackson反序列化漏洞
mapper.enable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

// 配置反序列化白名单
SimpleModule module = new SimpleModule();
module.addDeserializer(Product.class, new SafeProductDeserializer());
mapper.registerModule(module);

5.2 性能优化技巧

java 复制代码
// 复用ObjectWriter实例
private static final ObjectWriter productWriter = mapper.writerFor(Product.class);

public static String toJsonFast(Product product) {
    try {
        return productWriter.writeValueAsString(product);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
}

// 使用缓冲池提升性能
public static final ObjectMapper sharedMapper = new ObjectMapper();
private static final ObjectWriter sharedWriter = sharedMapper.writer();

六、常见问题解决方案

6.1 日期格式不生效

问题现象

输出仍为时间戳格式
解决方案

  1. 检查是否注册JavaTimeModule
  2. 确认时区配置正确
  3. 验证注解pattern拼写

6.2 字段重名冲突

问题现象

多个字段映射到同一JSON属性
解决方案

java 复制代码
public class Order {
    @JsonProperty("contact_phone")
    private String phone; // 映射为contact_phone
    
    @JsonAlias({"phone", "mobile"}) // 兼容多个反序列化字段名
    private String contactPhone;
}

相关推荐
闲猫10 分钟前
go orm GORM
开发语言·后端·golang
丁卯40431 分钟前
Go语言中使用viper绑定结构体和yaml文件信息时,标签的使用
服务器·后端·golang
bing_1584 小时前
简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用
spring boot·后端·简单工厂模式
天上掉下来个程小白5 小时前
案例-14.文件上传-简介
数据库·spring boot·后端·mybatis·状态模式
编程星空6 小时前
css主题色修改后会多出一个css吗?css怎么定义变量?
开发语言·后端·rust
程序员侠客行6 小时前
Spring事务原理 二
java·后端·spring
dmy7 小时前
docker 快速构建开发环境
后端·docker·容器
sjsjsbbsbsn7 小时前
Spring Boot定时任务原理
java·spring boot·后端
计算机毕设指导67 小时前
基于Springboot学生宿舍水电信息管理系统【附源码】
java·spring boot·后端·mysql·spring·tomcat·maven