Spring的Controller中接收Date类型的参数,实际前端传入的是String类型的日期,或者接收一个@ModelAttribute的Object,里面有Date类型的成员,测试代码如下:
@Controller
public class TestController {
@RequestMapping("/test")
public @ResponseBody String test(@RequestParam(value = "date", required = false) Date date) {
return date.toString();
}
@RequestMapping(value = "/save_user")
public
@ResponseBody
String saveUser(@ModelAttribute("info") User user) {
return "name: " + user.getName() + ", birthday: " + user.getBirthday().toString();
}
}
class User {
private String name;
private Date birthday;//测试接收Date类型转换
//省略getter and setter
}
前端发送请求:
http://localhost:8080/test?date=2021-07-20 09:29:10 Controller中是无法解析的,会报400错误
或者post的object是{user: "Terry", birthday: "1988-08-08"},Controller中也是无法解析的,报错:Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'birthday'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@javax.persistence.Column java.util.Date] for value '1988-08-08'; nested exception is java.lang.IllegalArgumentException
原因是Spring不知道这样的String类型,如何解析成Date,需要告诉Spring怎么取解析,Spring使用了一个叫WebDataBinder来做这样事情。
实现
我们的需求是Spring能比较智能的解析各种常用的DateFormat转成Date,比如日期可以是
- yyyy-MM-dd 如:2021-08-12
- yyyy-MM-dd HH:mm 如:2021-08-12 13:48
- yyyy-MM-dd HH:mm:ss 如:2021-08-12 13:48:35
等等。
准备好:CustomDateTimeEditor.java extends PropertyEditorSupport
/*
* Copyright (c) 2021.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package cn.org.pcoic.manage.util;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
/**
* @author Terry E-mail: yaoxinghuo at 126 dot com
* @date 2021-7-19 16:06
* @description
*/
public class CustomDateTimeEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String dateFormatString = text == null ? null : determineDateFormat(text);
Date date = null;
if (dateFormatString != null) {
try {
SimpleDateFormat format = new SimpleDateFormat(dateFormatString);
date = format.parse(text);
} catch (ParseException ignored) {
}
}
setValue(date);
}
private static final HashMap<String, String> DATE_FORMAT_REGEXPS = new HashMap<String, String>() {{
put("^\\d{8}$", "yyyyMMdd");
put("^\\d{1,2}-\\d{1,2}-\\d{4}$", "dd-MM-yyyy");
put("^\\d{4}-\\d{1,2}-\\d{1,2}$", "yyyy-MM-dd");
put("^\\d{1,2}/\\d{1,2}/\\d{4}$", "MM/dd/yyyy");
put("^\\d{4}/\\d{1,2}/\\d{1,2}$", "yyyy/MM/dd");
put("^\\d{1,2}\\s[a-z]{3}\\s\\d{4}$", "dd MMM yyyy");
put("^\\d{1,2}\\s[a-z]{4,}\\s\\d{4}$", "dd MMMM yyyy");
put("^\\d{12}$", "yyyyMMddHHmm");
put("^\\d{8}\\s\\d{4}$", "yyyyMMdd HHmm");
put("^\\d{1,2}-\\d{1,2}-\\d{4}\\s\\d{1,2}:\\d{2}$", "dd-MM-yyyy HH:mm");
put("^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{2}$", "yyyy-MM-dd HH:mm");
put("^\\d{1,2}/\\d{1,2}/\\d{4}\\s\\d{1,2}:\\d{2}$", "MM/dd/yyyy HH:mm");
put("^\\d{4}/\\d{1,2}/\\d{1,2}\\s\\d{1,2}:\\d{2}$", "yyyy/MM/dd HH:mm");
put("^\\d{1,2}\\s[a-z]{3}\\s\\d{4}\\s\\d{1,2}:\\d{2}$", "dd MMM yyyy HH:mm");
put("^\\d{1,2}\\s[a-z]{4,}\\s\\d{4}\\s\\d{1,2}:\\d{2}$", "dd MMMM yyyy HH:mm");
put("^\\d{14}$", "yyyyMMddHHmmss");
put("^\\d{8}\\s\\d{6}$", "yyyyMMdd HHmmss");
put("^\\d{1,2}-\\d{1,2}-\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "dd-MM-yyyy HH:mm:ss");
put("^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{2}:\\d{2}$", "yyyy-MM-dd HH:mm:ss");
put("^\\d{1,2}/\\d{1,2}/\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "MM/dd/yyyy HH:mm:ss");
put("^\\d{4}/\\d{1,2}/\\d{1,2}\\s\\d{1,2}:\\d{2}:\\d{2}$", "yyyy/MM/dd HH:mm:ss");
put("^\\d{1,2}\\s[a-z]{3}\\s\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "dd MMM yyyy HH:mm:ss");
put("^\\d{1,2}\\s[a-z]{4,}\\s\\d{4}\\s\\d{1,2}:\\d{2}:\\d{2}$", "dd MMMM yyyy HH:mm:ss");
}};
/**
* 根据所给的String,尝试选择一种DateFormat,根据上面的一些基本的pattern来选择,如果选不到就返回null
*/
public static String determineDateFormat(String dateString) {
for (String regexp : DATE_FORMAT_REGEXPS.keySet()) {
if (dateString.toLowerCase().matches(regexp)) {
return DATE_FORMAT_REGEXPS.get(regexp);
}
}
return null; // Unknown format.
}
}
然后在Controller中注册一下,这样Spring就知道如何将String转成Date了!
@Controller
public class TestController {
@InitBinder
public void dataBinding(WebDataBinder binder) {
// 注册CustomDateTimeEditor,告诉Spring如何将String解析成Date
binder.registerCustomEditor(Date.class, new CustomDateTimeEditor());
}
@RequestMapping("/test")
public @ResponseBody String test(@RequestParam(value = "date", required = false) Date date) {
return date.toString();
}
@RequestMapping(value = "/save_user")
public
@ResponseBody
String saveUser(@ModelAttribute("info") User user) {
return "name: " + user.getName() + ", birthday: " + user.getBirthday().toString();
}
}
class User {
private String name;
private Date birthday;
//省略getter and setter
}
重新启动下应用,就OK了。
文章评论