转载

springboot2中的全局异常处理(包含Intercepter中的异常)

说明

之所以写这篇文章,是因为在项目中处理全局异常是发现自定义Intercepter中的异常没发通过 @ControllerAdvice 捕获。

项目中使用 @ControllerAdvice 处理了controller中的异常,但发现在自定义拦截器( extends HandlerInterceptorAdapter )中抛出的异常没有被拦截,跳转到了/error下,所以想要重写/error请求,过程比较曲折,现将测试通过的代码进行记录。

最终结果如下:

springboot2中的全局异常处理(包含Intercepter中的异常)

package com.xxx.core.controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
@Slf4j
public class CustomerExceptionController extends AbstractErrorController {
    private final ErrorProperties errorProperties;

    @Autowired
    public CustomerExceptionController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
        super(errorAttributes);
        this.errorProperties = serverProperties.getError();
    }

    @Override
    public String getErrorPath() {
        return errorProperties.getPath();
    }

    @RequestMapping(produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        ModelAndView modelAndView = new ModelAndView("error");
        Map<String, Object> errorMap = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        if (errorMap != null) {
            /* timestamp status error message path */
            modelAndView.addObject("msg", errorMap.get("error"));
            modelAndView.addObject("statusCode", errorMap.get("status"));
            logHandler(errorMap);
        }
        return modelAndView;
    }

    @RequestMapping
    @ResponseBody
    public ResponseEntity<JsonResult<Map<String, Object>>> error(HttpServletRequest request) {
        Map<String, Object> errorMap = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.APPLICATION_JSON));
        logHandler(errorMap);
        Map<String, Object> data = new HashMap<>();
        data.putAll(errorMap);
        data.remove("trace");
        // HttpStatus status = getStatus(request);
        return new ResponseEntity<>(JsonResult.failure("", data), HttpStatus.OK);
    }

    private void logHandler(Map<String, Object> errorMap) {
        log.error("url:{},status{},time:{},errorMsg:{}", errorMap.get("path"), errorMap.get("status"),
                errorMap.get("timestamp"), errorMap.get("message"));
    }

    protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
        IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
        if (include == IncludeStacktrace.ALWAYS) {
            return true;
        }
        if (include == IncludeStacktrace.ON_TRACE_PARAM) {
            return getTraceParameter(request);
        }
        return false;
    }

    private ErrorProperties getErrorProperties() {
        return this.errorProperties;
    }
}

本来想直接继承 BasicErrorController,重写error方法 完事,结果发现继承后启动报错,提示没有ErrorProperties。

后来找到一篇文章,构造方法中注入的是ServerProperties serverProperties(和本例类似),通过serverProperties获取ErrorProperties,修改后提示没有无参的构造方法。

心好累,不想努力了,就直接继承了AbstractErrorController,抄了一些BasicErrorController的内容成了上面的代码。完美解决了纠结的问题。

注意事项

拦截器中要排除 /error路径

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizeIntercepter).addPathPatterns("/**").excludePathPatterns("/login", "/login/**",
                "/static/**", "/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**","/v2/**","/error");
    }
原文  https://segmentfault.com/a/1190000021280797
正文到此结束
Loading...