1. 请求处理
1.1 场景:
在开发javaweb项目是,往往需要传递时间,当前台传递的时字符串(如“2018-09-09”),后台却用时间类型接受会报错。
2018 六月 15 16:53:01.557 WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Failed to bind request element: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam java.util.Date] for value '2018-09-09'; nested exception is java.lang.IllegalArgumentException
大概意思就是String到Date类型不支持。
1.2. 分析:
在用SpringMVC 开发时,主要有两种接收方式,一种是普通的form表单提交,另一种是JSON格式提交。
1. form表单提交:不管是GET还是POST提交,都可以从request.getParameter中到参数,并且默认返回类型为String。@RequestParam就是拿取该数据并做类型转换映射到响应的参数上,因为Spring没有实现String到Date的转换导致报错。
2. JSON格式提交:这个时候用request.getParameter就得不到数据,因为数据被存到请求体中,可以用流的方式得到。Spring中可以用@RequestBody注解映射得到。
注:你可能疑惑,form表单提交的POST请求也不是放到请求体中,不也应该用流的形式取么?
1.3. 方案:
1.3.1 form表单提交
方法一
可以在参数前加@DateTimeFormat(pattern=”yyyyMMdd”)注解。
代码:
$("#saveBtn").click(function(e){
$.ajax({
url: '<%=basePath%>/date/date',
type: 'post',
dataType: 'json',
data: {'date':$("#date").val()},
success: function(data) {
console.info(data);
}
});
});
<form action="">
时间:<input type = "text" name="date" id = "date"><br/>
<input type="button" id = "saveBtn" value="提交">
</form>
/**
* 测试有@DateTimeFormat
* 前台传过来的时间为字符串
*/
@RequestMapping("/date")
public Date date(
@DateTimeFormat(pattern="yyyy-MM-dd") Date date,
HttpServletRequest request) throws IOException {
System.out.println("\n");
System.out.println("******测试有@DateTimeFormat,前台传过来的时间为字符串******");
System.out.println(date);
System.out.println(request.getParameter("date"));
return date;
}
输出:
******测试有@DateTimeFormat,前台传过来的时间为字符串******
Sun Sep 09 00:00:00 CST 2018
2018-09-09
方法二
前台传递时间格式的数据。
$("#saveBtn21").click(function(e){
$.ajax({
url: '<%=basePath%>/date/date21',
type: 'post',
dataType: 'json',
data: {'date':new Date()},
success: function(data) {
console.info(data);
}
});
});
<form action="">
时间21:<input type = "text" name="date" id = "date21"><br/>
<input type="button" id = "saveBtn21" value="提交">
</form>
/**
* 测试没有@DateTimeFormat
* 前台传过来的时间为时间
*/
@RequestMapping("/date21")
public Date date21(
Date date,
HttpServletRequest request) throws IOException {
System.out.println("\n");
System.out.println("******测试没有@DateTimeFormat,前台传过来的时间为时间******");
System.out.println(date);
System.out.println(request.getParameter("date"));
return date;
}
输出:
******测试没有@DateTimeFormat,前台传过来的时间为时间******
Sat Jun 16 10:30:36 CST 2018
Sat Jun 16 2018 10:30:36 GMT+0800 (中国标准时间)
1.3.2 JSON格式提交
方法一:
在JSON格式提交如果用@DateTimeFormat(pattern=”yyyyMMdd”)是不起作用的,
此时可以用json的@JsonDeserialize注解,将值反序列化。
经测试:JSON格式提交,如果前台传过来的时yyyy-MM-dd格式的字符串,后台不做处理可以正常接收。
代码:
public class DateEntity {
@JsonDeserialize(using = DateJsonDeserialize.class)
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "DateEntity [date=" + date + "]";
}
}
public class DateJsonDeserialize extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
String text = p.getText();
if(StringUtils.isBlank(text)){
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(text);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
$("#saveBtn3").click(function(e){
var param = {'date':$("#date3").val()};
$.ajax({
url: '<%=basePath%>/date/date3',
type: 'post',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(param),
success: function(data) {
console.info(data);
}
});
});
<form action="">
时间3:<input type = "text" name="date" id = "date3"><br/>
<input type="button" id = "saveBtn3" value="提交">
</form>
/**
* 测试有@RequestBody
* 前台传过来的时间为字符串
*/
@RequestMapping("/date3")
public DateEntity date3(
@RequestBody DateEntity dateEntity,
HttpServletRequest request) throws IOException {
System.out.println("\n");
System.out.println("******测试有@RequestBody,前台传过来的时间为字符串******");
System.out.println(dateEntity);
return dateEntity;
}
输出:
******测试有@RequestBody,前台传过来的时间为字符串******
DateEntity [date=Sun Sep 09 08:00:00 CST 2018]
null
方法二:
前台传递时间格式的数据。
2. 响应处理
2.1 场景
在Spring开发中,发现如果响应中含有时间格式的数据,会自动转换成long类型传递。
2.2 方案
以JSON提交为例,可以增加 @JsonSerialize注解,对响应参数的时间类型数据序列化
代码:
public class DateEntity {
@JsonDeserialize(using = DateJsonDeserialize.class)// 请求时:将字符串类型的格式转换成时间类型
@JsonSerialize(using=DateJsonSerialize.class)// 响应结果:将时间类型的格式化
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "DateEntity [date=" + date + "]";
}
}
public class DateJsonSerialize extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if(value != null){
if(value.getClass().isAssignableFrom(Date.class)){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format((Date) value);
gen.writeString(format);
}
}
}
}
$("#saveBtn3").click(function(e){
var param = {'date':$("#date3").val()};
$.ajax({
url: '<%=basePath%>/date/date3',
type: 'post',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(param),
success: function(data) {
console.info(data);
}
});
});
<form action="">
时间3:<input type = "text" name="date" id = "date3"><br/>
<input type="button" id = "saveBtn3" value="提交">
</form>
/**
* 测试有@RequestBody
* 前台传过来的时间为字符串
*/
@RequestMapping("/date3")
public DateEntity date3(
@RequestBody DateEntity dateEntity,
HttpServletRequest request) throws IOException {
System.out.println("\n");
System.out.println("******测试有@RequestBody,前台传过来的时间为字符串******");
System.out.println(dateEntity);
System.out.println(request.getParameter("date"));
return dateEntity;
}
响应结果: