详解SpringBoot 处理异常的几种常见姿势
一、使用 @controlleradvice 和 @exceptionhandler 处理全局异常
这是目前很常用的一种方式,非常推荐。测试代码中用到了 junit 5,如果你新建项目验证下面的代码的话,记得添加上相关依赖。
1. 新建异常信息实体类
非必要的类,主要用于包装异常信息。
src/main/java/com/twuc/webapp/exception/errorresponse.java
/** * @author shuang.kou */ public class errorresponse { private string message; private string errortypename; public errorresponse(exception e) { this(e.getclass().getname(), e.getmessage()); } public errorresponse(string errortypename, string message) { this.errortypename = errortypename; this.message = message; } ......省略getter/setter方法 }
2. 自定义异常类型
src/main/java/com/twuc/webapp/exception/resourcenotfoundexception.java
一般我们处理的都是 runtimeexception ,所以如果你需要自定义异常类型的话直接集成这个类就可以了。
/** * @author shuang.kou * 自定义异常类型 */ public class resourcenotfoundexception extends runtimeexception { private string message; public resourcenotfoundexception() { super(); } public resourcenotfoundexception(string message) { super(message); this.message = message; } @override public string getmessage() { return message; } public void setmessage(string message) { this.message = message; } }
3. 新建异常处理类
我们只需要在类上加上@controlleradvice注解这个类就成为了全局异常处理类,当然你也可以通过 assignabletypes指定特定的 controller 类,让异常处理类只处理特定类抛出的异常。
src/main/java/com/twuc/webapp/exception/globalexceptionhandler.java
/** * @author shuang.kou */ @controlleradvice(assignabletypes = {exceptioncontroller.class}) @responsebody public class globalexceptionhandler { errorresponse illegalargumentresponse = new errorresponse(new illegalargumentexception("参数错误!")); errorresponse resoursenotfoundresponse = new errorresponse(new resourcenotfoundexception("sorry, the resourse not found!")); @exceptionhandler(value = exception.class)// 拦截所有异常, 这里只是为了演示,一般情况下一个方法特定处理一种异常 public responseentity<errorresponse> exceptionhandler(exception e) { if (e instanceof illegalargumentexception) { return responseentity.status(400).body(illegalargumentresponse); } else if (e instanceof resourcenotfoundexception) { return responseentity.status(404).body(resoursenotfoundresponse); } return null; } }
4. controller模拟抛出异常
src/main/java/com/twuc/webapp/web/exceptioncontroller.java
/** * @author shuang.kou */ @restcontroller @requestmapping("/api") public class exceptioncontroller { @getmapping("/illegalargumentexception") public void throwexception() { throw new illegalargumentexception(); } @getmapping("/resourcenotfoundexception") public void throwexception2() { throw new resourcenotfoundexception(); } }
使用 get 请求 localhost:8080/api/resourcenotfoundexception[1] (curl -i -s -x get url),服务端返回的 json 数据如下:
{ "message": "sorry, the resourse not found!", "errortypename": "com.twuc.webapp.exception.resourcenotfoundexception" }
5. 编写测试类
mockmvc 由org.springframework.boot.test包提供,实现了对http请求的模拟,一般用于我们测试 controller 层。
/** * @author shuang.kou */ @autoconfiguremockmvc @springboottest public class exceptiontest { @autowired mockmvc mockmvc; @test void should_return_400_if_param_not_valid() throws exception { mockmvc.perform(get("/api/illegalargumentexception")) .andexpect(status().is(400)) .andexpect(jsonpath("$.message").value("参数错误!")); } @test void should_return_404_if_resourse_not_found() throws exception { mockmvc.perform(get("/api/resourcenotfoundexception")) .andexpect(status().is(404)) .andexpect(jsonpath("$.message").value("sorry, the resourse not found!")); } }
二、 @exceptionhandler 处理 controller 级别的异常
我们刚刚也说了使用@controlleradvice注解 可以通过 assignabletypes指定特定的类,让异常处理类只处理特定类抛出的异常。所以这种处理异常的方式,实际上现在使用的比较少了。
我们把下面这段代码移到 src/main/java/com/twuc/webapp/exception/globalexceptionhandler.java 中就可以了。
@exceptionhandler(value = exception.class)// 拦截所有异常 public responseentity<errorresponse> exceptionhandler(exception e) { if (e instanceof illegalargumentexception) { return responseentity.status(400).body(illegalargumentresponse); } else if (e instanceof resourcenotfoundexception) { return responseentity.status(404).body(resoursenotfoundresponse); } return null; }
三、 responsestatusexception
研究 responsestatusexception 我们先来看看,通过 responsestatus注解简单处理异常的方法(将异常映射为状态码)。
src/main/java/com/twuc/webapp/exception/resourcenotfoundexception.java
@responsestatus(code = httpstatus.not_found) public class resoursenotfoundexception2 extends runtimeexception { public resoursenotfoundexception2() { } public resoursenotfoundexception2(string message) { super(message); } }
src/main/java/com/twuc/webapp/web/responsestatusexceptioncontroller.java
@restcontroller @requestmapping("/api") public class responsestatusexceptioncontroller { @getmapping("/resourcenotfoundexception2") public void throwexception3() { throw new resoursenotfoundexception2("sorry, the resourse not found!"); } }
使用 get 请求 localhost:8080/api/resourcenotfoundexception2[2] ,服务端返回的 json 数据如下:
{ "timestamp": "2019-08-21t07:11:43.744+0000", "status": 404, "error": "not found", "message": "sorry, the resourse not found!", "path": "/api/resourcenotfoundexception2" }
这种通过 responsestatus注解简单处理异常的方法是的好处是比较简单,但是一般我们不会这样做,通过responsestatusexception会更加方便,可以避免我们额外的异常类。
@getmapping("/resourcenotfoundexception2") public void throwexception3() { throw new responsestatusexception(httpstatus.not_found, "sorry, the resourse not found!", new resourcenotfoundexception()); }
使用 get 请求 localhost:8080/api/resourcenotfoundexception2[3] ,服务端返回的 json 数据如下,和使用 responsestatus 实现的效果一样:
{ "timestamp": "2019-08-21t07:28:12.017+0000", "status": 404, "error": "not found", "message": "sorry, the resourse not found!", "path": "/api/resourcenotfoundexception3" }
responsestatusexception 提供了三个构造方法:
public responsestatusexception(httpstatus status) { this(status, null, null); } public responsestatusexception(httpstatus status, @nullable string reason) { this(status, reason, null); } public responsestatusexception(httpstatus status, @nullable string reason, @nullable throwable cause) { super(null, cause); assert.notnull(status, "httpstatus is required"); this.status = status; this.reason = reason; }
构造函数中的参数解释如下:
- status :http status
- reason :response 的消息内容
- cause :抛出的异常
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。