美文网首页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