前端传递不同格式时间后端统一转化

这几天遇到了一个问题,就是我后端再接受查询条件的时候,关于条件我都是用 TimeQuery 来接受的,但是因为前端的比较混乱,就导致了有些传参是年月日,有些传参是年月日时分秒格式,就导致我后端一直出转化异常的错误,当时就是叫前端传参都用下统一的格式

package com.state.time;
@Data
public class  TimeQuery implements Serializable {

//    @DateTimeFormat(pattern = DatePattern.NORM_DATE_PATTERN)
    private Date beginTime;

//    @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
    private Date endTime;
}

后来空下来了之后就在想有没有什么方法能够解决这块的问题


1:我一开始就是想到了aop ,但是后来在写的过程中就发现不对劲了,我就想到的是平时都用aop来打印controller层的入参,这就说明aop拦截的时候那个前端的传参早就已经转化了,果然在实验的过程中就发现这样不行的

2:面对着这种没有思路的问题,我就试着能不能通过 通义灵码的插件看看有没有方法

首先就是提问:

image-20240518192836579

他给的回答是

1. 请求映射(@RequestMapping)
2. 参数绑定
3. 消息转换器(HttpMessageConverter)

就感觉这个参数绑定是我想要的,因为我想的是在前端传递了yyyy-MM-dd ,要在后端赋值到Date上,总是和参数绑定有关的

于是就

image-20240518193236233

它提到了一点

image-20240518194239445

这个RequestBodyAdviceAdapter听起来就像是@RequestBody使用的,而我想要的是url请求

于是就开始尝试 HttpMessageConverter

image-20240518201251528

在这过程中我发现

通过url 传参
@DateTimeFormat(pattern = "yyyy-MM-dd") 
如果里面的格式是 yyyy-MM-dd 那么他能够兼容 传递的是年月日或者年月日时分秒  但是 他会把时分秒 给忽略掉
如果格式是 yyyy-MM-dd HH:mm:ss 那么只能传递的格式必须是年月日时分秒  否则就会出错

发现无法满足要求了接着提问

image-20240518200230285

再描述下需求

image-20240518200308428

这边已经成功了。按照提示写了代码

package com.state.time;
/**
 * @author zhang
 * @date 2024-05-18 18:40
 **/
import org.springframework.core.convert.converter.Converter;
import java.util.Date;
public class FlexibleDateTimeConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        return TimeQuery.parseDateTime(source);
    }
}
package com.state.time;
import com.state.time.convert.FlexibleDateTimeConverter;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
 * @author zhang
 * @date 2024-05-18 14:04
 **/
@Component
public class MyWebConfigur implements WebMvcConfigurer  {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //加入头部,第一个被解析
        converters.add(0, new MyHttpMessageConverter());
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new FlexibleDateTimeConverter());
    }
}

但是他有瑕疵,就是convert 是属于全局的转化器,就是别的地方一旦遇到了Date 他也会进行转化,这就很难控制,毕竟会对别的地方产生影响

于是再接着问:

image-20240518200429148

在然后就是给了解决的方法 @InitBinder 在想要转化的controller类文件里面加入这个

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

下面是代码:

package com.state.controller;
import com.state.time.TimeQuery;
import com.state.time.convert.FlexibleDateTimeEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import java.util.Date;

/**
 * @author zhang
 * @date 2024-03-13 10:46
 **/
@RestController
@RequestMapping("test")
public class TestController {
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Date.class, new FlexibleDateTimeEditor());
    }
    @GetMapping
    public Object test(TimeQuery timeQuery){

        System.out.println(timeQuery);
        return timeQuery;
    }
}
package com.state.time.convert;

import java.beans.PropertyEditorSupport;
/**
 * @author zhang
 * @date 2024-05-18 19:04
 **/
public class FlexibleDateTimeEditor extends PropertyEditorSupport {

    private final FlexibleDateTimeConverter converter = new FlexibleDateTimeConverter();

    @Override
    public void setAsText(String text) {
        setValue(converter.convert(text));
    }
}
package com.state.time.convert;

/**
 * @author zhang
 * @date 2024-05-18 18:40
 **/
import com.state.time.TimeQuery;
import lombok.Data;
import org.springframework.core.convert.converter.Converter;
import java.util.Date;


@Data
public class FlexibleDateTimeConverter implements Converter<String, Date> {

    @Override
    public Date convert(String source) {
        return TimeQuery.parseDateTime(source);
    }
}
package com.state.time;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
/**
 * 分页查询实体类
 *
 * @author zhang
 */

@Data
public class  TimeQuery implements Serializable {

    @DateTimeFormat(pattern = DatePattern.NORM_DATE_PATTERN)
    private Date beginTime;

//    @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
//    @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
    private Date endTime;



    private static final List<DateTimeFormatter> FORMATTERS = Arrays.asList(
            DateTimeFormatter.ofPattern("yyyy-MM-dd"), // 年月日
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") // 年月日 时分秒
    );
    public static Date parseDateTime(String input) {
        return FORMATTERS.stream()
                .map(formatter -> {
                    try {
                        return DateUtil.parse(input, formatter);
                    } catch (DateTimeParseException e) {
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Invalid date/time format"));
    }

}

顺便问问

image-20240518201538189

@InitBinder 是 Spring MVC 框架中的一个注解,用于在控制器类 (@Controller@RestController) 中声明一个方法,该方法会在每次控制器处理请求之前执行,用于初始化数据绑定过程。这个初始化方法通常用于设置数据绑定的特定行为,比如注册自定义的属性编辑器(PropertyEditor)或格式化器(Formatter),以及设置数据绑定的约束和验证规则。  @InitBinder 注解的方法可以设置一个或多个参数,这些参数通常使用 WebDataBinder 类型,它提供了配置数据绑定行为的API。例如,你可以使用 WebDataBinder 注册自定义的转换器或编辑器,以便在将请求参数绑定到控制器方法的参数时使用这些转换器。

给的例子

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(LocalDateTime.class, new FlexibleDateTimeEditor());
    }

    // 其他控制器方法...
}

在这个例子中,initBinder 方法会在每个控制器方法执行之前调用,FlexibleDateTimeEditor 负责将请求参数转换为 LocalDateTime 类型。 请注意,@InitBinder 方法只对当前控制器类有效,不会影响其他控制器类。如果你有多个控制器需要同样的初始化行为,你可以创建一个基类控制器,然后在这些控制器中继承并重用 @InitBinder 方法,或者使用 @ControllerAdvice 注解来创建一个全局的初始化逻辑,但后者通常用于更广泛的用途,例如全局异常处理或模型属性的初始化。

posted @   冷扑星  阅读(374)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示