項目開發中保證零異常彷佛是不可能的,不管是系統異常仍是程序自己的編碼問題形成的異常信息都要以一種約定的數據結構返回,友好的處理方式在先後端分離模式下(後端提供API接口給到前端)能大大增長你們的溝通、工做效率。基於Spring Boot進行異常統一處理,本文中主要用到
@ControllerAdvice
註解。html
[統一返回數據結構]
定義接口返回數據結構[統一返回數據結構]
數據接口字段模型定義[統一返回數據結構]
封裝接口返回方法(成功、失敗)[統一異常處理]
狀態消息枚舉[統一異常處理]
自定義異常類[統一異常處理]
@ControllerAdvice統一處理異常[測試]
測試正常返回及空指針系統異常[測試]
自定義異常測試本文示例基於Spring Boot實戰系列(3)AOP面向切面編程 /chapter3/chapter3-1可在Github獲取源碼前端
先定義接口返回數據結構,code爲0表示操做成功,非0表示異常。其中data只有在處理成功纔會返回,其餘狀況不會返回,或者那些不須要返回數據的接口(更新、刪除...)java
{
"code": 0,
"message": "SUCCESS",
"data": {
}
}
複製代碼
建立/domain/Result.java
類,對以上數據接口涉及的字段進行定義。git
Result.java
github
package com.angelo.domain;
public class Result<T> {
private Integer code; // 狀態碼
private String message; // 狀態描述信息
private T data; // 定義爲範型
// 如下 getter、setter方法省略
}
複製代碼
建立/util/MessageUtil.java
類,對返回的成功、失敗進行統一封裝。web
MessageUtil.java
spring
package com.angelo.util;
import com.angelo.domain.Result;
public class MessageUtil {
/** * 成功方法 * @param object * @return */
public static Result success(Object object) {
Result result = new Result();
result.setCode(0);
result.setMessage("SUCCESS");
if (object != null) {
result.setData(object);
}
return result;
}
/** * 成功可是 */
public static Result success() {
return success(null);
}
/** * 失敗方法 * @param code * @param message * @return */
public static Result error(Integer code, String message) {
Result result = new Result();
result.setCode(code);
result.setMessage(message);
return result;
}
}
複製代碼
項目用到的狀態碼、描述信息要有個文件統一去作枚舉定義,一方面能夠實現複用,另外一方面若是狀態碼、描述有改動只須要在定義枚舉的地方改動便可。編程
新建/enums/MessageEnum.java
枚舉json
package com.angelo.enums;
public enum MessageEnum {
SYSTEM_ERROR(1001, "系統異常"),
NAME_EXCEEDED_CHARRACTER_LIMIT(2000, "姓名超過了限制,最大4個字符!");
private Integer code;
private String message;
MessageEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
複製代碼
Spring Boot框架只對拋出的RuntimeException異常進行事物回滾,那麼Spring Boot封裝的RuntimeException異常也是繼承的Exception後端
新建/exception/UserException.java
類,繼承於RuntimeException
UserException.java
package com.angelo.exception;
import com.angelo.enums.MessageEnum;
public class UserException extends RuntimeException {
private Integer code;
public UserException(MessageEnum messageEnum) {
super(messageEnum.getMessage());
this.code = messageEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
複製代碼
關於@ControllerAdvice
更多內容可參考官方文檔https://docs.spring.io/spring-framework/docs/5.0.0.M1/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
@ControllerAdvice
,spring3.2新增長,用於定義 @ExceptionHandler
, @InitBinder
, 和 @ModelAttribute
方法,並應用到全部的@RequestMapping
方法。
@ExceptionHandler
,攔截異常,方法裏的value是指須要攔截的異常類型,經過該註解可實現自定義異常處理。
注意:
以前講過AOP面向切面編程,註解@AfterThrowing
會捕捉到項目中的錯誤信息,若是使用了此註解,它捕獲到錯誤信息以後,會直接返回,是不會觸發@ControllerAdvice
註解的。package com.angelo.handle;
import com.angelo.domain.Result;
import com.angelo.exception.UserException;
import com.angelo.util.MessageUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
logger.info("進入error");
// 是否屬於自定義異常
if (e instanceof UserException) {
UserException userException = (UserException) e;
return MessageUtil.error(userException.getCode(), userException.getMessage());
} else {
logger.error("系統異常 {}", e);
return MessageUtil.error(1000, "系統異常!");
}
}
}
複製代碼
修改Usercontroller.java
類,在查詢用戶列表接口增長返回值處理,以下所示:
/** * 查詢用戶列表 * @return */
@RequestMapping(value = "/user/list/{exception}")
public Result<User> userList(@PathVariable("exception") Boolean exception) {
if (exception) {
return null; // 測試空指針異常
}
return MessageUtil.success(userRepository.findAll());
}
複製代碼
修改Usercontroller.java
類,在保存用戶信息接口增長姓名長度校驗拋出自定義錯誤,以下所示:
/** * 保存一個用戶 * @param name * @param age * @return */
@PostMapping(value = "/user")
public User userAdd(@RequestBody User userParams) throws Exception {
User user = new User();
user.setName(userParams.getName());
user.setAge(userParams.getAge());
if (userParams.getName().length() > 4) { // 校驗測試異常類
throw new UserException(MessageEnum.NAME_EXCEEDED_CHARRACTER_LIMIT);
}
return userRepository.save(user);
}
複製代碼
做者:五月君
連接:www.imooc.com/article/260…
來源:慕課網
Github: Spring Boot實戰系列