这个问题不是专门针对Springboot的,Springmvc也同样适用于这一个问题。
昨的是Springboot前后端分离的项目,今天和前端对接口发现前端的请求走不到后台,检查了请求什么的都没有问题,最后发现问题在于后台处理前端传过来的时间(Date)问题。
一般前端提交表单的时候Controller控制器会把表单元素注入到一个command类中,然后发送到后台,但是前端所能传递到后台的数据类型一般是int、char、String等这些基本数据类型,如果我们需要传递一些复杂的数据类型入Integer或者Date这些的时候我们就需要自己去处理了。
这里我们主要讲解如何处理前端传递过来的Date类型数据。我们这边以接受模型为例,下面代码后台需要接受前端传递过来的时间类型参数startTime(开始时间)和endTime(结束时间),前端数据类型为(2018-11-29 14:48:06)格式数据。
@RequestMapping(value = "/ask",method = RequestMethod.POST) public Result ask(Test test) {
public class Test { // 开始时间 private Date startTime; // 结束时间 private Date endTime; public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; }}
这里有三种方式解决这个问题,三种方式解决问题的原理基本相同,我们可以根据具体需求进行选择。
方法一:
使用@DatetimeFormat注解加载需要接受Date数据的字段上,在接受前端时间的时候会将时间转换为我们需要的格式。
public class Test { // 开始时间 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date startTime; // 结束时间 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date endTime; public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; }}
方法二:
在对应需要接受Date参数的后台控制器层添加如下代码。
由@InitBinder表示的方法,可以对WebDataBinder对象进行初始化。WebDataBinder是Spring自带的一个类,通过这个类我们可以将前端传递过来的类进行格式转换。当后台接受到前端传递过来的数据类型的时候会在我们的Test这个类里面进行数据的getter个setter,当set的类型不是基本数据类型的时候,由于在目前控制器层这个类中有者下面一段代码,于是日期类型的数据会进到下面代码中进行一次数据转换,我们这里是将前端的数据类型转化为了Date类型然后调用Test类中的set方法设置字段。
dateFormat.setLenient(false);这里的作用是设置是否严格解析时间,这里默认是true,我们设为false就是要严格解析时间,因为当传递过来的时间格式不规范的时候SimpleDateFormat拥有自动计算功能,这时候会自动解析传递过来的时间然后显示规范的格式。
@InitBinderpublic void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dateFormat.setLenient(false);//是否严格解析时间 false则严格解析 true宽松解析 binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));}
我们这里不仅仅可以来处理时间类型,还可以来处理其它的数据类型(非基本类型数据)如CustomDateEditor、CustomBooleanEditor、CustomNumberEditor等。
@InitBinderpublic void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Double.class, new DoubleEditor()); binder.registerCustomEditor(Integer.class, new IntegerEditor());}
方法三:
第三种方式是在第二种方式的基础上实现的。同样适用第二种方法中的代码,但是不同在与我们不用在每一个控制器类中都实现一个方法二中的代码,只需要写一个拦截器出来拦截所有的@RequestMapping注解就好。
如下代码我们新建一个类:
@ControllerAdvicepublic class TimeHandler { @InitBinder public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dateFormat.setLenient(false);//是否严格解析时间 false则严格解析 true宽松解析 binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); }}
@ControllerAdvice注解被@Component注解,也相当于Spring中的一个组件。@ControllerAdvice有控制器增强的作用,它主要用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,我们这里只给出了@InitBinder的使用方式。
方法二和方法三各有各的优势:方法二需要在每一个用到Date类型接收的控制器层创建一个上面的方法,比较麻烦。方法三比较简单只需要写一个类即可,但是它会拦截每一个前端过来的请求,这样在这方面就不如方法二了。具体如果代码里面只有少数几个地方用到数据类型转换可以使用方法二,如果很多地方需要使用则选用方法三。
注意:
在最开始写这个时间数据类型的时候遇到了一个问题造成了一直接受不到请求如下:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
区别只在与小时的字母大小写问题,上面是接受24小时制时间,下面是接受12小时制时间。同样方法一中也要注意这个问题。
yyyy 代表年 MM 代表月(注意这里要用大写) dd 代表日 HH/hh 代表时(24小时形式/12小时形式) mm 代表分(这里用小写表示分钟)
其中代表月的MM大写是因为为了和时间的分minute区分开,代表日的字母大小写是为了区分24小时形式和12小时形式。