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 handlers = Lists.newArrayList(returnValueHandlers.getHandlers()); decorateHandlers(handlers); adapter.setReturnValueHandlers(handlers); } private void decorateHandlers(List 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; } } } }