SpringBoot

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

2021-03-22  本文已影响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模块下

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

上一篇下一篇

猜你喜欢

热点阅读