最近使用mybatis-plus的过程中,最近遇到一个让我比较无语的问题
本来条件查询都是没有问题的,但就在我点完❌,清空已选择的时间后,出现了错误!
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'accident' on field 'startTime': rejected value [null]; codes [typeMismatch.accident.startTime,typeMismatch.startTime,typeMismatch.java.time.LocalDateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [accident.startTime,startTime]; arguments []; default message [startTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'startTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat @com.fasterxml.jackson.annotation.JsonFormat java.time.LocalDateTime] for value 'null'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [null]]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:164)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
Failed to convert property value of type ‘java.lang.String’ to required type ‘java.time.LocalDateTime’ for property 'startTime’
经过我的认真排查,我发现:
原来在我点完❌后,前端给我传过来了个“null”!
不是空!是一个String型的null!
所以产生了类型转换异常!
可能大家觉得类型转化一下不就可以了吗?
entity层:
/**
* 事故开始时间
*/
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private LocalDateTime startTime;
/**
* 事故结束时间
*/
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private LocalDateTime endTime;
Controller层
@GetMapping("/accident")
public ObjectResponseResult listAccident(Page<Accident> page, Accident accident) {
return new ObjectResponseResult(CommonCode.SUCCESS, accidentService.page(page, Wrappers.<Accident>lambdaQuery()
.like(nonNull(accident.getName()),Accident::getName,accident.getName())
.like(nonNull(accident.getType()),Accident::getType,accident.getType())
.like(nonNull(accident.getLevel()),Accident::getLevel,accident.getLevel())
.between(nonNull(accident.getStartTime()),Accident::getStartTime,accident.getStartTime(),accident.getEndTime())
));
}
由于数据库中的类型定义的是timestamp,所以我一早就将实体类定义成了LocalDateTime(以前我用的Stirng)
而且Controller层接收的时候是整个实体类接收的,因此,这个报错是在未进入我的Controller就产生的,是因为实体类类型( LocalDateTime)与传参类型(String)不匹配造成的,所以,我也没有办法在Controller层进行类型转换。
而且由于这张表与其他表之间关联较大,我也不能修改数据库中或实体类中的事件类型。
首先
我先复制这个实体类(Accident),将其中的时间类型变成了Stirng,新实体类名为 AccidentExample
然后
我用AccidentExample作为参数接收前端数据,并进行了判断转换,将String类型的null变成了null,
然后使用 BeanUtils.copyProperties,将accidentExample接收到的参数赋值给accident
这样就避免了报错的产生。
@GetMapping("/accident")
public ObjectResponseResult listAccident(Page<Accident> page, AccidentExample accidentExample) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
Accident accident = new Accident();
if("null".equals(accidentExample.getStartTime()) ||
"null".equals(accidentExample.getEndTime())){
BeanUtils.copyProperties(accidentExample,accident);
accident.setEndTime(null);
accident.setStartTime(null);
}else {
LocalDateTime start = LocalDateTime.parse(accidentExample.getStartTime(),df);
LocalDateTime end = LocalDateTime.parse(accidentExample.getEndTime(),df);
System.out.println("String类型的时间转成LocalDateTime:"+start);
BeanUtils.copyProperties(accidentExample,accident);
accident.setStartTime(start);
accident.setEndTime(end);
}
return new ObjectResponseResult(CommonCode.SUCCESS, accidentService.page(page, Wrappers.<Accident>lambdaQuery()
.like(nonNull(accident.getName()),Accident::getName,accident.getName())
.like(nonNull(accident.getType()),Accident::getType,accident.getType())
.like(nonNull(accident.getLevel()),Accident::getLevel,accident.getLevel())
.between(nonNull(accident.getStartTime()),Accident::getStartTime,accident.getStartTime(),accident.getEndTime())
));
}
虽然问题解决了,但是感觉这个方法比较笨,欢迎大家指导!
另外,如果有后端朋友遇到这样的问题,可以直接给前端提issue,其实这个时间选择器清空后传值“null”的问题不算是后端的问题,主要是新来的前端同事不会处理,我在后端帮忙处理了一下,如果有前端朋友看到这篇文章,亲参考这位作者的文章 https://blog.csdn.net/lixinhua_man/article/details/109257316,有详细的处理过程。
如有转载,请标明出处,谢谢!