J'ai une méthode de contrôleur qui gère les appels ajax et retourne JSON. J'utilise la bibliothèque JSON de json.org pour créer le JSON.
Je pourrais faire ce qui suit:
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public String getJson()
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson.toString();
}
Mais il est inefficace de rassembler la chaîne JSON, seulement pour que Spring l'écrive dans le flux de sortie de la réponse.
Au lieu de cela, je peux l'écrire directement dans le flux de sortie de réponse comme ceci:
@RequestMapping(method = RequestMethod.POST)
public void getJson(HttpServletResponse response)
{
JSONObject rootJson = new JSONObject();
// Populate JSON
rootJson.write(response.getWriter());
}
Mais il semble qu'il y aurait une meilleure façon de procéder que d'avoir à passer le HttpServletResponse
dans la méthode du gestionnaire.
Y a-t-il une autre classe ou interface qui peut être renvoyée par la méthode du gestionnaire que je peux utiliser, avec le @ResponseBody
annotation?
Vous pouvez avoir le flux de sortie ou l'enregistreur comme paramètre de votre méthode de contrôleur.
@RequestMapping(method = RequestMethod.POST)
public void getJson(Writer responseWriter) {
JSONObject rootJson = new JSONObject();
rootJson.write(responseWriter);
}
@see Spring Reference Documentation 3.1 Chapitre 16.3.3.1 Types d'arguments de méthode pris en charge
p.s. Je pense que l'utilisation de OutputStream
ou Writer
comme paramètre est encore plus facile à utiliser dans les tests qu'un HttpServletResponse
- et merci de faire attention à ce que je ont écrit ;-)
Au final, j'ai écrit un HttpMessageConverter
pour cela. Avec lui, je peux faire ce qui suit:
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public JSONObject getJson()
throws JSONException
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson;
}
Voici ma classe HttpMessageConverter
:
package com.example;
import Java.io.IOException;
import Java.io.OutputStreamWriter;
import Java.io.PrintWriter;
import Java.nio.charset.Charset;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
public class JsonObjectHttpMessageConverter
extends AbstractHttpMessageConverter<JSONObject>
{
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public JsonObjectHttpMessageConverter()
{
super(new MediaType("application", "json"), new MediaType("text", "javascript"));
}
@Override
protected boolean supports(Class<?> clazz)
{
return JSONObject.class.equals(clazz);
}
@Override
protected JSONObject readInternal(Class<? extends JSONObject> clazz,
HttpInputMessage inputMessage)
throws IOException,
HttpMessageNotReadableException
{
throw new UnsupportedOperationException();
}
@Override
protected void writeInternal(JSONObject jsonObject,
HttpOutputMessage outputMessage)
throws IOException,
HttpMessageNotWritableException
{
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputMessage.getBody(),
getContentTypeCharset(outputMessage)));
try
{
jsonObject.write(writer);
writer.flush();
}
catch (JSONException e)
{
throw new HttpMessageNotWritableException(e.getMessage(), e);
}
}
private Charset getContentTypeCharset(HttpMessage message)
{
MediaType contentType = message.getHeaders().getContentType();
Charset charset = (contentType != null) ? contentType.getCharSet() : null;
return (charset != null) ? charset : DEFAULT_CHARSET;
}
}
HttpMessageConverter
doit être enregistré auprès de Spring. Cela peut être fait dans le dispatcher-servlet.xml
fichier comme celui-ci:
<beans ...>
...
<mvc:annotation-driven conversion-service="conversionService" validator="validator">
<mvc:argument-resolvers>
...
</mvc:argument-resolvers>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
<value>*/*</value>
</list>
</property>
<property name="writeAcceptCharset" value="false" />
</bean>
<bean class="com.example.JsonObjectHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
...
</beans>
Comme vous pouvez le voir, j'ai également enregistré d'autres objets HttpMessageConverter
. L'ordre est important.
Notez que si vous utilisez OutputStream ou Writer, vous devez écrire les en-têtes vous-même.
Une solution de contournement consiste à utiliser InputStreamResource/ResourceHttpMessageConverter