主要利用 spring-webmvc
提供的@ControllerAdvice
註解和@ExceptionHandler
註解,所以springwebmvc的依賴必不可少。
@ControllerAdvice
作用在類上,表明使用該類對controller中拋出的異常進行捕獲處理。
@ExceptionHandler
作用在方法上,需要指定異常的字節碼數組,以便說明該方法是用來處理哪些異常。
下面我們用一個demo來幫助我們理解這兩個註解。
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
@ControllerAdvice
public class CommonExceptionHandler {
@ExceptionHandler(IOException.class)
@ResponseBody
public String handleIOException(IOException ioException) {
//IOException會被自動注入
return ioException.getMessage();
}
@ExceptionHandler({IOException.class,RuntimeException.class})
@ResponseBody
public String handleIOException(IOException ioException,RuntimeException runtimeException) {
String msg1 = ioException.getMessage();
String msg2 = runtimeException.getMessage();
return "";
}
}
上面的代碼讓我們初步瞭解了全局的異常捕獲處理,但是和實際開發中的異常處理還是差很多,下面我們按步驟演示一個完整的異常處理。
注:下面的代碼爲了方便使用了lombok。
1. 定義ExceptionResult類(VO),因爲項目是前後端分離,出現異常後,我們需要將一些必要的異常信息返回給前端展示。一般定義一個狀態碼,異常的提示信息,時間戳等等,這些字段根據自己的需要添加。
@Data
public class ExceptionResult {
private int status;
private String message;
private Long timestamp;
// ExceptionEnums是一個枚舉類,管理我們項目中自定義的異常信息和狀態碼
public ExceptionResult(ExceptionEnums exceptionEnums) {
this.status = exceptionEnums.getCode();
this.message = exceptionEnums.getMsg();
this.timestamp = System.currentTimeMillis();
}
}
2. 自定義ExceptionEnums枚舉類,管理我們項目中自定義的異常信息和狀態碼。
@Getter
@AllArgsConstructor
public enum ExceptionEnums {
USERNAME_CANNOT_BE_NULL(400,"用戶名不能爲空"),
PASSWORD_CANNOT_BE_NULL(401,"密碼不能爲空");
private final int code;
private final String msg;
}
3. 自定義CustomException異常類,有了該異常類,我們就可以在全局異常處理器中捕獲他,進行處理。該異常類需要繼承RuntimeException而不是Exception。因而該自定義異常可以直接拋出,而不用在controller方法上聲明。
@Getter
@AllArgsConstructor
public class LyException extends RuntimeException{
// 在拋該異常實例化的時候需要傳入我們的枚舉類對象,這樣做的目的是攜帶我們自定義的異常信息和狀態碼
private ExceptionEnums exceptionEnums;
}
4. 創建全局異常處理器,捕獲我們第三步自定義的異常,實現通用的異常處理。
@ControllerAdvice
public class CommonExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<ExceptionResult> handleException(CustomException customException) {
// 獲取存儲自定義異常信息和狀態碼的枚舉對象
ExceptionEnums exceptionEnums = customException.getExceptionEnums();
return ResponseEntity.status(exceptionEnums.getCode()).body(new ExceptionResult(exceptionEnums));
}
}
關於ResponseEntity<T>
,使用這個類我們可以設置響應行的status,同時可以序列化不同類型的數據到響應體中。
5. 在controller方法中需要的地方拋出異常。這裏注意一點,如果service層出現異常,不要try catch,直接向上拋到controller這一層,不然全局異常處理器捕獲不到。
@Controller("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("login")
public ResponseEntity<Item> login(User user) {
if (StringUtils.isBlank(user.getUsername)) {
throw new CustomException(ExceptionEnums.USERNAME_CANNOT_BE_NULL);
}
user = userService.login(user);
return ResponseEntity.ok(user);
}
}