详解SpringBoot 处理异常的几种常见姿势

网友投稿 418 2023-07-25

详解SpringBoot 处理异常的几种常见姿势

详解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. 新建异常处理类

我们只需要在类上加上@ControllerAdvicOknsuesUBQe注解这个类就成为了全局异常处理类,当然你也可以通过 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 exceptionHandler(Exception e) {

if (e instanceof IllegalArgumentException) {

return ResponseEntity.status(400).body(illegalArgumentResponse);

} else if (e instanceof ResourceNotFoundException) {

return ResponseEntity.status(404)OknsuesUBQ.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.ResourceNotFounhttp://dException"

}

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(staOknsuesUBQtus().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 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 :抛出的异常

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:银行敏捷开发工具 - 提高效率的利器还是空中楼阁?
下一篇:移动应用敏捷开发工具 - 提高开发效率的利器
相关文章

 发表评论

暂时没有评论,来抢沙发吧~