Fixed formatting issues with SpringMVC's return Java8 time JSON data

  • 2020-06-03 06:36:50
  • OfStack

Sometimes the @ResponseBody annotation is used in Spring MVC to return response in JSON, but it can be difficult to deal with the time in java8. Generally, we use HTTPMessageConverter MappingJackson2HttpMessageConverter, which returns the default time format like this:


"startDate" : {
  "year" : 2010,
  "month" : "JANUARY",
  "dayOfMonth" : 1,
  "dayOfWeek" : "FRIDAY",
  "dayOfYear" : 1,
  "monthValue" : 1,
  "hour" : 2,
  "minute" : 2,
  "second" : 0,
  "nano" : 0,
  "chronology" : {
   "id" : "ISO",
   "calendarType" : "iso8601"
  }
 }

However, we will not return such data to the front end. For LocalDate, the format we want to return is 2016-11-26, while LocalDateTime wants to return such data as 21:04:34 2016-11-26. Through project research and access to relevant materials, here are two ways of doing personal research.

Solution 1:

For the maven project, introduce the following jar packages in pom:


<dependency>
   <groupId>com.fasterxml.jackson.datatype</groupId>
   <artifactId>jackson-datatype-jsr310</artifactId>
   <version>2.8.5</version>
 </dependency>

Then add one @JsonSerializer annotation to the get function of the POJO field that you want to JSON, as follows


import com.fasterxml.jackson.annotation.JsonFormat;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public LocalDateTime getBirthday() {
    return this.loginTime;
  }

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime getLastLoginTime() {
    return this.loginTime;
  }

The advantage of this approach is that you can set different display modes for specific domain types, but it is also a disadvantage, as each date attribute is added manually, is a common requirement in practice, and requires the introduction of the jar package jsr310.

Solution 2:

Inherit from ObjectMapper to return the json string. MappingJackson2HttpMessageConverter returns the json string mainly through ObjectMapper. Here we write an JsonUtil class to get ObjectMapper to register the corresponding JsonSerializer for the new date and time API in java8 < T > .


/**
 * json Processing tool class 
 * 
 * 
 */
@Component
public class JsonUtil {

  private static final ObjectMapper mapper;

  public ObjectMapper getMapper() {
    return mapper;
  }

  static {

    mapper = new ObjectMapper();

    SimpleModule module = new SimpleModule();
    module.addSerializer(LocalDate.class, new LocalDateSerializer());
    module.addSerializer(LocalTime.class, new LocalTimeSerializer());
    module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
    mapper.registerModule(module);
  }

  public static String toJson(Object obj) {
    try {
      return mapper.writeValueAsString(obj);
    } catch (Exception e) {
      throw new RuntimeException(" conversion json Character failure !");
    }
  }

  public <T> T toObject(String json, Class<T> clazz) {
    try {
      return mapper.readValue(json, clazz);
    } catch (IOException e) {
      throw new RuntimeException(" will json Failed to convert character to object !");
    }
  }
}

class LocalDateSerializer extends JsonSerializer<LocalDate> {

  private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

  @Override
  public void serialize(LocalDate value, JsonGenerator jgen, SerializerProvider provider)
      throws IOException, JsonProcessingException {
    jgen.writeString(dateFormatter.format(value));
  }
}

class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

  private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

  @Override
  public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider provider)
      throws IOException, JsonProcessingException {
    jgen.writeString(dateTimeFormatter.format(value));
  }

}

class LocalTimeSerializer extends JsonSerializer<LocalTime> {

  private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");

  @Override
  public void serialize(LocalTime value, JsonGenerator jgen, SerializerProvider provider)
      throws IOException, JsonProcessingException {
    jgen.writeString(timeFormatter.format(value));

  }

}

Then in the springmvc configuration file, again < mvc:annotation-driven/ > Instead, configure a new json converter and set its ObjectMapper object to the objectMapper object in JsonUtil. This converter has a higher priority than the built-in json converter in spring, so spring will take precedence over json-related conversions.


<mvc:annotation-driven>
    <mvc:message-converters>
      <bean
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="objectMapper" value="#{jsonUtil.mapper}" />
        <property name="supportedMediaTypes">
          <list>
            <value>application/json;charset=UTF-8</value>
          </list>
        </property>
      </bean>
    </mvc:message-converters>
  </mvc:annotation-driven>

Several of the date and time types in java8 are then displayed in a friendly way. The advantage is that global 1 manages types such as date and time, while the disadvantage is that a domain in pojo does special processing.


Related articles: