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

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

(0)
上一篇 2022年4月9日 下午4:20
下一篇 2022年4月9日 下午4:40


相关推荐

  • 写了很久,这是一份最适合/贴切普通大众/科班/非科班的『学习路线』

    写了很久,这是一份最适合/贴切普通大众/科班/非科班的『学习路线』说实话,对于学习路线这种文章我一般是不写的,大家看我的文章也知道,我是很少写建议别人怎么样怎么样的文章,更多的是,写自己的真实经历,然后供大家去参考,这样子,我内心也比较踏实,也不怕误导他人。但是,最近好多人问我学习路线,而且很多大一大二的,说自己很迷茫,看到我那篇普普通通,我的三年大学之后很受激励,觉得自己也能行,(是的,别太浪,你一定能行)希望我能给他个学习路线,说…

    2022年7月16日
    23
  • 单隐层前馈神经网络网络构造_前馈型神经网络常用于

    单隐层前馈神经网络网络构造_前馈型神经网络常用于这篇博客主要介绍神经网络基础,单隐层前馈神经网络与反向传播算法。神经网络故名思议是由人的神经系统启发而得来的一种模型。神经网络可以用来做分类和回归等任务,其具有很好的非线性拟合能力。接下来我们就来详细介绍一下但隐层前馈神经网络。首先我们来看一下神经元的数学模型,如下图所示:可以看到为输入信号,而神经元最终输出为,由此我们可以看到,单个神经元是多输入单输出的。但是从上图我们可以看到,…

    2025年6月19日
    4
  • yum 安装vsftp_yum安装vsftp「建议收藏」

    yum 安装vsftp_yum安装vsftp「建议收藏」1、安装vsftp,本文采用yum安装:#yuminstallvsftpd2、安装后运行:#servicevsftpdrestartShuttingdownvsftpd:[OK]Startingvsftpdforvsftpd:[OK]3、新增加系统用户ftptest:#useradd-d/var/www-s/sbin/nologinftptest//增加新用…

    2025年12月4日
    7
  • 检测Chrome headless的技巧

    检测Chrome headless的技巧原文链接 https antoinevaste com bot 20detection 2018 01 17 detect chrome headless v2 html 更新 我创建了一个库 可以通过浏览器指纹来检测脚本和爬虫 这个库仍然在开发过程中 不过你可以开始尝试使用了 代码已经在 Github 上了 目前 我在测试一个新的检测方法 欢迎来进行挑战 并给出反馈 之前我写了一个博

    2026年3月17日
    2
  • JWPlayer_nplayer浏览器

    JWPlayer_nplayer浏览器网盘:https://pan.baidu.com/s/1mmtppZSFOni5tLI2TJWKrw<scripttype=”text/javascript”>varthePlayer;//保存当前播放器以便操作$(function(){thePlayer=jwplayer(‘container’).setu…

    2022年10月8日
    4
  • gitHub新手教程

    gitHub新手教程gitHub新手教程

    2022年4月24日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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