mvc:annotation-driven 不能解决 406 错误

Posted

技术标签:

【中文标题】mvc:annotation-driven 不能解决 406 错误【英文标题】:mvc:annotation-driven doesnt solve 406 error 【发布时间】:2018-02-15 12:29:15 【问题描述】:

我正在尝试为 Spring 编写一个 Junit 测试用例,经过大量阅读后,我得到了一个返回 text/plain 的方法的一切工作。当我尝试返回 application/json 时遇到了问题。

关于 SO 的共识似乎是:使用mvc:annotation-driven。我试过这个(通过根据here创建下面显示的spring-web-servlet.xml。但这并没有解决我的问题。有人知道我还在做错什么吗?

spring-web-servlet.xml(在 WEB-INF 文件夹中)

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <mvc:resources mapping="/resources/**" location="/resources/" />

    <mvc:annotation-driven />

</beans>

有问题的方法(在 HelloService 类中)

@GET
@RequestMapping("/json2")
@Produces("application/json")
@ResponseBody
public Object getUserInfoJSON(@RequestParam(value="p",defaultValue="0") Integer userId)
    try (Connection conn = conn()) 
        String query = "SELECT * FROM pulse.customer WHERE userId = ?";
        PreparedStatement preparedStmt = conn.prepareStatement(query);
        preparedStmt.setInt(1, userId);
        ResultSet rs=preparedStmt.executeQuery();
        if(rs.next())
            return Json.createObjectBuilder().add("login name", rs.getString("loginName"));

            return Json.createObjectBuilder().add("login name", "shit broke yo!!!");
    
    catch(SQLException s)
        return "sql exception:"+s.toString();
    
    catch (NoResultException nre) 
        //throw new UserNotFoundException(userId);
        return "UserNotFoundException";
     catch (PersistenceException e) 
        //throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
        return "WebApplicationException";
    

Junit测试方法(带String的版本完美运行)

   @Test
    public void testUserInfoResponseJSON() throws Exception

      MvcResult result=mockMvc.perform(get("/helloservice/json2?p=103")
              .contentType(MediaType.APPLICATION_JSON))
              .andExpect(status().isOk())
              .andExpect(content().contentTypeCompatibleWith("application/json"))
              .andReturn();

      String content = result.getResponse().getContentAsString();

      assertNotNull(content,"login name:jbray");
    

如果需要,这是我的 pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId> 
        <version>1.5.6.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
        </dependency>
        <!-- Adding RESTEasy support to Bean Validations -->
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-validator-provider-11</artifactId>
            <version>3.1.4.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-links -->
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-links</artifactId>
            <version>3.1.4.Final</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>javax.cache</groupId>
          <artifactId>cache-api</artifactId>
        </dependency>
                      <!--SPRING-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId> 
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.paypal.springboot</groupId>
            <artifactId>resteasy-spring-boot-starter</artifactId>
            <version>2.3.3-RELEASE</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId> 
        </dependency>

        <!--JUNIT-->
        <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.0.RELEASE</version>
    <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20160810</version>
</dependency>

<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>javax.json</artifactId>
  <version>1.0.4</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.4.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.1.1</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
</dependency>

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>

<dependency>
     <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <scope>test</scope>
 </dependency>

    </dependencies>

【问题讨论】:

请检查***.com/a/30549204/3530898,需要添加转换器才能将java对象转换为JSON,反之亦然&lt;beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"&gt; &lt;/beans:bean&gt; 我将转换器添加到 spring-web-xml,但这似乎没有帮助。我还根据您链接的帖子尝试使用 ResponseEntity 。无法让它工作。 如果你得到它的工作,我会感谢你分享代码,因为我可能只是在测试时误解/错误实施了你的建议 你有什么异常吗? 我会尝试运行您的代码,但您可以先尝试保持 jackson-databind、jackson-core 和 jackson-databind 版本相同,并添加对 jackson-annotations 的依赖项,我使用的是 2.8.7在我的代码中 【参考方案1】:

我详细查看了您的依赖项和代码,发现您正在使用 Glassfish 的 JSR 353 提供程序实现。这些类是 org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImpl, org.glassfish.json.JsonStringImpl, and org.glassfish.json.JsonNumberImpl, and javax.json.JsonValue$3 (an anonymous class for the value FALSE)

您需要更改以下代码

return Json.createObjectBuilder().add("login name", rs.getString("loginName"));

return Json.createObjectBuilder().add("login name", "shit broke yo!!!");

return Json.createObjectBuilder().add("login name", rs.getString("loginName")).build().toString();

return Json.createObjectBuilder().add("login name", "shit broke yo!!!").build().toString();

并将getUserInfoJSON()方法的返回类型更改为String。 JSR 353 类及其映射到 ObjectMapper 的详细说明可在https://***.com/a/19205116/3530898获得。

【讨论】:

我试图让该方法返回一个 JSON 对象,返回一个字符串有什么帮助?字符串是否解析为 JSON? 如果你返回 JSONObject 那么它就像一个地图然后你会看到下面的响应 "login name": "chars": "shit broke yo!!!", "string": "shit broke yo!!!", "valueType": "STRING" 而您只是试图返回 JsonObjectBuilder 的对象,因为您没有在 JSONObjectBuilder 类上调用 build()。要返回 JsonObject,您需要调用 build() 方法。

以上是关于mvc:annotation-driven 不能解决 406 错误的主要内容,如果未能解决你的问题,请参考以下文章

160331使用@Controller注解为什么要配置<mvc:annotation-driven />

<mvc:annotation-driven/>与<mvc:default-servlet-handler/>之间的一个问题

如何摆脱 <mvc:annotation-driven />?

springMVC-mvc:annotation-driven

在 applicationContext.xml 中添加 <mvc:annotation-driven> 时出错

SpringMVC源码总结mvc annotation-driven和mvc message-converters