36-自定义全局异常

Spring Boot 自定义异常

Spring Boot项目中已经有一定的异常处理了,但在开发中还不太合适,我们要对异常进行统一的处理

Spring Boot 中的@ControllerAdvice注解表示开启全局异常处理

然后在这个类中定义一个方法去捕获异常@ExceptionHandler(value = BizException.class)

value = BizException.class表示捕获这一种类型的异常

通常这样使用:

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultBody bizExceptionHandler(BizException e){
        logger.error("发生业务异常!原因是:{}",e.getMessage());
        return ResultBody.error(e.getErrorCode(), e.getMessage());
    }
}

下面开始实现自定义异常:

  • 新建Spring Boot 项目,导入依赖
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.5.RELEASE</version>
    <relativePath />
</parent>
<dependencies>
    <!-- Spring Boot Web 依赖 核心 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Boot Test 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.41</version>
    </dependency>
</dependencies>

目录结构

在这里插入图片描述

  • 自定义基础接口类
public interface BaseError {

    /**
     *错误码
     */
    String getResultCode();

    /**
     *错误描述
     */
    String getResultMsg();

}
  • 自定义枚举类

定义一个枚举类,并实现基础接口类接口

public enum CommonEnum implements BaseError {

    //数据操作错误定义

    SUCCESS("200","成功!"),
    BODY_NOT_MATCH("400","请求的数据格式不符!"),
    SIGNATURE_NOT_MATCH("401","请求的数字签名不匹配!"),
    NOT_FOUND("404","未找到资源!"),
    INTERNAL_SERVER_ERROR("500","服务器内部错误!"),
    SERVER_BUSY("503","服务器正忙,请稍后再试!"),
    ;

    /** 错误码 */
    private String resultCode ;

    /** 错误描述 */
    private String resultMsg;

    CommonEnum(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }

    @Override
    public String getResultCode() {
        return resultCode;
    }

    @Override
    public String getResultMsg() {
        return resultMsg;
    }
}
  • 自定义异常类

自定义一个异常类,用于处理我们发生的业务异常

public class BizException extends Exception {

    private static final long serialVersionUID = 1L;

    /**
     *错误码
     */
    protected String errorCode;

    /**
     *错误描述
     */
    protected String errorMsg;


    public BizException() {
        super();
    }

    public BizException(BaseError baseError){
        super(baseError.getResultCode());
        this.errorCode = baseError.getResultCode();
        this.errorMsg = baseError.getResultMsg();
    }

    public BizException(BaseError baseError,Throwable cause){
        super(baseError.getResultCode(),cause);
        this.errorCode = baseError.getResultCode();
        this.errorMsg = baseError.getResultMsg();
    }

    public BizException(String errorMsg){
        super(errorMsg);
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg) {
        super(errorCode);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public BizException(String errorCode, String errorMsg, Throwable cause) {
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public String getMessage() {
        return errorMsg;
    }

    @Override
    public synchronized Throwable fillInStackTrace() {
        return super.fillInStackTrace();
    }
}
  • 自定义数据格式
public class ResultBody {
    
     /** 200:操作成功  -1:操作失败**/
    
    /**
     * 响应代码
     */
    private String code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应结果
     */
    private Object result;

    public ResultBody() {
    }

    public ResultBody(BaseError errorInfo) {
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    /**
     * 成功
     *
     * @return
     */
    public static ResultBody success() {
        return success(null);
    }

    /**
     * 成功
     * @param data
     * @return
     */
    public static ResultBody success(Object data) {
        ResultBody rb = new ResultBody();
        rb.setCode(CommonEnum.SUCCESS.getResultCode());
        rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
        rb.setResult(data);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultBody error(BaseError errorInfo) {
        ResultBody rb = new ResultBody();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultBody error(String code, String message) {
        ResultBody rb = new ResultBody();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    /**
     * 失败
     */
    public static ResultBody error( String message) {
        ResultBody rb = new ResultBody();
        rb.setCode("-1");
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

或者使用比较简单的返回数据格式,两种都可以

@Data
public class ResponseBean<T> {

    // http 状态码
    private boolean success;

    // 返回的数据
    private T data;

    public static <T> ResponseBean<T> success(T data) {
        ResponseBean<T> responseBean = new ResponseBean<>();
        responseBean.setSuccess(true);
        responseBean.setData(data);
        return responseBean;
    }


    public static <T> ResponseBean<T> error(T errorData) {
        ResponseBean<T> responseBean = new ResponseBean<>();
        responseBean.setSuccess(false);
        responseBean.setData(errorData);
        return responseBean;
    }

    public static <T> ResponseBean<T> success() {
        ResponseBean<T> responseBean = new ResponseBean<>();
        responseBean.setSuccess(true);
        return responseBean;
    }
}
  • 自定义全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultBody bizExceptionHandler(BizException e){
        logger.error("发生业务异常!原因是:{}",e.getMessage());
        return ResultBody.error(e.getErrorCode(), e.getMessage());
    }

    /**
     * 处理空指针的异常
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ResultBody exceptionHandler(NullPointerException e){
        logger.error("发生空指针异常!原因是:",e);
        return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
    }

    /**
     * 处理其他异常
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ResultBody exceptionHandler( Exception e){
        logger.error("未知异常!原因是:",e);
        return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
    }

    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public ResultBody handleShiroException(Exception e) {
        return ResultBody.error("无权限!");
    }
    @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public ResultBody AuthorizationException(Exception e) {
        return ResultBody.error("权限认证失败!");

    }

}

功能测试

用户表

public class User{
    
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String username;

    private String password;

    private String salt;

    private String roles;

    private String permission;
    //get、set省略
}
  • Controller 控制层

控制层这边也比较简单,使用Restful风格实现的CRUD功能,不同的是这里我故意弄出了一些异常,好让这些异常被捕获到然后处理。这些异常中,有自定义的异常抛出,也有空指针的异常抛出,当然也有不可预知的异常抛出(这里我用类型转换异常代替),那么我们在完成代码编写之后,看看这些异常是否能够被捕获处理成功吧!

@RestController
@RequestMapping(value = "/api")
public class RestfulController {

    @PostMapping("/user")
    public boolean insert() throws BizException {
        User user = new User();
        System.out.println("开始新增...");
        //如果姓名为空就手动抛出一个自定义的异常!
        if(user.getUsername()==null){
            throw  new BizException("-1","用户姓名不能为空!");
        }
        return true;
    }

    @PutMapping("/user")
    public boolean update() {
        User user = new User();
        System.out.println("开始更新...");
        //这里故意造成一个空指针的异常,并且不进行处理
        String str=null;
        str.equals("111");
        return true;
    }

    @DeleteMapping("/user")
    public boolean delete()  {
        User user = new User();
        System.out.println("开始删除...");
        //这里故意造成一个异常,并且不进行处理
        Integer.parseInt("abc123");
        return true;
    }

    @GetMapping("/user")
    public List<User> findByUser() {
        User user = new User();
        System.out.println("开始查询...");
        List<User> userList =new ArrayList<>();
        User user2=new User();
        user2.setId(1L);
        user2.setUsername("xuwujing");
        userList.add(user2);
        return userList;
    }

}
  • 启动Spring Boot项目,使用Postman工具进行接口测试
  1. 查看程序正常运行是否ok,使用POST 方式进行请求。

http://127.0.0.1:8081/api/user

返回的参数

{"code":"-1","message":"用户姓名不能为空!","result":null}

在这里插入图片描述

  1. 使用PUT 方式进行请求。

在这里插入图片描述

  1. 使用DELETE 方式进行请求。

在这里插入图片描述

  1. 使用GET方式进行请求。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值