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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 求平方根C++

    求平方根C++

    2021年11月14日
    42
  • origin2018多因子组柱状图_对比柱状图怎么做

    origin2018多因子组柱状图_对比柱状图怎么做如图1,数据包含两个分组列(X轴),A列表示小分组,B列表示大分组,C/D/E三列表示三个因子列,作为Y轴。同样的方式,可以在E轴后侧依次添加数据增加四,五,六等多个因子。图1数据输入格式按照上图方式输入数据后,选中数据Origin多因子柱状图教程(二)origin图表坐标轴下的分组表格是怎么添加的?…

    2022年9月29日
    0
  • Android开发之《Android应用开发揭秘》UI事件汇总

    Android开发之《Android应用开发揭秘》UI事件汇总Android开发之《Android应用开发揭秘》UI事件汇总/* * Android开发之《Android应用开发揭秘》UI事件汇总 * 北京Android俱乐部群:167839253 * Createdon:2011-12-01 * Author:blueeagle * Email:liujiaxiang@gmail.com */思想跑毛是很可

    2022年4月28日
    58
  • 利用perl一键生成符合LEFse差异分析的Table表

    利用perl一键生成符合LEFse差异分析的Table表利用perl一键生成符合在线LEFse差异分析的Table表LEfSe分析的在线+本地运行的详细教程参考刘尧博客基于Picrust2进行宏基因预测后,我们往往需要对数据进行可视化话,其中LEFse就是非常不错的选择,这里通过perl实现对表的格式化。LEFse–Galaxy平台:http://huttenhower.sph.harvard.edu/galaxyusestrict;usewarnings;my$mapFile=$ARGV[0];my$tableFile=$ARG

    2022年6月3日
    25
  • 数据库设计 ER图

    数据库设计 ER图一、ER图简介ER图,简单来说,E是实体,实体有一组属性;R是关系。找打系统中的实体以及实体关系就可以绘制出ER图了。例如,下图是网上找到的ER图,矩形的是实体,椭圆是属性,实体何实体时间的关系用菱形,关系也有熟悉,例如,学生选修课程,有成绩属性,当然如果系统需要,也可以记录选修的时间等属性信息。认真看下,你会发现ER图理解起来还是比较容易的二、ER图绘制常见问题但是真的落实到自己绘制,很多同学就会遇到困难。下面我们通过反例来学习ER图1.反例1区分功能和关系.

    2022年6月21日
    37
  • 公安大数据平台应用与公安大数据建模「建议收藏」

    公安大数据平台应用与公安大数据建模「建议收藏」基于沃达德大数据平台,通过对海量数据采集、处理、存储、分析和数据挖掘,根据数据的特性,采用合适的可视化方式,将数据直观地展现出来,以帮助人们认识数据、理解数据,同时找出包含在海量数据中的规律或者信息。公安大数据主要由公安业务数据、地理信息数据、互联网数据等组成。通过沃达德大数据平台,对公安大数据进行信息提取、分析、数据挖掘和可视化,用于警情时空分布和时空演化、犯罪事件热点分析、关注对象的轨迹跟踪等多个公安业务领域,全面提升公安机关的整体工作效率。沃达德公安大数据平台,利用接警数据进行警情密度分析,以大数

    2022年6月6日
    199

发表回复

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

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