SpringMVC @RequestBody Date類型的Json轉換方式

SpringMVC @RequestBody Date類型的Json轉換

正常使用Json或Gson對Date類型序列化成字符串時,得到的是類似”Dec 5, 2017 8:03:34 PM”這種形式的字符串,前端得到瞭這種格式的很難明白這個具體是什麼時間,可讀性很低。

同時如果用這種形式的字符串來反序列化為Date對象,也會失敗,這個過程是不可逆的。如何將Date對象序列化為指定格式的字符串,比如”yyyy-MM-dd”格式的字符串,以Gson的使用為例來說明。

對於Gson對象,可以使用GsonBuilder來實例化

通過GsonBuilder設置DateFormat的格式

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

經過這樣設置後,使用toJson(Object obj)方法對Date對象序列化時,會輸出”yyyy-MM-dd HH:mm:ss”格式的字符串;

也可以將”yyyy-MM-dd HH:mm:ss”格式的字符串反序列化為一個Date對象。值得註意的是,當一個Date對象未指定”HH:mm:ss”時,會使用當前時間來填充以補齊格式長度。

以上講的是Date對象的序列化和反序列化為字符串的方法,在SpingMVC框架中並不適用,下面講SpringMVC中Date的序列化和反序列化。

SpringMVC中,如果前端以GET的形式傳遞字符串,後端想將此字符串反序列化為Date對象,最常用的就是註冊Formatter對象

以零配置框架為例

public class String2DateFormatter implements Formatter<Date> {
    private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String DATE_FORMAT = "yyyy-MM-dd";
    @Override
    public String print(Date object, Locale locale) {
        return new GsonBuilder().setDateFormat(DATE_TIME_FORMAT).create().toJson(object);
    }
    @Override
    public Date parse(String text, Locale locale) throws ParseException {
        if (text.length() > 10) {
            return new SimpleDateFormat(DATE_TIME_FORMAT).parse(text);
        } else {
            return new SimpleDateFormat(DATE_FORMAT).parse(text);
        }
    }
}
public class MvcContextConfig extends WebMvcConfigurerAdapter {
    ......
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new String2DateFormatter());
    }
    ......
}

當然也可以用配置文件的形式配置,具體方法請百度。

當前端傳遞字符串,Controller用Date類型的參數接受時,會使用Formatter將字符串反序列化為Date對象。

如果前端以POST形式傳遞一個Json對象,對象內部有一個Date屬性,前端傳遞的是字符串,後端用一個標識@RequestBody的復合對象接收時,Formatter是不會起作用的。

此時起作用的是HttpMessageConverter的實現類。正常情況下項目內有Jackson或Gson依賴,能夠將Json反序列化為復合對象。

如果依賴瞭Jackson,且使用Jackson的HttpMessageConverter反序列化Json,那麼僅支持反序列化簡單數據類型的屬性,不支持Date類型;但是如果是Gson類型,是支持”yyyy-MM-dd HH:mm:ss”格式的反序列化的,確定不支持”yyyy-MM-dd”格式,其他格式不確定。

也就是說依賴Gson可以將前端的”yyyy-MM-dd HH:mm:ss”格式的字符串反序列化為Date對象,但是將Date對象返回給前端時,解析得到的還是類似”Dec 5, 2017 8:03:34 PM”這種形式的字符串,並不可取。

當我們使用Jackson作為Json對象的序列化和反序列化的解析器時

以零配置形式框架下的代碼實現為例講解

public class MvcContextConfig extends WebMvcConfigurerAdapter {
    ......
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        stringConverter.setWriteAcceptCharset(false);
        converters.add(stringConverter);
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new ResourceHttpMessageConverter());
        converters.add(new MappingJackson2XmlHttpMessageConverter());
        //設置Date類型使用HttpMessageConverter轉換後的格式,或者註冊一個GsonHttpMessageConverter,能直接支持字符串到日期的轉換
        //當指定瞭日期字符串格式後,如果傳的日志格式不符合,則會解析錯誤
        converters.add(new MappingJackson2HttpMessageConverter(
            new ObjectMapper().setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))));
        //GsonHttpMessageConverter不支持yyyy-MM-dd形式的字符串轉換為日期
        //converters.add(new GsonHttpMessageConverter());
    }
    ......
}

當我們選擇使用Jackson作為Json的解析器時,需要註冊一個MappingJackson2HttpMessageConverter,對內部默認的objectMapper對象做一個拓展,需要指定日期格式化器,當我們指定瞭具體的格式時,隻支持這種格式的轉換,其他的格式轉換時會報錯。

因此需要前端在傳遞日期字符串時,加上默認的時間,比如”2017-12-2 00:00:00”,雖然多瞭點工作,但是能確保格式轉換的正確。

當然並不是一定要”yyyy-MM-dd HH:mm:ss”,其他的格式也都支持的,比如”yyyy-MM-dd”等等,具體可以看項目需求自定義,前端傳遞日期字符串的格式需要符合自定義的格式。

當配置瞭DateFormat時,傳遞對象給前端,對象內部有Date屬性,也會將其序列化為這個格式的字符串。

XML文件形式配置HttpMessageConverter的方法可自行百度。

@RequestBody接收json字符串,自動將日期字符串轉換為java.util.Date

1.配置springMVC可以接收json字符串

