• SpringBoot系列——自定义统一异常处理


      前言

      springboot内置的/error错误页面并不一定适用我们的项目,这时候就需要进行自定义统一异常处理,本文记录springboot进行自定义统一异常处理。

      

      1、使用@ControllerAdvice、@RestControllerAdvice捕获运行时异常。

      2、重写ErrorController,手动抛出自定义ErrorPageException异常,方便404、403等被统一处理。

      官网文档相关介绍:

      https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-error-handling

      

      代码

      项目结构

      引入我们父类pom即可,无需引入其他依赖

      开始之前,需要先定下统一返回对象、自定义异常枚举类

    /**
     * 自定义异常枚举类
     */
    public enum ErrorEnum {
        //自定义系列
        USER_NAME_IS_NOT_NULL("10001","【参数校验】用户名不能为空"),
        PWD_IS_NOT_NULL("10002","【参数校验】密码不能为空"),
    
        //400系列
        BAD_REQUEST("400","请求的数据格式不符!"),
        UNAUTHORIZED("401","登录凭证过期!"),
        FORBIDDEN("403","抱歉,你无权限访问!"),
        NOT_FOUND("404", "请求的资源找不到!"),
    
        //500系列
        INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
        SERVICE_UNAVAILABLE("503","服务器正忙,请稍后再试!"),
    
        //未知异常
        UNKNOWN("10000","未知异常!");
    
    
        /** 错误码 */
        private String code;
    
        /** 错误描述 */
        private String msg;
    
        ErrorEnum(String code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public String getCode() {
            return code;
        }
    
        public String getMsg() {
            return msg;
        }
    }
    /**
     * 统一返回对象
     */
    
    @Data
    public class Result<T> implements Serializable {
        /**
         * 通信数据
         */
        private T data;
        /**
         * 通信状态
         */
        private boolean flag = true;
        /**
         * 通信描述
         */
        private String msg = "操作成功";
    
        /**
         * 通过静态方法获取实例
         */
        public static <T> Result<T> of(T data) {
            return new Result<>(data);
        }
    
        public static <T> Result<T> of(T data, boolean flag) {
            return new Result<>(data, flag);
        }
    
        public static <T> Result<T> of(T data, boolean flag, String msg) {
            return new Result<>(data, flag, msg);
        }
    
        public static <T> Result<T> error(ErrorEnum errorEnum) {
            return new Result(errorEnum.getCode(), false, errorEnum.getMsg());
        }
    
        @Deprecated
        public Result() {
    
        }
    
        private Result(T data) {
            this.data = data;
        }
    
        private Result(T data, boolean flag) {
            this.data = data;
            this.flag = flag;
        }
    
        private Result(T data, boolean flag, String msg) {
            this.data = data;
            this.flag = flag;
            this.msg = msg;
        }
    
    }

      新增两个自定义异常,便于统一处理时捕获异常

    /**
     * 自定义业务异常
     */
    public class ServiceException extends RuntimeException {
    
        /**
         * 自定义异常枚举类
         */
        private ErrorEnum errorEnum;
    
        /**
         * 错误码
         */
        private String code;
    
        /**
         * 错误信息
         */
        private String errorMsg;
    
    
        public ServiceException() {
            super();
        }
    
        public ServiceException(ErrorEnum errorEnum) {
            super("{code:" + errorEnum.getCode() + ",errorMsg:" + errorEnum.getMsg() + "}");
            this.errorEnum = errorEnum;
            this.code = errorEnum.getCode();
            this.errorMsg = errorEnum.getMsg();
        }
    
        public ServiceException(String code,String errorMsg) {
            super("{code:" + code + ",errorMsg:" + errorMsg + "}");
            this.code = code;
            this.errorMsg = errorMsg;
        }
    
        public ErrorEnum getErrorEnum() {
            return errorEnum;
        }
    
        public String getErrorMsg() {
            return errorMsg;
        }
    
        public void setErrorMsg(String errorMsg) {
            this.errorMsg = errorMsg;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    }
    /**
     * 自定义错误页面异常
     */
    public class ErrorPageException extends ServiceException {
    
        public ErrorPageException(ErrorEnum errorEnum) {
            super(errorEnum);
        }
    }

      重写ErrorController,不在跳转原生错误页面,而是抛出我们的自定义异常

    /**
     * 自定义errorPage
     */
    @Controller
    public class ErrorPageConfig implements ErrorController{
    
        private final static String ERROR_PATH = "/error" ;
    
        @Override
        public String getErrorPath() {
            return ERROR_PATH;
        }
    
        @RequestMapping(ERROR_PATH)
        public void errorPathHandler(HttpServletResponse response) {
            //抛出ErrorPageException异常,方便被ExceptionHandlerConfig处理
            ErrorEnum errorEnum;
            switch (response.getStatus()) {
                case 404:
                    errorEnum = ErrorEnum.NOT_FOUND;
                    break;
                case 403:
                    errorEnum = ErrorEnum.FORBIDDEN;
                    break;
                case 401:
                    errorEnum = ErrorEnum.UNAUTHORIZED;
                    break;
                case 400:
                    errorEnum = ErrorEnum.BAD_REQUEST;
                    break;
                default:
                    errorEnum = ErrorEnum.UNKNOWN;
                    break;
            }
            throw new ErrorPageException(errorEnum);
        }
    }

       @RestControllerAdvice,统一异常处理,捕获并返回统一返回对象Result,同时把异常信息打印到日志中

    /**
     * 统一异常处理
     */
    @Slf4j
    @RestControllerAdvice
    public class ExceptionHandlerConfig{
    
        /**
         * 业务异常 统一处理
         */
        @ExceptionHandler(value = ServiceException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ResponseBody
        public Result exceptionHandler400(ServiceException e){
            //把错误信息输入到日志中
            log.error(ErrorUtil.errorInfoToString(e));
            return Result.error(e.getErrorEnum());
        }
    
        /**
         * 错误页面异常 统一处理
         */
        @ExceptionHandler(value = ErrorPageException.class)
        @ResponseBody
        public Result exceptionHandler(ErrorPageException e){
            //把错误信息输入到日志中
            log.error(ErrorUtil.errorInfoToString(e));
            return Result.error(e.getErrorEnum());
        }
    
        /**
         * 空指针异常 统一处理
         */
        @ExceptionHandler(value =NullPointerException.class)
        @ResponseBody
        public Result exceptionHandler500(NullPointerException e){
            //把错误信息输入到日志中
            log.error(ErrorUtil.errorInfoToString(e));
            return Result.error(ErrorEnum.INTERNAL_SERVER_ERROR);
        }
    
        /**
         * 未知异常 统一处理
         */
        @ExceptionHandler(value =Exception.class)
        @ResponseBody
        public Result exceptionHandler(Exception e){
            //把错误信息输入到日志中
            log.error(ErrorUtil.errorInfoToString(e));
            return Result.error(ErrorEnum.UNKNOWN);
        }
    }

      新建测试controller,新增几个测试接口,模拟多种异常报错的情况

    /**
     * 模拟异常测试
     */
    @RestController
    @RequestMapping("/test/")
    public class TestController {
        /**
         * 正常返回数据
         */
        @GetMapping("index")
        public Result index(){
            return Result.of("正常返回数据");
        }
    
        /**
         * 模拟空指针异常
         */
        @GetMapping("nullPointerException")
        public Result nullPointerException(){
            //故意制造空指针异常
            String msg = null;
            msg.equals("huanzi-qch");
            return Result.of("正常返回数据");
        }
    
        /**
         * 模拟业务异常,手动抛出业务异常
         */
        @GetMapping("serviceException")
        public Result serviceException(){
            throw new ServiceException(ErrorEnum.USER_NAME_IS_NOT_NULL);
        }
    }

      效果

      正常数据返回

      http://localhost:10010/test/index

      模拟空指针异常

      http://localhost:10010/test/nullPointerException

      模拟业务异常

      http://localhost:10010/test/serviceException

       调用错误接口,404

      http://localhost:10010/test/serviceException111

      后记

      自定义统一异常处理暂时先记录到这,后续再进行补充。

      

      代码开源

      代码已经开源、托管到我的GitHub、码云:

      GitHub:https://github.com/huanzi-qch/springBoot

      码云:https://gitee.com/huanzi-qch/springBoot

    版权声明

    作者:huanzi-qch
    若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.


    捐献、打赏

    请注意:作者五行缺钱,如果喜欢这篇文章,请随意打赏!

    支付宝

    微信


    QQ群交流群

    QQ群交流群
    有事请加群,有问题进群大家一起交流!

  • 相关阅读:
    信息的表示和处理
    Linux基础与Linux下C语言编程基础
    Linux基础入门
    第4次实验
    第三次实验
    第二次实验
    java第一次实验
    数据库提示日志文件不可用
    SQL Server 2012 列存储索引分析(翻译)
    修改delphi xe6 FMX Label字体颜色
  • 原文地址:https://www.cnblogs.com/huanzi-qch/p/14788991.html
Copyright © 2020-2023  润新知