美文网首页SpringBoot
SpringBoot项目自定义异常,配置全局异常统一处理,避免出

SpringBoot项目自定义异常,配置全局异常统一处理,避免出

作者: 天不生我小金 | 来源:发表于2021-03-22 17:15 被阅读0次

    前言:该博客主要是记录自己学习的过程,方便以后查看,当然也希望能够帮到大家。

    完整代码地址在结尾!!

    第一步,创建一个SpringBoot项目,此处不赘述

    第二步,编写application.yml配置文件,如下

    server:
      port: 8085
    
    spring:
      application:
        name: exception-demo-server
    

    第三步,创建响应码枚举ResponseEnums,统一响应类Response,如下

    ResponseEnums
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    /**
     * @version 1.0
     * @author jinhaoxun
     * @date 2018-05-09
     * @description 响应码枚举
     */
    @Getter
    @AllArgsConstructor
    public enum ResponseEnums {
    
        /**
         * 请求成功
         */
        SUCCESS(200,"请求成功"),
        /**
         * 系统异常,请稍后重试
         */
        EXCEPTION(10000,"系统异常,请稍后重试"),
        /**
         * 请求的资源(网页等)不存在
         */
        NOT_FOUND(404,"请求的资源(网页等)不存在"),
    
        /**
         * 共6位,1:系统异常码和值定义在该类中,大家公用
         * 前2位表示大板块(10:系统,11:管理后台模块,12:文章模块,13:公共模块,14:上传下载文件模块)
         * 第3,4位表示项目的小模块,5,6位代表具体错误
         */
        /**************************           系统模块             *******************************/
        /**
         * 登陆超时
         */
        LOGIN_TIMEOUT(100001  ,"登陆超时"),
        /**
         * 参数有误
         */
        WRONG_PARAM(100002  ,"参数有误"),
        /**
         * 缺少必要的参数
         */
        MISS_PARAM(100003  ,"缺少必要的参数"),
        /**
         * Hystrix 降级开启抛出异常
         */
        HYSTRIX_THROW_EXCEPTION(100004  ,"请求超时,请稍后重试"),
    
        /**************************           账号模块             *******************************/
        /**
         * 您没有该权限
         */
        MNG_PERMISSION_DENY(110101,"您没有该权限"),
        /**
         * 密码错误
         */
        PASSWORD_WRONG(110102,"密码错误"),
        /**
         * 用户不存在
         */
        USER_NOT_EXIST(110103,"用户不存在"),
        /**
         * 账号被封禁
         */
        ACCOUNT_IS_BLOCKED(110104,"账号被封禁"),
        /**
         * 账号已注销
         */
        ACCOUNT_IS_CANCELLED(110105,"账号已注销"),
        /**
         * 验证码已过期
         */
        VERIFICATION_CODE_EXPIRED(110106,"验证码已过期"),
        /**
         * 从Redis中获取验证码错误
         */
        GET_CODE_WRONG_FROM_REDIS(110107,"从Redis中获取验证码错误"),
        /**
         * 身份信息已过期
         */
        IDENTITY_INFORMATION_IS_EXPIRED(110108,"身份信息已过期"),
        /**
         * 用户未登录
         */
        USER_NOT_LOG_IN(110109,"用户未登录"),
        /**
         * 用户退出登录失败
         */
        USER_LOG_OUT_FAIL(110110,"用户退出登录失败"),
    
        /**
         * 密码修改失败
         */
        PASSWORD_CHANGE_FAIL(110112,"密码修改失败"),
        /**
         * 账号封禁失败
         */
        ACCOUNT_BLOCK_FAIL(110113,"账号封禁失败"),
        /**
         * 账号解封失败
         */
        ACCOUNT_UNSEALING_FAIL(110114,"账号解封失败"),
        /**
         * 账号注册失败
         */
        ACCOUNT_REGISTRATION_FAIL(110115,"账号注册失败"),
        /**
         * 获取手机验证码失败
         */
        GET_PHONE_CODE_FAIL(110116,"获取手机验证码失败"),
        /**
         * 获取邮箱验证码失败
         */
        GET_EMAIL_CODE_FAIL(110117,"获取邮箱验证码失败"),
        /**
         * 获取用户信息失败
         */
        GET_USERINFO_FAIL(110118,"获取用户信息失败"),
        /**
         * 更新用户信息失败
         */
        UPDATE_USERINFO_FAIL(110119,"更新用户信息失败"),
        /**
         * 账号注销失败
         */
        ACCOUNT_CANAEL_FAIL(110120,"账号注销失败"),
        /**
         * 重复获取验证码
         */
        REPEAT_GET_USER_LOG_IN_CODE(110121,"重复获取验证码"),
        /**
         * 验证码已过期
         */
        USER_LOG_IN_CODE_EXPIRATIONED(110122,"验证码已过期"),
        /**
         * 验证码错误
         */
        USER_LOG_IN_CODE_WRONG(110123,"验证码错误"),
        ;
    
        public Integer code;
        public String msg;
    
    }
    
    Response
    import com.luoyu.exception.constant.ResponseEnums;
    import lombok.Data;
    
    import java.io.Serializable;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    /**
     * Response
     *
     * @author luoyu
     * @date 2018/10/07 13:28
     * @description 通用返回类
     */
    @Data
    public class Response implements Serializable {
    
        private String msg;
        private int code;
        private Object data;
        private String time;
    
        private Response() {
        }
    
        private Response(int code, String msg) {
            this.code = code;
            this.msg = msg;
            this.time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
        }
    
        private Response(int code, String msg, Object data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
            this.time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
        }
    
        public static Response success() {
            return new Response(ResponseEnums.SUCCESS.getCode(), ResponseEnums.SUCCESS.getMsg());
        }
    
        public static Response success(Object data) {
            return new Response(ResponseEnums.SUCCESS.getCode(), ResponseEnums.SUCCESS.getMsg(), data);
        }
    
        public static Response success(Object data, String msg) {
            return new Response(ResponseEnums.SUCCESS.getCode(), msg, data);
        }
    
        public static Response fail() {
            return new Response(ResponseEnums.EXCEPTION.getCode(), ResponseEnums.EXCEPTION.getMsg());
        }
    
        public static Response fail(ResponseEnums responseEnums) {
            return new Response(responseEnums.getCode(), responseEnums.getMsg());
        }
    
        public static Response fail(ResponseEnums responseEnums, Object data) {
            return new Response(responseEnums.getCode(), responseEnums.getMsg(), data);
        }
    
        public static Response fail(int code, String msg) {
            return new Response(code, msg);
        }
    
        public static Response fail(int code, String msg, Object data) {
            return new Response(code, msg, data);
        }
    
    }
    

    第四步,创建自定义异常类CustomException,如下

    import lombok.Data;
    
    import java.io.Serializable;
    
    /**
     * @version 1.0
     * @author jinhaoxun
     * @date 2018-05-09
     * @description 自定义统一异常(相当于业务异常)
     */
    @Data
    public class CustomException extends Exception implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private Integer code;
    
        private String log;
    
        /**
         * @author jinhaoxun
         * @description 构造器
         * @param code 异常状态码
         * @param log 异常打印日志
         * @param msg 异常返回信息
         */
        public CustomException(Integer code, String log, String msg) {
            super(msg);
            this.code = code;
            this.log = log;
        }
    
    }
    

    第五步,创建全局异常统一处理类ExceptionHandle,如下

    import com.luoyu.exception.constant.ResponseEnums;
    import com.luoyu.exception.entity.vo.Response;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    /**
     * @version 1.0
     * @author jinhaoxun
     * @date 2018-05-09
     * @description 统一的异常处理
     */
    @Slf4j
    @RestControllerAdvice
    public class ExceptionHandle {
    
        /**
         * @author jinhaoxun
         * @description 统一的异常处理方法
         * @param e 抛出的异常
         * @return 返回给前端的错误信息提示
         */
        @ExceptionHandler(value = Exception.class)
        public Response handleException(Exception e){
            if(e instanceof CustomException) {
                CustomException ex = (CustomException)e;
                log.info("自定义业务异常:msg:" + ex.getMessage() + ",log:" + ex.getLog(), e);
                return Response.fail(ex.getCode(), ex.getMessage(),null);
            }else if(e instanceof MethodArgumentNotValidException) {
                MethodArgumentNotValidException ex = (MethodArgumentNotValidException)e;
                log.error("参数校验异常:msg:" + ex.getBindingResult().getFieldError().getDefaultMessage());
                return Response.fail(ResponseEnums.WRONG_PARAM.getCode(),
                        ResponseEnums.WRONG_PARAM.getMsg() + ":"
                                + ex.getBindingResult().getFieldError().getDefaultMessage(), null);
            }else{
                log.error("统一系统异常:msg:" + e.getMessage(), e);
                return Response.fail(ResponseEnums.EXCEPTION.getCode(), ResponseEnums.EXCEPTION.getMsg(), null);
            }
        }
    
    }
    
    说明
    1. @ExceptionHandler用于统一处理某一类异常,从而能够减少代码重复率和复杂度,所有抛出来的异常都会在这里被捕获

    第六步,创建TestService,TestServiceImpl,TestController,如下

    TestService
    /**
     * @Description:
     * @Author: jinhaoxun
     * @Date: 2020/7/10 10:31 上午
     * @Version: 1.0.0
     */
    public interface TestService {
    
        void get1() throws Exception;
    
        void get2() throws Exception;
    
    }
    
    TestServiceImpl
    import com.luoyu.exception.exception.CustomException;
    import com.luoyu.exception.service.TestService;
    import org.springframework.stereotype.Service;
    
    /**
     * @Description:
     * @Author: jinhaoxun
     * @Date: 2020/7/10 10:32 上午
     * @Version: 1.0.0
     */
    @Service
    public class TestServiceImpl implements TestService {
    
        @Override
        public void get1() throws Exception {
            int i = 1/0;
        }
    
        @Override
        public void get2() throws Exception {
            try {
                int i = 1/0;
            }catch (Exception e){
                throw new CustomException(10086, "自定义打印异常", "自定义返回异常");
            }
        }
        
    }
    
    TestController
    import com.luoyu.exception.entity.vo.Response;
    import com.luoyu.exception.service.TestService;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    /**
     * @Description:
     * @Author: jinhaoxun
     * @Date: 2020/7/10 10:31 上午
     * @Version: 1.0.0
     */
    @RestController
    @RequestMapping("/test")
    public class TestController {
    
        @Resource
        private TestService testService;
    
        /**
         * @author jinhaoxun
         * @description 测试接口1
         */
        @GetMapping("/get1")
        public Response get1() throws Exception {
            testService.get1();
            return Response.success();
        }
    
        /**
         * @author jinhaoxun
         * @description 测试接口2
         */
        @GetMapping("/get2")
        public Response get2() throws Exception {
            testService.get2();
            return Response.success();
        }
    
    }
    
    解释
    1. 从可能出现异常的地方往外面抛异常,本文是从service开始,直到controller往外面抛出异常后,会被ExceptionHandle捕获,然后自行进行处理,打印日志,统一状态码,错误信息返回给前端。

    第七步,启动项目,使用postman调接口,如下图

    测试1,使用GET请求http://localhost:8085/test/get1
    image.png
    image.png
    测试2,使用GET请求http://localhost:8085/test/get2
    image.png
    image.png
    完整代码地址:https://github.com/Jinhx128/springboot-demo
    注:此工程包含多个module,本文所用代码均在exception-demo模块下

    后记:本次分享到此结束,本人水平有限,难免有错误或遗漏之处,望大家指正和谅解,欢迎评论留言。

    相关文章

      网友评论

        本文标题:SpringBoot项目自定义异常,配置全局异常统一处理,避免出

        本文链接:https://www.haomeiwen.com/subject/kwzzcltx.html