spring boot 統一返回資料及全域性異常處理
阿新 • • 發佈:2018-11-06
記錄關於spring boot 統一返回資料及全域性異常處理的操作實現。
一、統一返回資料
1、定義一個超類:BaseResponseVo
@Data
@NoArgsConstructor
public class BaseResponseVo{
protected Integer rtn;
protected String message;
}
2、定義一個列舉類來管理返回狀態碼:ResponseEnum
public enum ResponseEnum { /** * 請求成功 */ SUCCESS(0, "ok"), /** * 前臺請求引數錯誤 */ BAD_REQUEST_PARAMETER(1, "請求引數不符合規定"), /** * 請求錯誤 */ BAD_REQUEST(2, "請求錯誤"), /** * 請求的Content-Type錯誤 */ MEDIA_TYPE_NOT_SUPPORTED(3, "請求的Content-Type錯誤"); private Integer rtn; private String message; ResponseEnum(Integer rtn, String message) { this.rtn = rtn; this.message = message; } public Integer getRtn() { return rtn; } public String getMessage() { return message; } }
3、定義帶資料的返回模型:ResponseDataVo
@Data
@NoArgsConstructor
public class ResponseDataVo<T> extends BaseResponseVo {
private T data;
}
4、定義分頁返回資料模型:PageResponseDataVo
public class PageResponseDataVo<T> extends BaseResponseVo { /** * 當前頁 */ private Integer pageNum; /** * 每頁記錄數 */ private Integer pageSize; /** * 總記錄數 */ private Long total; /** * 當前頁記錄 */ private Integer pageCount; /** * 總頁數 */ private Integer tatalPage; /** * 資料起始位置 */ private Integer start; /** * 資料 */ private List<T> list=new ArrayList<>(); }
5、定義返回資料處理工具類:ResponseDataUtils
public class ResponseDataUtils { /** * 請求成功時封裝資料 * * @param data 資料 * @return 返回BaseResponseVo封裝後的資料 */ public BaseResponseVo success(Object data) { ResponseDataVo result = new ResponseDataVo(); result.setRtn(SUCCESS.getRtn()); result.setMessage(SUCCESS.getMessage()); result.setData(data); return result; } /** * 請求成功時封裝資料 * * @return 返回BaseResponseVo封裝後的資料 */ public BaseResponseVo success() { return success(null); } /** * 請求失敗結果封裝 * * @param responseEnum 響應狀態碼 * @param message 響應資訊 * @return 返回BaseResponseVo封裝後的資料 */ public BaseResponseVo error(ResponseEnum responseEnum, String message) { BaseResponseVo result = new BaseResponseVo(); result.setRtn(responseEnum.getRtn()); String msg = StringUtils.isEmpty(message) ? responseEnum.getMessage() : message; result.setMessage(msg); return result; } /** * 請求失敗結果封裝 * * @param responseEnum 響應狀態碼 * @return 返回BaseResponseVo封裝後的資料 */ public BaseResponseVo error(ResponseEnum responseEnum) { return error(responseEnum, null); } }
6:定義GlobalResponseHandler 實現ResponseBodyAdvice介面統一攔截介面返回資料。
要對返回值是String的型別單獨處理下。
@Slf4j
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
/**
* Whether this component supports the given controller method return type
* and the selected {@code HttpMessageConverter} type.
*
* @param returnType the return type
* @param converterType the selected converter type
* @return {@code true} if {@link #beforeBodyWrite} should be invoked;
* {@code false} otherwise
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//判斷支援的型別,因為我們定義的BaseResponseVo 裡面的data可能是任何型別,這裡就不判斷統一放過
//如果你想對執行的返回體進行操作,可將上方的Object換成你自己的型別
return true;
}
/**
* Invoked after an {@code HttpMessageConverter} is selected and just before
* its write method is invoked.
*
* @param body the body to be written
* @param returnType the return type of the controller method
* @param selectedContentType the content type selected through content negotiation
* @param selectedConverterType the converter type selected to write to the response
* @param request the current request
* @param response the current response
* @return the body that was passed in or a modified (possibly new) instance
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
log.info("請求返回資料型別class={}", body.getClass().getName());
BaseResponseVo result = null;
//相容原來的介面返回
if (body instanceof ResponseDataVo) {
result = (ResponseDataVo) body;
} else if (body instanceof PageResponseDataVo) {
result = (PageResponseDataVo) body;
} else if (body instanceof BaseResponseVo) {
result = (BaseResponseVo) body;
} else {
result = ResponseDataUtils.success(body);
}
//debug時列印響應結果
if (log.isDebugEnabled()) {
log.debug("響應引數:{} ", JSON.toJSONString(result));
}
//處理返回值是String的情況
if (body instanceof String) {
return JSON.toJSONString(result);
}
return result;
}
}
7、定義GlobalExceptionHandler類統一異常處理
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* Create by lrt<br/>
* Date:2018/10/24
* Description: 攔截異常進行處理返回前臺友好資訊
*
* @param e 異常物件
* @return java.lang.String 返回前臺資訊
*/
@ExceptionHandler(Exception.class)
public BaseResponseVo exceptionHandler(Exception e) {
e.printStackTrace();
//引數校驗錯誤
if (e instanceof BindException) {
BindException bindException = (BindException) e;
List<ObjectError> objectErrors = bindException.getBindingResult().getAllErrors();
return getValidExceptionResult(objectErrors);
}
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException bindException = (MethodArgumentNotValidException) e;
List<ObjectError> objectErrors = bindException.getBindingResult().getAllErrors();
return getValidExceptionResult(objectErrors);
}
//post請求未傳引數
if (e instanceof HttpMessageNotReadableException) {
return ResponseDataUtils.error(ResponseEnum.BAD_REQUEST);
}
//請求Content type不支援
if (e instanceof HttpMediaTypeNotSupportedException) {
return ResponseDataUtils.error(ResponseEnum.MEDIA_TYPE_NOT_SUPPORTED);
}
return ResponseDataUtils.error(ResponseEnum.SERVER_ERROR);
}
//引數校驗異常處理
private BaseResponseVo getValidExceptionResult(List<ObjectError> objectErrors) {
StringBuilder sb = new StringBuilder();
for (ObjectError error : objectErrors) {
sb.append(error.getDefaultMessage()).append(";");
}
String message = sb.length() > 0 ? sb.toString().substring(0, sb.length() - 1) : sb.toString();
return ResponseDataUtils.error(ResponseEnum.BAD_REQUEST_PARAMETER, message);
}
}