springmvc4.3.7中使用RequestBody,传入json参数时,得到错误415 Unsupported Media Type

在新建一个maven的项目的时候,当时并非springboot项目,是通过xml来配置的项目。在项目中DispatcherServlet的配置文件中配置了annotation-driven的,

<?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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <description>spring Configuration</description>
    
    <mvc:annotation-driven />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <context:component-scan base-package="org.xuan.springmvc.controller"
        use-default-filters="false"><!-- base-package 如果多个,用“,”分隔 -->
        <context:include-filter type="annotation"
            expression="org.springframework.stereotype.Controller" /> <!-- 子标签是用来添加扫描注解的 -->
    </context:component-scan>
</beans>

后台接口定义方式:

    @RequestMapping("testrequest")
    @ResponseBody
    public String testRequest(@RequestBody User user) throws Exception {
        System.out.println(user);
        return "OK";
    }

User.java定义

package org.xuan.springmvc.model;


public class User {

    private int id;
    private String username;
    
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

前台请求方式:

    $("#test").click(function () {
        alert("aa")
        var param={
            id:1,
            username:"test"
        };
        $.ajax({
            url : "/testrequest",
            type : "POST",
            dataType : "json",
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(param),
            success:function (data) {
                alert(data)
            }
        });
    })

结果发现不能请求成功:

发现请求类型不正确。

跟踪源码到AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters发现消息装换器messageConverters没有列出解析json格式的解析器:

查询文档https://docs.spring.io/spring-framework/docs/4.3.7.RELEASE/spring-framework-reference/html/mvc.html看默认的消息转换器有哪些

To enable MVC Java config add the annotation @EnableWebMvc to one of your @Configuration classes:

@Configuration
@EnableWebMvc
public class WebConfig {

}

To achieve the same in XML use the mvc:annotation-driven element in your DispatcherServlet context (or in your root context if you have no DispatcherServlet context defined):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven/>

</beans>

The above registers a RequestMappingHandlerMapping, a RequestMappingHandlerAdapter, and an ExceptionHandlerExceptionResolver (among others) in support of processing requests with annotated controller methods using annotations such as @RequestMapping@ExceptionHandler, and others.

It also enables the following:

  1. Spring 3 style type conversion through a ConversionService instance in addition to the JavaBeans PropertyEditors used for Data Binding.
  2. Support for formatting Number fields using the @NumberFormat annotation through the ConversionService.
  3. Support for formatting DateCalendarLong, and Joda Time fields using the @DateTimeFormat annotation.
  4. Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath.
  5. HttpMessageConverter support for @RequestBody method parameters and @ResponseBody method return values from @RequestMapping or @ExceptionHandler methods.

    This is the complete list of HttpMessageConverters set up by mvc:annotation-driven:

    1. ByteArrayHttpMessageConverter converts byte arrays.
    2. StringHttpMessageConverter converts strings.
    3. ResourceHttpMessageConverter converts to/from org.springframework.core.io.Resource for all media types.
    4. SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.
    5. FormHttpMessageConverter converts form data to/from a MultiValueMap<String, String>.
    6. Jaxb2RootElementHttpMessageConverter converts Java objects to/from XML — added if JAXB2 is present and Jackson 2 XML extension is not present on the classpath.
    7. MappingJackson2HttpMessageConverter converts to/from JSON — added if Jackson 2 is present on the classpath.
    8. MappingJackson2XmlHttpMessageConverter converts to/from XML — added if Jackson 2 XML extension is present on the classpath.
    9. AtomFeedHttpMessageConverter converts Atom feeds — added if Rome is present on the classpath.
    10. RssChannelHttpMessageConverter converts RSS feeds — added if Rome is present on the classpath.

原来使用MappingJackson2HttpMessageConverter 需要引入相关的jar

然后引入包:

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.8.5</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.5</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.5</version>
        </dependency>

在调一次接口发现增加了json解析:

最后调用成功。

 原因是在创建RequestMappingHandlerAdapter的时候加载messageConverters

    public RequestMappingHandlerAdapter() {
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
        stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316

        this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(stringHttpMessageConverter);
        this.messageConverters.add(new SourceHttpMessageConverter<Source>());
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    }

在AllEncompassingFormHttpMessageConverter中会判断是否jvm是否加载了类com.fasterxml.jackson.databind.ObjectMapper和com.fasterxml.jackson.core.JsonGenerator,只有加载了才会创建

public AllEncompassingFormHttpMessageConverter() {
        addPartConverter(new SourceHttpMessageConverter<Source>());

        if (jaxb2Present && !jackson2XmlPresent) {
            addPartConverter(new Jaxb2RootElementHttpMessageConverter());
        }

        if (jackson2Present) {
            addPartConverter(new MappingJackson2HttpMessageConverter());
        }
        else if (gsonPresent) {
            addPartConverter(new GsonHttpMessageConverter());
        }

        if (jackson2XmlPresent) {
            addPartConverter(new MappingJackson2XmlHttpMessageConverter());
        }
    }

 

备注:

 解析传入的参数是:AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters

 解析返回值是:AbstractMessageConverterMethodProcessor#writeWithMessageConverters
原文地址:https://www.cnblogs.com/grasp/p/11075884.html