<?xml version="1.0" encoding="UTF-8"?>
<beans
 xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.1.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
 http://www.springframework.org/schema/mvc
 http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
 <!-- 解決@ResponseBody返回中文亂碼,解決@RequestBody接收Json字符串自動轉換為實體、List、Map格式轉換器 -->
 <bean 
  class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
  <property name="messageConverters">
   <list>
    <!-- 
    <bean 
     class="org.springframework.http.converter.StringHttpMessageConverter">
     <property name="supportedMediaTypes">
      <list>
       <value>text/html;charset=UTF-8</value>
      </list>
     </property>
    </bean>
    -->
    <bean 
     class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
     <property name="supportedMediaTypes">
      <list>
       <value>application/json;charset=UTF-8</value>
      </list>
     </property>
    </bean>
   </list>
  </property>
 </bean>
 <!-- 掃描包,應用Spring的註解 -->
 <context:component-scan base-package="com.mvc.action"></context:component-scan>
 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  p:viewClass="org.springframework.web.servlet.view.JstlView"
  p:prefix="/"
  p:suffix=".jsp">
 </bean>
 <!-- SpringMVC自定義攔截器,使SpringMVC開啟CORS支持 -->
 <!-- 
 <mvc:interceptors>
  <mvc:interceptor>
   <mvc:mapping path="/*"/>
   <bean class="com.mvc.dao.CorsInterceptor"></bean>
  </mvc:interceptor>
 </mvc:interceptors>
 -->
 <context:annotation-config/>
 <mvc:annotation-driven/>
</beans>

2.@Controller類代碼

@RequestMapping(value="/addDicAppUsers.do")
 @ResponseBody
 public boolean addDicAppUsers(@RequestBody DicAppUsersModel dicAppUsersModel)
 {
  if(dicAppUsersService.addDicAppUsers(dicAppUsersModel))
  {
   return true;
  }
  else
  {
   return false;
  }
 }

3.實體類對象代碼

package com.mvc.model; 
import java.util.Date;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import com.mvc.imp.DateJsonDeserializer;
import com.mvc.imp.DateJsonSerializer;
 
/**
 * 用戶視圖類
 * @author suyunlong
 *
 */
@SuppressWarnings("serial")
public class DicAppUsersModel implements java.io.Serializable
{
 private long id;
 private String loginid;
 private String loginname;
 private String loginpassword;
 private String loginunitcode;
 private String workplace;
 @JsonSerialize(using=DateJsonSerializer.class)
 @JsonDeserialize(using=DateJsonDeserializer.class)
 private Date addtime;
 private long sourceid;
 @JsonSerialize(using=DateJsonSerializer.class)
 @JsonDeserialize(using=DateJsonDeserializer.class)
 private Date createdate;
 public DicAppUsersModel() {
  super();
 }
 public DicAppUsersModel(long id, String loginid, String loginname,
   String loginpassword, String loginunitcode, String workplace,
   Date addtime, long sourceid, Date createdate) {
  super();
  this.id = id;
  this.loginid = loginid;
  this.loginname = loginname;
  this.loginpassword = loginpassword;
  this.loginunitcode = loginunitcode;
  this.workplace = workplace;
  this.addtime = addtime;
  this.sourceid = sourceid;
  this.createdate = createdate;
 }
 public long getId() {
  return id;
 }
 public void setId(long id) {
  this.id = id;
 }
 public String getLoginid() {
  return loginid;
 }
 public void setLoginid(String loginid) {
  this.loginid = loginid;
 }
 public String getLoginname() {
  return loginname;
 }
 public void setLoginname(String loginname) {
  this.loginname = loginname;
 }
 public String getLoginpassword() {
  return loginpassword;
 }
 public void setLoginpassword(String loginpassword) {
  this.loginpassword = loginpassword;
 }
 public String getLoginunitcode() {
  return loginunitcode;
 }
 public void setLoginunitcode(String loginunitcode) {
  this.loginunitcode = loginunitcode;
 }
 public String getWorkplace() {
  return workplace;
 }
 public void setWorkplace(String workplace) {
  this.workplace = workplace;
 }
 public Date getAddtime() {
  return addtime;
 }
 public void setAddtime(Date addtime) {
  this.addtime = addtime;
 }
 public long getSourceid() {
  return sourceid;
 }
 public void setSourceid(long sourceid) {
  this.sourceid = sourceid;
 }
 public Date getCreatedate() {
  return createdate;
 }
 public void setCreatedate(Date createdate) {
  this.createdate = createdate;
 }
}

4.DateJsonSerializer類代碼

package com.mvc.imp; 
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
 
public class DateJsonSerializer extends JsonSerializer<Date>
{
 public static final SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 public void serialize(Date date,JsonGenerator jsonGenerator,SerializerProvider serializerProvider)
   throws IOException,JsonProcessingException 
 {
  jsonGenerator.writeString(format.format(date));  
    }  
}

5.DateJsonDeserializer類代碼

package com.mvc.imp; 
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
 
public class DateJsonDeserializer extends JsonDeserializer<Date>
{
 public static final SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 public Date deserialize(JsonParser jsonParser,DeserializationContext deserializationContext)
   throws IOException,JsonProcessingException
 {
  try
  {
   return format.parse(jsonParser.getText());
  }
  catch(Exception e)
  {
   System.out.println(e.getMessage());
   throw new RuntimeException(e);
  } 
 }
}

這樣,就可以把接收到的json日期字符串轉換為Date瞭。後面,就可以直接通過Date類型保存日期數據瞭。

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: