1遣蚀、需求
通過POST接口傳List<Object> 類型的參數(shù),由于項(xiàng)目比較老誊册,使用的ssh框架,spring的版本是4.0.9暖璧,這種需求在springboot里面很好實(shí)現(xiàn)案怯,可是在老版本的ssh里面就遇到了問題。
2漆撞、問題排查
1殴泰、首先接口信息如下:
@RequestMapping(value = "/receiveHiddens", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ApiResultJson receiveHiddens(@RequestBody List<TSBaseUser> users){
ApiResultJson resultJson = new ApiResultJson();
System.out.println(users);
return resultJson;
}
2、postman測試
測試報(bào)錯(cuò)結(jié)果如下
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.readWithMessageConverters(HandlerMethodInvoker.java:645)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestBody(HandlerMethodInvoker.java:604)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:353)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:170)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.jeecgframework.core.interceptors.CrosFilter.doFilter(CrosFilter.java:31)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.jeecgframework.core.aop.GZipFilter.doFilter(GZipFilter.java:88)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:140)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:150)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:409)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
3浮驳、debug問題查找
由于是ssh項(xiàng)目悍汛,接口肯定會走DispatchServlet里面的doDispatch()方法,在這個(gè)方法里面一直走下去至会。
在HandlerMethodInvoker.readWithMessageConverters 方法里面報(bào)錯(cuò)了离咐。具體代碼如下。
在messageConverter.canRead(paramType, contentType)方法里面,繼續(xù)往下找
List<MediaType> allSupportedMediaTypes = new ArrayList();
if (this.messageConverters != null) {
HttpMessageConverter[] var6 = this.messageConverters;
int var7 = var6.length;
for(int var8 = 0; var8 < var7; ++var8) {
HttpMessageConverter<?> messageConverter = var6[var8];
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
if (messageConverter.canRead(paramType, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType + "\" using [" + messageConverter + "]");
}
return messageConverter.read(paramType, inputMessage);
}
}
}
public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
JavaType javaType = this.getJavaType(type, contextClass);
return this.objectMapper.canDeserialize(javaType) && this.canRead(mediaType);
}
//上面的 this.canRead(mediaType)是在AbstractHttpMessageConverter里面canRead()方法
protected boolean canRead(MediaType mediaType) {
if (mediaType == null) {
return true;
} else {
Iterator var2 = this.getSupportedMediaTypes().iterator();
MediaType supportedMediaType;
do {
//就是在這里宵蛀,getSupportedMediaTypes()方法里沒有找到Content type為 'application/json;charset=UTF-8'的昆著,所以報(bào)錯(cuò)
if (!var2.hasNext()) {
return false;
}
supportedMediaType = (MediaType)var2.next();
} while(!supportedMediaType.includes(mediaType));
return true;
}
}
3、分析過程
Content type為 'application/json;charset=UTF-8'是最常見的類型术陶,其它接口都正常凑懂,為什么就這個(gè)接口不行,后來查很多 blog發(fā)現(xiàn)是因?yàn)闆]有配置解析List<Object>類型參數(shù)的解析器梧宫,所以HandlerMethodInvoker無法解析方法參數(shù)接谨,最后找到了解決方法,在xml配置文件里面添加如下配置塘匣,里面重要的就是Jaxb2RootElementHttpMessageConverter和MappingJackson2HttpMessageConverter兩個(gè)messageConverter脓豪,這樣才能正常解析List類型參數(shù)。
<!-- 定義注解驅(qū)動(dòng)Controller方法處理適配器 ,注:該適配器必須聲明在<mvc:annotation-driven />之前忌卤,否則不能正常處理參數(shù)類型的轉(zhuǎn)換 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
<!-- 會自動(dòng)注冊RequestMappingHandlerMapping與RequestMappingHandlerAdapter
兩個(gè)bean,是spring MVC為@Controllers分發(fā)請求所必須的扫夜。 并提供了:數(shù)據(jù)綁定支持,@NumberFormatannotation支持驰徊,@DateTimeFormat支持笤闯,@Valid支持,讀寫XML的支持(JAXB)辣垒,讀寫JSON的支持(Jackson) -->
<mvc:annotation-driven />
4望侈、postman測試結(jié)果