web-dev-qa-db-fra.com

Printemps REST service: récupération de JSON à partir de la requête

Je construis un service REST sur Spring 3.1. J'utilise l'annotation @EnableWebMVC pour cela. Étant donné que mon service n'acceptera que les requêtes JSON, je souhaite également vider la requête entrante dans une collection MongoDB pour la journalisation (et, ultérieurement, pour la transformation des données). J'aimerais accéder à la requête JSON brute (ce que je pouvais faire avec une implémentation non-print en utilisant "@Content HttpServletRequest request" comme paramètre de méthode).

Je suis un débutant au printemps. Alors, aidez-moi gentiment avec les instructions pour y parvenir. Merci!

UPDATE: Le problème n'est pas complètement résolu. Seuls mes tests avec GET ont fonctionné. Il échoue avec POST. Donc décoché la réponse acceptée

Le problème est que, même si je crée un HttpServletRequestWrapper, je ne peux pas transférer la demande après avoir traité et emballé la demande. Voici ce qui se passe:

Intercepteur:

public class DBLogInterceptor extends HandlerInterceptorAdapter {
    MyRequestWrapper requestWrapper;

    private final static Logger logger = Logger.getLogger(DBLogInterceptor.class);

    @Override
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception 
    {
        requestWrapper = new MyRequestWrapper(request);
        // Code removed, but it just dumps requestWrapper.getBody() into DB
        return super.preHandle(requestWrapper, response, handler);
    }
}

HTTP POST Méthode de traitement

@RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "employee")
@ResponseBody
public String updateEntity(@RequestBody Employee emp) {
    // Do some DB Stuff. Anyway, the control flow does not reach this place.
    return "Employee " + emp.getName() + " updated successfully!";
}

Maintenant, je reçois une exception chaque fois que j'envoie un POST:

12:04:53,821 DEBUG DBLogInterceptor:22 - {"name":"Van Damme","dept":"Applied Martial Arts"}
12:04:53,843 DEBUG RequestResponseBodyMethodProcessor:117 - Reading [com.test.webapp.login.domain.Employee] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@154174f9]
12:04:53,850 DEBUG ExceptionHandlerExceptionResolver:132 - Resolving exception from handler [public Java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: Java.io.IOException: Stream closed
12:04:53,854 DEBUG ResponseStatusExceptionResolver:132 - Resolving exception from handler [public Java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: Java.io.IOException: Streamclosed
12:04:53,854 DEBUG DefaultHandlerExceptionResolver:132 - Resolving exception from handler [public Java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: Java.io.IOException: Streamclosed
12:04:53,859 DEBUG DispatcherServlet:910 - Could not complete request
Java.io.IOException: Stream closed
        at org.Apache.catalina.connector.InputBuffer.read(InputBuffer.Java:312)
        at org.Apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.Java:200)
        at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.Java:507)
        at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.Java:129)
        at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.Java:224)
        at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.Java:785)
        at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.Java:561)
        at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.Java:1914)
        at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.Java:124)
        at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.Java:153)
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.Java:120)
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.Java:91)
        at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.Java:71)
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.Java:75)
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.Java:156)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.Java:117)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.Java:96)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.Java:617)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.Java:578)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.Java:80)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:923)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.Java:852)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:882)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.Java:789)
        at javax.servlet.http.HttpServlet.service(HttpServlet.Java:641)
        at javax.servlet.http.HttpServlet.service(HttpServlet.Java:722)
        at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:305)
        at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:210)
        at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:225)
        at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:169)
        at org.Apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.Java:472)
        at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:168)
        at org.Apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:98)
        at org.Apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.Java:927)
        at org.Apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:118)
        at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:407)
        at org.Apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.Java:999)
        at org.Apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.Java:565)
        at org.Apache.Tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.Java:307)
        at Java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
        at Java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at Java.lang.Thread.run(Unknown Source)

Je m'attendais à ce que HttpServletRequestWrapper s'occupe de la mise en cache de la demande. Mais cela n'arrive pas d'une manière ou d'une autre.

17
user1323865

En utilisant l'objet HttpServletRequest , vous pouvez accéder à l'URL utilisée par le client pour effectuer la demande, à la méthode utilisée (GET, POST, PUT, etc.), à la chaîne de requête et aux en-têtes.

Obtenir le RequestBody peut être un peu plus compliqué et nécessiter l'utilisation de l'objet HttpServletRequestWrapper . Etant donné que le corps de la demande ne peut être lu qu'une seule fois, vous devez étendre l'encapsuleur pour y accéder, de sorte que votre contrôleur cible puisse toujours y accéder ultérieurement pour désérialiser votre JSON en objets POJO. 

public class MyRequestWrapper extends HttpServletRequestWrapper {
 private final String body;
 public MyRequestWrapper(HttpServletRequest request) throws IOException {
   super(request);
   StringBuilder stringBuilder = new StringBuilder();
   BufferedReader bufferedReader = null;
   try {
     InputStream inputStream = request.getInputStream();
     if (inputStream != null) {
       bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
       char[] charBuffer = new char[128];
       int bytesRead = -1;
       while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
         stringBuilder.append(charBuffer, 0, bytesRead);
       }
     } else {
       stringBuilder.append("");
     }
   } catch (IOException ex) {
       throw ex;
   } finally {
     if (bufferedReader != null) {
       try {
         bufferedReader.close();
       } catch (IOException ex) {
         throw ex;
       }
     }
   }
   body = stringBuilder.toString();
 }

 @Override
 public ServletInputStream getInputStream() throws IOException {
   final ByteArrayInputStream byteArrayInputStream = new     ByteArrayInputStream(body.getBytes());
   ServletInputStream servletInputStream = new ServletInputStream() {
     public int read() throws IOException {
       return byteArrayInputStream.read();
     }
   };
   return servletInputStream;
 }

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

 public String getBody() {
   return this.body;
 }
}

Pour accéder aux demandes dans un emplacement central, vous pouvez utiliser un filtre ou un intercepteur de ressort. Ces deux éléments sont appelés avant que la demande ne soit déléguée au contrôleur et tous deux ont accès au servlet.

Voici un exemple de journalisation avec utilisant un Spring Interceptor :

package com.vaannila.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.Apache.log4j.BasicConfigurator;
import org.Apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler. HandlerInterceptorAdapter;

public class LoggerInterceptor extends HandlerInterceptorAdapter {
    static Logger logger = Logger.getLogger(LoggerInterceptor.class);

    static {
        BasicConfigurator.configure();
    }

    @Override

    public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception {

        logger.info("Before handling the request");
        return super.preHandle(request, response, handler);
    }

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

        logger.info("After handling the request");
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
        HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

        logger.info("After rendering the view");
        super.afterCompletion(request, response, handler, ex);
    }
}


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="viewResolver" class="org.springframework.web.servlet.view.    InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

    <bean id="handlerMapping" class="org.springframework.web.servlet.handler. BeanNameUrlHandlerMapping" p:interceptors-ref="loggerInterceptor" />

    <bean id="loggerInterceptor" class="com.vaannila.interceptor.LoggerInterceptor" />

    <bean id="userService" class="com.vaannila.service.UserServiceImpl" />

    <bean name="/userRegistration.htm" class="com.vaannila.web.UserController" p:userService-ref="userService" p:formView="userForm" p:successView="userSuccess" />

</beans>

Dans LoggerInterceptor, vous pouvez utiliser le code suivant pour accéder à la demande:

MyRequestWrapper myRequestWrapper = new MyRequestWrapper((HttpServletRequest) request);

String body = myRequestWrapper.getBody();
String clientIP = myRequestWrapper.getRemoteHost();
int clientPort = request.getRemotePort();
String uri = myRequestWrapper.getRequestURI();

System.out.println(body);
System.out.println(clientIP);
System.out.println(clientPort);
System.out.println(uri);
22
jmort253

Je doute que HttpServletRequestWrapper puisse un jour fonctionner. Jetez un coup d’œil à l’implémentation DispatcherServlet:

            HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
            if (interceptors != null) {
                for (int i = 0; i < interceptors.length; i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
                        triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
                        return;
                    }
                    interceptorIndex = i;
                }
            }

            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

Il passe encore référence à "processedRequest", qui fait référence à une demande HttpServletRequest dont le flux a déjà été lu.

4
user1323865

