订单日期原来为字符串字段。如 2020-06-06
版本升级,变为Date字段。
接口报文显示有了差别:

原来报文 2020-06-06
现在报文 2020-06-06 00:00:00

接口面对客户,尽量不动,所以调整代码来适配。

方案一:
实体字段仍为String,调整sql语句为to_char(createDate,‘yyyy-MM-dd’)。
评估:
数据库方面其实还好,因为函数是加在select的列上,对性能方面没太大影响。
代码改动方面不太友好,因为该字段可能多个mapper调用,所有用到该字段地方都要改。

方案二(推荐):
实体字段修改为Date,添加注解只对这个字段进行格式化。
评估:
实体一般唯一,改动量较小。而且注解代码清爽,易于维护。

那么就用注解的方式来实现吧。需要注意的是,格式化json的方式不只一种,例如:jackjson,gson,fastjson等。 所以实现的时候要配对。

jackjson实现格式化

配置类代码:

@JsonComponent
public class DateFormatConfig {
    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm}")
    private String pattern;
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilder() {
        return builder -> {
            TimeZone tz = TimeZone.getTimeZone("UTC");
            DateFormat df = new SimpleDateFormat(pattern);
            df.setTimeZone(tz);
            builder.failOnEmptyBeans(false)
                    .failOnUnknownProperties(false)
                    .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                    .dateFormat(df);
    @Bean
    public LocalDateTimeSerializer localDateTimeDeserializer() {
        return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeDeserializer());

实体代码:

@Data
public class User {
    @NotBlank(message = "这个姓名不能为空")
    private String username;
    private String password;
    @JsonFormat(pattern="yyyy-MM-dd",timezone="GMT+8")
//    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date createDate;

fastjson实现序列化

@Configuration
public class FastJsonConverterConfig {
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        HttpMessageConverter<?> converter = fastConverter;
        return new HttpMessageConverters(converter);
@Data
public class User {
    @NotBlank(message = "这个姓名不能为空")
    private String username;
    private String password;
    @JSONField(format = "yyyy-MM-dd")
    private Date createDate;

实测成功。

这种配置,自定义注解无效:

@Configuration
public class FastJsonConverterConfig {
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullBooleanAsFalse,
                SerializerFeature.PrettyFormat  // 不写这行,格式化无效
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //全局指定了日期格式
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm");
        //该设置目的,为了兼容jackson
  		fastConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON,MediaType.APPLICATION_JSON_UTF8,MediaType.APPLICATION_OCTET_STREAM));
        HttpMessageConverter<?> converter = fastConverter;
        return new HttpMessageConverters(converter);

Gson实现格式化

Gson配置类:

@Configuration
public class GsonConfig {
    @Bean
    public HttpMessageConverters gsonHttpMessageConverters() {
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Date.class, new MyDateTypeAdapter())
                .serializeNulls()        //null值属性也需要序列化
                .setDateFormat("yyyy-MM-dd HH:mm") //设置日期转换
                .create();
        gsonHttpMessageConverter.setGson(gson);
        HttpMessageConverter<?> converter = gsonHttpMessageConverter;
        return new HttpMessageConverters(converter);

自定义转换类:

public class MyDateTypeAdapter extends TypeAdapter<Date> {
    @Override
    public void write(JsonWriter jsonWriter, Date date) throws IOException {
        if(null!=date){
          jsonWriter.value(DateUtils.formatDate(date,DateUtils.YYYY_MM_DD));
    @Override
    public Date read(JsonReader in) throws IOException {
        return null;

对象使用类:

@JsonAdapter(value=MyDateTypeAdapter.class)
private Date createDate;

发现了吧Gson是没有直接可以使用的注解的,需要自定义。

spring中HttpMessageConverter负责处理格式化。
默认的json工具是jackjson。
如果想用其他json工具,重写HttpMessageConverter即可。

jackjson,fastjson,gson的格式化方式不同:

种类用法备注
jackjson@JsonFormat(pattern=“yyyy-MM-dd”)-
fastjson@JSONField(format = “yyyy-MM-dd”)-
gson自定义TypeAdapter,然后加到字段上无直接可用的注解

数据库是Date,实体字段是String,用哪个注解呢

用下面代码吗?

@JsonFormat(pattern="yyyy-MM-dd",timezone="GMT+8")
private String createDate;

不对。
因为这个注解都是对日期才有效。
如果字段类型为String的话,那么可以在查询语句中格式化下。

常见的相关注解

要给报文格式化,加上这2个注解即可。

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") // 返回到前台
@DateTimeFormat(pattern = "yyyy-MM-dd") // 到后台,例如入参报文到后台
private Date createDate;

为什么不用InitBinder呢

controller配置@InitBinder来进行格式化。
评估: 搞清楚,@InitBinder使用来处理前端到后台字段不会字段转换的问题,不应该用在这里,所以pass掉。

要给报文格式化,加上这2个注解即可。@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")@DateTimeFormat(pattern = "yyyy-MM-dd")private Date createDate;
@JsonFormat与@DateTimeFormat注解的区分和使用 时间问题一直是个比较头疼的问题。 以后台为基准参考:我们想要在后台对从数据库、第三方API接口获取到的时间进行“格式化”需要用到【@JsonFormat】注解;我们通过后台给前台传递指定格式的时间也是通过【@JsonFormat】;如果是后台接收前台传来的时间进行格式化需要用到【@DateTimeFormat】。 @JsonFormatjackson包的。 2.@JsonFormat代码示例 1.使用maven引入
//timezone:是时间设置为东八区,避免时间在转换有误差 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private Date createDate; 从前台页面将时间类型的数据传入数据库,这个时候前台传递给后台的时间格式同样是不一致的,我们通过使用@DataTimeFormat注解就可以很好的解
@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”, timezone=“GMT+8”) private Date createTime;@DateTimeFormat(pattern = “yyyy-MM-dd”) @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”,timezone=“GMT+8”) private Date symstarttime;
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); User user = new User(); String s = gson.toJson(user); //出餐格式化注解 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JSONField(format = "yyyy-MM-dd HH:mm:ss") //建议这种 由于@RequestBody注解先将json字符串转换成对应的Vo对象,Vo对象的字段上添加的注解再生效,@DateTimeForma
从数据库获取日期类型的数据传到前台展示的是个时间戳类型并且时间少了八个小时,我们通过使用@JsonFormat注解就可以很好的解决后台到前台时间格式保持一致的问题。 从前台页面将时间类型的数据传入数据库,这个时候前台传递给后台的时间格式同样是不一致的,我们通过使用@DataTimeFormat注解就可以很好的解决这个问题。 使用详情: 1. @JsonFormat