responseentity handling example controlleradvice spring spring-mvc httpresponse

handling - Transmitir directamente al flujo de salida de respuesta en el método del controlador del controlador Spring MVC 3.1



spring response exception handler (3)

Tengo un método de controlador que maneja las llamadas ajax y devuelve JSON. Estoy utilizando la biblioteca JSON de json.org para crear el JSON.

Yo podría hacer lo siguiente:

@RequestMapping(method = RequestMethod.POST) @ResponseBody public String getJson() { JSONObject rootJson = new JSONObject(); // Populate JSON return rootJson.toString(); }

Pero es ineficiente armar la cadena JSON, solo para que Spring la escriba en el flujo de salida de la respuesta.

En su lugar, puedo escribirlo directamente en la secuencia de salida de respuesta de esta manera:

@RequestMapping(method = RequestMethod.POST) public void getJson(HttpServletResponse response) { JSONObject rootJson = new JSONObject(); // Populate JSON rootJson.write(response.getWriter()); }

Pero parece que habría una mejor manera de hacerlo que tener que recurrir a pasar HttpServletResponse en el método del controlador.

¿Hay otra clase o interfaz que pueda devolverse desde el método del controlador que puedo usar, junto con la anotación @ResponseBody ?


Al final, escribí un HttpMessageConverter para esto. Con ello, puedo hacer lo siguiente:

@RequestMapping(method = RequestMethod.POST) @ResponseBody public JSONObject getJson() throws JSONException { JSONObject rootJson = new JSONObject(); // Populate JSON return rootJson; }

Aquí está mi clase 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; } }

El HttpMessageConverter debe estar registrado con Spring. Esto se puede hacer en el archivo dispatcher-servlet.xml esta manera:

<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>

Como puede ver, también tengo otros objetos HttpMessageConverter registrados. El orden sí importa.


Puede tener el flujo de salida o el escritor como un parámetro de su método de controlador.

@RequestMapping(method = RequestMethod.POST) public void getJson(Writer responseWriter) { JSONObject rootJson = new JSONObject(); rootJson.write(responseWriter); }

@see Spring Reference Documentation 3.1 Capítulo 16.3.3.1 Tipos de argumentos de métodos compatibles

ps. Siento que usar OutputStream o Writer como parámetro es mucho más fácil de usar en las pruebas que en HttpServletResponse , y gracias por prestar atención a lo que he escrito ;-)


Tenga en cuenta que si utiliza OutputStream o Writer, deberá escribir los encabezados usted mismo.

Una solución es usar InputStreamResource / ResourceHttpMessageConverter