詳解SpringBoot 處理異常的幾種常見(jiàn)姿勢(shì)
一、使用 @ControllerAdvice 和 @ExceptionHandler 處理全局異常
這是目前很常用的一種方式,非常推薦。測(cè)試代碼中用到了 Junit 5,如果你新建項(xiàng)目驗(yàn)證下面的代碼的話(huà),記得添加上相關(guān)依賴(lài)。
1. 新建異常信息實(shí)體類(lèi)
非必要的類(lèi),主要用于包裝異常信息。
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. 自定義異常類(lèi)型
src/main/java/com/twuc/webApp/exception/ResourceNotFoundException.java
一般我們處理的都是 RuntimeException ,所以如果你需要自定義異常類(lèi)型的話(huà)直接集成這個(gè)類(lèi)就可以了。
/**
* @author shuang.kou
* 自定義異常類(lèi)型
*/
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. 新建異常處理類(lèi)
我們只需要在類(lèi)上加上@ControllerAdvice注解這個(gè)類(lèi)就成為了全局異常處理類(lèi),當(dāng)然你也可以通過(guò) assignableTypes指定特定的 Controller 類(lèi),讓異常處理類(lèi)只處理特定類(lèi)拋出的異常。
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("參數(shù)錯(cuò)誤!"));
ErrorResponse resourseNotFoundResponse = new ErrorResponse(new ResourceNotFoundException("Sorry, the resourse not found!"));
@ExceptionHandler(value = Exception.class)// 攔截所有異常, 這里只是為了演示,一般情況下一個(gè)方法特定處理一種異常
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 請(qǐng)求 localhost:8080/api/resourceNotFoundException[1] (curl -i -s -X GET url),服務(wù)端返回的 JSON 數(shù)據(jù)如下:
{
"message": "Sorry, the resourse not found!",
"errorTypeName": "com.twuc.webApp.exception.ResourceNotFoundException"
}
5. 編寫(xiě)測(cè)試類(lèi)
MockMvc 由org.springframework.boot.test包提供,實(shí)現(xiàn)了對(duì)Http請(qǐng)求的模擬,一般用于我們測(cè)試 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("參數(shù)錯(cuò)誤!"));
}
@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 級(jí)別的異常
我們剛剛也說(shuō)了使用@ControllerAdvice注解 可以通過(guò) assignableTypes指定特定的類(lèi),讓異常處理類(lèi)只處理特定類(lèi)拋出的異常。所以這種處理異常的方式,實(shí)際上現(xiàn)在使用的比較少了。
我們把下面這段代碼移到 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 我們先來(lái)看看,通過(guò) ResponseStatus注解簡(jiǎn)單處理異常的方法(將異常映射為狀態(tài)碼)。
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 請(qǐng)求 localhost:8080/api/resourceNotFoundException2[2] ,服務(wù)端返回的 JSON 數(shù)據(jù)如下:
{
"timestamp": "2019-08-21T07:11:43.744+0000",
"status": 404,
"error": "Not Found",
"message": "Sorry, the resourse not found!",
"path": "/api/resourceNotFoundException2"
}
這種通過(guò) ResponseStatus注解簡(jiǎn)單處理異常的方法是的好處是比較簡(jiǎn)單,但是一般我們不會(huì)這樣做,通過(guò)ResponseStatusException會(huì)更加方便,可以避免我們額外的異常類(lèi)。
@GetMapping("/resourceNotFoundException2")
public void throwException3() {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Sorry, the resourse not found!", new ResourceNotFoundException());
}
使用 Get 請(qǐng)求 localhost:8080/api/resourceNotFoundException2[3] ,服務(wù)端返回的 JSON 數(shù)據(jù)如下,和使用 ResponseStatus 實(shí)現(xiàn)的效果一樣:
{
"timestamp": "2019-08-21T07:28:12.017+0000",
"status": 404,
"error": "Not Found",
"message": "Sorry, the resourse not found!",
"path": "/api/resourceNotFoundException3"
}
ResponseStatusException 提供了三個(gè)構(gòu)造方法:
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;
}
構(gòu)造函數(shù)中的參數(shù)解釋如下:
- status :http status
- reason :response 的消息內(nèi)容
- cause :拋出的異常
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
synchronized及JUC顯式locks?使用原理解析
JavaWeb?Listener?利用Session統(tǒng)計(jì)在線(xiàn)人數(shù)
Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔
Java實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接的最詳細(xì)教程分享
Java實(shí)現(xiàn)簡(jiǎn)易計(jì)算器(逆波蘭表達(dá)式)

