spring4.1 请求rest接口406问题解决(转换JSON)
来源:互联网 发布:机械优化设计 编辑:程序博客网 时间:2024/06/05 18:37
前文说明,本来项目使用的是springmvc 的模式,然后接口都是使用的是
@Controller + @ResponseBody
配置json转换的代码是
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> String 转换器 <ref bean="stringHttpMessageConverter" /> JSON 转换器 <ref bean="jsonHttpMessageConverter" /> </list> </property> </bean> <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter" /> <bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" /> </bean> </property> <property name="serializationInclusion"> <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value> </property> </bean> </property> </bean>
后来想直接使用 @RestController 这个注解直接使用
但是接口却一直报 406错误
网上找了很多解决办法,一般都是说的是 JAR缺少,可是我的不缺。spring 是 4.1.4 版本的
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency>
还有说是
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd //这里标准的和版本不一致 4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd " default-lazy-init="true">
我的也是一样的,没问题。
web.xml配置
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>smk_activity</display-name> <!-- webSpringMVC 用户后台页面的配置 --> <!-- actionSpringMVC MVC 配置--> <servlet> <servlet-name>actionSpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/spring/spring-action-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>actionSpringMVC</servlet-name> <url-pattern>*.ext</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>actionSpringMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
spring 配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd " default-lazy-init="true"> <aop:aspectj-autoproxy/> <context:annotation-config /> <context:component-scan base-package="com.smk.activity.action.ext" /> <context:component-scan base-package="com.smk.activity.action.web" /> <context:component-scan base-package="com.cat.sy.action" /> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**/*.ext" /> <bean class="com.cat.interceptor.FHandlerInterceptor" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**/*.do"/> <bean class="com.cat.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors> <bean id="exceptionMessageAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver"> <property name="messageConverters"> <list> <!-- Support JSON --> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> </list> </property> </bean> <mvc:annotation-driven> <mvc:message-converters> <bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" /> </bean> </property> <property name="serializationInclusion"> <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value> </property> </bean> </property> </bean> <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter" /> </mvc:message-converters> </mvc:annotation-driven> <!-- 视图处理器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/page/" /> <property name="suffix" value=".jsp" /> </bean>
但是还是问题依旧的额,所以追踪源码查看问题。
1.追踪请求路径
其他的就不说了,直接看代码
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor
方法 : writeWithMessageConverters
@SuppressWarnings("unchecked") protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException { Class<?> returnValueClass = getReturnValueType(returnValue, returnType); HttpServletRequest servletRequest = inputMessage.getServletRequest(); // 获取支持的文件内型。 List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest); // 获取系统支付的类型 List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass); Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>(); for (MediaType requestedType : requestedMediaTypes) { for (MediaType producibleType : producibleMediaTypes) { //比对是否匹配 if (requestedType.isCompatibleWith(producibleType)) { compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType)); } } } //比对不成功,就抛异常出去 if (compatibleMediaTypes.isEmpty()) { if (returnValue != null) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } return; } List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes); MediaType.sortBySpecificityAndQuality(mediaTypes); MediaType selectedMediaType = null; for (MediaType mediaType : mediaTypes) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> messageConverter : this.messageConverters) { if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { returnValue = this.adviceChain.invoke(returnValue, returnType, selectedMediaType, (Class<HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage); if (returnValue != null) { ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); } } return; } } } if (returnValue != null) { throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); } }
List requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
在org.springframework.web.accept.ContentNegotiationManager
@Override public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException { for (ContentNegotiationStrategy strategy : this.contentNegotiationStrategies) { List<MediaType> mediaTypes = strategy.resolveMediaTypes(webRequest); if (mediaTypes.isEmpty() || mediaTypes.equals(MEDIA_TYPE_ALL)) { continue; } return mediaTypes; } return Collections.emptyList(); }
继续跟踪 List mediaTypes = strategy.resolveMediaTypes(webRequest);
org.springframework.web.accept.AbstractMappingContentNegotiationStrategy
@Override public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException { String key = getMediaTypeKey(webRequest); if (StringUtils.hasText(key)) { //本地缓存中查找KEY key=ext 这里就是我们请求的后缀 //tomcat 本身会自带有一套 MediaType 一般的后缀.html,.json,.js等待会自动转换,但是我们自带的 .ext 是没有的。 MediaType mediaType = lookupMediaType(key); //第一次请求是一定为空 if (mediaType != null) { handleMatch(key, mediaType); return Collections.singletonList(mediaType); } //处理找不到的后缀 mediaType = handleNoMatch(webRequest, key); if (mediaType != null) { addMapping(key, mediaType); return Collections.singletonList(mediaType); } } return Collections.emptyList(); }
继续跟踪
org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy
@Override protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) throws HttpMediaTypeNotAcceptableException { MediaType mediaType = null; if (this.servletContext != null) { String mimeType = this.servletContext.getMimeType("file." + extension); if (StringUtils.hasText(mimeType)) { mediaType = MediaType.parseMediaType(mimeType); } } if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { MediaType superMediaType = super.handleNoMatch(webRequest, extension); if (superMediaType != null) { mediaType = superMediaType; } } return mediaType; }
这里就看到了。SPRING4.1版本的 是根据后缀 来生成 mimeType 。这里生成了一个类型application/vnd.novadigm.ext 然而我并不能查到是什么玩意
这时候,回到AbstractMessageConverterMethodProcessor
看到自带支持的 mimeType 并没有这个类型,所有抛异常出去了。到这里问题就明了了。自定义的.ext 接口,在spring 4.1 以上会抛出这个文件类型不匹配的异常。
现在开始解决。解决的点就在
org.springframework.web.accept.AbstractMappingContentNegotiationStrategy
方法:resolveMediaTypes
@Override public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException { String key = getMediaTypeKey(webRequest); if (StringUtils.hasText(key)) { //第一次缓存会返回空 MediaType mediaType = lookupMediaType(key); if (mediaType != null) { handleMatch(key, mediaType); return Collections.singletonList(mediaType); } //执行这句代码,处理没有匹配的 mediaType = handleNoMatch(webRequest, key); if (mediaType != null) { addMapping(key, mediaType); return Collections.singletonList(mediaType); } } return Collections.emptyList(); }
继续看
org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy
@Override protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) throws HttpMediaTypeNotAcceptableException { MediaType mediaType = null; if (this.servletContext != null) { //从容器中获取 file.ext 的mimeType String mimeType = this.servletContext.getMimeType("file." + extension); if (StringUtils.hasText(mimeType)) { mediaType = MediaType.parseMediaType(mimeType); } } if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { MediaType superMediaType = super.handleNoMatch(webRequest, extension); if (superMediaType != null) { mediaType = superMediaType; } } return mediaType; }
从这里就知道了解决办法了,
String mimeType = this.servletContext.getMimeType(“file.” + extension);
根据file.ext 这个key 来获取mimeType
所以在web.xml 中添加 这个对应的类型就能解决问题
//可以添加多个 <mime-mapping> <extension>ext</extension> <mime-type>application/json</mime-type> </mime-mapping> <mime-mapping> <extension>in</extension> <mime-type>application/json</mime-type> </mime-mapping>
- spring4.1 请求rest接口406问题解决(转换JSON)
- 解决Spring4.0 MVC请求json数据报406错误
- Spring4 转换返回json数据
- 请求rest服务,报网页406问题解决办法
- SpringMVC4.0实现rest风格接口,json格式请求和返回
- Spring4.0 RestController Rest风格请求参数详解
- http请求远程接口获得JSON数据(1) --- 利用HttpURLConnection发送post/get请求
- 最近使用spring4.0的Mvc,json请求时,客户端报错,406 Not Acceptable
- spring4 json 返回406问题
- json-server+mockjs 模拟REST接口
- Httpclient 请求带Authorization(授权)的REST API 返回JSON数据
- easyui+rest服务,ajax请求session过期不跳转问题解决
- springcloud入门系列(2)-Feign、Ribbon实现Rest接口请求和负载均衡
- .net Rest Web Api Controller 返回JSON格式大小写问题解决.
- Json学习总结(3)——Jsonp跨域及Rest接口实现
- Ryu控制器部署及其与Rest API接口调用问题解决
- 将请求转换为json请求
- [CXF REST标准实战系列] 二、Spring4.0 整合 CXF3.0,实现测试接口
- 小白的github初体验
- 【正确姿势】解决EditText软键盘引起的其他布局移动问题
- eclipse 配置Maven问题解决办法:新建maven工程时报错:Could not resolve archetype org.apache.maven.archetypes . 时间 2013
- 安桌Log打印封装类
- Java中File类创建文件
- spring4.1 请求rest接口406问题解决(转换JSON)
- offsetX, clientX, pageX, screenX, layerX,
- cookie的使用方法
- 【NIO引入】BIO、AIO与NIO的区别
- 计算机网络-运输层
- jdbc连接数据库六步走
- JAVA ActiveMQ 详解
- CenTos 7上开端口号
- 一个困扰了我三天的SQL优化问题。(多条数据取最近的数据)