浅谈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(){
//通知具体开发人员
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。