SpringBoot 全域性日期格式化(基於註解)

weixin_34337265發表於2018-12-26

學習目標

快速學會通過註解@JsonComponent自定義日期格式化的序列化器。

快速查閱

專題閱讀:《SpringBoot 佈道系列》

原始碼下載:SpringBoot Date Format Anno

— Hey Man,Don't forget to Star or Fork . —

使用教程

根據官方文件 Custom JSON Serializers and Deserializers ,想要接管Jackson的JSON的序列化和反序列化,只需通過註解@JsonComponent來宣告其靜態內部類即可。

首先根據專案要求提供自定義的日期序列化器和反序列化器,其中包括:

  • DateJsonSerializer extends JsonSerializer<Date> 表示將Date格式化為日期字串。

  • DateJsonDeserializer extends JsonDeserializer<Date> 表示將日期字串解析為Date日期。

/**
 * 全域性日期格式化
 */
@JsonComponent
public class DateFormatConfig {

    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 日期格式化
     */
    public static class DateJsonSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString(dateFormat.format(date));
        }
    }

    /**
     * 解析日期字串
     */
    public static class DateJsonDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            try {
                return dateFormat.parse(jsonParser.getText());
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

然後提供相應的測試資訊,這裡以查詢使用者為例:

/**
 * 查詢使用者資訊
 */
@RestController
public class UserController {
    @GetMapping("/")
    public User get() {
        return new User("1", "socks", "123456", new Date(), "GMT");
    }
}

/**
 * 使用者資訊
 */
public class User {

    private String userId;
    private String username;
    private String password;
    private Date createTime;
    private String timezone;

    public User(String userId, String username, String password, Date createTime, String timezone) {
        this.userId = userId;
        this.username = username;
        this.password = password;
        this.createTime = createTime;
        this.timezone = timezone;
    }

   //省略getters&setters
}

大功告成,接下來啟動應用並訪問 http://127.0.0.1:8080 ,可以拿到正確結果:

{
  "userId": "1",
  "username": "socks",
  "password": "123456",
  "createTime": "2018-12-26 01:03:25"
}

除了日期格式化解析之外,我們還可以在DateFormatConfig 注入業務變數,例如根據當前登入人的所屬時區(雖然SimpleDateFormat預設讀取了當地時區,但在實際的國際化系統中,使用者的所屬時區是指其在系統錄入的所屬時區,而不是指當地時區。例如Tony這個使用者賬號掛在GMT+0時區,但此時他出差在香港使用,系統仍需要按照GMT+0時區來顯示時間),為了解決這個問題,此時我們可以在DateFormatConfig 注入當前登入人然後改變日期工具類的TimeZone來動態修改時區。

根據當前登入人動態展示時區:


/**
 * 全域性日期格式化
 */
@JsonComponent
public class DateFormatConfig {

    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z") {
        @Override
        public Date parse(String source) throws ParseException {
            try {
                if (StringUtils.isEmpty(source)) {
                    return null;
                }
                return super.parse(source);
            } catch (Exception e) {
                return new StdDateFormat().parse(source);
            }
        }
    };

    private static UserController userController;//這裡是指獲取當前登入人的工具類

    @Autowired
    public void setUserController(UserController userController) {
        DateFormatConfig.userController = userController;
    }

    /**
     * 日期格式化
     */
    public static class DateJsonSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            //獲取當前登入人的所屬時區
            dateFormat.setTimeZone(TimeZone.getTimeZone(userController.get().getTimezone()));
            //格式化日期
            jsonGenerator.writeString(dateFormat.format(date));
        }
    }

    /**
     * 解析日期字串
     */
    public static class DateJsonDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            try {
                //獲取當前登入人的所屬時區
                dateFormat.setTimeZone(TimeZone.getTimeZone(userController.get().getTimezone()));
                //解析日期
                return dateFormat.parse(jsonParser.getText());
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

修改完後重新啟動應用並訪問 http://127.0.0.1:8080 ,可以拿到正確結果:

{
  "userId": "1",
  "username": "socks",
  "password": "123456",
  "createTime": "2018-12-25 17:35:50 +0000",
  "timezone": "GMT"
}

小結

1、使用註解@JsonComponent 可以快速自定義日期格式化的序列化器,免除傳統通過模組註冊的煩惱。

2、使用註解@JsonComponent 實現與當地無關的動態時區的精髓就在於將獲取當前等人的方法寫在解析日期和格式化日期的程式碼裡。

3、使用註解@JsonComponent 是直接處理String和Date的相互轉換的,所以要注意空串問題。例如dateFormat.parse()要預防空串。

相關文章