场景:
在开发中,通常我们需要对异常分类捕捉处理,例如全局异常、空指针异常、运行时异常、自定义业务异常、springframework.validation验证表单消息等,捕捉记录日志文件后,再把捕捉到的异常消息统一响应到前端。这就需要我们配置相应的策略
捕捉异常并打印记录日志,代码如下:
package com.hkl.modules.exception;
import cn.hutool.core.util.ObjectUtil;
import com.hkl.enums.ResultCode;
import com.hkl.exception.BizException;
import com.hkl.vo.resp.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
/**
* <p>捕捉异常并处理</p >
* <p>Description:</p >
* <p>Author:hkl</p >
* <p>Date: 2021-11-27</p >
*/
@Slf4j
@ControllerAdvice
public class ExceptionAdvice {
/**
* <p>捕捉全局异常</p >
* @author hkl
* @date 2021-11-27
* @param ex 捕捉的异常信息回应对象
*/
@ResponseBody
@ExceptionHandler(value = {Exception.class})
public CommonResult<String> exceptionHandler(Exception ex) {
log.info("捕捉的异常信息:" + ex.getMessage());
//打印异常信息
printStackTraceInfo(ex.getStackTrace());
//获取servlet容器
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
return new CommonResult(ResultCode.FAIL.getCode(), ResultCode.FAIL.getMsg(), ex.getMessage(), request.getRequestURI());
}
/**
* <p>捕捉空指针异常(空指针异常需要单独捕捉处理,异常消息在fillInStackTrace()方法中)</p >
* @author hkl
* @date 2021-11-27
* @param nullEx 捕捉的异常信息回应对象
*/
@ResponseBody
@ExceptionHandler(value = {NullPointerException.class})
public CommonResult<String> exceptionHandler(NullPointerException nullEx) {
//打印异常信息。空指针异常比较特殊,必须放在下面一行代码 log.info() 之前才可以正常打印出异常类的路径(暂不知为何)
printStackTraceInfo(nullEx.getStackTrace());
log.info("捕捉的异常信息:" + nullEx.getMessage());
//获取servlet容器
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
return new CommonResult(ResultCode.FAIL.getCode(), ResultCode.FAIL.getMsg(), String.valueOf(nullEx.getMessage()), request.getRequestURI());
}
/**
* <p>捕捉自定义异常</p >
* @author hkl
* @date 2021-11-27
* @param bizEx 捕捉的异常信息回应对象
*/
@ResponseBody
@ExceptionHandler(value = BizException.class)
public CommonResult<String> exceptionHandler(BizException bizEx) {
log.info("捕捉的异常信息:" + bizEx.getMessage());
//打印异常信息
printStackTraceInfo(bizEx.getStackTrace());
//获取servlet容器
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
return new CommonResult(ResultCode.FAIL.getCode(), ResultCode.FAIL.getMsg(), bizEx.getMessage(), request.getRequestURI());
}
/**
* <p>捕捉springframework.validation验证表单消息</p >
* @author hkl
* @date 2021-11-27
* @param ex 捕捉的异常信息回应对象
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public CommonResult<String> exceptionHandler(MethodArgumentNotValidException ex) {
log.error("异常信息:{}", ex.getMessage());
//打印异常信息
printStackTraceInfo(ex.getStackTrace());
//获取Servlet容器
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//获取request请求
HttpServletRequest request = attributes.getRequest();
CommonResult<String> commonResult = new CommonResult<>();
return commonResult
.setCode(ResultCode.FAIL.getCode())
.setMessage(ResultCode.FAIL.getMsg())
.setPath(request.getRequestURI())
.setData(ex.getBindingResult().getFieldError().getDefaultMessage());
}
/**
* <p>打印异常栈追踪的信息</p >
* @author hkl
* @date 2021/11/27
* @param stackTraceElements 追踪到的栈异常信息集合
*/
private void printStackTraceInfo(StackTraceElement[] stackTraceElements){
log.error("追踪栈异常信息:");
for(StackTraceElement stackTraceElement : Optional.ofNullable(stackTraceElements).orElse(new StackTraceElement[0])){
if(ObjectUtil.isNotNull(stackTraceElement)){
String errMsg = String.valueOf(stackTraceElement);
//只打印此项目业务中捕捉到的异常信息
if(errMsg.contains("com.hkl")){
log.error(errMsg);
}
}
}
}
}