9

我有一个简单的 REST API,使用 Spring MVC@Controller@RequestMapping. 我想开始包装响应以提供额外的元数据。

例如,给定一个将返回的调用

HTTP GET: /users/1
{
    "userName" : "Jack Jackerson"
}

我想把它包装起来,如下:

{
    "metadata" : 
    {
        "callLimit" : "50",
        "callsRemaining" : "49"
    },
    "result" :
    {
        "userName" : "Jack Jackerson"
    }
}  ..etc..

此外,我想支持用于管理列表(limitoffset)的标准参数集。

由于这涉及到所有的 api 方法,我想将它实现为一些 spring 内部服务的装饰器,因此方法本身可以专注于它们的实际逻辑,并保持这些样板文件的集中。

我已经开始装饰HttpMessageConverter已注册的 's,并用装饰器包装它们。

但是,这并不能让我访问对未声明 a 的方法的入站请求@RequestBody。(很多没有)

理想情况下,我需要在堆栈中更高 -RequestResponseBodyMethodProcessor.writeWithMessageConverters()看起来是一个不错的候选人,但我不知道如何在这里挂钩。

Spring MVC 有哪些可用选项来实现这种类型的 API-Wide 请求/响应处理?

4

1 回答 1

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;
            }
        }       
    }

}
于 2012-11-01T11:24:40.167 回答