欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

浅谈Spring Boot 异常处理篇

程序员文章站 2024-02-23 10:47:34
前言 先谈谈“异常处理”这件事。下面有 2 份伪代码,对比下: // ① 基于 if/else 判断 if(deletepage(page) == e_ok)...

前言

先谈谈“异常处理”这件事。下面有 2 份伪代码,对比下:

// ① 基于 if/else 判断
if(deletepage(page) == e_ok){
 if(registry.deletereference(page.name) == e_ok){
  if(configkeys.deletekey(page.name.makekey()) == e_ok){
   logger.log("page deleted");
  }else{
   logger.log("configkey not deleted");
  }
 }else{
  logger.log("deletereference from registry failed");
 }
}else{
 logger.log("delete failed");
 return e_rror;
}
// ② 基于异常处理
try{
 deletepage(page);
 registry.deletereference(page.name);
 configkeys.deletekey(page.name.makekey());
}catch(exception e){
 logerror(e);
}

可以看出,如果使用异常替代返回错误码,错误处理代码就能从主路径逻辑中分离出来,得到简化!

②中,基于异常处理的代码真的好吗?其实是丑陋不堪的,它搞乱了代码结构,把错误处理与正常流程混为一谈。最好把 try 和 catch 代码块的主体部分抽离出来,形成另外的函数。

// ③ 优雅的异常处理逻辑
public void delete(page page){
 try{
  deletepageandallreferences(page);
 }catch(exception e){
  logerror(e);
 }
}

private void deletepageandallreferences(page page) throw exception{
 deletepage(page);
 registry.deletereference(page.name);
 configkeys.deletekey(page.name.makekey());
}

private void logerror(exception e){
 logger.log(e.getmessage());
}

③中,函数各司其职,更易于理解和修改了。

总结:使用异常而不是错误码,优雅地使用异常!函数应该只做一件事,处理错误就是一件事。因此,处理错误的函数不该做其他事!

在 spring boot 中处理异常

1、默认的异常处理

例如 401,404,500,5xx 等异常,spring boot 默认会跳转到预配置的页面,此处以 thymeleaf 模板引擎为例:

+ resources
 + templates
  + error
   - 401.html
   - 404.html
   - 500.html

只需在 resources/templates/error/ 路径下添加对应的html文件即可。

2、局部异常处理

局部异常一般处理业务逻辑出现的异常情况,在 controller 下使用 @exceptionhandler 注解来处理异常。举个小例子:

先定义 responsebean 和 exceptionenum 两个对象,辅助完成优雅的代码。

/**
 * 统一响应
 * @author anoy
 */
public class responsebean<t> {

  private int code;

  private string message;

  private t data;

  public responsebean(){}

  public responsebean(exceptionenum exceptionenum){
    this.code = exceptionenum.getcode();
    this.message = exceptionenum.getmessage();
  }

  // 省略 setter/getter
}

/**
 * 异常类型枚举
 * @author anoy
 */
public enum exceptionenum {

  girl_friend_not_found(100000, "girl friend not found");

  private int code;

  private string message;

  exceptionenum(int code, string message){
    this.code = code;
    this.message = message;
  }

  public int getcode() {
    return code;
  }

  public string getmessage() {
    return message;
  }
}

今天七夕,写个 girlfriendnotfoundexception(很有同感,是不是?)

@controller
public class usercontroller {

  @requestmapping("/friend/{id}")
  public string friend(@pathvariable("id") long id) throws girlfriendnotfoundexception {
    if (id == 1l){
      throw new girlfriendnotfoundexception();
    }
    return "friend";
  }

  @exceptionhandler(girlfriendnotfoundexception.class)
  @responsebody
  public responsebean handlegirlfriendnotfound(girlfriendnotfoundexception exception){
    loggererror(exception);
    return new responsebean(exceptionenum.girl_friend_not_found);
  }
  
  private void logerror(exception e){
    logger.error(e.getmessage());
  }
}

3、全局异常处理

个人观点:全局异常应该处理系统故障级别的问题,像参数校验这种类型的异常,应该作为局部异常来处理,例如 redis 连接断开,无法请求数据,这种异常就应该当做全局异常来处理,在异常处理的逻辑中,还应该添加通知到开发人员的功能,方便开发人员及时处理错误!

全局异常处理,使用 @controlleradvice @exceptionhandler 来配合。

@controlleradvice
public class globalexceptionhandler {

  @exceptionhandler(redisconnectionfailureexception.class)
  public void handlerredisconnectionfailureexception(redisconnectionfailureexception exception){
    logerror(exception);
    noticetodev();
  }

  private void logerror(exception e){
    logger.error(e.getmessage());
  }

  private void noticetodev(){
    // 通知具体开发人员
  }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。