webentwicklung-frage-antwort-db.com.de

Spring MVC 4: Der Inhaltstyp "application/json" wird nicht richtig festgelegt

Ich habe einen Controller mit der folgenden Anmerkung zugeordnet:

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public String bar() {
    return "{\"test\": \"jsonResponseExample\"}";
}

Ich gebe eine gültige JSON-Zeichenfolge zurück. Der Inhaltstyp ist jedoch nicht application/json, wenn ich die Antwort in Chrome Dev Tools im Browser sehe, sondern einfach nur text/html. Warum wird der Inhaltstyp nicht festgelegt?

Mein web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true" version="3.0"
    xmlns="http://Java.Sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Spring MVC Web Application</display-name>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- static assets -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

Mein dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
    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">


    <context:annotation-config />

    <context:component-scan base-package="com.mydomain.controllers" />

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

Verwenden von WildFly 8.1 als App-Server.

20
user1757703

Das erste, was zu verstehen ist, ist das Element RequestMapping#produces() in

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")

dient nur zur Einschränkung der Zuordnung für Ihre Request-Handler. Es tut nichts anderes.

Wenn Ihre Methode den Rückgabetyp String besitzt und mit @ResponseBody versehen ist, wird der Rückgabewert von StringHttpMessageConverter gehandhabt, wodurch der Content-type-Header auf text/plain gesetzt wird. Wenn Sie selbst einen JSON-String zurückgeben und den Header auf application/json setzen möchten, verwenden Sie den Rückgabetyp ResponseEntity (entfernen Sie @ResponseBody) und fügen Sie dem Header die entsprechenden Header hinzu.

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<String> bar() {
    final HttpHeaders httpHeaders= new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    return new ResponseEntity<String>("{\"test\": \"jsonResponseExample\"}", httpHeaders, HttpStatus.OK);
}

Beachten Sie, dass Sie dies wahrscheinlich sollten

<mvc:annotation-driven /> 

in Ihrer Servlet-Kontextkonfiguration können Sie Ihre MVC-Konfiguration mit den am besten geeigneten Standardwerten einrichten.

55

Verwenden Sie beim Rückgabetyp für den Controller die jackson-Bibliothek und die @ResponseBody-Anmerkung.

Dies funktioniert, wenn Sie POJOs als JSon zurückgeben möchten. Wenn Sie String und nicht POJOs als JSon zurückgeben möchten, lesen Sie bitte die Antwort von Sotirious.

3
John

Wie andere Personen kommentiert haben, da der Rückgabetyp Ihrer Methode String ist. Spring hat das Gefühl, dass er nichts mit dem Ergebnis tun muss.

Wenn Sie Ihre Signatur so ändern, dass der Rückgabetyp etwas Rangieren erfordert, sollte dies helfen:

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public Map<String, Object> bar() {
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("test", "jsonRestExample");
    return map;
}
2
ninj

Nicht genau für dieses OP, aber für diejenigen, die auf 404 gestoßen sind und keine Antwort setzen können content-type bis "application/json" (irgendein content-type). Eine Möglichkeit besteht darin, dass ein Server tatsächlich antwortet 406, aber der Explorer (z. B. Chrome) druckt ihn als 404.

Wenn Sie den Nachrichtenkonverter nicht anpassen, verwendet spring AbstractMessageConverterMethodProcessor.Java. Es würde laufen:

List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);

und wenn sie keine Überlappung haben (das gleiche Element), würde es HttpMediaTypeNotAcceptableException werfen und dies verursacht schließlich 406. Egal, ob es ein Ajax oder GET/POST oder eine Form-Aktion ist, wenn die Anfrage uri endet mit einem .html oder ein beliebiges Suffix, das requestedMediaTypes wäre "text/[das Suffix]", und dies steht im Konflikt mit producibleMediaTypes, was normalerweise ist:

"application/json"  
"application/xml"   
"text/xml"          
"application/*+xml" 
"application/json"  
"application/*+json"
"application/json"  
"application/*+json"
"application/xml"   
"text/xml"          
"application/*+xml"
"application/xml"  
"text/xml"         
"application/*+xml"
0
Tiina