2012-11-01 5 views
9

Ho una semplice API REST, costruita utilizzando Spring MVC @Controller se @RequestMapping. Vorrei iniziare a inserire le risposte per fornire ulteriori metadati.MVC primaverile: appropriato punto di estensione per il wrapping delle risposte API

Ad esempio, data una chiamata che sarebbe tornato

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

mi piacerebbe avvolgerlo, come segue:

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

Inoltre, mi piacerebbe sostenere set standard di parametri per la gestione degli elenchi (limit e offset).

Dato che questo tocca tutti i metodi API, mi piacerebbe implementarlo come decoratore di alcuni servizi interni primaverili, quindi i metodi stessi possono concentrarsi sulla loro logica effettiva, e mantenere questo roba del materiale sintetico centralizzato.

Ho iniziato il percorso di decorazione degli HttpMessageConverter che sono registrati e li avvolgo con un decoratore.

Tuttavia, questo non mi consente di accedere alla richiesta in entrata per i metodi che non dichiarano uno @RequestBody. (Molti non lo fanno)

Idealmente, ho bisogno di essere più in alto nello stack - RequestResponseBodyMethodProcessor.writeWithMessageConverters() sembra un buon candidato, ma non so come collegare qui.

Quali opzioni sono disponibili con Spring MVC per implementare questo tipo di elaborazione API di richieste/risposte?

risposta

6

Ecco l'implementazione che ho usato:

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

} 
+0

ha funzionato perfettamente. Grazie! –

+0

Penso che sia possibile usare ['@ ControllerAdvice'] (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-controller-advice) combinato con ['ResponseBodyAdvice'] (https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyAdvice.html) per semplificare questa soluzione . –

+0

@AmirAbiri, non consente di modificare il tipo di risposta. È possibile solo arricchire la risposta con alcuni dati, ma non per avvolgere l'oggetto con un'altra struttura. –

Problemi correlati