zoukankan      html  css  js  c++  java
  • 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;
    
    }
  • 相关阅读:
    设计模式开篇——7大设计原则
    MySQL MVCC专题
    Spring常考的面试题
    HashMap常考面试题
    Equals和==的比较
    高并发编程
    一文读懂JVM
    scala实现定时任务的方法
    PLAY2.6-SCALA(十二) 表单的处理
    PLAY2.6-SCALA(十一) 模板常用场景
  • 原文地址:https://www.cnblogs.com/ding-dang/p/13049181.html
Copyright © 2011-2022 走看看