浅谈Spring Boot 异常处理篇
前言
先谈谈“异常处理”这件事。下面有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("pagedeleted"); }else{ logger.log("configKeynotdeleted"); } }else{ logger.log("deleteReferencefromregistryfailed"); } }else{ logger.log("deletefailed"); returnE_RROR; }
//②基于异常处理 try{ deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey()); }catch(Exceptione){ logError(e); }
可以看出,如果使用异常替代返回错误码,错误处理代码就能从主路径逻辑中分离出来,得到简化!
②中,基于异常处理的代码真的好吗?其实是丑陋不堪的,它搞乱了代码结构,把错误处理与正常流程混为一谈。最好把try和catch代码块的主体部分抽离出来,形成另外的函数。
//③优雅的异常处理逻辑 publicvoiddelete(Pagepage){ try{ deletePageAndAllReferences(page); }catch(Exceptione){ logError(e); } } privatevoiddeletePageAndAllReferences(Pagepage)throwException{ deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey()); } privatevoidlogError(Exceptione){ logger.log(e.getMessage()); }
③中,函数各司其职,更易于理解和修改了。
总结:使用异常而不是错误码,优雅地使用异常!函数应该只做一件事,处理错误就是一件事。因此,处理错误的函数不该做其他事!
在SpringBoot中处理异常
1、默认的异常处理
例如401,404,500,5XX等异常,SpringBoot默认会跳转到预配置的页面,此处以thymeleaf模板引擎为例:
+resources +templates +error -401.html -404.html -500.html
只需在resources/templates/error/路径下添加对应的html文件即可。
2、局部异常处理
局部异常一般处理业务逻辑出现的异常情况,在Controller下使用@ExceptionHandler注解来处理异常。举个小例子:
先定义ResponseBean和ExceptionEnum两个对象,辅助完成优雅的代码。
/** *统一响应 *@authoranoy */ publicclassResponseBean{ privateintcode; privateStringmessage; privateTdata; publicResponseBean(){} publicResponseBean(ExceptionEnumexceptionEnum){ this.code=exceptionEnum.getCode(); this.message=exceptionEnum.getMessage(); } //省略setter/getter }
/** *异常类型枚举 *@authoranoy */ publicenumExceptionEnum{ GIRL_FRIEND_NOT_FOUND(100000,"girlfriendnotfound"); privateintcode; privateStringmessage; ExceptionEnum(intcode,Stringmessage){ this.code=code; this.message=message; } publicintgetCode(){ returncode; } publicStringgetMessage(){ returnmessage; } }
今天七夕,写个GirlFriendNotFoundException(很有同感,是不是?)
@Controller publicclassUserController{ @RequestMapping("/friend/{id}") publicStringfriend(@PathVariable("id")Longid)throwsGirlFriendNotFoundException{ if(id==1L){ thrownewGirlFriendNotFoundException(); } return"friend"; } @ExceptionHandler(GirlFriendNotFoundException.class) @ResponseBody publicResponseBeanhandleGirlFriendNotFound(GirlFriendNotFoundExceptionexception){ loggerError(exception); returnnewResponseBean(ExceptionEnum.GIRL_FRIEND_NOT_FOUND); } privatevoidlogError(Exceptione){ logger.error(e.getMessage()); } }
3、全局异常处理
个人观点:全局异常应该处理系统故障级别的问题,像参数校验这种类型的异常,应该作为局部异常来处理,例如Redis连接断开,无法请求数据,这种异常就应该当做全局异常来处理,在异常处理的逻辑中,还应该添加通知到开发人员的功能,方便开发人员及时处理错误!
全局异常处理,使用@ControllerAdvice和@ExceptionHandler来配合。
@ControllerAdvice publicclassGlobalExceptionHandler{ @ExceptionHandler(RedisConnectionFailureException.class) publicvoidhandlerRedisConnectionFailureException(RedisConnectionFailureExceptionexception){ logError(exception); noticeToDev(); } privatevoidlogError(Exceptione){ logger.error(e.getMessage()); } privatevoidnoticeToDev(){ //通知具体开发人员 } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。