Spring REST service: retrieving JSON from Request

后端 未结 11 595
甜味超标
甜味超标 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:45

    Currently in spring-mvc repo, interceptors are invoked in 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);
    ...
    

    Can I define my own DispatcherServlet, and override doDispatch(...) to inject a HttpRequestWrapper with a ByteArrayInputStream on 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);
    
        }
    ...
    

    Will this work for the above situation?

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

    For getting data from Body you can try to read and recreate InputStream in RequestBodyAdviceAdapter:

    @ControllerAdvice
    public class CustomRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {
    
        @Override
        public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
            String body = IOUtils.toString(inputMessage.getBody(), UTF_8.name());
    
            HttpInputMessage myMessage = new HttpInputMessage(){
                @Override
                public InputStream getBody() throws IOException {
                    return new ByteArrayInputStream(body.getBytes());
                }
                @Override
                public HttpHeaders getHeaders() {
                    return inputMessage.getHeaders();
                }
            };
    
            System.out.println("Data from Body: " + body);
    
            return super.beforeBodyRead(myMessage, parameter, targetType, converterType);
        }
    
        @Override
        public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
            System.out.println("Data from Body is empty");
            return super.handleEmptyBody(body, inputMessage, parameter, targetType, converterType);
        }
    
        @Override
        public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
            return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
        }
    
        @Override
        public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
            return true;
        }
    }
    
    0 讨论(0)
  • 2020-11-27 04:46

    You need to implement the requestWrapper as follows:

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

    and then inside the chain.doFilter method of filter class pass the requestWrapper object instead of the request object as follows:

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

    Thus solving the IOStream closed exception.

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

    In my experiences,just develop as follows: Using the filter in order to wrapper ServletRequest,then you can repeatly use getting request input stream.

    0 讨论(0)
  • 2020-11-27 05:03

    Hey can you try with this:

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

    Here: it you proving URI with the '/' it allows all the operations to perform. such as get post update and delete with same URI value.

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