Je sais que c'est une vieille question, mais pour ceux d'entre vous qui recherchent encore une solution, cela a fonctionné pour moi:

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.OutputStream;
import Java.io.PrintWriter;
import Java.util.Collection;
import Java.util.Enumeration;
import Java.util.HashMap;
import Java.util.Locale;
import Java.util.Map;
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.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.Apache.commons.io.output.TeeOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpLoggingFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(HttpLoggingFilter.class);

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

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;

            Map<String, String> requestMap = this
                    .getTypesafeRequestMap(httpServletRequest);
            BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(
                    httpServletRequest);
            BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(
                    httpServletResponse);

            final StringBuilder logMessage = new StringBuilder(
                    "REST Request - ").append("[HTTP METHOD:")
                    .append(httpServletRequest.getMethod())
                    .append("] [PATH INFO:")
                    .append(httpServletRequest.getPathInfo())
                    .append("] [REQUEST PARAMETERS:").append(requestMap)
                    .append("] [REQUEST BODY:")
                    .append(bufferedRequest.getRequestBody())
                    .append("] [REMOTE ADDRESS:")
                    .append(httpServletRequest.getRemoteAddr()).append("]");

            chain.doFilter(bufferedRequest, bufferedResponse);
            logMessage.append(" [RESPONSE:")
                    .append(bufferedResponse.getContent()).append("]");
            logger.debug(logMessage.toString());
        } catch (Throwable a) {
            logger.error(a.getMessage());
        }
    }

    private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
        Map<String, String> typesafeRequestMap = new HashMap<String, String>();
        Enumeration<?> requestParamNames = request.getParameterNames();
        while (requestParamNames.hasMoreElements()) {
            String requestParamName = (String) requestParamNames.nextElement();
            String requestParamValue = request.getParameter(requestParamName);
            typesafeRequestMap.put(requestParamName, requestParamValue);
        }
        return typesafeRequestMap;
    }

    @Override
    public void destroy() {
    }

    private static final class BufferedRequestWrapper extends
            HttpServletRequestWrapper {

        private ByteArrayInputStream bais = null;
        private ByteArrayOutputStream baos = null;
        private BufferedServletInputStream bsis = null;
        private byte[] buffer = null;

        public BufferedRequestWrapper(HttpServletRequest req)
                throws IOException {
            super(req);
            // Read InputStream and store its content in a buffer.
            InputStream is = req.getInputStream();
            this.baos = new ByteArrayOutputStream();
            byte buf[] = new byte[1024];
            int read;
            while ((read = is.read(buf)) > 0) {
                this.baos.write(buf, 0, read);
            }
            this.buffer = this.baos.toByteArray();
        }

        @Override
        public ServletInputStream getInputStream() {
            this.bais = new ByteArrayInputStream(this.buffer);
            this.bsis = new BufferedServletInputStream(this.bais);
            return this.bsis;
        }

        String getRequestBody() throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    this.getInputStream()));
            String line = null;
            StringBuilder inputBuffer = new StringBuilder();
            do {
                line = reader.readLine();
                if (null != line) {
                    inputBuffer.append(line.trim());
                }
            } while (line != null);
            reader.close();
            return inputBuffer.toString().trim();
        }

    }

    private static final class BufferedServletInputStream extends
            ServletInputStream {

        private ByteArrayInputStream bais;

        public BufferedServletInputStream(ByteArrayInputStream bais) {
            this.bais = bais;
        }

        @Override
        public int available() {
            return this.bais.available();
        }

        @Override
        public int read() {
            return this.bais.read();
        }

        @Override
        public int read(byte[] buf, int off, int len) {
            return this.bais.read(buf, off, len);
        }

    }

    public class TeeServletOutputStream extends ServletOutputStream {

        private final TeeOutputStream targetStream;

        public TeeServletOutputStream(OutputStream one, OutputStream two) {
            targetStream = new TeeOutputStream(one, two);
        }

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

        public void flush() throws IOException {
            super.flush();
            this.targetStream.flush();
        }

        public void close() throws IOException {
            super.close();
            this.targetStream.close();
        }
    }

    public class BufferedResponseWrapper implements HttpServletResponse {

        HttpServletResponse original;
        TeeServletOutputStream tee;
        ByteArrayOutputStream bos;

        public BufferedResponseWrapper(HttpServletResponse response) {
            original = response;
        }

        public String getContent() {
            return bos.toString();
        }

        public PrintWriter getWriter() throws IOException {
            return original.getWriter();
        }

        public ServletOutputStream getOutputStream() throws IOException {
            if (tee == null) {
                bos = new ByteArrayOutputStream();
                tee = new TeeServletOutputStream(original.getOutputStream(),
                        bos);
            }
            return tee;

        }

        @Override
        public String getCharacterEncoding() {
            return original.getCharacterEncoding();
        }

        @Override
        public String getContentType() {
            return original.getContentType();
        }

        @Override
        public void setCharacterEncoding(String charset) {
            original.setCharacterEncoding(charset);
        }

        @Override
        public void setContentLength(int len) {
            original.setContentLength(len);
        }

        @Override
        public void setContentType(String type) {
            original.setContentType(type);
        }

        @Override
        public void setBufferSize(int size) {
            original.setBufferSize(size);
        }

        @Override
        public int getBufferSize() {
            return original.getBufferSize();
        }

        @Override
        public void flushBuffer() throws IOException {
            tee.flush();
        }

        @Override
        public void resetBuffer() {
            original.resetBuffer();
        }

        @Override
        public boolean isCommitted() {
            return original.isCommitted();
        }

        @Override
        public void reset() {
            original.reset();
        }

        @Override
        public void setLocale(Locale loc) {
            original.setLocale(loc);
        }

        @Override
        public Locale getLocale() {
            return original.getLocale();
        }

        @Override
        public void addCookie(Cookie cookie) {
            original.addCookie(cookie);
        }

        @Override
        public boolean containsHeader(String name) {
            return original.containsHeader(name);
        }

        @Override
        public String encodeURL(String url) {
            return original.encodeURL(url);
        }

        @Override
        public String encodeRedirectURL(String url) {
            return original.encodeRedirectURL(url);
        }

        @SuppressWarnings("deprecation")
        @Override
        public String encodeUrl(String url) {
            return original.encodeUrl(url);
        }

        @SuppressWarnings("deprecation")
        @Override
        public String encodeRedirectUrl(String url) {
            return original.encodeRedirectUrl(url);
        }

        @Override
        public void sendError(int sc, String msg) throws IOException {
            original.sendError(sc, msg);
        }

        @Override
        public void sendError(int sc) throws IOException {
            original.sendError(sc);
        }

        @Override
        public void sendRedirect(String location) throws IOException {
            original.sendRedirect(location);
        }

        @Override
        public void setDateHeader(String name, long date) {
            original.setDateHeader(name, date);
        }

        @Override
        public void addDateHeader(String name, long date) {
            original.addDateHeader(name, date);
        }

        @Override
        public void setHeader(String name, String value) {
            original.setHeader(name, value);
        }

        @Override
        public void addHeader(String name, String value) {
            original.addHeader(name, value);
        }

        @Override
        public void setIntHeader(String name, int value) {
            original.setIntHeader(name, value);
        }

        @Override
        public void addIntHeader(String name, int value) {
            original.addIntHeader(name, value);
        }

        @Override
        public void setStatus(int sc) {
            original.setStatus(sc);
        }

        @SuppressWarnings("deprecation")
        @Override
        public void setStatus(int sc, String sm) {
            original.setStatus(sc, sm);
        }

        @Override
        public String getHeader(String arg0) {
            return original.getHeader(arg0);
        }

        @Override
        public Collection<String> getHeaderNames() {
            return original.getHeaderNames();
        }

        @Override
        public Collection<String> getHeaders(String arg0) {
            return original.getHeaders(arg0);
        }

        @Override
        public int getStatus() {
            return original.getStatus();
        }

    }
}

