REST API 响应设计

模型设计

使用统一的 REST 方式定义响应模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// code 后端状态码
// message 简短消息
// data 后端数据
public class R extends HashMap<String, Object> {
private R(ErrorCode errorCode) {
put("code", errorCode.getCode());
put("message", errorCode.getMessage());
}

public static R ok(Object data) {
R r = new R(OK);
r.put("data", data);
return r;
}

public static R error(ErrorCode errorCode) {
return new R(errorCode);
}

private R(String message) {
put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
put("message", message);
}

public static R error(String message) {
return new R(message);
}
}

包装响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 隐式将返回值包装成 R 对象
public class MyHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
private final HandlerMethodReturnValueHandler handler;

public MyHandlerMethodReturnValueHandler(HandlerMethodReturnValueHandler handler) {
this.handler = handler;
}

/**
* 返回值不是 {@link R},并且使用 Rest 方式返回 true
*
* @param returnType returnType
* @return boolean ? 处理 : 不处理
*/
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return handler.supportsReturnType(returnType) && !returnType.getParameterType().equals(R.class);
}

@Override
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
R ok = R.ok(returnValue);
handler.handleReturnValue(ok, returnType, mavContainer, webRequest);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
public class WebMvcConfiguration {
// 调整 RequestMappingHandlerAdapter#getReturnValueHandlers
@Resource
public void resetRequestMappingHandlerAdapter(RequestMappingHandlerAdapter adapter) {
List<HandlerMethodReturnValueHandler> originHandlers = adapter.getReturnValueHandlers();
if (CollectionUtils.isEmpty(originHandlers)) {
return;
}
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<>(originHandlers.size());
for (HandlerMethodReturnValueHandler originHandler : originHandlers) {
if (originHandler instanceof RequestResponseBodyMethodProcessor) {
// 未使用 R 包装返回值,隐式包装
newHandlers.add(new MyHandlerMethodReturnValueHandler(originHandler));
// 使用 R 包装返回值,跳过包装
newHandlers.add(originHandler);
} else {
newHandlers.add(originHandler);
}
}
adapter.setReturnValueHandlers(newHandlers);
}
}

统一异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@RestControllerAdvice
public class ExceptionAdvice {
// 业务定义的非运行时异常
@ExceptionHandler(value = AppNonRuntimeException.class)
public ResponseEntity<R> appException(AppNonRuntimeException e) {
e.printStackTrace();
R error = R.error(e.getErrorCode());
return new ResponseEntity<>(error, HttpStatus.OK);
}

// 业务定义的运行时异常
@ExceptionHandler(value = AppRuntimeException.class)
public ResponseEntity<R> appRuntimeException(AppRuntimeException e) {
e.printStackTrace();
R error = R.error(e.getErrorCode());
return new ResponseEntity<>(error, HttpStatus.OK);
}

// 非业务定义的异常
@ExceptionHandler(value = Exception.class)
public ResponseEntity<R> exception(Exception e) {
e.printStackTrace();
R error = R.error(e.getMessage());
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

代码

here