Spring MVC:用于包装API响应的适当扩展点
问题内容:
我有一个简单的REST API,使用Spring MVC
@Controller
和构建@RequestMapping
。我想开始包装响应以提供其他元数据。
例如,给定一个将返回的呼叫
HTTP GET: /users/1
{
"userName" : "Jack Jackerson"
}
我想包装一下,如下所示:
{
"metadata" :
{
"callLimit" : "50",
"callsRemaining" : "49"
},
"result" :
{
"userName" : "Jack Jackerson"
}
} ..etc..
另外,我想支持用于管理列表(limit
和offset
)的标准参数集。
由于这涉及到所有api方法,因此我想将其实现为某些spring内部服务的装饰器,因此这些方法本身可以专注于其实际逻辑,并使此样板内容集中化。
我已经开始装饰装饰的HttpMessageConverter
,然后用装饰器包装它们。
但是,对于没有声明的方法,这不能使我访问入站请求@RequestBody
。(很多都没有)
理想情况下,我需要在堆栈中更高–
RequestResponseBodyMethodProcessor.writeWithMessageConverters()
看起来不错,但我不知道该怎么做。
Spring MVC提供哪些选项来实现这种类型的请求/响应的API范围处理?
问题答案:
这是我使用的实现:
public class MetadataInjectingReturnValueHandler implements HandlerMethodReturnValueHandler {
private final HandlerMethodReturnValueHandler delegate;
public MetadataInjectingReturnValueHandler(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 {
returnValue = wrapResult(returnValue); //Omitted
delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
@Component
public class MetadataInjectionFactoryBean implements InitializingBean {
@Autowired
private RequestMappingHandlerAdapter adapter;
@Override
public void afterPropertiesSet() throws Exception {
HandlerMethodReturnValueHandlerComposite returnValueHandlers = adapter.getReturnValueHandlers();
List<HandlerMethodReturnValueHandler> handlers = Lists.newArrayList(returnValueHandlers.getHandlers());
decorateHandlers(handlers);
adapter.setReturnValueHandlers(handlers);
}
private void decorateHandlers(List<HandlerMethodReturnValueHandler> handlers) {
for (HandlerMethodReturnValueHandler handler : handlers) {
if (handler instanceof RequestResponseBodyMethodProcessor)
{
MetadataInjectingReturnValueHandler decorator = new MetadataInjectingReturnValueHandler(handler);
int index = handlers.indexOf(handler);
handlers.set(index, decorator);
log.info("Metadata Injecting decorator wired up");
break;
}
}
}
}