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;
    
    }
  • 相关阅读:
    Java基础之线程——派生自Thread类的子类(TryThread)
    Java基础之一组有用的类——为标记定义自己的模式(ScanString)
    Java基础之一组有用的类——使用Scanner对象(TryScanner)
    Java基础之一组有用的类——使用正则表达式查找和替换(SearchAndReplace)
    Java基础之一组有用的类——使用正则表达式搜索子字符串(TryRegex)
    Java基础之一组有用的类——使用公历日历(TryCalendar)
    Java基础之一组有用的类——生成日期和时间(TryDateFormats)
    Java基础之一组有用的类——Observable和Observer对象(Horrific)
    Java基础之一组有用的类——使用二叉树搜索算法搜索某个作者(TryBinarySearch)
    Java基础之一组有用的类——使用比较器对数组排序(TrySortingWithComparator)
  • 原文地址:https://www.cnblogs.com/ding-dang/p/13049181.html
Copyright © 2011-2022 走看看