全局异常处理
全局异常处理
项目中的异常在GlobalExceptionHandler类
中进行统一的拦截处理
捕获到的异常会在doLog方法
中存储进eb_exception_log表中,方便对异常进行回溯处理。
当然在这里,如果觉得所有异常都进表会产生无效数据,校验性的异常可以不进行存储,只需判断e.getCode()值不为空,并且排除特定code值即可。
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
private static String REQUESTBODY = "requestBodyMessage";
@Autowired
private ExceptionLogService exceptionLogService;
/**
* 处理自定义的业务异常
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(value = CrmebException.class)
public CommonResult crmebExceptionHandler(HttpServletRequest request, CrmebException e) {
doLog(request, e);
if (ObjectUtil.isNull(e.getCode())) {
return CommonResult.failed(e.getMessage());
}
return CommonResult.failed(e);
}
/**
* 处理业务业务异常
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(value = BusinessException.class)
public CommonResult crmebExceptionHandler(HttpServletRequest request, BusinessException e) {
doLog(request, e);
if (ObjectUtil.isNull(e.getCode())) {
return CommonResult.failed(e.getMessage());
}
return CommonResult.failed(e);
}
/**
* 统一处理非自定义异常外的所有异常
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(value = Exception.class)
public CommonResult crmebExceptionHandler(HttpServletRequest request, Exception e) {
doLog(request, e);
return CommonResult.failed(e.getMessage());
}
/**
* 兼容Validation校验框架:忽略参数异常处理器
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(MissingServletRequestParameterException.class)
public CommonResult parameterMissingExceptionHandler(HttpServletRequest request, MissingServletRequestParameterException e) {
doLog(request, e);
return CommonResult.failed(CommonResultCode.VALIDATE_FAILED, "请求参数 " + e.getParameterName() + " 不能为空");
}
/**
* 兼容Validation校验框架:缺少请求体异常处理器
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(HttpMessageNotReadableException.class)
public CommonResult parameterBodyMissingExceptionHandler(HttpServletRequest request, HttpMessageNotReadableException e) {
doLog(request, e);
return CommonResult.failed(CommonResultCode.VALIDATE_FAILED, "参数体不能为空");
}
/**
* 兼容Validation校验框架:参数效验异常处理器
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(MethodArgumentNotValidException.class)
public CommonResult parameterExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
doLog(request, e);
// 获取异常信息
BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (exceptions.hasErrors()) {
List<ObjectError> errors = exceptions.getAllErrors();
if (!errors.isEmpty()) {
// 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
FieldError fieldError = (FieldError) errors.get(0);
return CommonResult.failed(CommonResultCode.VALIDATE_FAILED, fieldError.getDefaultMessage());
}
}
return CommonResult.failed(CommonResultCode.VALIDATE_FAILED, "请求参数校验异常");
}
/**
* 拦截表单参数校验
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler({BindException.class})
public CommonResult bindException(HttpServletRequest request, BindException e) {
doLog(request, e);
BindingResult bindingResult = e.getBindingResult();
return CommonResult.failed(CommonResultCode.VALIDATE_FAILED, Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
}
/**
* 拦截参数类型不正确
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public CommonResult bindException(HttpServletRequest request, HttpMediaTypeNotSupportedException e) {
doLog(request, e);
return CommonResult.failed(CommonResultCode.VALIDATE_FAILED, Objects.requireNonNull(e.getMessage()));
}
/**
* 由于body在接口读取后无法获取,这里把body提前取出放到参数中,在上面处理异常时使用
*/
@ModelAttribute
public void getBobyInfo(HttpServletRequest request) {
//获取requestBody
try {
ContentCachingRequestWrapper requestWapper = null;
if (request instanceof HttpServletRequest) {
requestWapper = (ContentCachingRequestWrapper) request;
}
String body = IOUtils.toString(requestWapper.getBody(), request.getCharacterEncoding());
request.setAttribute(REQUESTBODY, body);
} catch (Exception e) {
}
}
/**
* 打印日志
*/
private void doLog(HttpServletRequest request, Exception e) {
LOGGER.error("捕获到异常:", e);
// 加入数据库日志记录
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw, true));
// 异常的详情
String expDetail = sw.toString();
try {
sw.close();
} catch (IOException ioException) {
LOGGER.error("异常日志:关闭异常详情Writer异常");
}
// 异常的url
String expUrl = request.getRequestURI();
// 异常的参数
Object body = request.getAttribute(REQUESTBODY);
String expParams = ObjectUtil.isNotNull(body) ? body.toString() : "";
// 异常的类型
String expType = e.getClass().getName();
// 异常的类名
StackTraceElement stackTraceElement = e.getStackTrace()[0];
String expController = stackTraceElement.getClassName();
// 异常的方法名
String expMethod = stackTraceElement.getMethodName();
ExceptionLog exceptionLog = new ExceptionLog();
exceptionLog.setExpUrl(expUrl);
exceptionLog.setExpParams(expParams);
exceptionLog.setExpType(expType);
exceptionLog.setExpController(expController);
exceptionLog.setExpMethod(expMethod);
exceptionLog.setExpDetail(expDetail);
exceptionLogService.save(exceptionLog);
}
}