Spring REST service: retrieving JSON from Request

后端 未结 11 594
甜味超标
甜味超标 2020-11-27 04:35

I am building a REST service on Spring 3.1. I am using @EnableWebMVC annotation for that. Since my service will only be accepting JSON requests, I would also like to dump th

相关标签:
11条回答
  • 2020-11-27 04:38

    Using the HttpServletRequest object, you can get access to the URL the client used to make the request, the method used (GET, POST, PUT, etc), the query string, and headers.

    Getting the RequestBody may be a bit trickier and may require using the HttpServletRequestWrapper object. Since the request body can only be read once, you'll need to extend the wrapper to access it so that your target controller can still access it later to deserialize your JSON into POJO objects.

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

    To access the requests in a central location, you can use either a Filter or a Spring Interceptor. Both of these are invoked prior to the request being delegated to the controller, and both have access to the servlet.

    Here is an actual Logging example using a 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>
    

    In the LoggerInterceptor, you could use the following code to access the request:

    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);
    
    0 讨论(0)
  • 2020-11-27 04:40

    You can simply use :

    import org.apache.commons.io.IOUtils;
    import java.nio.charset.Charset;
    
    String requestBody = IOUtils.toString(request.getInputStream(), Charset.forName("UTF-8").toString());
    
    0 讨论(0)
  • 2020-11-27 04:42

    I know this is an old question, but for those of you that are still looking for a solution, this worked for me:

    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();
            }
    
        }
    }
    

    Then simply register the filter in web.xml and you're done. All credits to: http://wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431 (I just did some minor fix to it).

    0 讨论(0)
  • 2020-11-27 04:42

    One simple way to do this would be to get the request body as String and then parse as a Java object. You can use this String then as you want.

    So in your example:

    @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!";
    }
    

    As a note, if you need it as a list you can use:

    List<Employee> eventsList =
                    mapper.readValue(jsonInString, mapper.getTypeFactory().constructCollectionType(List.class, Employee.class));
    
    0 讨论(0)
  • 2020-11-27 04:43

    I make a Ouputstream version without any dependency to 3rd party libs for easier re-use. You can use this 2 wrapper class to get the request & response body easily.
    But anyway, I have to use a filter to do this instead of interceptor. Because as @user1323865 mentioned, in spring 4, the processedRequest is used in both interceptor and handler, so you cannot use these methods for interceptor.
    Also you can find some help in this link if you're using Writer version instead. Capture and log the response body

    
    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();
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 04:44

    I doubt if HttpServletRequestWrapper can ever work... Take a look at the DispatcherServlet implementation:

                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());
    

    It passes reference to "processedRequest" still, which refers to a HttpServletRequest request whose stream has already been read.

    0 讨论(0)
提交回复
热议问题