SpringBoot快速开发(五)【异常管理】

一、引入依赖

在SpringBoot中引入AOP是一件很方便的事,和其他引入依赖一样,我们只需要在POM中引入starter就可以了:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

二、自定义异常信息枚举类

 这里可以自定义服务中的一些异常信息

/**
 * 异常信息枚举类
 *
 * @author renjie
 * @version 1.0.0
 */
public enum ExceptionEnum {

    SYSTEM_ERROR("500","系统异常"),
    PARAM_ERROR("231","参数错误");

    private String code;

    private String msg;

    ExceptionEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

二、自定义错误信息类

  一般系统抛出的错误是不含错误代码的,除去部分的404,400,500错误之外,我们如果想把错误代码定义的更细致,就需要自己继承RuntimeException这个类后重新定义一个构造方法来定义我们自己的错误信息:

/**
 * 自定义错误信息类
 *
 * @author renjie
 * @version 1.0.0
 */
public class DescribeException extends RuntimeException{
    private String code;

    /**
     * 继承exception,加入错误状态值
     * @param exceptionEnum
     */
    public DescribeException(ExceptionEnum exceptionEnum) {
        super(exceptionEnum.getMsg());
        this.code = exceptionEnum.getCode() + "";
    }

    /**
     * 自定义错误信息
     * @param message
     * @param code
     */
    public DescribeException(String message, String code) {
        super(message);
        this.code = code;
    }

    /**
     * 自定义错误信息
     * @param e
     */
    public DescribeException(Exception e){
        super(e.getMessage());
        this.code = ExceptionEnum.SYSTEM_ERROR.toString();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

三、自定义返回类

在上一篇SpringBoot快速开发(四)【Controller层】贴出的代码中,控制层返回的类型为:ObjectResult,该类即为自定义的返回类型,内容如下。注意到其中的几个静态方法:success、error等,这些方法可直接在Controller层封装成功或错误信息,并返回。

/**
 * 返回的对象
 *
 * @author renjie
 * @version 1.0.0
 */
public class ObjectResult<T> implements Serializable {
    private static final long serialVersionUID = -9146805371831100892L;

    final public static ObjectResult SUCCESS = new ObjectResult("200", "操作成功");

    private String code;

    private String msg;

    private T data;

    public ObjectResult() {
    }

    public ObjectResult(String code, String msg) {
        this(code, msg, null);
    }

    public ObjectResult(String code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    private ObjectResult copyThis() {
        return new ObjectResult(code, msg, null);
    }

    /**
     * 操作成功(有返回数据)
     * @param object
     * @return
     */
    public static ObjectResult success(Object object) {
        ObjectResult r = ObjectResult.SUCCESS.copyThis();
        r.setData(object);
        return r;
    }

    /**
     * 操作成功(无返回数据)
     * @return
     */
    public static ObjectResult success() {
        ObjectResult r = ObjectResult.SUCCESS.copyThis();
        r.setData(null);
        return r;
    }

    /**
     * 自定义错误信息
     * @param describeException
     * @return
     */
    public static ObjectResult error(DescribeException describeException){
        ObjectResult objectResult = new ObjectResult();
        objectResult.setCode(describeException.getCode());
        objectResult.setMsg(describeException.getMessage());
        return objectResult;
    }

    /**
     * 返回异常信息,在已知的范围内
     * @param exceptionEnum
     * @return
     */
    public static ObjectResult error(ExceptionEnum exceptionEnum){
        ObjectResult objectResult = new ObjectResult();
        objectResult.setCode(exceptionEnum.getCode());
        objectResult.setMsg(exceptionEnum.getMsg());
        return objectResult;
    }



    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

四、异常捕获并处理

 上面已经创建了异常枚举类、错误信息封装类、自定义返回类,还需要最重要的异常信息捕获类。

  Spring为我们提供了两个比较好的注解:

  • @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
  • @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开
/**
 * 异常信息处理类
 *
 * @author renjie
 * @version 1.0.0
 */
@ControllerAdvice
public class ExceptionHandle {
    private final static Logger log = LoggerFactory.getLogger(ExceptionHandle.class);

    /**
     * 判断错误是否是已定义的已知错误,不是则由未知错误代替,同时记录在log中
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ObjectResult exceptionGet(Exception e){
        if(e instanceof DescribeException){
            DescribeException MyException = (DescribeException) e;
            return ObjectResult.error(MyException);
        }

        log.error("【系统异常】{}",e);
        return ObjectResult.error(ExceptionEnum.SYSTEM_ERROR);
    }
}

到这里为止,我们已经完成了对结果以及异常的统一返回管理,并且在出现异常时,我们可以不返回错误信息给前端,而是用未知错误进行代替,只有查看log我们才会知道真实的错误信息。

五、AOP对接口调用进行管理

我们使用接口若出现了异常,很难知道是谁调用接口,是前端还是后端出现的问题导致异常的出现,那这时,AOP久发挥作用了,我们之前已经引入了AOP的依赖,现在我们编写一个切面类,切点如何配置不需要我多说了吧:

/**
 * 切面配置信息
 *
 * @author renjie
 * @version 1.0.0
 */
@Aspect
@Component
public class HttpAspect {
    private final static Logger log = LoggerFactory.getLogger(HttpAspect.class);

    @Pointcut("execution(public * com.rj.demo.test.controller.*.*(..))")
    public void log(){

    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //url
        log.info("url={}",request.getRequestURL());
        //method
        log.info("method={}",request.getMethod());
        //ip
        log.info("id={}",request.getRemoteAddr());
        //class_method
        log.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
        //args[]
        log.info("args={}",joinPoint.getArgs());
    }

    @Around("log()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
                    return proceedingJoinPoint.proceed();

    }

    @AfterReturning(pointcut = "log()",returning = "object")//打印输出结果
    public void doAfterReturing(Object object){
        if(CommUtil.isNotNullOrEmpty(object)){
            log.info("response={}",object.toString());
        }
    }
}

六、异常管理测试

接下来我们心新写一个ResultController来测试一下:

/**
 * 控制层
 *
 * @author renjie
 * @version 1.0.0
 */
@RestController
@RequestMapping("/demo")
public class Controller {
    @Autowired
    Rj rj;
    @RequestMapping(value="/test", method = RequestMethod.GET)
    public ObjectResult test(String id){
        if(CommUtil.isNullOrEmpty(id)){
            throw new DescribeException(ExceptionEnum.PARAM_ERROR);
        }
        String name = rj.getName();
        return ObjectResult.success(name + ":" + id);
    }
}

异常的情况:

正常的情况:

猜你喜欢

转载自blog.csdn.net/nsxqf/article/details/85716866
今日推荐