How to get the @RequestBody in an @ExceptionHandler (Spring REST)

前端 未结 3 989
一生所求
一生所求 2020-12-01 14:03

I am using Spring Boot 1.4.1 which includes spring-web-4.3.3. I have a class annotated with @ControllerAdvice and methods annotated with @ExceptionHandle

3条回答
  •  情深已故
    2020-12-01 14:39

    You should be able to get the content of the request body by using the RequestBodyAdvice interface. If you implement this on a class annotated with @ControllerAdvice it should be picked up automatically.

    To get other request information like the HTTP method and query params I'm using an interceptor. I'm capturing all this request info for error reporting in a ThreadLocal variable which I clear on the afterCompletion hook in that same interceptor.

    The class below implements this and can be used in your ExceptionHandler to get all request information:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Type;
    import java.util.HashMap;
    import java.util.Map;
    
    @ControllerAdvice
    public class RequestInfo extends HandlerInterceptorAdapter implements RequestBodyAdvice {
        private static final Logger logger = LoggerFactory.getLogger(RequestInfo.class);
        private static final ThreadLocal requestInfoThreadLocal = new ThreadLocal<>();
    
        private String method;
        private String body;
        private String queryString;
        private String ip;
        private String user;
        private String referrer;
        private String url;
    
        public static RequestInfo get() {
            RequestInfo requestInfo = requestInfoThreadLocal.get();
            if (requestInfo == null) {
                requestInfo = new RequestInfo();
                requestInfoThreadLocal.set(requestInfo);
            }
            return requestInfo;
        }
    
        public Map asMap() {
            Map map = new HashMap<>();
            map.put("method", this.method);
            map.put("url", this.url);
            map.put("queryParams", this.queryString);
            map.put("body", this.body);
            map.put("ip", this.ip);
            map.put("referrer", this.referrer);
            map.put("user", this.user);
            return map;
        }
    
        private void setInfoFromRequest(HttpServletRequest request) {
            this.method = request.getMethod();
            this.queryString = request.getQueryString();
            this.ip = request.getRemoteAddr();
            this.referrer = request.getRemoteHost();
            this.url = request.getRequestURI();
            if (request.getUserPrincipal() != null) {
                this.user = request.getUserPrincipal().getName();
            }
        }
    
        public void setBody(String body) {
            this.body = body;
        }
    
        private static void setInfoFrom(HttpServletRequest request) {
            RequestInfo requestInfo = requestInfoThreadLocal.get();
            if (requestInfo == null) {
                requestInfo = new RequestInfo();
            }
            requestInfo.setInfoFromRequest(request);
            requestInfoThreadLocal.set(requestInfo);
        }
    
        private static void clear() {
            requestInfoThreadLocal.remove();
        }
    
        private static void setBodyInThreadLocal(String body) {
            RequestInfo requestInfo = get();
            requestInfo.setBody(body);
            setRequestInfo(requestInfo);
        }
    
        private static void setRequestInfo(RequestInfo requestInfo) {
            requestInfoThreadLocal.set(requestInfo);
        }
    
        // Implementation of HandlerInterceptorAdapter to capture the request info (except body) and be able to add it to the report in case of an error
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            RequestInfo.setInfoFrom(request);
            return true;
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
            RequestInfo.clear();
        }
    
        // Implementation of RequestBodyAdvice to capture the request body and be able to add it to the report in case of an error
    
        @Override
        public boolean supports(MethodParameter methodParameter, Type targetType, Class> converterType) {
            return true;
        }
    
        @Override
        public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType) {
            return inputMessage;
        }
    
        @Override
        public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType) {
            RequestInfo.setBodyInThreadLocal(body.toString());
            return body;
        }
    
        @Override
        public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType) {
            return body;
        }
    }
    

提交回复
热议问题