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