SpringBoot基础之统一时间类型参数处理

1,257 阅读2分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

前言

在前后端交互过程中,日期类型的参数是绕不过的的一种类型,但是日期类型的数据有多种多样的格式,但是默认的情况下,日期类型的转换多数情况下就会出错.

Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2021-12-12'; nested exception is java.lang.IllegalArgumentException

日期参数处理的多种方式

日期参数的处理包含两个部分,一是@RequestBody参数的解析方式

   @PostMapping("/typeBody")
    public ResultVo typeBody(@RequestBody StudentSimpleDto dto){
        return R.success(dto);
    }

StudentSimpleDto.java中有日期参数

@Data
public class StudentSimpleDto {
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone = "GMT+8")
    private LocalDateTime birthdate;
}

二是非@RequestBody参数的解析方式

 @PostMapping("/type")
    public ResultVo token(Date date, LocalDate localDate ){
        return R.success("Date",date,"LocalDate",localDate);
    }

(一) 在对象的参数上使用@JsonFormat

public class Dto{
 @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone = "GMT+8")
 private Date createtime;
 }

只适用于接收为对象类型,springboot的默认JSON解析器为Jackson,这个注解是Jackson的,非Jackson不管用,非RequestBody接收的参数无效,适合个别日期参数有特殊的格式

该方案的进阶方案就是配置Jackson的ObjectMapper配置,不想写.

(二) 在@ControllerAdvice@InitBinder中添加Converter

@ControllerAdvice
public class RequestHandler {
    
    @InitBinder
    public void initBinder(WebDataBinder binder) {
    
        GenericConversionService genericConversionService = (GenericConversionService) binder.getConversionService();
        if (genericConversionService != null) {
            genericConversionService.addConverter(new Converter<String, Date>(){
                @Override
                public Date convert(String source) {
                    try {
                        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(source);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
            });
            // //可以添加多个Converter
        }
    }
}

可以新增多个Converter,比如<String,LocalDate> 但是只是用于入参数据解析

(三) 实现WebMvcConfigurer类,重写addFormatters方法(个人认为最好)

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
 
 @Override
    public void addFormatters(FormatterRegistry registry) {
        //LocalDate 类型
        registry.addFormatter(new LocalDateFormatter());
        //LocalDateTime
        registry.addFormatter(new LocalDateTimeFormatter());
        //Date
        registry.addFormatter(new DateFormatter());
    }*/
}

该实现能支持非RequestBodyRequestBody的参数,且可以用于软件数据的解析,也能用户返回数据的格式化,我认为是最好的一种方式. 其中LocalDateFormatter,LocalDateTimeFormatter,DateFormatter为自定义方法.

DateFormatter.java

public class DateFormatter implements Formatter<Date> {
    //年月日
    String pattern_date ="^[\\d]{4}-[\\d]{1,2}-[\\d]{1,2}$";
    //年月日时分秒
    String pattern_datetime ="^[\\d]{4}-[\\d]{1,2}-[\\d]{1,2}[ ][\\d]{1,2}:[\\d]{1,2}:[\\d]{1,2}$";
    //秒
    String pattern_second ="^[\\d]{10}$";
    //毫秒
    String pattern_millsecond ="^[\\d]{13}$";

    SimpleDateFormat sdf_date =new SimpleDateFormat("yyyy-MM-dd");
    SimpleDateFormat  sdf_datetime =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Date parse(String s, Locale locale) throws ParseException {

        if(StringUtils.isEmpty(s)){
            return null;
        }

        if (Pattern.matches(pattern_date,s)) {
            return sdf_date.parse(s);
        }
        if (Pattern.matches(pattern_datetime,s)) {
            return sdf_datetime.parse(s);
        }
        if (Pattern.matches(pattern_second,s)) {
            return new Date(Long.parseLong(s)*1000);
        }
        if (Pattern.matches(pattern_millsecond,s)) {
            return new Date(Long.parseLong(s));
        }
        throw  new CustomException("未能识别的日期格式");
    }

    @Override
    public String print(Date date, Locale locale) {
        return sdf_datetime.format(date);
    }
}

LocalDateTimeFormatter.java

public class LocalDateTimeFormatter implements Formatter<LocalDateTime> {
    @Override
    public String print(LocalDateTime localDateTime, Locale locale) {
        return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
    @Override
    public LocalDateTime parse(String s, Locale locale) {
        if(StringUtils.isEmpty(s)){
            return null;
        }
        return LocalDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
}

LocalDateFormatter.java

public class LocalDateFormatter implements Formatter<LocalDate> {

    @Override
    public String print(LocalDate localDate, Locale locale) {
        return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }
    @Override
    public LocalDate parse(String s, Locale locale) {
        if(StringUtils.isEmpty(s)){
            return null;
        }
        return LocalDate.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }
}

    作者:ZOUZDC
    链接:https://juejin.cn/post/7028963866063306760
    来源:稀土掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。