使用正規表示式優雅的解決 SpringMVC 時間轉換問題

GitLqr發表於2019-03-02

一、簡述

使用SpringMVC接收過時間引數的程式設計師都應該知道,時間轉換是一個令人頭疼的問題,雖然這不是什麼大問題,解決的方法也有多種,但解決不妥的話感覺起來會很不舒服,因為處理不當會把時間的接收格式寫死,如果開發後期想更改時間格式呢?又或者專案要求可以接收不同格式的時間引數的話那又該怎麼辦呢?這時就可以通過正規表示式來解決這種問題了。下面就來看看如何用正規表示式優雅的解決這種問題。

二、全域性時間轉換

1、自定義時間轉換器

/**
 * 日期轉換器
 */
public class DataConverter implements Converter<String, Date> {

    public Date convert(String source) {
        SimpleDateFormat sdf = getSimpleDateFormat(source);
        try {
            Date date = sdf.parse(source);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    private SimpleDateFormat getSimpleDateFormat(String source) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        if (Pattern.matches("^\d{4}-\d{2}-\d{2}$", source)) { // yyyy-MM-dd
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        } else if (Pattern.matches("^\d{4}-\d{2}-\d{2} \d{2}-\d{2}-\d{2}$", source)) { // yyyy-MM-dd HH-mm-ss
            sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        } else if (Pattern.matches("^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$", source)) { // yyyy-MM-dd HH:mm:ss
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else if (Pattern.matches("^\d{4}/\d{2}/\d{2}$", source)) { // yyyy/MM/dd
            sdf = new SimpleDateFormat("yyyy/MM/dd");
        } else if (Pattern.matches("^\d{4}/\d{2}/\d{2} \d{2}/\d{2}/\d{2}$", source)) { // yyyy/MM/dd HH/mm/ss
            sdf = new SimpleDateFormat("yyyy/MM/dd HH/mm/ss");
        }  else if (Pattern.matches("^\d{4}\d{2}\d{2}$", source)) { // yyyyMMdd
            sdf = new SimpleDateFormat("yyyyMMdd");
        }  else if (Pattern.matches("^\d{4}\d{2}\d{2} \d{2}\d{2}\d{2}$", source)) { // yyyyMMdd HHmmss
            sdf = new SimpleDateFormat("yyyyMMdd HHmmss");
        } else if (Pattern.matches("^\d{4}\.\d{2}\.\d{2}$", source)) { // yyyy.MM.dd
            sdf = new SimpleDateFormat("yyyy.MM.dd");
        }  else if (Pattern.matches("^\d{4}\.\d{2}\.\d{2} \d{2}\.\d{2}\.\d{2}$", source)) { // yyyy.MM.dd HH.mm.ss
            sdf = new SimpleDateFormat("yyyy.MM.dd HH.mm.ss");
        }else{
            System.out.println("TypeMismatchException");
            throw new TypeMismatchException();
        }
        return sdf;
    }

}複製程式碼

2、註冊時間轉換器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    ...

    <!-- 轉換器服務工廠Bean -->
    <bean id="conversion-service"
        class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.lqr.convert.DataConverter" />
            </set>
        </property>
    </bean>

    <!-- 註冊轉化器 -->
    <mvc:annotation-driven conversion-service="conversion-service" />

</beans>複製程式碼

這樣就可以接收絕大部分的時間格式了,如:2017-02-15、2017.02.15、2017/02/15、2017-02-15 14:20:55。。。

三、區域性時間轉換

區域性時間轉換,就是在Controller中使用@InitBinder註解一個引數型別為WebDataBinder的方法,通過WebDataBinder物件的registerCustomEditor()方法來解決時間轉換問題,例子如下:

@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = "/register.do", method = RequestMethod.POST)
    public ModelAndView register(String name, Date date) throws Exception {
        ModelAndView mv = new ModelAndView();
        System.out.println("name = " + name);
        System.out.println("date = " + date);
        mv.addObject("name", name);
        mv.addObject("date", date);
        mv.setViewName("/WEB-INF/jsp/welcome.jsp");
        return mv;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(df, true));
    }
}複製程式碼

這裡的CustomDateEditor類是SpringMVC提供的,卻無法獲取日期資料,所以無法根據日期格式來建立不同的SimpleDateFormat物件,也就是說這種方式會把時間的格式寫死,解決方法,可以自定義DateEditor。

1、建立自定義DateEditor

public class MyDateEditor extends PropertiesEditor {

    @Override
    public void setAsText(String source) throws IllegalArgumentException {
        SimpleDateFormat df = getSimpleDateFormat(source);
        try {
            Date date = df.parse(source);
            setValue(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    private SimpleDateFormat getSimpleDateFormat(String source) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        if (Pattern.matches("^\d{4}-\d{2}-\d{2}$", source)) { // yyyy-MM-dd
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        } else if (Pattern.matches("^\d{4}-\d{2}-\d{2} \d{2}-\d{2}-\d{2}$", source)) { // yyyy-MM-dd HH-mm-ss
            sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        } else if (Pattern.matches("^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$", source)) { // yyyy-MM-dd HH:mm:ss
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else if (Pattern.matches("^\d{4}/\d{2}/\d{2}$", source)) { // yyyy/MM/dd
            sdf = new SimpleDateFormat("yyyy/MM/dd");
        } else if (Pattern.matches("^\d{4}/\d{2}/\d{2} \d{2}/\d{2}/\d{2}$", source)) { // yyyy/MM/dd HH/mm/ss
            sdf = new SimpleDateFormat("yyyy/MM/dd HH/mm/ss");
        }  else if (Pattern.matches("^\d{4}\d{2}\d{2}$", source)) { // yyyyMMdd
            sdf = new SimpleDateFormat("yyyyMMdd");
        }  else if (Pattern.matches("^\d{4}\d{2}\d{2} \d{2}\d{2}\d{2}$", source)) { // yyyyMMdd HHmmss
            sdf = new SimpleDateFormat("yyyyMMdd HHmmss");
        } else if (Pattern.matches("^\d{4}\.\d{2}\.\d{2}$", source)) { // yyyy.MM.dd
            sdf = new SimpleDateFormat("yyyy.MM.dd");
        }  else if (Pattern.matches("^\d{4}\.\d{2}\.\d{2} \d{2}\.\d{2}\.\d{2}$", source)) { // yyyy.MM.dd HH.mm.ss
            sdf = new SimpleDateFormat("yyyy.MM.dd HH.mm.ss");
        }else{
            System.out.println("TypeMismatchException");
            throw new TypeMismatchException();
        }
        return sdf;
    }
}複製程式碼

2、使用自定義DateEditor

@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = "/register.do", method = RequestMethod.POST)
    public ModelAndView register(String name, Date date) throws Exception {
        ModelAndView mv = new ModelAndView();
        System.out.println("name = " + name);
        System.out.println("date = " + date);
        mv.addObject("name", name);
        mv.addObject("date", date);
        mv.setViewName("/WEB-INF/jsp/welcome.jsp");
        return mv;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Date.class, new MyDateEditor());
    }

}複製程式碼

四、總結

這兩種方式我推薦使用第一種,因為是全域性的,配置過一次之後,整個專案的時間引數都可以隨便接收,且不需要在Controller中寫任何程式碼,減少程式碼入侵。而第二種方式的優點就是不用在配置檔案中做任何操作,全部由程式碼解決,不過是隻對當前Controller生效。總的來說,使用正規表示式可以很好的解決多格式時間引數問題,如果專案中存在其他的時間格式,可以在對應的自定義時間轉換器類或自定義的DateEditor中追加正規表示式以滿足專案需求。

相關文章