2013-01-23 16 views
6

Provare a creare un servizio Web RESTful utilizzando Spring MVC.Come si progetta un Generatore di risposte generico/Servizio Web RESTful utilizzando Spring MVC?

Il controller deve restituire tipi specifici di Java, ma il corpo della risposta deve essere una busta generica. Come si può fare?

le seguenti sezioni di codice sono ciò che ho finora: metodo

Controller:

@Controller 
    @RequestMapping(value = "/mycontroller") 
    public class MyController { 

     public ServiceDetails getServiceDetails() { 
      return new ServiceDetails("MyService"); 
     } 
    } 

busta di risposta:

public class Response<T> { 

     private String message; 
     private T responseBody; 

    } 

ServiceDetails codice:

public class ServiceDetails { 

     private String serviceName; 

     public ServiceDetails(String serviceName) { 
      this.serviceName = serviceName; 
     } 
    } 

Destinato risposta finale ai clienti dovrebbe apparire come:

{ 

    "message" : "Operation OK" 
    "responseBody" : { 
         "serviceName" : "MyService" 
         } 

    } 
+0

Se si utilizza Jackson o FlexJson, perché non si può semplicemente restituire l'oggetto Risposta nel proprio metodo? Il serializzatore JSON dovrebbe essere in grado di serializzare qualsiasi oggetto complesso. – CodeChimp

+0

sto usando jackson. ma vorrei comunque che il controller restituisse i tipi java specifici della richiesta. penso sia più pulito e più intuitivo. –

+0

più c'è qualche codice piastra di cottura nella costruzione dell'oggetto risposta, quindi mi piacerebbe farlo da un solo punto –

risposta

0

Che cosa si può fare è avere un MyRestController solo avvolgendo il risultato in una Response come questo:

@Controller 
@RequestMapping(value = "/mycontroller") 
public class MyRestController { 

    @Autowired 
    private MyController myController; 

    @RequestMapping(value = "/details") 
    public @ResponseBody Response<ServiceDetails> getServiceDetails() { 
     return new Response(myController.getServiceDetails(),"Operation OK"); 
    } 
} 

Questa soluzione a mantenere il vostro MyController indipendente originale il tuo codice REST. Sembra è necessario includere Jackson nel classpath in modo che la primavera si auto-magicamente serializzare JSON (vedi this per i dettagli)

EDIT

Sembra avete bisogno di qualcosa di più generico ... ecco un consiglio.

@Controller 
@RequestMapping(value = "/mycontroller") 
public class MyGenericRestController { 

    @Autowired 
    private MyController myController; 

    //this will match all "/myController/*" 
    @RequestMapping(value = "/{operation}") 
    public @ResponseBody Response getGenericOperation(String @PathVariable operation) { 
      Method operationToInvoke = findMethodWithRequestMapping(operation); 
      Object responseBody = null; 
      try{ 
       responseBody = operationToInvoke.invoke(myController); 
      }catch(Exception e){ 
       e.printStackTrace(); 
       return new Response(null,"operation failed"); 
      } 
     return new Response(responseBody ,"Operation OK"); 
    } 

    private Method findMethodWithRequestMapping(String operation){ 
     //TODO 
     //This method will use reflection to find a method annotated 
     //@RequestMapping(value=<operation>) 
     //in myController 
     return ... 
    } 
} 

E mantenere il vostro "myController" originale quasi come lo era:

@Controller 
public class MyController { 

    //this method is not expected to be called directly by spring MVC 
    @RequestMapping(value = "/details") 
    public ServiceDetails getServiceDetails() { 
     return new ServiceDetails("MyService"); 
    } 
} 

grosso problema con questo: il @RequestMapping in MyController bisogno probabilmente per essere sostituito da un po 'di annotazione personalizzati (e adattarsi a findMethodWithRequestMapping eseguire l'introspezione su questa annotazione personalizzata).

+0

la cosa è che voglio evitare di scrivere una nuova risposta() un sacco di volte. Voglio che la persona che implementa i metodi del controller non debba essere a conoscenza dell'inviluppo della risposta, ma restituisca solo un tipo specifico e che l'intercettore prenda quel tipo e lo inserisca nella busta della risposta. –

+0

E per quanto riguarda il campo del messaggio? Qualcuno deve riempirlo da qualche parte ... – ben75

+0

@Eli ha appena modificato il mio post con un suggerimento più generico – ben75

0

Per impostazione predefinita, Spring MVC utilizza org.springframework.http.converter.json.MappingJacksonHttpMessageConverter per serializzare/deserializzare JSON tramite Jackson.

io non sono sicuro se è una grande idea, ma un modo per risolvere il tuo problema è quello di estendere questa classe, e sovrascrivere il metodo writeInternal:

public class CustomMappingJacksonHttpMessageConverter extends MappingJacksonHttpMessageConverter { 

    @Override 
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { 
     super.writeInternal(new Response(object, "Operation OK"), outputMessage); 
    } 
} 

Se si sta utilizzando la configurazione XML, è potrebbe abilitare il convertitore personalizzato in questo modo:

<mvc:annotation-driven> 
    <mvc:message-converters> 
     <bean class="path.to.CustomMappingJacksonHttpMessageConverter"> 
    </mvc:message-converters> 
</mvc:annotation-driven> 
+0

che sembra bello. ma questo significa che questo convertitore verrà utilizzato per tutti i miei controller? ne ho bisogno solo per uno specifico ... è possibile? fondamentalmente quello che dovevo era scavalcare il MappingJacksonJsonView e usare la vista personalizzata come vista per quel controller specifico, ma questo non sembra funzionare. spring usa sempre la visualizzazione predefinita di jackson per qualche motivo –

+0

Non sono proprio sicuro di come impostare un convertitore specifico per un singolo controller. Noioso, ma forse una soluzione accettabile sarebbe quella di creare un contesto di primavera separato (cioè servlet) per questo controller specifico? – reidarok

Problemi correlati