说明
之所以写这篇文章,是因为在项目中处理全局异常是发现自定义Intercepter中的异常没发通过 @ControllerAdvice
捕获。
项目中使用 @ControllerAdvice
处理了controller中的异常,但发现在自定义拦截器( extends HandlerInterceptorAdapter )中抛出的异常没有被拦截,跳转到了/error下,所以想要重写/error请求,过程比较曲折,现将测试通过的代码进行记录。
最终结果如下:
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");
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。