Saltar al contenido

Spring MVC: Cómo modificar la respuesta json enviada desde el controlador

Solución:

Me he encontrado con un problema similar y le sugiero que utilice filtros de servlet para resolverlo.

Los filtros de servlet son clases de Java que se pueden utilizar en la programación de servlet para interceptar solicitudes de un cliente antes de que accedan a un recurso en el back-end o para manipular las respuestas del servidor antes de que se envíen de vuelta al cliente.

Su filtro debe implementar la interfaz javax.servlet.Filter y anular tres métodos:

public void doFilter (ServletRequest, ServletResponse, FilterChain)

Este método se llama cada vez que se pasa un par de solicitud / respuesta a través de la cadena debido a una solicitud del cliente de un recurso al final de la cadena.

public void init(FilterConfig filterConfig)

Se llama antes de que el filtro entre en servicio y establece el objeto de configuración del filtro.

public void destroy()

Llamado después de que el filtro ha sido puesto fuera de servicio.

Existe la posibilidad de utilizar cualquier número de filtros, y el orden de ejecución será el mismo que el orden en el que están definidos en web.xml.

web.xml:

...
<filter>
    <filter-name>restResponseFilter</filter-name>
    <filter-class>
        com.package.filters.ResponseFilter
    </filter-class>
</filter>

<filter>
    <filter-name>anotherFilter</filter-name>
    <filter-class>
        com.package.filters.AnotherFilter
    </filter-class>
</filter>
...

Entonces, este filtro obtiene la respuesta del controlador, la convierte en String, agrega como campo a su objeto de clase RestResponse (con campos de estado y mensaje), serializa el objeto en Json y envía la respuesta completa al cliente.

ResponseFilter clase:

public final class ResponseFilter implements Filter {

@Override
    public void init(FilterConfig filterConfig) {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {

    ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);

    chain.doFilter(request, responseWrapper);

    String responseContent = new String(responseWrapper.getDataStream());

    RestResponse fullResponse = new RestResponse(/*status*/, /*message*/,responseContent);

    byte[] responseToSend = restResponseBytes(fullResponse);

    response.getOutputStream().write(responseToSend);

}

@Override
public void destroy() {
}

private byte[] restResponseBytes(RestResponse response) throws IOException {
    String serialized = new ObjectMapper().writeValueAsString(response);
    return serialized.getBytes();
}
}

El método chain.doFilter (request, responseWrapper) invoca el siguiente filtro de la cadena, o si el filtro de llamada es el último filtro de la cadena, invoca la lógica del servlet.

El contenedor de respuesta de servlet HTTP utiliza un flujo de salida de servlet personalizado que permite al contenedor manipular los datos de respuesta después de que el servlet haya terminado de escribirlos. Normalmente, esto no se puede hacer después de que se haya cerrado el flujo de salida del servlet (esencialmente, después de que el servlet lo haya comprometido). Esa es la razón para implementar una extensión específica de filtro para la clase ServletOutputStream.

FilterServletOutputStream clase:

public class FilterServletOutputStream extends ServletOutputStream {

DataOutputStream output;
public FilterServletOutputStream(OutputStream output) {
    this.output = new DataOutputStream(output);
}

@Override
public void write(int arg0) throws IOException {
    output.write(arg0);
}

@Override
public void write(byte[] arg0, int arg1, int arg2) throws IOException {
    output.write(arg0, arg1, arg2);
}

@Override
public void write(byte[] arg0) throws IOException {
    output.write(arg0);
}
}

Para usar la clase FilterServletOutputStream se debe implementar una clase que pueda actuar como un objeto de respuesta. Este objeto contenedor se envía de vuelta al cliente en lugar de la respuesta original generada por el servlet.

ResponseWrapper clase:

public class ResponseWrapper extends HttpServletResponseWrapper {

ByteArrayOutputStream output;
FilterServletOutputStream filterOutput;
HttpResponseStatus status = HttpResponseStatus.OK;

public ResponseWrapper(HttpServletResponse response) {
    super(response);
    output = new ByteArrayOutputStream();
}

@Override
public ServletOutputStream getOutputStream() throws IOException {
    if (filterOutput == null) {
        filterOutput = new FilterServletOutputStream(output);
    }
    return filterOutput;
}

public byte[] getDataStream() {
    return output.toByteArray();
}
}

Creo que este enfoque será una buena solución para su problema.

Por favor, haga una pregunta, si algo no está claro y corríjame si me equivoco.

Si usa Spring 4.1 o superior, puede usar ResponseBodyAdvice para personalizar la respuesta antes de que se escriba el cuerpo.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *