前言:
在springMVC中对于Date类型数据前台格式要求默认只能是“2021/1/1”,否则会发生请求错误:
由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。
如何实现前台多种日期格式请求。
示例:
前台:
<body>
<form action="/user/getUser.action" method="post">
用户名:<input type="text" name="name"><br>
密码:<input type="text" name="password"><br>
日期:<input type="text" name="date"><br>
<input type="submit" value="提交">
</form>
</body>
实体
public class User {
private String name;
private String password;
private Date date;
}
Controller
@RequestMapping("/getUser.action")
public String getUser(User user){
System.out.println("User---->"+user);
return "/home.html";
}
错误演示:
错误原因是在springMVC中默认只能对“2021/1/1”这种格式进行解析。
解决方案:
方案一:@DateTimeFormat注解
在Date类型字段上加上@DateTimeFormat注解,并指定格式
public class User {
private String name;
private String password;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date date;
}
缺点:实体类每个Date类型字段都要写该注解,并且只能指定一种格式
方案二:@InitBinder
在Controller类中写一个方法指定格式,并加上注解@InitBinder,代码如下:
@InitBinder
public void initBinder(WebDataBinder binder){
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class,new CustomDateEditor(dateFormat,true));//需要指定Date类型
}
缺点:多个Controller不能公用,并且只能指定一种格式
方案三:解决多种格式问题
可以看到在方案二中的方法里我们创建了一个指定格式的DateFormat对象,并将dateFormat对象传入CustomDateEditor构造中。想象如果CustomDateEditor构造中能够传入一个dateFormat数组,是不是就能解决只能指定一种格式的问题。代码如下:
第一步:创建DateFormat数组,指定多种格式
@InitBinder
protected void initBinder(WebDataBinder binder){
DateFormat[] dateFormat = {
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("yyyy/MM/dd"),
new SimpleDateFormat("yyyy:MM:dd"),
new SimpleDateFormat("yyyy年MM月dd日"),
};
binder.registerCustomEditor(Date.class,new MyCustomDateEditor(dateFormat,true));
}
第二步:查看CustomDateEditor类的源码,改写CustomDateEditor类,写一个我们自己的MyCustomDateEditor类。
改写CustomDateEditor 类:
1.将成员属性dareFormat改为数组
2.改构造函数
3.参考源码改setAsText方法和getAsText方法,将原本的处理一个DareFormat对象改写为处理一组DareFormat对象
package com.fwk.editor;
import java.beans.PropertyEditorSupport;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
//改写的数据处理
public class MyCustomDateEditor extends PropertyEditorSupport {
private final DateFormat[] dateFormat;
private final boolean allowEmpty;
private final int exactDateLength;
public MyCustomDateEditor(DateFormat[] dateFormat, boolean allowEmpty) {
this.dateFormat = dateFormat;
this.allowEmpty = allowEmpty;
this.exactDateLength = -1;
}
public MyCustomDateEditor(DateFormat[] dateFormat, boolean allowEmpty, int exactDateLength) {
this.dateFormat = dateFormat;
this.allowEmpty = allowEmpty;
this.exactDateLength = exactDateLength;
}
@Override
public void setAsText(@Nullable String text) throws IllegalArgumentException {
if (this.allowEmpty && !StringUtils.hasText(text)) {
// Treat empty String as null value.
setValue(null);
}
else if (text != null && this.exactDateLength >= 0 && text.length() != this.exactDateLength) {
throw new IllegalArgumentException(
"Could not parse date: it is not exactly" + this.exactDateLength + "characters long");
}
else {
for (int i = 0; i < dateFormat.length; i++) {
try {
setValue(dateFormat[i].parse(text));
break;
}
catch (ParseException ex) {
if (i==dateFormat.length-1){
throw new IllegalArgumentException("Could not parse date: " + ex.getMessage(), ex);
}else {
continue;
}
}
}
}
}
@Override
public String getAsText() {
Date value = (Date) getValue();
for (int i = 0; i < dateFormat.length; i++) {
try {
String s = dateFormat[i].format(value);
return s;
}catch (Exception e){
continue;
}
}
return "";
}
}
方案三增强:解决多个Controller共用问题
单独写一个类,类上加上@ControllerAdvice,进行全局数据预处理,并将@InitBinder注解标志的方法放在里面
@ControllerAdvice
public class DateAdvice {
@InitBinder
protected void initBinder(WebDataBinder binder){
System.out.println("date");
DateFormat[] dateFormat = {
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("yyyy/MM/dd"),
new SimpleDateFormat("yyyy:MM:dd"),
new SimpleDateFormat("yyyy年MM月dd日"),
};
binder.registerCustomEditor(Date.class,new MyCustomDateEditor(dateFormat,true));
}
}