spring4.1 请求rest接口406问题解决(转换JSON)[通俗易懂]

前文说明,本来项目使用的是springmvc的模式,然后接口都是使用的是@Controller+@ResponseBody配置json转换的代码是

大家好,又见面了,我是你们的朋友全栈君。

前文说明,本来项目使用的是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>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/127359.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • mysql和oracle的区别有什么_oracle数据库收费

    mysql和oracle的区别有什么_oracle数据库收费MySQL和Oracle的区别一、宏观上:1、Oracle是大型的数据库而Mysql是中小型数据库;Mysql是开源的,Oracle是收费的,且价格昂贵。2、Oracle支持大并发,大访问量,是OLTP的最好的工具。3、安装占用的内存也是有差别,Mysql安装完成之后占用的内存远远小于Oracle所占用的内存,并且Oracle越用所占内存也会变多。二、微观上:1、对于事务的支持Mys…

  • 0xC0000005: 写入位置 0x00000000 时发生访问冲突的解决办法「建议收藏」

    0xC0000005: 写入位置 0x00000000 时发生访问冲突的解决办法「建议收藏」我是新手,其实对这个东西我自己也不是很清楚,当更不可能将有的情况都列举出来,在这里我只是将自己见到的,可能的情况做一个汇总:上面的意识就是你吧值付给了不该赋给的变量,或者说你把值付给了不能付给的变量(或者常量)(1)最简单也最直接的错误可能就是scanf()的问题,我们都知道输入的时候都是scanf(“%格式”,&变量),那么除了字符串(可要&,可不要)之外,所有的输入都需要&,如果你

  • 加密芯片介绍 加密芯片选择(加密IC) 加密芯片原理

    加密芯片介绍 加密芯片选择(加密IC) 加密芯片原理原文链接:https://blog.csdn.net/chengjian815/article/details/107516575前端时间有研究多款加密芯片,加密算法实现,以及激活成功教程可能,也有一些个人的观点,仅供参考;一,加密芯片的来源及工作流程:市面上的加密芯片,基本都是基于某款单片机,使用I2C或SPI等通讯,使用复杂加密算法加密来实现的,流程大致如下:主控芯片生成随机码–>主控芯片给加密芯片发送明文–>加密芯片通过加密算法对明文进行加密生成密文–>

  • 学分查询与统计软件使用说明

    学分查询与统计软件使用说明

  • 教程-经典Delphi教程网

    教程-经典Delphi教程网有理想+志同道合的人+取长补短去协同工作=完美团队一流的项目+三流的执行者=垃圾项目三流的项目+一流的执行者=完美项目自己公司网址:http://www.kaideruixin.icoc.cc/电脑管家误报提交地址:http://bbs.guanjia.qq.com/forum.php?mod=forumdisplay&fid=63本本驱动网站:http://www….

  • 【笔记】嵩天.Python语言程序设计.完成两个简单实例(温度转换和绘图)

    【笔记】嵩天.Python语言程序设计.完成两个简单实例(温度转换和绘图)PyCharm下编写、运行两个实例:温度转换,蟒蛇绘制

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号