SpringBoot 全局日期格式 注解

目标

快速学会通过注解 @JsonComponent自定义日期格式化的序列化器。

使用教程

根据官方文档 Custom JSON Serializers and Deserializers ,想要接管Jackson的JSON的序列化和反序列化,只需通过注解 @JsonComponent来声明其静态内部类即可。

首先根据项目要求提供自定义的日期序列化器和反序列化器,其中包括:

  • DateJsonSerializerextendsJsonSerializer<Date> 表示将Date格式化为日期字符串。
  • DateJsonDeserializerextendsJsonDeserializer<Date> 表示将日期字符串解析为Date日期。
    1. /**
    2. * 全局日期格式化
    3. */
    4. @JsonComponent
    5. public class DateFormatConfig {
    6. private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    7. /**
    8. * 日期格式化
    9. */
    10. public static class DateJsonSerializer extends JsonSerializer<Date> {
    11. @Override
    12. public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    13. jsonGenerator.writeString(dateFormat.format(date));
    14. }
    15. }
    16. /**
    17. * 解析日期字符串
    18. */
    19. public static class DateJsonDeserializer extends JsonDeserializer<Date> {
    20. @Override
    21. public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    22. try {
    23. return dateFormat.parse(jsonParser.getText());
    24. } catch (ParseException e) {
    25. throw new RuntimeException(e);
    26. }
    27. }
    28. }
    29. }
    然后提供相应的测试信息,这里以查询用户为例:
    1. /**
    2. * 查询用户信息
    3. */
    4. @RestController
    5. public class UserController {
    6. @GetMapping("/")
    7. public User get() {
    8. return new User("1", "socks", "123456", new Date(), "GMT");
    9. }
    10. }
    11. /**
    12. * 用户信息
    13. */
    14. public class User {
    15. private String userId;
    16. private String username;
    17. private String password;
    18. private Date createTime;
    19. private String timezone;
    20. public User(String userId, String username, String password, Date createTime, String timezone) {
    21. this.userId = userId;
    22. this.username = username;
    23. this.password = password;
    24. this.createTime = createTime;
    25. this.timezone = timezone;
    26. }
    27. //省略getters&setters
    28. }
    接下来启动应用并访问 http://127.0.0.1:8080 ,可以拿到正确结果:
    1. {
    2. "userId": "1",
    3. "username": "socks",
    4. "password": "123456",
    5. "createTime": "2018-12-26 01:03:25"
    6. }
    除了日期格式化解析之外,还可以在 DateFormatConfig 注入业务变量,例如根据当前登录人的所属时区(虽然 SimpleDateFormat默认读取了当地时区,但在实际的国际化系统中,用户的所属时区是指其在系统录入的所属时区,而不是指当地时区。例如Tony这个用户账号挂在GMT+0时区,但此时他出差在香港使用,系统仍需要按照GMT+0时区来显示时间),为了解决这个问题,此时可以在 DateFormatConfig 注入当前登录人然后改变日期工具类的 TimeZone来动态修改时区。根据当前登录人动态展示时区:
    1. /**
    2. * 全局日期格式化
    3. */
    4. @JsonComponent
    5. public class DateFormatConfig {
    6. private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z") {
    7. @Override
    8. public Date parse(String source) throws ParseException {
    9. try {
    10. if (StringUtils.isEmpty(source)) {
    11. return null;
    12. }
    13. return super.parse(source);
    14. } catch (Exception e) {
    15. return new StdDateFormat().parse(source);
    16. }
    17. }
    18. };
    19. private static UserController userController;//这里是指获取当前登录人的工具类
    20. @Autowired
    21. public void setUserController(UserController userController) {
    22. DateFormatConfig.userController = userController;
    23. }
    24. /**
    25. * 日期格式化
    26. */
    27. public static class DateJsonSerializer extends JsonSerializer<Date> {
    28. @Override
    29. public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    30. //获取当前登录人的所属时区
    31. dateFormat.setTimeZone(TimeZone.getTimeZone(userController.get().getTimezone()));
    32. //格式化日期
    33. jsonGenerator.writeString(dateFormat.format(date));
    34. }
    35. }
    36. /**
    37. * 解析日期字符串
    38. */
    39. public static class DateJsonDeserializer extends JsonDeserializer<Date> {
    40. @Override
    41. public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    42. try {
    43. //获取当前登录人的所属时区
    44. dateFormat.setTimeZone(TimeZone.getTimeZone(userController.get().getTimezone()));
    45. //解析日期
    46. return dateFormat.parse(jsonParser.getText());
    47. } catch (ParseException e) {
    48. throw new RuntimeException(e);
    49. }
    50. }
    51. }
    52. }
    修改完后重新启动应用并访问 http://127.0.0.1:8080 ,可以拿到正确结果:
    1. {
    2. "userId": "1",
    3. "username": "socks",
    4. "password": "123456",
    5. "createTime": "2018-12-25 17:35:50 +0000",
    6. "timezone": "GMT"
    7. }

    小结

    1、使用注解 @JsonComponent 可以快速自定义日期格式化的序列化器,免除传统通过模块注册的烦恼。
    2、使用注解 @JsonComponent 实现与当地无关的动态时区的精髓就在于将获取当前等人的方法写在解析日期和格式化日期的代码里。
    3、使用注解 @JsonComponent 是直接处理String和Date的相互转换的,所以要注意空串问题。例如dateFormat.parse()要预防空串。