SpringBoot全局异常处理
在SpringMVC中可以使用ControllerAdvice来做controller内部的全局异常处理,但对于未进入controller前的异常,该处理方法是无法进行捕获处理的,SpringBoot提供了ErrorController的处理类来处理所有的异常。
20190530补充:
springboot提供了/error的错误管理端点和默认的BasicErrorController实现类,但这个Controller实现类其实不一定符合我们的需求,所以我们才需要来覆盖这个默认实现。
其中:BasicErrorController extend AbstractErrorController ,AbstractErrorController 又 implements ErrorController。
下面的类是直接实现了ErrorController,其实我们也可以仿照BasicErrorController来继承AbstractErrorController减少一些代码的编写。
1 import java.util.Map; 2 3 import javax.servlet.http.HttpServletRequest; 4 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.boot.autoconfigure.web.ErrorAttributes; 7 import org.springframework.boot.autoconfigure.web.ErrorController; 8 import org.springframework.http.HttpStatus; 9 import org.springframework.web.bind.annotation.RequestMapping; 10 import org.springframework.web.bind.annotation.ResponseStatus; 11 import org.springframework.web.bind.annotation.RestController; 12 import org.springframework.web.context.request.RequestAttributes; 13 import org.springframework.web.context.request.ServletRequestAttributes; 14 15 import com.tomato.boss.common.base.ResponseResult; 16 17 import lombok.extern.slf4j.Slf4j; 18 import springfox.documentation.annotations.ApiIgnore; 19 20 /** 21 * 全局异常处理,当异常被@ControllerAdvice时不会走到这个处理类,没被处理时会走到这里 22 * 例如 @valid入参校验失败的是不会走ControllerAdvice的,但会走这个处理器 23 * @author yangzhilong 24 * 25 */ 26 @RestController 27 @ApiIgnore 28 @Slf4j 29 public class GolablExceptionEndpoint implements ErrorController{ 30 31 private static final String PATH = "/error"; 32 33 @Autowired 34 private ErrorAttributes errorAttributes; 35 36 @Override 37 public String getErrorPath() { 38 return PATH; 39 } 40 41 /** 42 * 全局异常处理 43 * 增加@ResponseStatus注解将非200的http状态码转成200 44 * @return 45 */ 46 @RequestMapping(value = PATH) 47 @ResponseStatus(code=HttpStatus.OK) 48 public ResponseResult<Object> error(HttpServletRequest request) { 49 return handlerError(request, false); 50 } 51 52 /** 53 * 具体的处理 54 * @param request 55 * @param includeStackTrace 56 * @return 57 */ 58 private ResponseResult<Object> handlerError(HttpServletRequest request, boolean includeStackTrace) { 59 RequestAttributes requestAttributes = new ServletRequestAttributes(request); 60 Throwable e = errorAttributes.getError(requestAttributes); 61 62 Map<String, Object> data = errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace); 63 64 String message = null; 65 StringBuilder detailMessage = new StringBuilder(""); 66 67 HttpStatus status = getStatus(request); 68 if(status == HttpStatus.BAD_REQUEST) { 69 log.error("参数校验失败", e); 70 message = "请检查数据填写是否合法"; 71 } else if(status == HttpStatus.INTERNAL_SERVER_ERROR) { 72 log.error("系统错误", e); 73 message = "系统繁忙"; 74 } else if(status == HttpStatus.NOT_FOUND) { 75 log.error("404错误"); 76 message = "服务或者页面不存在"; 77 } else { 78 log.error("系统错误", e); 79 message = "系统出错,未知错误"; 80 } 81 if(null != data.get("error")) { 82 detailMessage.append(String.valueOf(data.get("error"))).append(":"); 83 } 84 if(null == e || null == e.getMessage()) { 85 if(null != data.get("message")) { 86 detailMessage.append(String.valueOf(data.get("message"))); 87 } 88 } else { 89 detailMessage.append(e.getMessage()); 90 } 91 92 return ResponseResult.buildFailResponse(String.valueOf(data.get("status")), message, detailMessage.toString()); 93 } 94 95 /** 96 * 获取错误编码 97 * @param request 98 * @return 99 */ 100 private HttpStatus getStatus(HttpServletRequest request) { 101 Integer statusCode = (Integer) request 102 .getAttribute("javax.servlet.error.status_code"); 103 if (statusCode == null) { 104 return HttpStatus.INTERNAL_SERVER_ERROR; 105 } 106 try { 107 return HttpStatus.valueOf(statusCode); 108 } 109 catch (Exception ex) { 110 return HttpStatus.INTERNAL_SERVER_ERROR; 111 } 112 } 113 }