自定義 Spring 相應的包裝類就是實現(xiàn) HandlerMethodReturnValueHandler
本文是基于Spring Boot 2環(huán)境進行開發(fā)的
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
-
supportsReturnType
表示是否支持該返回類型 -
handleReturnValue
對于返回值的處理
spring的默認處理類是RequestResponseBodyMethodProcessor
,它是根據(jù)判斷是否有@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直接創(chuàng)建的鲫懒,看下面
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
我們是不是可以通過在customReturnValueHandlers
添加自定義返回處理類呢,但是spring在選擇handler
的時候是根據(jù)順序進行選取的忍弛,所以自定義包裝處理類肯定在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了谋作,返回的是實際的數(shù)據(jù)芋肠,包裝實際的數(shù)據(jù)就可以交給你寫的包裝類去做了,效果如下
{
"code": 200,
"data": [{
"id": 1,
"name": "xxx"
}]
}