rest-spring-boot-starter
rest-spring-boot-starter
基于spring boot,统一业务异常处理,统一返回格式包装
依赖
<dependency>
<groupId>tk.fishfish</groupId>
<artifactId>rest-spring-boot-starter</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
统一业务异常处理
@RestController
public class DemoController {
@GetMapping("/list")
public List<String> list() {
throw new BizException(10001, "xxx错误");
}
}
业务异常统一处理:
{
"code": 10001,
"msg": "xxx错误",
"data": null
}
统一返回格式包装
@RestController
public class DemoController {
@GetMapping("/list")
public List<String> list() {
return Arrays.asList("1", "2");
}
}
返回值进行包装,忽略org.springframework.http.ResponseEntity
值类型。
{
"code": 0,
"msg": null,
"data": [
"1",
"2"
]
}
原理
定义统一格式:
{
"code": 返回码,
"msg": 描述,
"data": 数据
}
约定:
- code:-1,代表全局异常处理的错误;0,成功;正数,业务错误码
- msg:一段描述
- data:真正的数据
异常处理
使用org.springframework.web.bind.annotation.RestControllerAdvice
,全局捕获异常。
package tk.fishfish.rest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理,优先级为100
*
* @author 奔波儿灞
* @since 1.0
*/
@Order(100)
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(BizException.class)
public ApiResult<Void> handleBizException(BizException e) {
LOG.warn("handle bizException", e);
Integer code = e.getCode();
String msg = e.getMessage();
return ApiResult.fail(code, msg);
}
@ExceptionHandler(Exception.class)
public ApiResult<Void> handleException(Exception e) {
LOG.warn("handle exception", e);
String msg = e.getMessage();
return ApiResult.fail(-1, msg);
}
}
统一返回
通过实现org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice
,在写入响应前统一包装返回内容。
package tk.fishfish.rest;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 返回body处理,包装成ApiResult。如果是ResponseEntity,则不包装
*
* @author 奔波儿灞
* @see tk.fishfish.rest.ApiResult
* @since 1.0
*/
@RestControllerAdvice(annotations = RestController.class)
public class ApiResultResponseBodyAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter,
MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
// ResponseEntity,则不包装
if (body instanceof ResponseEntity) {
return body;
}
// ApiResult,也不包装
if (body instanceof ApiResult) {
return body;
}
// todo 基本数据类型是否特殊处理
// 其余统一包装成ApiResult
return ApiResult.ok(body);
}
}