【Spring Boot】统一处理Web请求的JSON日期格式


问题背景

在Spring Web开发中,前后端交互经常会遇到日期时间格式的问题。默认情况下:

  1. 后端返回给前端的时间戳是一个长整型数字
  2. 前端传递的日期格式可能各不相同
  3. 不同接口对日期格式要求不一致

这些问题会导致:

  • 前端需要手动处理时间格式转换
  • 代码中充斥着大量的日期格式化代码
  • 可能出现日期解析错误

解决方案

1. 全局日期格式化配置

创建配置类统一处理日期格式:

@Configuration
public class DateFormatConfig {
    
    private static final String DATE_FORMAT = "yyyy-MM-dd";
    private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> {
            builder.simpleDateFormat(DATE_TIME_FORMAT);
            builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
            builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
            builder.deserializers(new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
            builder.deserializers(new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
        };
    }
}

2. 使用@JsonFormat注解

对于特定字段需要自定义格式时:

public class User {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthday;
    
    // getter setter
}

3. 自定义日期序列化和反序列化

对于更复杂的日期处理需求:

public class CustomLocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) 
            throws IOException {
        if (value != null) {
            gen.writeString(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    }
}

public class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) 
            throws IOException {
        String dateStr = p.getText();
        if (StringUtils.isEmpty(dateStr)) {
            return null;
        }
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
}

实际应用示例

1. Controller层使用

@RestController
@RequestMapping("/api")
public class UserController {
    
    @PostMapping("/user")
    public Result<User> createUser(@RequestBody User user) {
        // LocalDateTime会自动按配置格式处理
        System.out.println("创建时间: " + user.getCreateTime());
        System.out.println("生日: " + user.getBirthday());
        return Result.success(user);
    }
    
    @GetMapping("/user/{id}")
    public Result<User> getUser(@PathVariable Long id) {
        User user = new User();
        user.setCreateTime(LocalDateTime.now());
        user.setBirthday(LocalDate.now());
        // 返回的日期会自动格式化
        return Result.success(user);
    }
}

2. 测试验证

@SpringBootTest
public class DateFormatTest {
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Test
    public void testDateFormat() throws Exception {
        User user = new User();
        user.setCreateTime(LocalDateTime.now());
        user.setBirthday(LocalDate.now());
        
        String json = objectMapper.writeValueAsString(user);
        System.out.println("序列化结果: " + json);
        
        User parsedUser = objectMapper.readValue(json, User.class);
        System.out.println("反序列化结果: " + parsedUser);
    }
}

最佳实践建议

  1. 统一使用LocalDateTime和LocalDate替代Date类型

  2. 在配置文件中集中管理日期格式模式字符串

  3. 考虑时区问题,建议:

    • 服务器统一使用UTC时间
    • 在展示层处理时区转换
    • 在配置中明确指定时区
  4. 对于特殊格式要求:

    • 优先使用@JsonFormat注解
    • 其次考虑自定义序列化器
  5. 添加参数校验:

public class User {
    @NotNull(message = "创建时间不能为空")
    private LocalDateTime createTime;
    
    @Past(message = "生日必须是过去的日期")
    private LocalDate birthday;
}

常见问题

  1. 时区问题

    • 现象:前后端显示时间相差几个小时
    • 解决:指定正确的时区,如 timezone = "GMT+8"
  2. 格式解析异常

    • 现象:日期字符串无法正确解析
    • 解决:检查日期格式是否匹配,增加异常处理
  3. 性能问题

    • 现象:日期转换影响接口性能
    • 解决:使用缓存,避免重复创建DateTimeFormatter

总结

通过合理配置和规范使用,我们可以优雅地解决JSON日期格式问题:

  1. 全局配置处理通用场景
  2. 注解处理特殊需求
  3. 自定义序列化处理复杂情况

这样既保证了代码的统一性,又提供了足够的灵活性。

参考资料


希望这篇文章能帮助您更好地解决全局日期配置的问题。如果您有任何问题,欢迎在评论区讨论!


文章作者: lucky845
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lucky845 !
评论
  目录