首页 > 编程 > Java > 正文

浅谈Spring Boot 异常处理篇

2019-11-26 11:33:28
字体:
来源:转载
供稿:网友

前言

先谈谈“异常处理”这件事。下面有 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(很有同感,是不是?)

@Controllerpublic 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 来配合。

@ControllerAdvicepublic 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(){    // 通知具体开发人员  }}

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表