SpringMVC/SpringBoot字符类型时间日期(各种format)请求参数自动转成Date类型

2021-07-21 1340点热度 0人点赞 0条评论

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了。

admin

这个人很懒,什么都没留下

文章评论

您需要 登录 之后才可以评论