springboot+aop+自定义注解,打造通用的全局异常处理和参数校验(注解版)

一.引入相应的maven依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

二.自定义参数校验注解

/**
 * @Author: guandezhi
 * @Date: 2019/3/11 13:07
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ParamValidate {
    String value() default "";
}

三.自定义异常切面

package com.gdz.paramvalidate.aspect;

import com.gdz.paramvalidate.annotation.ParamValidate;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;

import java.lang.reflect.Method;
import java.util.List;

/**
 * 异常处理切面
 * @Author: guandezhi
 * @Date: 2019/3/11 13:03
 */
@Slf4j
@Aspect
@Component
public class ExceptionAspect {

    @Before("@annotation(com.gdz.paramvalidate.annotation.ParamValidate)")
    public void before(JoinPoint jp) throws Exception {
        doBefore(jp);
    }

    private void doBefore(JoinPoint jp) throws Exception {
        if (getParamValidate(jp) != null) {
            Object[] args = jp.getArgs();
            if (args == null) {
                return;
            }
            //将异常格式化成通用格式
            formateException(args);
        }
    }

    private ParamValidate getParamValidate(JoinPoint jp) {
        MethodSignature methodSignature = (MethodSignature) jp.getSignature();
        Method method = methodSignature.getMethod();
        return method.getAnnotation(ParamValidate.class);
    }

    private void formateException(Object[] args) throws Exception {
        for (Object arg : args) {
            if (arg instanceof BindingResult) {
                BindingResult result = (BindingResult) arg;
                if (result != null && result.getErrorCount() > 0) {
                    List<ObjectError> errors = result.getAllErrors();
                    String errorMsg = "";
                    for (ObjectError error : errors) {
                        if (error instanceof FieldError) {
                            FieldError fe = (FieldError) error;
                            errorMsg = String.format("%s:%s", fe.getField(), error.getDefaultMessage());
                        } else {
                            errorMsg = String.format("%s:%s ", error.getCode(), error.getDefaultMessage());
                        }
                        log.error(errorMsg);
                        throw new Exception(errorMsg);
                    }
                }
            }
        }
    }

}

四.自定义全局异常处理器

package com.gdz.paramvalidate.exception;

import com.gdz.paramvalidate.bean.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 全局异常处理
 *
 * @Author: guandezhi
 * @Date: 2019/3/11 14:43
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {


    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public ResultVo<Object> handleException(Exception e) {
        String errorMsg = "";
        if (e instanceof NullPointerException) {
            errorMsg = "参数空指针异常";
        } else if (e instanceof HttpMessageNotReadableException) {
            errorMsg = "请求参数匹配错误," + e.getLocalizedMessage();
        } else {
            errorMsg = e.getMessage();
        }
        log.error(String.format("请求异常[%s]", e));

        ResultVo<Object> resultVo = new ResultVo<>();
        resultVo.setResultCode("501");
        resultVo.setResultMsg(errorMsg);
        return resultVo;
    }
}

其中的resultVo如下:

/**
 * @Author: guandezhi
 * @Date: 2019/3/11 12:14
 */
@Data
public class ResultVo<T> {

    private String resultCode;

    private String resultMsg;

    private T data;

}

五.在需要校验入参的controller方法上加上自定义注解

/**
 * @Author: guandezhi
 * @Date: 2019/3/11 12:15
 */
@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {

    @ParamValidate
    @RequestMapping("/addUser")
    public String addUser(@RequestBody @Valid User user, BindingResult result) throws Exception {
        int i = 1 / 0;
        return "success";
    }
}

这里必须加上@ParamValidate  @Valid这两个注解才能生效

其中User类如下:

/**
 * @Author: guandezhi
 * @Date: 2019/3/11 12:19
 */
@Data
public class User {

    @NotNull(message = "用户名不能为空")
    private String name;

    @NotNull(message = "手机号不能为空")
    private String mobile;
}

六.测试一下

1.当入参为空值时

springboot+aop+自定义注解,打造通用的全局异常处理和参数校验(注解版)




 

1.当程序有异常时

springboot+aop+自定义注解,打造通用的全局异常处理和参数校验(注解版)

 

代码地址:

上一篇:springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)


下一篇:Spark核心思想