J'ai un contrôleur mappé avec l'annotation suivante:
@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public String bar() {
return "{\"test\": \"jsonResponseExample\"}";
}
Je retourne une chaîne JSON valide, cependant, le type de contenu lorsque je visualise la réponse dans Chrome Dev Tools dans le navigateur n'est pas application/json
, mais simplement text/html
. Pourquoi le type de contenu n'est-il pas défini?
Mon 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>
Mon 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>
Utilisation de WildFly 8.1 comme serveur d'applications.
La première chose à comprendre est que le RequestMapping#produces()
élément de
@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
sert uniquement à restreindre le mappage pour vos gestionnaires de demandes. Cela ne fait rien d'autre.
Ensuite, étant donné que votre méthode a un type de retour de String
et est annotée de @ResponseBody
, la valeur de retour sera gérée par StringHttpMessageConverter
qui définit l'en-tête Content-type
sur text/plain
. Si vous souhaitez renvoyer vous-même une chaîne JSON et définir l'en-tête sur application/json
, utilisez un type de retour de ResponseEntity
(supprimez @ResponseBody
) et ajoutez-lui les en-têtes appropriés.
@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);
}
Notez que vous devriez probablement avoir
<mvc:annotation-driven />
dans la configuration de contexte de votre servlet pour configurer votre configuration MVC avec les valeurs par défaut les plus appropriées.
Utilisez la bibliothèque jackson et l'annotation @ResponseBody
sur le type de retour pour le contrôleur.
Cela fonctionne si vous souhaitez retourner des POJO représentés par JSon. Si vous souhaitez retourner String et non les POJO en tant que JSon, veuillez vous reporter à la réponse Sotirious.
Comme d'autres personnes l'ont commenté, le type de résultat de votre méthode étant String
, Spring n'aura pas besoin de faire quoi que ce soit avec le résultat.
Si vous modifiez votre signature de sorte que le type de retour soit quelque chose qui nécessite une mise en forme, cela devrait aider:
@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;
}
Pas exactement pour cet OP, mais pour ceux qui ont rencontré 404 et ne peuvent pas définir la réponse content-type
à "application/json"
(aucun content-type
). Une possibilité est qu'un serveur réponde en réalité 406 mais Explorer (par exemple, chrome) l’imprime en tant que 404.
Si vous ne personnalisez pas le convertisseur de message, spring utilisera AbstractMessageConverterMethodProcessor.Java
. Il courrait:
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
et s’ils n’ont aucun chevauchement (le même élément), il lancera HttpMediaTypeNotAcceptableException
et cela aboutira finalement à 406. Peu importe s’il s’agisse d’un ajax, d’un GET/POST ou d’une action de forme, si la demande uri se termine par un .html
n'importe quel suffixe, la requestedMediaTypes
serait "text/[ce suffixe]", et ceci est en conflit avec producibleMediaTypes
, qui est habituellement:
"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"