Ensuite, enregistrez simplement le filtre dans web.xml et vous avez terminé. Tous les crédits à: http://wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431 (je viens de le corriger).

3
Aurasphere

Hé, tu peux essayer avec ça:

@RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "/employee")
@ResponseBody
public String updateEntity(@RequestBody Employee emp) {
    // Do some DB Stuff. Anyway, the control flow does not reach this place.
    return "Employee " + emp.getName() + " updated successfully!";
}

Ici: s’il prouve l’URI avec le '/' il permet à toutes les opérations de s’exécuter. tels que get post update et delete avec la même valeur URI.

2
user3094823

Je crée une version Ouputstream sans aucune dépendance vis-à-vis des bibliothèques tierces pour une réutilisation plus facile. Vous pouvez utiliser cette classe 2 wrapper pour obtenir facilement le corps de la demande et de la réponse .
Mais de toute façon, je dois utiliser un filtre pour le faire à la place de l'intercepteur. Comme @ user1323865 l'a mentionné, au printemps 4, la demande traitée est utilisée à la fois dans l'intercepteur et le gestionnaire, de sorte que vous ne pouvez pas utiliser ces méthodes pour l'intercepteur .
Vous pouvez également trouver de l’aide sur ce lien si vous utilisez plutôt la version Writer . Capturez et enregistrez le corps de la réponse


