2013-06-24 3 views
10

В нашем приложении мы используем JSON для запроса и ответа. Методы контроллера аннотируются с помощью @RequestBody(). Возвращаемый объект, например. TransferResponse. Я хотел бы получить этот объект из @ResponseBody. Я установка метод postHandle перехватчика:Spring MVC 3.2 @ResponseBody перехватчик

@Override 
    public void postHandle(HttpServletRequest request, 
          HttpServletResponse response, 
          Object handler, 
          ModelAndView modelAndView) throws java.lang.Exception 

    { 
.... 

} 

Так как же я получаю JSON в этом методе postHandle?

Заранее спасибо GM

+3

Это хороший вариант. Я не думаю, что вы можете добраться до объекта '@ ResponseBody', поскольку он обрабатывается (перенаправляется в выходной поток ответа сервлета) задолго до того, как элемент управления возвращается к' DispatcherServlet' (который отвечает за вызов перехватчиков обработчиков). В зависимости от вашего прецедента вам нужно будет найти другой способ. –

ответ

0

Как Павел сказал, вы, вероятно, не может получить к JSON ответ таким образом. Я считаю, что лучше всего реализовать Filter, который смотрит на ответ, прежде чем записывать его клиенту. Посмотрите на OncePerRequestFilter для отправной точки.

+0

Спасибо всем, что я попробую. – user2279337

6

Как уже упоминалось Pavel Horal, когда вызывается метод postHandle(), объект тела ответа уже преобразован в JSON и записан в ответ. Вы можете попытаться написать свою собственную аннотацию и аспект, чтобы перехватить объекты тела ответа контроллера.

// 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; 
    } 
} 

Включить поддержку AspectJ аспекты использования @EnableAspectJAutoProxy

+0

Спасибо всем, что я попробую. – user2279337

1

я, наконец, работать (но не элегантное) решение для этого случая. Я думаю, что это может быть лучшее решение, но я не могу это найти.

Сначала я был создан оболочку Request and Response, которая инкапсулирует полезную нагрузку, в результате чего мой запрос Input Stream и ответный поток Output reutilizable и overridable. Мне нужно использовать это в своем фильтре для манипулирования как запросами, так и полезными данными ответа.

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

Поскольку вопрос был опубликован, ResponseBodyAdvice был добавлен в Spring MVC 4.1. Этот интерфейс позволяет приложениям изменять или полностью изменять корпус, прежде чем конвертор будет применен. documentation for intercepting requests был также обновлен специально для этого вопроса:

Обратите внимание, что метод postHandle из HandlerInterceptor не всегда идеально подходит для использования с @ResponseBody и ResponseEntity методами. В таких случаях HttpMessageConverter записывает и передает ответ до того, как вызывается postHandle, что делает невозможным изменение ответа, например, для добавления заголовка. Вместо этого приложение может реализовать ResponseBodyAdvice и объявить его как компонент @ControllerAdvice или настроить его непосредственно на RequestMappingHandlerAdapter.

Смежные вопросы