1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 看看人家SpringBoot的全局异常处理多么优雅...

看看人家SpringBoot的全局异常处理多么优雅...

时间:2024-06-26 20:13:41

相关推荐

看看人家SpringBoot的全局异常处理多么优雅...

点击上方 "编程技术圈"关注,星标或置顶一起成长

后台回复“大礼包”有惊喜礼包!

日英文

I can accept failure but I can't accept not trying.

我可以接受失败,但绝对不能接受未曾奋斗过的自己。

每日掏心话

人生贵在行动,迟疑不决时,不妨先迈出小小一步。前进不必遗憾,若是美好,叫做精彩;若是糟糕,叫做经历!

责编:乐乐|来自:虚无境链接:/xuwujing/p/10933082.html

编程技术圈(ID:study_tech)第 1250次推文

往日回顾:身家破亿!86版西游记“红孩儿”拒绝出道成学霸,已是中科院博士,名下52家公司

正文

SpringBoot全局异常准备说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码。开发准备环境要求JDK:1.8SpringBoot:1.5.17.RELEASE首先还是Maven的相关依赖:<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>1.8</java.version><piler.source>1.8</piler.source><piler.target>1.8</piler.target></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.17.RELEASE</version><relativePath/></parent><dependencies><!--SpringBootWeb依赖核心--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--SpringBootTest依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.41</version></dependency></dependencies>配置文件这块基本不需要更改,全局异常的处理只需在代码中实现即可。代码编写SpringBoot的项目已经对有一定的异常处理了,但是对于我们开发者而言可能就不太合适了,因此我们需要对这些异常进行统一的捕获并处理。SpringBoot中有一个ControllerAdvice的注解,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。我们根据下面的这个示例来看该注解是如何使用吧。示例代码:@ControllerAdvicepublicclassMyExceptionHandler{@ExceptionHandler(value=Exception.class)publicStringexceptionHandler(Exceptione){System.out.println("未知异常!原因是:"+e);returne.getMessage();}}上述的示例中,我们对捕获的异常进行简单的二次处理,返回异常的信息,虽然这种能够让我们知道异常的原因,但是在很多的情况下来说,可能还是不够人性化,不符合我们的要求。那么我们这里可以通过自定义的异常类以及枚举类来实现我们想要的那种数据吧。自定义基础接口类首先定义一个基础的接口类,自定义的错误描述枚举类需实现该接口。代码如下:publicinterfaceBaseErrorInfoInterface{/**错误码*/StringgetResultCode();/**错误描述*/StringgetResultMsg();}自定义枚举类然后我们这里在自定义一个枚举类,并实现该接口。代码如下:publicenumCommonEnumimplementsBaseErrorInfoInterface{//数据操作错误定义SUCCESS("200","成功!"),BODY_NOT_MATCH("400","请求的数据格式不符!"),SIGNATURE_NOT_MATCH("401","请求的数字签名不匹配!"),NOT_FOUND("404","未找到该资源!"),INTERNAL_SERVER_ERROR("500","服务器内部错误!"),SERVER_BUSY("503","服务器正忙,请稍后再试!");/**错误码*/privateStringresultCode;/**错误描述*/privateStringresultMsg;CommonEnum(StringresultCode,StringresultMsg){this.resultCode=resultCode;this.resultMsg=resultMsg;}@OverridepublicStringgetResultCode(){returnresultCode;}@OverridepublicStringgetResultMsg(){returnresultMsg;}}自定义异常类然后我们在来自定义一个异常类,用于处理我们发生的业务异常。代码如下:publicclassBizExceptionextendsRuntimeException{privatestaticfinallongserialVersionUID=1L;/***错误码*/protectedStringerrorCode;/***错误信息*/protectedStringerrorMsg;publicBizException(){super();}publicBizException(BaseErrorInfoInterfaceerrorInfoInterface){super(errorInfoInterface.getResultCode());this.errorCode=errorInfoInterface.getResultCode();this.errorMsg=errorInfoInterface.getResultMsg();}publicBizException(BaseErrorInfoInterfaceerrorInfoInterface,Throwablecause){super(errorInfoInterface.getResultCode(),cause);this.errorCode=errorInfoInterface.getResultCode();this.errorMsg=errorInfoInterface.getResultMsg();}publicBizException(StringerrorMsg){super(errorMsg);this.errorMsg=errorMsg;}publicBizException(StringerrorCode,StringerrorMsg){super(errorCode);this.errorCode=errorCode;this.errorMsg=errorMsg;}publicBizException(StringerrorCode,StringerrorMsg,Throwablecause){super(errorCode,cause);this.errorCode=errorCode;this.errorMsg=errorMsg;}publicStringgetErrorCode(){returnerrorCode;}publicvoidsetErrorCode(StringerrorCode){this.errorCode=errorCode;}publicStringgetErrorMsg(){returnerrorMsg;}publicvoidsetErrorMsg(StringerrorMsg){this.errorMsg=errorMsg;}publicStringgetMessage(){returnerrorMsg;}@OverridepublicThrowablefillInStackTrace(){returnthis;}}自定义数据格式顺便这里我们定义一下数据的传输格式。代码如下:publicclassResultBody{/***响应代码*/privateStringcode;/***响应消息*/privateStringmessage;/***响应结果*/privateObjectresult;publicResultBody(){}publicResultBody(BaseErrorInfoInterfaceerrorInfo){this.code=errorInfo.getResultCode();this.message=errorInfo.getResultMsg();}publicStringgetCode(){returncode;}publicvoidsetCode(Stringcode){this.code=code;}publicStringgetMessage(){returnmessage;}publicvoidsetMessage(Stringmessage){this.message=message;}publicObjectgetResult(){returnresult;}publicvoidsetResult(Objectresult){this.result=result;}/***成功**@return*/publicstaticResultBodysuccess(){returnsuccess(null);}/***成功*@paramdata*@return*/publicstaticResultBodysuccess(Objectdata){ResultBodyrb=newResultBody();rb.setCode(CommonEnum.SUCCESS.getResultCode());rb.setMessage(CommonEnum.SUCCESS.getResultMsg());rb.setResult(data);returnrb;}/***失败*/publicstaticResultBodyerror(BaseErrorInfoInterfaceerrorInfo){ResultBodyrb=newResultBody();rb.setCode(errorInfo.getResultCode());rb.setMessage(errorInfo.getResultMsg());rb.setResult(null);returnrb;}/***失败*/publicstaticResultBodyerror(Stringcode,Stringmessage){ResultBodyrb=newResultBody();rb.setCode(code);rb.setMessage(message);rb.setResult(null);returnrb;}/***失败*/publicstaticResultBodyerror(Stringmessage){ResultBodyrb=newResultBody();rb.setCode("-1");rb.setMessage(message);rb.setResult(null);returnrb;}@OverridepublicStringtoString(){returnJSONObject.toJSONString(this);}}自定义全局异常处理类最后我们在来编写一个自定义全局异常处理的类。代码如下:@ControllerAdvicepublicclassGlobalExceptionHandler{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(GlobalExceptionHandler.class);/***处理自定义的业务异常*@paramreq*@parame*@return*/@ExceptionHandler(value=BizException.class)@ResponseBodypublicResultBodybizExceptionHandler(HttpServletRequestreq,BizExceptione){logger.error("发生业务异常!原因是:{}",e.getErrorMsg());returnResultBody.error(e.getErrorCode(),e.getErrorMsg());}/***处理空指针的异常*@paramreq*@parame*@return*/@ExceptionHandler(value=NullPointerException.class)@ResponseBodypublicResultBodyexceptionHandler(HttpServletRequestreq,NullPointerExceptione){logger.error("发生空指针异常!原因是:",e);returnResultBody.error(CommonEnum.BODY_NOT_MATCH);}/***处理其他异常*@paramreq*@parame*@return*/@ExceptionHandler(value=Exception.class)@ResponseBodypublicResultBodyexceptionHandler(HttpServletRequestreq,Exceptione){logger.error("未知异常!原因是:",e);returnResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);}}因为这里我们只是用于做全局异常处理的功能实现以及测试,所以这里我们只需在添加一个实体类和一个控制层类即可。实体类又是万能的用户表 (^▽^)代码如下:publicclassUserimplementsSerializable{privatestaticfinallongserialVersionUID=1L;/**编号*/privateintid;/**姓名*/privateStringname;/**年龄*/privateintage;publicUser(){}publicintgetId(){returnid;}publicvoidsetId(intid){this.id=id;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}publicStringtoString(){returnJSONObject.toJSONString(this);}}Controller 控制层控制层这边也比较简单,使用Restful风格实现的CRUD功能,不同的是这里我故意弄出了一些异常,好让这些异常被捕获到然后处理。这些异常中,有自定义的异常抛出,也有空指针的异常抛出,当然也有不可预知的异常抛出(这里我用类型转换异常代替),那么我们在完成代码编写之后,看看这些异常是否能够被捕获处理成功吧!代码如下:@RestController@RequestMapping(value="/api")publicclassUserRestController{@PostMapping("/user")publicbooleaninsert(@RequestBodyUseruser){System.out.println("开始新增...");//如果姓名为空就手动抛出一个自定义的异常!if(user.getName()==null){thrownewBizException("-1","用户姓名不能为空!");}returntrue;}@PutMapping("/user")publicbooleanupdate(@RequestBodyUseruser){System.out.println("开始更新...");//这里故意造成一个空指针的异常,并且不进行处理Stringstr=null;str.equals("111");returntrue;}@DeleteMapping("/user")publicbooleandelete(@RequestBodyUseruser){System.out.println("开始删除...");//这里故意造成一个异常,并且不进行处理Integer.parseInt("abc123");returntrue;}@GetMapping("/user")publicList<User>findByUser(Useruser){System.out.println("开始查询...");List<User>userList=newArrayList<>();Useruser2=newUser();user2.setId(1L);user2.setName("xuwujing");user2.setAge(18);userList.add(user2);returnuserList;}}App 入口和普通的SpringBoot项目基本一样。代码如下:@SpringBootApplicationpublicclassApp{publicstaticvoidmain(String[]args){SpringApplication.run(App.class,args);System.out.println("程序正在运行...");}}功能测试我们成功启动该程序之后,使用Postman工具来进行接口测试。首先进行查询,查看程序正常运行是否ok,使用GET 方式进行请求。“GET http://localhost:8181/api/user”返回参数为:“{"id":1,"name":"xuwujing","age":18}”示例图:可以看到程序正常返回,并没有因自定义的全局异常而影响。然后我们再来测试下自定义的异常是否能够被正确的捕获并处理。使用POST方式进行请求“POST http://localhost:8181/api/user”Body参数为:“{"id":1,"age":18}”返回参数为:“{"code":"-1","message":"用户姓名不能为空!","result":null}”示例图:可以看出将我们抛出的异常进行数据封装,然后将异常返回出来。然后我们再来测试下空指针异常是否能够被正确的捕获并处理。在自定义全局异常中,我们除了定义空指针的异常处理,也定义最高级别之一的Exception异常,那么这里发生了空指针异常之后,它是回优先使用哪一个呢?这里我们来测试下。使用PUT方式进行请求。“PUT http://localhost:8181/api/user”Body参数为:“{"id":1,"age":18}”返回参数为:“{"code":"400","message":"请求的数据格式不符!","result":null}”示例图:我们可以看到这里的的确是返回空指针的异常护理,可以得出全局异常处理优先处理子类的异常。那么我们在来试试未指定其异常的处理,看该异常是否能够被捕获。使用DELETE方式进行请求。“DELETE http://localhost:8181/api/user”Body参数为:“{"id":1}”返回参数为:“{"code":"500","message":"服务器内部错误!","result":null}”这里可以看到它使用了我们在自定义全局异常处理类中的Exception异常处理的方法。到这里,测试就结束了。顺便再说一下,自义定全局异常处理除了可以处理上述的数据格式之外,也可以处理页面的跳转,只需在新增的异常方法的返回处理上填写该跳转的路径并不使用ResponseBody注解即可。细心的同学也许发现了在GlobalExceptionHandler类中使用的是ControllerAdvice注解,而非RestControllerAdvice注解,如果是用的RestControllerAdvice注解,它会将数据自动转换成JSON格式,这种于Controller和RestController类似,所以我们在使用全局异常处理的之后可以进行灵活的选择处理。其它关于SpringBoot优雅的全局异常处理的文章就讲解到这里了,如有不妥,欢迎指正!项目地址SpringBoot全局异常的处理项目工程地址: /xuwujing/springBoot-study/tree/master/springboot-exceptionHandlerPS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!欢迎加入后端架构师交流群,在后台回复“学习”即可。最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份最新最全BAT等大厂Java面试经验总结。别找了,想获取史上最简单的Java大厂面试题学习资料扫下方二维码回复「面试」就好了猜你还想看阿里、腾讯、百度、华为、京东最新面试题汇集我见过最“骚”的代码注释!神兽版都来了发现一款好用到爆的数据库工具,被惊艳到了!一个基于SpringBoot + Mybatis + Vue的代码生成器嘿,你在看吗?

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。