Spring全局异常处理

简介

  项目中编写API的时候因为要处理异常,所以代码中最常见的就是try-catch-finally,有时一个try,多个catch,代码既不美观,写的时候还很麻烦,Spring中提供了处理全局异常的方式,一个项目中只需要定义一次就不用在四处try-catch了,省时省力又优雅。

用法

  Spring能够较好的处理这种问题,核心关注如下两个注解:

    • @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
    • @RestControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开,返回json (或使用@ControllerAdvice,与@Controller和@RestController的作用相似)

代码

全局异常处理类

  定义一个全局异常处理类,对需要分开捕获对异常使用@ExceptionHandler分开捕获,单独处理,不用单独捕获的异常可以捕获Exception进行兜底处理,返回值可以返回项目中定义的统一返回格式,这里因为是代码示例,所以返回的都是String或者Void,@ExceptionHandler里面可以定义多个异常。定义好之后Controller中发生的异常都会到这里来统一处理

/**
 * @author LiuHuan
 * @date 2019-11-22 15:55
 * @desc 全局异常处理类
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 全局处理Exception类型的异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public String processException(Exception e){
        System.out.println("进入全局处理Exception方法");
        System.out.println(getExceptionLocation(e));
        e.printStackTrace();
        System.out.println("结束全局处理Exception方法");
        return "参数非法";
    }

    /**
     * 全局处理NullPointerException类型的异常
     * @param e
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public void processNullPointerException(NullPointerException e){
        System.out.println("进入全局处理NullPointerException方法");
        System.out.println(getExceptionLocation(e));
        e.printStackTrace();
        System.out.println("结束全局处理NullPointerException方法");
    }

    /**
     * 全局处理IllegalArgumentException类型的异常
     * @param e
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public void processIllegalArgumentException(IllegalArgumentException e){
        System.out.println("进入全局处理IllegalArgumentException方法");
        System.out.println(getExceptionLocation(e));
        e.printStackTrace();
        System.out.println("结束全局处理IllegalArgumentException方法");
    }

    /**
     * 全局处理RuntimeException类型的异常
     * @param e
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public String processRuntimeException(RuntimeException e){
        System.out.println("进入全局处理RuntimeException方法");
        System.out.println(getExceptionLocation(e));
        e.printStackTrace();
        System.out.println("结束全局处理RuntimeException方法");
        return "参数非法";
    }

    /**
     * 获取异常发生的位置,可用于打印日志
     * @param e
     * @return
     */
    private String getExceptionLocation(Exception e){
        StackTraceElement[] stackTrace = e.getStackTrace();
        StackTraceElement stack = stackTrace[0];
        String string = "%s.%s#%s.%s";
        String format = String.format(string, stack.getClassName(), stack.getMethodName(), stack.getFileName(),
            stack.getLineNumber());
        return format;
    }
}

参数校验  

  结合sping的参数校验注解,对参数进行校验,然后按照项目中返回格式统一返回,避免在Controller中的try-catch捕获不到方法之前的参数校验异常

    /**
     * 全局处理BindException类型的异常
     * @param e
     * @return
     */
    @ExceptionHandler({BindException.class})
    public List<String> processBindException(BindException e) {
        System.out.println("进入全局处理BindException方法");
        System.out.println(getExceptionLocation(e));
        e.printStackTrace();

        List<ObjectError> allErrors = e.getAllErrors();
        List<String> error = allErrors.
            stream().
            map(objectError -> ((FieldError)objectError).getField() + objectError.getDefaultMessage()).collect(
            Collectors.toList());
        System.out.println("结束全局处理BindException方法");
        return error;
    }

  异常测试类

/**
 * @author LiuHuan
 * @date 2019-11-02 11:58
 * @desc 异常测试类
 */
@RestController
public class GlobalExceptionTestController {

    @RequestMapping("/hello")
    public String hello(){
        return "hello world";
    }

    @RequestMapping("/processException")
    public void processException(@Validated @RequestBody User user){
        System.out.println(user.toString());
    }

    @RequestMapping("/processNullPointerException")
    public void processNullPointerException(){
        throw new NullPointerException();
    }

    @RequestMapping("/processIllegalArgumentException")
    public void processIllegalArgumentException(Exception e){
        throw new IllegalArgumentException();
    }

    @RequestMapping("/processRuntimeException")
    public void processRuntimeException(Exception e){
        throw new RuntimeException();
    }
    

}

  需要校验的入参类

/**
 * @author LiuHuan
 * @date 2019-11-22 16:44
 * @desc 需要校验的入参
 */
@Data
public class User {

    @NotBlank
    private String name;

    @NotNull
    private Integer age;

    @NotEmpty
    private List<String> fruit;

}

 

posted @ 2020-06-05 13:14  叮叮叮叮叮叮当  阅读(689)  评论(0编辑  收藏  举报