我有一个简单的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范围的请求/响应处理?
答案 0 :(得分:6)
以下是我使用的实现:
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;
}
}
}
}