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。
推薦閱讀:
- SpringBoot利用jackson格式化時間的三種方法
- 實例詳解SpringBoot默認的JSON解析方案
- springboot前端傳參date類型後臺處理的方式
- SpringBoot @JsonDeserialize自定義Json序列化方式
- springboot2中使用@JsonFormat註解不生效的解決