这几天遇到了一个问题,就是我后端再接受查询条件的时候,关于条件我都是用 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:面对着这种没有思路的问题,我就试着能不能通过 通义灵码的插件看看有没有方法
首先就是提问:
他给的回答是
1. 请求映射(@RequestMapping)
2. 参数绑定
3. 消息转换器(HttpMessageConverter)
就感觉这个参数绑定是我想要的,因为我想的是在前端传递了yyyy-MM-dd ,要在后端赋值到Date上,总是和参数绑定有关的
于是就
它提到了一点
这个RequestBodyAdviceAdapter听起来就像是@RequestBody使用的,而我想要的是url请求
于是就开始尝试 HttpMessageConverter
在这过程中我发现
通过url 传参
@DateTimeFormat(pattern = "yyyy-MM-dd")
如果里面的格式是 yyyy-MM-dd 那么他能够兼容 传递的是年月日或者年月日时分秒 但是 他会把时分秒 给忽略掉
如果格式是 yyyy-MM-dd HH:mm:ss 那么只能传递的格式必须是年月日时分秒 否则就会出错
发现无法满足要求了接着提问
再描述下需求
这边已经成功了。按照提示写了代码
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 他也会进行转化,这就很难控制,毕竟会对别的地方产生影响
于是再接着问:
在然后就是给了解决的方法 @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"));
}
}
顺便问问
@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 注解来创建一个全局的初始化逻辑,但后者通常用于更广泛的用途,例如全局异常处理或模型属性的初始化。
标签:前端,time,springframework,传递,state,import,Date,格式,public From: https://www.cnblogs.com/zz0203/p/18199735