1. 复现错误
今天写完页面按钮排序
接口,如下代码所示:
@ApiOperationSupport(author = "super先生", order = 8)
@ApiOperation(value = "页面按钮排序")
@PostMapping("/sort/pageButton")
public ReturnResult sortPageButton(
@Validated @RequestBody SortPageButtonDto sortPageButtonDto,
BindingResult bindingResult) {
BindingParamUtil.checkParam(bindingResult);
return appPageButtonService.sortPageButton(sortPageButtonDto);
}
使用postman
测试时,却报出如下图错误:
此时,立即查看控制台报出的错误信息,如下代码所示:
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `com.xxx.SortPageButtonDto` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.xxx.SortPageButtonDto` out of START_ARRAY token
at [Source: (PushbackInputStream); line: 1, column: 1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:389)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:342)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:185)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.github.xiaoymin.knife4j.spring.filter.SecurityBasicAuthFilter.doFilter(SecurityBasicAuthFilter.java:87)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
......
由于错误信息较多,我们提取主要的错误信息,即Cannot deserialize instance of 'com.xxx.SortPageButtonDto' out of START_ARRAY token at [Source: (PushbackInputStream); line: 1, column: 1]
2. 分析错误
正赶上最近ChatGPT
比较火,借助它来帮助我分析错误,如下图所示:
ChatGPT
什么都没有返回,即无法理解我的问题,看来,只能通过我自己去排查错误了。
再次看错误信息Cannot deserialize instance of 'com.xxx.SortPageButtonDto' out of START_ARRAY token
,将它简单地翻译成中文就是无法反序列化SortPageButtonDto类的实例。
为什么无法反序列化SortPageButtonDto
类的实例呢?
首先,去排查SortPageButtonDto
类,如下代码所示:
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(description = "页面按钮排序请求类")
public class SortPageButtonDto {
@Size(min = 1)
@ApiModelProperty(name = "sortPageButtons", value = "页面按钮请求参数", required = true)
private List<SortPageButton> sortPageButtons;
@ApiModel(description = "查询条件请求类")
@Data
public class SortPageButton {
@NotNull(message = "id不能为空")
@ApiModelProperty(name = "id", value = "页面按钮id", required = true, example = "1")
private Long id;
@NotNull(message = "排序值不能为空")
@ApiModelProperty(name = "seq", value = "排序值", required = true, example = "1")
private Long seq;
}
}
此SortPageButtonDto
类是用来接收前端传的数组格式的参数,如下代码:
[
{
"id": 1,
"seq": 20
},
{
"id": 2,
"seq": 21
}
]
因而,我在SortPageButtonDto
类中,又定义一个SortPageButton
内部类。而SortPageButton
类作为SortPageButtonDto
类的属性,从而来接收前端传的数组。
这样写并没有问题,但却报出上面的错误,于是到处查找资料。
有资料说,上述json
格式存在问题,需要修改成如下格式:
{
"sortPageButtonDto": [
{
"id": 1,
"seq": 20
},
{
"id": 2,
"seq": 21
}
]
}
修改成如上格式后,再次使用postman
调用页面按钮排序
接口。虽然不报错了,但是后端接不到参数,也就是null
值,如下图所示:
既然上述方法行不通,那就使用如下方法解决。
3. 解决问题
尝试修改SortPageButtonDto
类,删除SortPageButton
内部类,如下代码所示:
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(description = "页面按钮排序请求类")
public class SortPageButtonDto {
@NotNull(message = "id不能为空")
@ApiModelProperty(name = "id", value = "页面按钮id", required = true, example = "1")
private Long id;
@NotNull(message = "排序值不能为空")
@ApiModelProperty(name = "seq", value = "排序值", required = true, example = "1")
private Long seq;
}
同时,修改上文起始/sort/pageButton
的接口代码,如下所示:
@ApiOperationSupport(author = "super先生", order = 8)
@ApiOperation(value = "页面按钮排序")
@PostMapping("/sort/pageButton")
public ReturnResult sortPageButton(
@Validated @RequestBody List<SortPageButtonDto> sortPageButtonDto,
BindingResult bindingResult) {
BindingParamUtil.checkParam(bindingResult);
return appPageButtonService.sortPageButton(sortPageButtonDto);
}
此时,重新启动项目,并再次使用postman
测试,仍旧报出同样的错误,如下图所示:
将上图中的json
格式的请求参数,恢复成起始请求的json
格式,再次向后端发送请求,如下图所示:
从上图可以清晰地看到,如上修改后,后端可成功地接收到前端传的数组参数。
经过反复尝试之后,终于解决了这个错误,如释重负般地关上电脑,下班回家。
4. 文末总结
出现这种错误,一般是后端使用集合或数组
来接收前端的参数,如下代码所示:
//集合接参
@Size(min = 1)
@ApiModelProperty(name = "sortPageButtons", value = "页面按钮请求参数", required = true)
private List<SortPageButton> sortPageButtons;
//数组接参
@Size(min = 1)
@ApiModelProperty(name = "sortPageButtons", value = "页面按钮请求参数", required = true)
private SortPageButton[] sortPageButtons;
但由于传参不规范,导致Jackson
解析数据时,无法拿到实际的参数值,从而报出上述的错误。
因而,在解决该错误时,前后端需要配合修改。不然后端修改了,前端没有修改,依然会报出上述错误。