自定义 Spring 相应的包装类就是实现 HandlerMethodReturnValueHandler
本文是基于Spring Boot 2环境进行开发的
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
-
supportsReturnType
表示是否支持该返回类型 -
handleReturnValue
对于返回值的处理
spring的默认处理类是RequestResponseBodyMethodProcessor
,它是根据判断是否有@ResponseBody
注解来处理的
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
}
我们的目标是要在RequestResponseBodyMethodProcessor
的基础上进行包装,并注入到Spring中,首先我们看一下RequestResponseBodyMethodProcessor
的注入方式
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
......
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
...
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
....
return handlers;
}
}
RequestResponseBodyMethodProcessor
在RequestMappingHandlerAdapter
通过new直接创建的,看下面
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
我们是不是可以通过在customReturnValueHandlers
添加自定义返回处理类呢,但是spring在选择handler
的时候是根据顺序进行选取的,所以自定义包装处理类肯定在RequestResponseBodyMethodProcessor
后面,达不到我们的要求
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
}
所以我们的做法就是把handlers
里的RequestResponseBodyMethodProcessor
替换成我们的自定义包装类,首先我们看我们的自定义包装类
/**
* @author 地菍
* @version v1.0 2018/9/18 下午2:26
*/
public class ResultWarpReturnValueHandler implements HandlerMethodReturnValueHandler {
private final HandlerMethodReturnValueHandler delegate;
public ResultWarpReturnValueHandler(HandlerMethodReturnValueHandler delegate) {
this.delegate = delegate;
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return delegate.supportsReturnType(returnType);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
delegate.handleReturnValue(Result.ok(returnValue), returnType, mavContainer, webRequest);
}
}
代码中的Result.ok(returnValue)
就是对响应结果进行包装,然后调用RequestResponseBodyMethodProcessor
的handleReturnValue
进行处理
/**
* @author 地菍
* @version v1.0 2018/9/18 下午3:12
*/
@Configuration
public class ReturnValueConfig implements InitializingBean {
@Autowired
RequestMappingHandlerAdapter requestMappingHandlerAdapter;
@Override
public void afterPropertiesSet() throws Exception {
List<HandlerMethodReturnValueHandler> unmodifiableList = requestMappingHandlerAdapter.getReturnValueHandlers();
List<HandlerMethodReturnValueHandler> list = new ArrayList<>(unmodifiableList.size());
for (HandlerMethodReturnValueHandler returnValueHandler : unmodifiableList) {
if (returnValueHandler instanceof RequestResponseBodyMethodProcessor) {
list.add(new ResultWarpReturnValueHandler(returnValueHandler));
} else {
list.add(returnValueHandler);
}
}
requestMappingHandlerAdapter.setReturnValueHandlers(list);
}
}
自己写一个配置类,注入RequestMappingHandlerAdapter
把其中的handlers
中的RequestResponseBodyMethodProcessor
替换成我们自定义的包装类就可以了
/**
* @author 地菍
* @version v1.0 2018/9/19 下午9:24
*/
@RestController
@RequestMapping
public class UserApi {
@GetMapping("/users")
List<User> getUsers() {
return ...
}
}
然后你就可以这样写一个controller了,返回的是实际的数据,包装实际的数据就可以交给你写的包装类去做了,效果如下
{
"code": 200,
"data": [{
"id": 1,
"name": "xxx"
}]
}