2012-04-03 9 views
5

JAX-RS offre un modo meraviglioso per specificare i tipi di contenuto in @Produces e il framework determinerà automaticamente il miglior tipo di contenuto dall'intestazione HTTP Accept del client e, meraviglia delle meraviglie, anche converti il ​​tuo oggetto in quel tipo (es. XML usando JAXB o JSON usando Jackson) quando restituisci informazioni al chiamante.Mapping dei tipi di contenuto di estensione in Apache CXF JAX-RS

Il mio client (di lavoro), come spesso fanno i clienti, ha reso più semplice un lavoro richiedendo di specificare il tipo di contenuto dall'estensione nell'URL, ad es. api/widgets.json. Questo mi avrebbe costretto ad avere vari getWidgetsXXX() metodi, uno con @Produces("application/json"), un altro con @Produces("application/xml"), ecc

ma sto usando Apache CXF e sono stato felice di scoprire che potevo configure CXF per mappare varie estensioni per i tipi di contenuto che utilizzano il jaxrs.extensions parametro init!

<!-- registers extension mappings --> 
<init-param> 
    <param-name>jaxrs.extensions</param-name> 
    <param-value> 
    xml=application/xml 
    json=application/json 
    </param-value> 
</init-param> 

Ma non riesco a trovare assolutamente nessuna documentazione su come funziona nel mondo reale. Ho ingenuamente pensato che avrei potuto solo annotare un metodo con un percorso con un'estensione e sarebbe imitare il Accepts intestazione:

@Path("/widgets.{extension}") 
@GET 
@Produces({ "application/json", "application/xml" }) 
public List<Widget> getWidgets(); 

Così mi chiamano utilizzando api/widgets.json, e restituisce XML! Il che è particolarmente strano, perché JAX-RS specifica che il tipo di contenuto predefinito è il primo elencato.

Dove posso trovare informazioni su come utilizzare la mappatura del tipo di contenuto dell'estensione CXF?

P.S. Non sto usando Spring.

risposta

0

Nella tua situazione, dichiaro che il metodo @ Produce il tipo di contenuto */* (cioè un carattere jolly completo) e quindi eseguo personalmente la negoziazione del contenuto. Si sarebbe probabilmente essere guardando una firma metodo come questo:

@javax.ws.rs.GET 
@javax.ws.rs.Path("{filename}") 
@javax.ws.rs.Produces("*/*") 
javax.ws.rs.core.Response getDirectoryOrFileContents(
     @javax.ws.rs.PathParam("filename") String filename, 
     @javax.ws.rs.core.Context javax.ws.rs.core.HttpHeaders headers); 

che consente di accedere ad entrambi il nome del file desiderato - un modo di indovinare il tipo di supporto per fornire - e l'insieme completo di intestazioni HTTP (suggerimento: utilizzare headers.getAcceptableMediaTypes()), che danno l'altra direzione. Come bilanciare i due è probabile che sia "interessante". (Il codice che devo fare è molto specifico per il modello interno della mia app, quindi non è probabilmente utile per te.) Quindi restituisci il risultato costruendo uno Response, che ti dà un controllo abbastanza stretto su ciò che il il cliente torna indietro

Sì, questo è più lavoro che lasciare che CXF gestisca tutto questo per te (normalmente genera un sacco di informazioni per fare tutto questo) ma in un caso complesso sarai contento del controllo.

+0

Grazie per il suggerimento. La tua risposta potrebbe rivelarsi utile --- ma temo che non risponda alla domanda. :( –

4

L'aggiunta dei seguenti nei tuoi <jaxrs:server> opere:

<jaxrs:extensionMappings> 
    <entry key="json" value="application/json" /> 
    <entry key="xml" value="application/xml" /> 
</jaxrs:extensionMappings> 

Fonte: http://cxf.apache.org/docs/jax-rs.html#JAX-RS-Debugging

+0

Vuoi dire nella sezione in cui si dice "Ecco un esempio di come può essere fatto con Spring"? –

+0

Oops, non avevo notato che è solo per Spring. – praseodym

+0

Anche se non era quello che l'OP stava cercando per, è stato molto utile per me, e non sto nemmeno usando Spring. Grazie! –

0

I imita l'estensione di intestazione Accept come avete indovinato.Tuttavia, non è necessario dichiarare l'extenstion nella @Path della nota:

@Path("/widgets") 
@GET 
@Produces({ "application/json", "application/xml" }) 
public List<Widget> getWidgets(); 

È quindi possibile chiamare widgets.xml o widgets.json

1

Non so se tale aiuto si o no, ma ero anche affrontando lo stesso problema di introdurre qualcosa del genere nei miei servizi JAX-RS. Ho raggiunto questa funzionalità utilizzando JAX-RS_Content_Negotiation La posizione seguente contiene dettagli a riguardo.

https://docs.jboss.org/resteasy/docs/3.0.6.Final/userguide/html/JAX-RS_Content_Negotiation.html

Non vi resta che mappare i tipi di media con i valori che si desidera

<context-param> 
     <param-name>resteasy.media.type.mappings</param-name> 
     <param-value> 
      html : text/html, json : application/json, xml :   
      application/xml 
     </param-value> 
</context-param> 


@GET 
     @Path("/second/{param}") 
     @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML}) 
     public Response printStudent(@PathParam("param") String msg) { 


} 

ora posso accedere al mio servizio del genere e la risposta è secondo l'estensione che ho messo alla fine

http://localhost:8080/RESTfulExample/rest/message/second/bill.json

si può mettere .xml o .json alla fine dell'URL e servic e genererà la risposta di conseguenza.