SpringBoot API 统一异常处理

前言

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

如何接管异常

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

例子:


// @ControllerAdvice指定所有@RestController注解的类由此类处理异常

@ControllerAdvice(annotations  =  RestController.class)

public  class  ExampleAdvice  {}

// 也可以直接使用@RestControllerAdvice指定

@RestControllerAdvice

public  class  ExampleAdvice  {}

全局的异常处理

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

特别注意 : 下面例子中的只是API响应状态码,区别于Http响应状态码。查看完整Http状态码

例子:


{

 "code":  0, // 这里是返回码,

 "msg":  "success",  // 返回消息的内容

 "data":  []

},

{

 "code":  10001, // 这里是返回码,

 "msg":  "您不是管理员",  // 返回消息的内容

},

{

 "code":  10001, // 这里是返回码,

 "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"  :  "密码错误"
}

完结

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

参考文档

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 2

这种设计挺好的,就是代码有问题

2个月前 评论
西巴以及 (楼主) 2个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!