SpringBoot如何编写统一异常管理呢?
下文笔者讲述使用AOP实现统一异常管理的方法分享,如下所示
结果集定义方式
实现思路:
1.引入AOP相应的jar包
2.编写相应的异常类
3.使用注解为编写exceptionhandler
4.编写AOP拦截所有错误信息
引入相应的starter器
<!--spring切面aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
定义返回报文的格式
返回报文包含以下信息:成功标志:是一个布尔值,用于表示是否运行正常 错误代码:使用整型作为标志位 错误信息:使用String作为错误信息的描述,留给前端是否展示给用户或者进入其他错误流程的使用。 结果集:在无错误信息的情况下所得到的正确数据信息。一般是个Map,前端根据Key取值例:
结果集定义方式
public class Result<T> {
// error_code 状态值:0 极为成功,其他数值代表失败
private Integer status;
// error_msg 错误信息,若status为0时,为success
private String msg;
// content 返回体报文的出参,使用泛型兼容不同的类型
private T data;
public Integer getStatus() {
return status;
}
public void setStatus(Integer code) {
this.status = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData(Object object) {
return data;
}
public void setData(T data) {
this.data = data;
}
public T getData() {
return data;
}
@Override
public String toString() {
return "Result{" +
"status=" + status +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
定义一个枚举类用于设置代码和信息的关联
public enum ExceptionEnum {
UNKNOW_ERROR(-1,"未知错误"),
USER_NOT_FIND(-101,"用户不存在"),
;
private Integer code;
private String msg;
ExceptionEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
统一返回的结果集工具类
public class ResultUtil {
/**
* 返回成功,传入返回体具体出參
* @param object
* @return
*/
public static Result success(Object object){
Result result = new Result();
result.setStatus(0);
result.setMsg("success");
result.setData(object);
return result;
}
/**
* 提供给部分不需要出參的接口
* @return
*/
public static Result success(){
return success(null);
}
/**
* 自定义错误信息
* @param code
* @param msg
* @return
*/
public static Result error(Integer code,String msg){
Result result = new Result();
result.setStatus(code);
result.setMsg(msg);
result.setData(null);
return result;
}
/**
* 返回异常信息,在已知的范围内
* @param exceptionEnum
* @return
*/
public static Result error(ExceptionEnum exceptionEnum){
Result result = new Result();
result.setStatus(exceptionEnum.getCode());
result.setMsg(exceptionEnum.getMsg());
result.setData(null);
return result;
}
}
异常类定义
public class DescribeException extends RuntimeException{ private Integer code; /** * 继承exception,加入错误状态值 * @param exceptionEnum */ public DescribeException(ExceptionEnum exceptionEnum) { super(exceptionEnum.getMsg()); this.code = exceptionEnum.getCode(); } /** * 自定义错误信息 * @param message * @param code */ public DescribeException(String message, Integer code) { super(message); this.code = code; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } }
异常处理类封装
@ControllerAdvice
public class ExceptionHandle {
private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionHandle.class);
/**
* 判断错误是否是已定义的已知错误,不是则由未知错误代替,同时记录在log中
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result exceptionGet(Exception e){
if(e instanceof DescribeException){
DescribeException MyException = (DescribeException) e;
return ResultUtil.error(MyException.getCode(),MyException.getMessage());
}
LOGGER.error("【系统异常】{}",e);
return ResultUtil.error(ExceptionEnum.UNKNOW_ERROR);
}
}
注意事项:
1.此处使用@ControllerAdvice注解
则Spring会加载该类
并将所有捕获的异常统一返回结果Result这个实体
2.此处的操作方式可捕捉类的异常,但如果接口出现异常
则无法知道是谁调用了接口,所以此时我们需引入AOP
AOP捕捉异常
@Aspect
@Component
public class HttpAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(HttpAspect.class);
@Autowired
private ExceptionHandle exceptionHandle;
@Pointcut("execution(public * com.java265.controller.*.*(..))")
public void log(){
}
@Before("log()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
LOGGER.info("url={}",request.getRequestURL());
//method
LOGGER.info("method={}",request.getMethod());
//ip
LOGGER.info("id={}",request.getRemoteAddr());
//class_method
LOGGER.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
//args[]
LOGGER.info("args={}",joinPoint.getArgs());
}
@Around("log()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Result result = null;
try {
} catch (Exception e) {
return exceptionHandle.exceptionGet(e);
}
if(result == null){
return proceedingJoinPoint.proceed();
}else {
return result;
}
}
@AfterReturning(pointcut = "log()",returning = "object")//打印输出结果
public void doAfterReturing(Object object){
LOGGER.info("response={}",object.toString());
}
}
以上代码将使用@Aspect来声明这是一个切面
使用@Pointcut来定义切面所需要切入的位置
此处AOP将对HTTP请求做一个切入
在进入方法之前我们使用@Before记录了调用的接口URL,调用的方法,调用方的IP地址以及输入的参数等
在整个接口代码运作期间
我们使用@Around来捕获异常信息,并用之前定义好的Result进行异常的返回
最后我们使用@AfterReturning来记录我们的出參。
通过以上方法即可实现日志监控
例:
Controller示例编写
@RestController
@RequestMapping("/result")
public class ResultController {
@Autowired
private ExceptionHandle exceptionHandle;
/**
* 返回体测试
* @param name
* @param pwd
* @return
*/
@RequestMapping(value = "/getResult",method = RequestMethod.POST)
public Result getResult(@RequestParam("name") String name, @RequestParam("pwd") String pwd){
Result result = ResultUtil.success();
try {
if (name.equals("maomaojava265")){
result = ResultUtil.success(new UserInfo());
}else if (name.equals("pzz")){
result = ResultUtil.error(ExceptionEnum.USER_NOT_FIND);
}else{
int i = 1/0;
}
}catch (Exception e){
result = exceptionHandle.exceptionGet(e);
}
return result;
}
}
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


