springboot全局异常拦截、以及日志参数打印

话不多说,直接上代码:

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @FileNName: BaseController
 * @Description: 全局统一处理controller
 * @Author: guoxingliang
 * @Create: 2019-08-06 10:08
 * @Copyright: (c)2018年 ***公司
 */
@Slf4j
@ControllerAdvice
public class BaseController {
    // 专门用来捕获和处理Controller层的校验时异常
    @ExceptionHandler(VerifyException.class)
    public ModelAndView verifyExceptionHandler(VerifyException e, HttpServletRequest request) {
        this.exceptionLogs(e, request);
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("code", ApiResult.ERROR_VALUE);
        mv.addObject("msg",e.getMessage());
        mv.addObject("data",null);
        return mv;
    }

    // 专门用来捕获和处理Controller层的异常
    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(Exception e, HttpServletRequest request) {
        this.exceptionLogs(e, request);
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("code", ApiResult.ERROR_SYSTEM);
        mv.addObject("msg", LanguageUtil.get(ConstantsUtils.FAIL_MSG));
        mv.addObject("data",null);
        return mv;
    }

    public void exceptionLogs(Exception e, HttpServletRequest request) {
        try{
            //日志打印
            log.error("BaseController->exceptionHandler:request url:[{}],request params:[{}];exception:[{}]", request.getRequestURI(), RequestUtils.getRequestJsonString(request), e);
        } catch (IOException ex) {
            log.error("BaseController getting parameter exceptions");
        }
    }
}

用到的工具类:

import org.springframework.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class RequestUtils {

    private RequestUtils() {}

    private static final String UNKNOWN = "unknown";

    public static String getRequestJsonString(HttpServletRequest request) throws IOException {
        String method = request.getMethod();
        if (method.equals("GET")) {
            if (StringUtils.isEmpty(request.getQueryString())) {
                return null;
            }
            return new String(request.getQueryString().getBytes("iso-8859-1"), "utf-8").replaceAll("%22", "\"");
        } else {
            return getRequestPostStr(request);
        }
    }

    public static String getRequestPostStr(HttpServletRequest request) throws IOException {
        byte[] buffer = getRequestPostBytes(request);
        String charEncoding = request.getCharacterEncoding();
        if (charEncoding == null) {
            charEncoding = "UTF-8";
        }
        return new String(buffer, charEncoding);
    }

    public static byte[] getRequestPostBytes(HttpServletRequest request) throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
            return null;
        }
        byte[] buffer = new byte[contentLength];
        for (int i = 0; i < contentLength; ) {
            int readLen = request.getInputStream().read(buffer, i, contentLength - i);
            if (readLen == -1) {
                break;
            }
            i += readLen;
        }
        return buffer;
    }

    public static String getCookie(HttpServletRequest request, String name) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie: cookies){
            if(cookie.getName().equals(name))
                return cookie.getValue();
        }
        return "";
    }
}

其中VerifyException是自定义的异常

大家都说post打印参数出现了问题,其实问题原因主要是由于request.getInputStream()在@Responsebody使用之后会自动关闭,导致日志打印时出现request stream close问题,以至于post参数无法打印,这里给大家提供一个解决办法

重写request构造方法,进行request缓存

代码如下:

新增类BodyReaderHttpServletRequestWrapper.java

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = readBytes(request.getInputStream());
    }

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

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

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

    public static byte[] readBytes(InputStream is) throws Exception {
        byte[] buffer=new byte[1024];  
        int len=0;  
        ByteArrayOutputStream bos=new ByteArrayOutputStream();  
        while((len=is.read(buffer))!=-1){  
            bos.write(buffer,0,len);  
        }  
        bos.flush();  
        return bos.toByteArray();  
    }
}

新增类:

@WebFilter(filterName = "httpServletRequestReplacedFilter", urlPatterns = "/*")
public class HttpServletRequestReplacedFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
        }
        if (requestWrapper == null) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
 
    @Override
    public void destroy() {
    }
}

最后在Application中加入注解:@ServletComponentScan

再次打印,发现问题解决

你可能感兴趣的:(springboot全局异常拦截、以及日志参数打印)