LocalDateTime与前端字符串时间数据交互问题

环境:JDK17 / SpringBoot 3.2.4

  • 注解方式

在接收参数上加注解: @JsonFormat(timezone = “GMT+8”, pattern = “yyyy-MM-dd HH:mm:ss”)

在返回参数上加注解:@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”)

  • 全局配置方式
  • GET请求,LocalDateTime接收前端字符串类型时间数据解析

自定义Converter

public class LocalDateTimeConverter implements Converter<String, LocalDateTime> {

   private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
   
   @Override
   public LocalDateTime convert(String source) {
      return LocalDateTime.parse(source,formatter);
   }
}

自定义Formatter

public class LocalDateTimeFormatter implements Formatter<LocalDateTime> {

   private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
   
   @Override
    public LocalDateTime parse(String text, Locale locale) throws ParseException {
        return LocalDateTime.parse(text, formatter);
    }

    @Override
    public String print(LocalDateTime object, Locale locale) {
        return DateUtils.formatLocalDateTime(object,"yyyy-MM-dd'T'HH:mm:ss");
    }
}

自定义Mvc配置,覆写addFormatters方法,注册Formatter或Converter
注:在自定义LocalDateTimeConverter 和LocalDateTimeFormatter时不要直接在MvcConfiguration中写内部类否则不生效。当然也可以直接实现接口。

@SpringBootConfiguration
public class MvcConfiguration implements WebMvcConfigurer {
   
    @Override
    public void addFormatters(FormatterRegistry registry) {
        //方法1:        
        registry.addFormatter(new LocalDateTimeFormatter());
        //方法2:
        registry.addConverter(new LocalDateTimeConverter());
        //方法3:
        registry.addFormatter(new Formatter<LocalDateTime>() {

            @Override
            public String print(LocalDateTime object, Locale locale) {
                return //LocalDateTime转String ;
            }

            @Override
            public LocalDateTime parse(String text, Locale locale) {
                return //String转LocalDateTime;
            }
        });

    }
}

controller接收参数

@GetMapping(value="/")
public Response<?> acceptTime(TimeDTO params){
  //用对象接收,对象中的部分属性类型为LocalDateTime
}

@GetMapping(value="/")
public Response<?> acceptTime(@RequestParam LocalDateTime time){
}

其它方法:在Mvc配置中注册自定义的参数解析器
目前测试Get方法用实体对象接收没问题,有个弊端就是需要所有的参数都自己解析,只解析部分另一部分有默认解析器解析还未找到方法。

@SpringBootConfiguration
public class MvcConfiguration implements WebMvcConfigurer {
   
  @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new HandlerMethodArgumentResolver() {

            @Override
            public boolean supportsParameter(MethodParameter parameter) {
                //这里定义需要解析的类型,注:parameter.getParameterType()获取到的是controller中方法上参数的类型,
                //如果是用@RequestParam或@ModelAttribute注解的则会用mvc默认的解析器
                return true;
            }

            @Override
            public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
                Object object = parameter.getParameterType().getDeclaredConstructor().newInstance();
                Map<String, String[]> params = webRequest.getParameterMap();

                for (Field field : parameter.getParameterType().getDeclaredFields()) {
                    String fieldName = field.getName();
                    if (!params.containsKey(fieldName)) {
                        //只对有值的参数做解析
                        continue;
                    }
                    field.setAccessible(true);
                    //解析LocalDateTime字段
                    if (LocalDateTime.class.isAssignableFrom(field.getType())) {
                        String fieldValue = params.get(fieldName)[0];
                        LocalDateTime dateTime = LocalDateTime.parse(fieldValue);
                        field.set(object, dateTime);
                    }
                    //解析其它类型的参数...
                }
                return object;
            }
        });
    }
}
  • POST请求,时间参数为Body中的Json数据,LocalDateTime接收并解析以及反回LocalDateTime数据问题

自定义Bean jsonObjectMapper 对LocalDateTime做序列化和返序列化
默认反序列化也就是处理接收的LocalDateTime时间格式为:yyyy-MM-dd’T’HH:mm:ss.SSSX
默认的序列化也就是后端返回前端LocalDateTime的时间格式为:yyyy-MM-dd’T’HH:mm:ss
JavaTimeModule继承SimpleModule,注册多个SimpleModule会被最后一个覆盖。

  @Bean
    public ObjectMapper jsonObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        //设置时间类型的不以时间戳序列化
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
          //忽略前端多传的参数
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        JavaTimeModule timeModule = new JavaTimeModule();
        //LocalDateTime序列化,并默认返回前端的字符串格式
        timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        //LocalDateTime反序列化
        timeModule.addDeserializer(LocalDateTime.class, new StdDeserializer<>(LocalDateTime.class) {
            @Override
            public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
                String text = jsonParser.getText();
                //这里提供一个方法用于适配几种格式的字符串转LocalDateTime
                return DateUtils.formatStringToLocalDate(text);
            }
        });
        mapper.registerModule(timeModule);
        return mapper;
    }

formatStringToLocalDate(String text)

public static LocalDateTime formatStringToLocalDate(String time) {
        //0[1-9]表示01到09,1[0-2]表示10到12,中间的|表示或,[12][0-9]表示10到29,3[01]表示30和31
        String regexToDay = "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$";
        if (time.matches(regexToDay)) {
            return formatStringToLocalDate(time, "yyyy-MM-dd");
        }
        //\s+:匹配一个或多个空白字符(空格、制表符等)
        String regexToSecond = "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])\\s+(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
        if (time.matches(regexToSecond)) {
            return formatStringToLocalDate(time, "yyyy-MM-dd HH:mm:ss");
        }
        
        String regexStandard = "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\.\\d{3}(Z)$";
        if (time.matches(regexStandard)) {
            return formatStringToLocalDate(time, "yyyy-MM-dd HH:mm:ss.SSSX");
        }
        throw new BusinessException("不支持当前日期时间格式");
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值