public class BufferedRequestWrapper extends HttpServletRequestWrapper
{
    private static final class BufferedServletInputStream extends ServletInputStream
    {
        private ByteArrayInputStream bais;

        public BufferedServletInputStream(ByteArrayInputStream bais)
        {
            this.bais = bais;
        }

        @Override
        public int available()
        {
            return this.bais.available();
        }

        @Override
        public int read()
        {
            return this.bais.read();
        }

        @Override
        public int read(byte[] buf, int off, int len)
        {
            return this.bais.read(buf, off, len);
        }

    }

    private byte[] mBodyBuffer;

    public BufferedRequestWrapper(HttpServletRequest request) throws IOException
    {
        super(request);

        InputStream in = request.getInputStream();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead = -1;
        while ((bytesRead = in.read(buffer)) > 0)
        {
            baos.write(buffer, 0, bytesRead);
        }
        mBodyBuffer = baos.toByteArray();
    }

    public String getRequestBody()
    {
        return new String(mBodyBuffer, Charset.forName("UTF-8"));
    }
    @Override
    public BufferedReader getReader() throws IOException
    {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream()
    {
        ByteArrayInputStream in = new ByteArrayInputStream(mBodyBuffer);
        return new BufferedServletInputStream(in);
    }
}


public class BufferedResponseWrapper extends HttpServletResponseWrapper
{
    private TeeServletOutputStream mTeeOutputStream;

    private static class TeeOutputStream extends OutputStream
    {
        private OutputStream mChainStream;
        private OutputStream mTeeStream;

        public TeeOutputStream(OutputStream chainStream, OutputStream teeStream)
        {
            mChainStream = chainStream;
            mTeeStream = teeStream;
        }

        @Override
        public void write(int b) throws IOException
        {
            mChainStream.write(b);
            mTeeStream.write(b);
            mTeeStream.flush();
        }

        @Override
        public void close() throws IOException
        {
            flush();
            mChainStream.close();
            mTeeStream.close();
        }

        @Override
        public void flush() throws IOException
        {
            mChainStream.close();
        }
    }

    public class TeeServletOutputStream extends ServletOutputStream
    {
        private final TeeOutputStream targetStream;

        public TeeServletOutputStream(OutputStream one, OutputStream two)
        {
            targetStream = new TeeOutputStream(one, two);
        }

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

        @Override
        public void flush() throws IOException
        {
            super.flush();
            this.targetStream.flush();
        }

        @Override
        public void close() throws IOException
        {
            super.close();
            this.targetStream.close();
        }
    }

    private ByteArrayOutputStream mByteArrayOutputStream;

    public BufferedResponseWrapper(HttpServletResponse response) throws IOException
    {
        super(response);
        mByteArrayOutputStream = new ByteArrayOutputStream();
        mTeeOutputStream = new TeeServletOutputStream(super.getResponse().getOutputStream(), mByteArrayOutputStream);
    }

    @Override
    public PrintWriter getWriter() throws IOException
    {
        return super.getResponse().getWriter();
    }

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

    public String getResponseBody()
    {
        return mByteArrayOutputStream.toString();
    }

}
2
Happier

Actuellement dans le référentiel spring-mvc, les intercepteurs sont appelés dans DispatcherServlet # doDispatch (...):

https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/Java/org/springframework/web/servlet/DispatcherServlet.Java

...
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
        }

        try {
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
        }

        applyDefaultViewName(request, mv);
        mappedHandler.applyPostHandle(processedRequest, response, mv);
...

Puis-je définir ma propre DispatcherServlet et remplacer doDispatch(...) pour injecter une HttpRequestWrapper avec une ByteArrayInputStream sur getInputStream()?

...

@Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        RequestWrapper wrappedRequest = new RequestWrapper(request);
        logger.debug("injecting RequestWrapper: " + wrappedRequest);

        super.doDispatch(wrappedRequest, response);

    }
...

Cela fonctionnera-t-il dans la situation ci-dessus?

2
JayabalanAaron

Vous devez implémenter le requestWrapper comme suit:

public class DocVerificationRequestWrapper extends HttpServletRequestWrapper {
 private final String body;
 public DocVerificationRequestWrapper(HttpServletRequest request) throws IOException {
   super(request);
   StringBuilder stringBuilder = new StringBuilder();
   BufferedReader bufferedReader = null;
   try {
     InputStream inputStream = request.getInputStream();
     if (inputStream != null) {
       bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
       char[] charBuffer = new char[128];
       int bytesRead = -1;
       while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
         stringBuilder.append(charBuffer, 0, bytesRead);
       }
     } else {
       stringBuilder.append("");
     }
   } catch (IOException ex) {
       throw ex;
   } finally {
     if (bufferedReader != null) {
       try {
         bufferedReader.close();
       } catch (IOException ex) {
         throw ex;
       }
     }
   }
   body = stringBuilder.toString();
 }

 @Override
 public ServletInputStream getInputStream() throws IOException {
   final ByteArrayInputStream byteArrayInputStream = new     ByteArrayInputStream(body.getBytes());
   ServletInputStream servletInputStream = new ServletInputStream() {
     public int read() throws IOException {
       return byteArrayInputStream.read();
     }

    @Override
    public boolean isFinished() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isReady() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void setReadListener(ReadListener listener) {
        // TODO Auto-generated method stub

    }
   };
   return servletInputStream;
 }

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

 public String getBody() {
   return this.body;
 }
}

puis à l'intérieur de la méthode chain.doFilter de la classe filter, transmettez l'objet requestWrapper à la place de l'objet request comme suit:

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

    logger.info("checking token in filter");
    HttpServletRequest request = (HttpServletRequest) arg0;

    DocVerificationRequestWrapper myRequestWrapper = new DocVerificationRequestWrapper((HttpServletRequest) request);

    String body = myRequestWrapper.getBody();
    logger.info("body = "+body);
    Token token = null;
    try {
        JSONObject jsonObj = new JSONObject(body);
        JSONObject tokenObj = (JSONObject) jsonObj.get("token");
        Gson gson = new Gson();
        token = gson.fromJson(tokenObj.toString(), Token.class);

        if(null != token) {
                if(userVerificationService==null){
                ServletContext servletContext = request.getServletContext();
                WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
                userVerificationService = webApplicationContext.getBean(UserVerificationService.class);
            }
                String verStatus = userVerificationService.verifyUser(token);
                logger.info("verStatus = "+verStatus);
                if(verStatus != null && verStatus.equalsIgnoreCase("success")) {
                    chain.doFilter(myRequestWrapper, response); //here replacing request with requestWrapper 
                }else
                    logger.error("Invalid token");
        }else {
                logger.error("token missing.");
        }
    } catch (JSONException e) {
            logger.error("exception in authetication filter " + e);
    }
}

Ainsi, la résolution de l'exception fermée IOStream.

1
KayV

Une méthode simple consiste à obtenir le corps de la demande sous forme de chaîne, puis à analyser en tant qu’objet Java. Vous pouvez utiliser cette chaîne à votre guise.

Donc dans votre exemple:

@RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "employee")
@ResponseBody
public String updateEntity(@RequestBody String empAsString) {

    // Do whatever with the json as String 
    System.out.println(empAsString);

    // Transform it into the Java Object you want
    ObjectMapper mapper = new ObjectMapper();
    Employee emp = mapper.readValue(empAsString, Employee.class);

    // Do some DB Stuff. Anyway, the control flow does not reach this place.
    return "Employee " + emp.getName() + " updated successfully!";
}

En note, si vous en avez besoin sous forme de liste, vous pouvez utiliser:

List<Employee> eventsList =
                mapper.readValue(jsonInString, mapper.getTypeFactory().constructCollectionType(List.class, Employee.class));
1
Giannis Smirnios

Vous pouvez simplement utiliser: 

import org.Apache.commons.io.IOUtils;
import Java.nio.charset.Charset;

String requestBody = IOUtils.toString(request.getInputStream(), Charset.forName("UTF-8").toString());
0
zeeshank1