美文网首页Spring-Boot
Web请求中的日期类型参数

Web请求中的日期类型参数

作者: 一曲畔上 | 来源:发表于2019-03-07 17:47 被阅读10次

    在web请求中,遇到日期类型(Date)一般情况下比较头疼,因为可能涉及到各种格式问题,比如“2019-03-07 17:10:21”、“2019-03-07 17:10”、“2019-03-07”,甚至还有1551949821、1551949821000等等各种问题。这些问题,仅仅靠文档说明,很难保证不出问题。
    那怎么解决这种棘手问题呢?其他各种数据绑定方式就不讲了,今天主要讲一种结合Springboot特性的无入侵无感知解决方案~
    在SpringBoot的WebMvc实现中,专门提供了下面接口用于解决各种格式问题

    /**
     * Add {@link Converter Converters} and {@link Formatter Formatters} in addition to the ones
     * registered by default.
     */
    default void addFormatters(FormatterRegistry registry) {
    }
    

    该方法默认是空的。该方法的作用是从注释上很容易就明白了,就是注册Converter和Formatter的,那我们只需要注册一个日期转换类型的Converter便可以解决问题了。
    那我们先写一个日期转换Converter

    public class StringDateConverter implements Converter<String, Date> {
        private static Logger logger = LoggerFactory.getLogger(StringDateConverter.class);
        
        private static final String TIME_PATTERN_REGEX = "^\\d{1,13}$";
        
        private static ThreadLocal<SimpleDateFormat[]> dateFormatLocal = new ThreadLocal<SimpleDateFormat[]>() {
            @Override
            protected SimpleDateFormat[] initialValue() {
                return new SimpleDateFormat[] {
                        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
                        new SimpleDateFormat("yyyy-MM-dd HH:mm"),
                        new SimpleDateFormat("yyyy-MM-dd HH"),
                        new SimpleDateFormat("yyyy-MM-dd")
                    };
            }
        };
        
        @Override
        public Date convert(final String source) {
            if (source == null || source.trim().equals("")) {
                return null;
            }
            
            Date result = null;
            String _src = source.trim();
            // 1,数字类型
            if (_src.matches(TIME_PATTERN_REGEX)) {
                try {
                    long lTime = Long.parseLong(_src);
                    if (_src.length() > 10) {
                        result = new Date(lTime);
                    } else {
                        result =  new Date(1000L * lTime);
                    }
                } catch (Exception e) {
                    result = null;
                    
                    logger.warn("[" + source + "]无法转化为日期!");
                }
                
                return result;
            }
            // 2,日期类型
            SimpleDateFormat[] dateFormats = dateFormatLocal.get();
            for (SimpleDateFormat dateFormat : dateFormats) {
                try {
                    dateFormat.setLenient(false);
                    
                    return dateFormat.parse(source);
                } catch (ParseException e) {
                    logger.warn("[" + source + "]无法转化为" + dateFormat.toPattern() + "格式的日期!");
                }
            }
            
            return null;
        }
    }
    

    该StringDateConverter转换器支持把“yyyy-MM-dd HH:mm:ss”、“yyyy-MM-dd HH:mm”、“yyyy-MM-dd HH”、“yyyy-MM-dd”格式的字符串和long类型的数字转化为日期类型,并且是线程安全的。
    然后,我们把该转换器注册到系统中即可。这也有两种方案:
    方法1,系统中的WebConfig文件继承WebMvcConfigurer并且重载addFormatters方法:

    @Configuration
    @Import({ WebMvcAutoConfiguration.class })
    @ComponentScan(
            value = "com.beyonds.phoenix.shine.web",
            includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
            })
    public class WebMvcConfiguration implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringDateConverter());
        }
    }
    

    方法2,直接把StringDateConverter注册成bean即可!

    @Configuration
    @Import({ WebMvcAutoConfiguration.class })
    @ComponentScan(
            value = "com.beyonds.phoenix.shine.web",
            includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
            })
    public class WebMvcConfiguration {
        /**
         * 自定义输入的日期格式
         * 覆盖spring.mvc.date-format
         * @return 日期格式转换器
         */
        @Bean
        public StringDateConverter dateConverter() {
            return new StringDateConverter();
        }
    }
    

    为什么方法2也能生效呢,这就是SpringBoot内部自动机制实现了~
    其实,在WebMvcAutoConfiguration内部实现中,有如下代码

    @Override
    public void addFormatters(FormatterRegistry registry) {
        for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
            registry.addConverter(converter);
        }
        for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
            registry.addConverter(converter);
        }
        for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
            registry.addFormatter(formatter);
        }
    }
    

    其作用很清楚,就是自动扫描并注册Converter、GenericConverter和Formatter到web处理器中~
    -End-

    相关文章

      网友评论

        本文标题:Web请求中的日期类型参数

        本文链接:https://www.haomeiwen.com/subject/likhpqtx.html