SpringBoot API 统一异常处理

前言

异常处理在一个可靠的程序中起着至关重要的工作,合理的异常是一个程序迭代的基石。 抛出异常不同于return只会返回当前上下文环境,异常可以从内层向外层不断抛出。

如何接管异常

springMvc 提供了@ControllerAdvice@RestControllerAdvice注解,用来接管所有由@Controller产生的异常,由于我们是API的异常处理所以只需要@RestControllerAdvice,当然这两者可以都可以使用
例子:

// @ControllerAdvice指定所有@RestController注解的类由此类处理异常
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice {}
// 也可以直接使用@RestControllerAdvice指定
@RestControllerAdvice
public class ExampleAdvice {}

全局的异常处理

在前后端交互项目中,前端需要根据错误代码把错误消息提示用户,这样能有最佳的用户体验,为了让跟前端同事配合往往需要统一异常的格式,这样前端同事仅需要判断错误码来提示用户。

例子:

{ 
  "code": 0,  // 这里是返回码, 
  "msg": "success", // 返回消息的内容
},
{ 
  "code": 401,  // 这里是返回码, 
  "msg": "Unauthorized", // 返回消息的内容
},
{ 
  "code": 403,  // 这里是返回码, 
  "msg": "没有权限", // 返回消息的内容
}

创建异常类

  • 在项目目录创建controllerexceptionconfigcommon目录

  • exception目录中创建BaseException.java类作为API的异常基类

package com.example.demo.exception;

/**
 * 异常基类
 */
public class BaseException extends Exception{
    /**
     * 错误码
     */
    private int code;

    /**
     * 错误消息
     */
    private String msg;

    /**
     * 有参构造
     */
    public BaseException(int code, String msg) {
        super();
        this.code = code;
        this.msg  = msg;
    }

    public int getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

  • 定义完针对所有API的异常,接下来就可以根据业务来定义对应的异常类, 在exception目录中创建PasswordException.java并继承先前定义的BaseException.java
package com.example.demo.exception;

public class PasswordException extends BasicException{


    /**
     * 有参构造
     *
     * @param code
     * @param msg
     */
    public PasswordException(int code, String msg) {
        /*
          这里可以设置自己想要的错误码,在抛出的时候需要指定错误码和错误消息
         */   
        super(code, msg);
    }

    /**
     * 无参构造
     */
    public PasswordException() {
        /*
          这里设置默认的错误码和错误消息在需要抛出错误的时候直接抛出即可
         */
        super(403, "默认消息");
    }
}

创建返回类

common目录中创建ResponseResult.java
这个类的作用是用于在统一处理异常的类ExampleAdvice.java

package com.example.demo.common;

import com.example.demo.exception.BaseException;
import lombok.Data;

@Data
public class ResponseResult {
    /**
     * 错误码
     */
    private int code;

    /**
     * 错误消息
     */
    private String msg;

    /**
     * 接收异常
     * @param exception
     */
    public ResponseResult(Exception exception) {
        if (exception instanceof BaseException) {
            this.code = ((BaseException) exception).getCode();
            this.msg  = ((BaseException) exception).getMsg();
        }
        // .... 其他情况
    }
}

创建统一处理异常类

config目录中创建ExampleAdvice.java

  • @ExceptionHandler(PasswordException.class)这个注解这是决定了该方法用来处理哪个异常
  • 同样你也可以使用如下方法来指定方法接收多种异常:
@ExceptionHandler({ ThisException.class, ThatException.class })
  • 同样你也可以指定处理基础异常类, 当然按照最佳实践,异常方法尽量只处理对应的异常,因为过度混用会异常类的继承引起的问题,如PasswordException 继承于Exception
@ExceptionHandler(Exception.class)
package com.example.demo.config;

import com.example.demo.common.ResponseResult;
import com.example.demo.exception.PasswordException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExampleAdvice {

    // @ExceptionHandler用来设置处理哪个异常
    @ExceptionHandler(PasswordException.class)
    public ResponseResult passwordException(PasswordException exception) {
        return new ResponseResult(exception);
    }
}

创建控制器

controller文件夹中创建ExceptionController.java

package com.example.demo.controller;

import com.example.demo.common.ResponseResult;
import com.example.demo.exception.PasswordException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/exp")
@RestController
public class ExceptionController {

    @RequestMapping("/result")
    public ResponseResult result() throws PasswordException {
        if (true) {
            
            throw new PasswordtException();
//            throw new PasswordException(403, "密码错误");
        }
        return new ResponseResult();
    }
}

测试

使用PostMan测试 localhost:8080/exp/result可以得到结果

{
  "code": 403,
  "msg" : "默认消息"
}

注释这一行代码

throw new PasswordtException();

取消注释这一行代码

//            throw new PasswordException(403, "密码错误");

再次测试可以得到

{
  "code": 403,
  "msg" : "密码错误"
}

完结

在实际项目中, 可以根据业务需要来定义异常。

参考文档
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值