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了。
文章评论