序列化 之 Jackson(三)springmvc特定类型处理
在 Spring MVC 中,若需对特定 Java 类型(如 LocalDateTime、自定义枚举、敏感字段等)实现自定义的 JSON 序列化(Java → JSON)和反序列化(JSON → Java)逻辑,可通过 Jackson 的 JsonSerializer 和 JsonDeserializer 实现,并结合 Spring 的配置机制全局生效。
下面从原理、步骤到完整示例进行详细说明。
一、核心原理
Jackson 使用 模块化注册机制 来扩展其序列化/反序列化能力:
JsonSerializer<T>:自定义如何将类型T转为 JSON。JsonDeserializer<T>:自定义如何从 JSON 构造类型T。SimpleModule:将自定义的序列化器/反序列化器注册到ObjectMapper。- Spring 集成:通过配置
ObjectMapperBean 或WebMvcConfigurer,使自定义逻辑全局生效。
二、使用场景举例
- 将
LocalDateTime统一格式化为"yyyy-MM-dd HH:mm:ss"。 - 对手机号中间四位脱敏(如
138****1234)。 - 自定义枚举的 JSON 表示(不用 name(),而用 code 字段)。
- 处理前端传来的字符串时间戳转为
Date。
三、完整示例:自定义 LocalDateTime 序列化/反序列化
3.1 定义序列化器(Java → JSON)
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value != null) {
gen.writeString(formatter.format(value));
} else {
gen.writeNull();
}
}
}
3.2 定义反序列化器(JSON → Java)
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.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getText();
if (value == null || value.trim().isEmpty()) {
return null;
}
return LocalDateTime.parse(value, formatter);
}
}
四、注册到 ObjectMapper(Spring Boot 方式)
方法一:通过 @Bean 配置(推荐)
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// 注册 JavaTimeModule 以支持 JSR310(可选,但建议保留)
mapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
// 创建自定义模块
SimpleModule module = new SimpleModule();
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
mapper.registerModule(module);
// 可选:关闭时间戳格式(避免与自定义冲突)
mapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
⚠️ 注意:
@Primary注解通常不需要,因为 Spring Boot 默认会使用你定义的ObjectMapperBean。
五、验证效果
Controller 示例
@RestController
public class TestController {
@GetMapping("/time")
public TimeResponse getTime() {
return new TimeResponse(LocalDateTime.now());
}
@PostMapping("/time")
public String setTime(@RequestBody TimeResponse request) {
System.out.println("接收到时间: " + request.getCreateTime());
return "OK";
}
}
class TimeResponse {
private LocalDateTime createTime;
public TimeResponse(LocalDateTime createTime) {
this.createTime = createTime;
}
// getter/setter
public LocalDateTime getCreateTime() { return createTime; }
public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
}
请求/响应示例
GET /time
{
"createTime": "2026-01-23 16:30:45"
}
POST /time
{
"createTime": "2026-01-23 16:30:45"
}
→ 后端能正确解析为 LocalDateTime 对象。
六、其他类型示例:手机号脱敏序列化
6.1 自定义序列化器(仅序列化,不反序列化)
public class PhoneSerializer extends JsonSerializer<String> {
@Override
public void serialize(String phone, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (phone != null && phone.length() == 11) {
String masked = phone.substring(0, 3) + "****" + phone.substring(7);
gen.writeString(masked);
} else {
gen.writeString(phone);
}
}
}
6.2 在实体类上使用(局部生效)
public class User {
private String name;
@JsonSerialize(using = PhoneSerializer.class)
private String phone;
// getter/setter
}
若想全局生效所有
String类型手机号字段,则需更复杂的逻辑(如字段命名规则 + 自定义BeanSerializerModifier),一般建议局部注解。
七、高级:基于字段名或注解的通用脱敏(可选)
若需更灵活的脱敏策略(如 @Sensitive(type = MOBILE)),可结合:
- 自定义注解
@Sensitive - 自定义
BeanSerializerModifier PropertyFilter或JsonSerializer动态判断
八、注意事项
- 不要重复注册:避免既用
JavaTimeModule又手动注册LocalDateTime,可能导致冲突。 - 线程安全:
JsonSerializer/JsonDeserializer必须是无状态的(不要持有可变成员变量)。 - 异常处理:在
deserialize()中抛出IOException或JsonProcessingException,Spring 会将其转为 400 错误。 - Spring Boot 自动配置:如果你只重写了
ObjectMapperBean,Spring Boot 会自动将其用于MappingJackson2HttpMessageConverter。
九、总结
| 步骤 | 操作 |
|---|---|
| 1 | 编写 JsonSerializer<T> 和/或 JsonDeserializer<T> |
| 2 | 通过 SimpleModule 注册到 ObjectMapper |
| 3 | 在 Spring 配置中提供自定义 ObjectMapper Bean |
| 4 | (可选)在字段上使用 @JsonSerialize/@JsonDeserialize 局部覆盖 |
本文来自博客园,作者:蓝迷梦,转载请注明原文链接:https://www.cnblogs.com/hewei-blogs/articles/19522960

浙公网安备 33010602011771号