11
votes

Printemps MVC 3.2 @Responsebody Interceptor

Dans notre application, nous utilisons JSON pour la demande et la réponse. Les méthodes de contrôleur sont annotées avec @requestbody (). L'objet étant retourné par ex. Transfère. Je voudrais obtenir la maintien de cet objet former le @Responsebody. J'ai configuré une méthode d'intercepteur posthandle: xxx

Alors, comment puis-je obtenir le JSON dans cette méthode posthandle?

Merci d'avance GM


1 commentaires

C'est une bonne. Je ne pense pas que vous puissiez accéder à l'objet @Responsebody tel qu'il est manipulé (marshaled dans le flux de sortie de réponse de servlet) bien avant que la commande ne revienne sur Disternersservlet (qui est responsable pour appeler des intercepteurs de gestionnaire). Selon votre cas d'utilisation, vous devrez trouver une manière différente.


4 Réponses :


0
votes

Comme Pavel dit, vous ne pouvez probablement pas arriver à la réponse JSON de cette façon. Je pense que le meilleur pari est de mettre en œuvre un filtre que Regarde la réponse avant de l'écrire au client. Jetez un coup d'œil à autre expérience pour un point de départ.


1 commentaires

Merci tout ce que je vais essayer cela.



6
votes

comme Pavel Horal déjà mentionné, lorsque posthandle () code> est appelé, L'objet corporel de réponse est déjà converti en JSON et écrit en réponse. Vous pouvez essayer d'écrire votre propre annotation personnalisée et votre propre aspect afin d'intercepter les objets du corps de réponse du contrôleur.

// custom annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation {
}

// aspect
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyCustomAnnotationAspect {
    @Around(value = "@annotation(org.package.MyCustomAnnotation)", argNames = "pjp")
    public Object aroundAdvice(final ProceedingJoinPoint pjp) {
        // this is your response body
        Object responseBody = pjp.proceed();
        return responseBody;
    }
}


1 commentaires

Merci tout ce que je vais essayer cela.



1
votes

J'ai enfin une solution de travail (mais pas élégante) pour ce cas. Je pense que cela peut avoir une meilleure solution, mais je ne trouve pas que.

Au début, j'ai été créé une enveloppe de demande et de réponse qui encapsule la charge utile, faisant ma demande de flux de saisie et de réponse de réponse réutilisable et répréhensible. Je dois l'utiliser dans mon filtre pour manipuler à la fois la demande et la charge de réponse des charges utiles. P>

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.springframework.context.ApplicationContext;

import br.com.vivo.core.controller.impl.utils.ApplicationContextUtils;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

@WebFilter(urlPatterns = { "/*" })
public class HeadBodyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

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

        ApplicationContext applicationContext = ApplicationContextUtils.getApplicationContext();

        ObjectMapper objectMapper = (ObjectMapper) applicationContext.getBean("jacksonObjectMapper");
        JsonFactory jsonFactory = objectMapper.getFactory();

        ByteResponseWrapper byteResponseWrapper = new ByteResponseWrapper((HttpServletResponse) response);
        ByteRequestWrapper byteRequestWrapper = new ByteRequestWrapper((HttpServletRequest) request);


        String jsonRequestString = new String(byteRequestWrapper.getBytes());
        JsonParser requestParser = jsonFactory.createParser(jsonRequestString);
        JsonNode rootRequestNode = objectMapper.readTree(requestParser);


        if(rootRequestNode != null && rootRequestNode.has("body")) {
            JsonNode requestBody = rootRequestNode.get("body");
            writeJsonIntoRequest(byteRequestWrapper, requestBody, objectMapper);
        }


        chain.doFilter(byteRequestWrapper, byteResponseWrapper);

        String jsonResponseString = new String(byteResponseWrapper.getBytes(), response.getCharacterEncoding());



        JsonParser responseParser = jsonFactory.createParser(jsonResponseString);
        JsonNode rootResponseNode = objectMapper.readTree(responseParser);

        Object head = "Whoo hoo!";

        ObjectNode responseObjectWrapper = objectMapper.createObjectNode();
        responseObjectWrapper.put("head", objectMapper.valueToTree(head));
        responseObjectWrapper.put("body", rootResponseNode);

        writeJsonIntoResponse(response, responseObjectWrapper, objectMapper);

    }


    private void writeJsonIntoRequest(ByteRequestWrapper request,
            JsonNode requestBody, ObjectMapper objectMapper) throws IOException {

        String json = objectMapper.writeValueAsString(requestBody);
        request.replaceRequestPayload(json.getBytes());

    }

    @Override
    public void destroy() {

    }



    /**
     * Escreve o json no response
     * 
     * @param response
     * @param rootNode
     * @throws IOException
     */
    private void writeJsonIntoResponse(final ServletResponse response, final JsonNode responseBody, final ObjectMapper objectMapper) throws IOException {

        String json = objectMapper.writeValueAsString(responseBody);

        // escreve o json
        response.getOutputStream().write((json + "\r\n").getBytes(response.getCharacterEncoding()));
    }



    static class ByteResponseWrapper extends HttpServletResponseWrapper {

        private PrintWriter writer;
        private ByteOutputStream output;

        public byte[] getBytes() {
            writer.flush();
            return output.getBytes();
        }

        public ByteResponseWrapper(HttpServletResponse response) {
            super(response);
            output = new ByteOutputStream();
            writer = new PrintWriter(output);
        }

        @Override
        public PrintWriter getWriter() {
            return writer;
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return output;
        }
    }



    static class ByteRequestWrapper extends HttpServletRequestWrapper {

        byte[] requestBytes = null;
        private ByteInputStream byteInputStream;


        public ByteRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            InputStream inputStream = request.getInputStream();

            byte[] buffer = new byte[4096];
            int read = 0;
            while ( (read = inputStream.read(buffer)) != -1 ) {
                baos.write(buffer, 0, read);
            }

            replaceRequestPayload(baos.toByteArray());
        }

        public byte[] getBytes() {
            return requestBytes;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            return byteInputStream;
        }

        public void replaceRequestPayload(byte[] newPayload) {
            requestBytes = newPayload;
            byteInputStream = new ByteInputStream(new ByteArrayInputStream(requestBytes));
        }
    }

    static class ByteOutputStream extends ServletOutputStream {

        private ByteArrayOutputStream bos = new ByteArrayOutputStream();

        @Override
        public void write(int b) throws IOException {
            bos.write(b);
        }

        public byte[] getBytes() {
            return bos.toByteArray();
        }
    }

    static class ByteInputStream extends ServletInputStream {

        private InputStream inputStream;

        public ByteInputStream(final InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public int read() throws IOException {
            return inputStream.read();
        }

    }

}


0 commentaires

1
votes

Étant donné que la question a été postée, ResponseBodyAdvice a été ajouté au printemps MVC 4.1. Cette interface permet aux applications de modifier ou de modifier complètement le corps avant l'application du convertisseur. Documentation pour intercepter Les demandes ont également été mises à jour spécifiquement pour ce problème:

Notez que la méthode posthandle de handlerinterint n'est pas toujours parfaitement adaptée à une utilisation avec @ReSponsebody et méthodes de réponse. Dans de tels cas, un site httpmessageconverter écrit et commet la réponse avant que POSTHANDLE n'est appelé, ce qui rend impossible la modification de la réponse, par exemple pour ajouter un en-tête. Au lieu de cela, une application peut implémenter la réponse de réponse et la déclarer comme un haricot @ControllerAdvice ou la configurer directement sur DemandeMappingHandlerDapter.


0 commentaires