2015-10-08 19 views
7

Ho un semplice controller REST scritto in un'applicazione Spring-boot ma non sono sicuro di come implementare la negoziazione del contenuto per farlo restituire JSON o XML in base al parametro Content-Type nell'intestazione della richiesta . Qualcuno potrebbe spiegarmi cosa sto sbagliando?Negoziazione del contenuto del controller di avvio Spring

metodo di controllo:

@RequestMapping(value = "/message", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) 
    public Message getMessageXML(@RequestParam("text") String text) throws Exception { 
    Message message = new Message(); 
    message.setDate(new Date()); 
    message.setName("Test"); 
    message.setAge(99); 
    message.setMessage(text); 

    return message; 
    } 

ottengo sempre JSON quando si chiama questo metodo (anche se a specificare la Content-Type essere application/xml o text/xml).

Quando implemento due metodi ciascuno con mappature e tipi di contenuto diversi, sono in grado di ottenere XML da quello xml ma non funziona se si specificano due mediaTypes in un unico metodo (come nell'esempio fornito).

Quello che vorrei è quello di chiamare il \message endpoint e ricevere

  • XML quando il Content-Type della richiesta GET è impostato su application/xml
  • JSON quando il Content-Type è application/json

Qualsiasi aiuto è apprezzato.

EDIT: ho aggiornato il mio controller di accettare tutti i tipi di media

@RequestMapping(value = "/message", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }, consumes = MediaType.ALL_VALUE) 
    public Message getMessageXML(@RequestParam("text") String text) throws Exception { 
    Message message = new Message(); 
    message.setDate(new Date()); 
    message.setName("Vladimir"); 
    message.setAge(35); 
    message.setMessage(text); 

    return message; 
    } 
+1

È necessario fornire un'intestazione 'Accept' con il valore' application/xml' o con qualsiasi tipo di supporto supportato. – systemfreund

+0

L'intestazione "Content-Type" definisce il tipo di contenuto che stai inviando, non quello che vuoi ricevere (questo è l'intestazione "Accept".) Quindi l'intestazione "Content-Type" per una richiesta GET non lo fa t ha senso, dato che non può avere alcun contenuto (corpo) Quindi nel tuo caso dovresti usare l'intestazione "Accetta" per la tua richiesta e nella risposta l'intestazione "Content-Type" per nominare il tipo di contenuto che è in effetti invia –

risposta

9

Potete trovare alcuni suggerimenti nel post sul blog @RequestMapping with Produces and Consumes al punto 6.

Prestare attenzione alla sezione su Content-Type e Accept intestazioni:

@RequestMapping con produce e consuma: possiamo usare intestazione Content-Type ed Accept per scoprire r equest contents e qual è il messaggio del mimo che vuole in risposta. Per chiarezza, @RequestMapping fornisce produce e consuma variabili in cui è possibile specificare il tipo di contenuto della richiesta per il quale verrà richiamato il metodo e il tipo di contenuto della risposta . Per esempio:

@RequestMapping(value="/method6", produces={"application/json","application/xml"}, consumes="text/html") 
@ResponseBody 
public String method6(){ 
    return "method6"; 
} 

Sopra metodo può consumare un messaggio solo con Content-Type come text/html ed è in grado di produrre messaggi di tipo application/JSON e application/xml.

Potete anche provare this approccio diverso (utilizzando oggetto ResponseEntity) che permette di scoprire il tipo di messaggio in entrata e produrre il messaggio corrispondente (anche expoliting l'annotazione @ResponseBody)

17

È possibile utilizzare ContentNegotiationConfigurer

in primo luogo, è necessario eseguire l'override del metodo configureContentNegotiation nella classe di configurazione:

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 
    configurer.favorPathExtension(false). 
      favorParameter(true). 
      defaultContentType(MediaType.APPLICATION_JSON). 
      mediaType("xml", MediaType.APPLICATION_XML); 
    } 
} 

favorParameter(true) - abilitare le espressioni del percorso di preferenza su parametro o accettare intestazioni.

defaultContentType(MediaType.APPLICATION_JSON) - imposta il tipo di contenuto predefinito. questo significa che se non si passa un'espressione di percorso, Spring genererà JSON come risposta.

mediaType("xml", MediaType.APPLICATION_XML) - imposta il codice di espressione del percorso per XML.

Ora, se si dichiara il controller come:

@Controller 
class AccountController { 

    @RequestMapping(value="/accounts", method=RequestMethod.GET) 
    @ResponseStatus(HttpStatus.OK) 
    public @ResponseBody List<Account> list(Model model, Principal principal) { 
     return accountManager.getAccounts(principal)); 
    } 
} 

e chiamare qualcosa come localhost:8080/app/accounts.json, allora Primavera genererà JSON come risposta. Quindi se chiami localhost:8080/app/accounts.xml riceverai risposta XML

Puoi trovare maggiori informazioni su questo here.

+2

solo una piccola nota sul defaultContentType: [i browser tendono ad inviare intestazioni che preferiscono XML] (https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring- mvc.html). Bypassare (supponendo che non lo stia usando) l'intestazione Accept può essere fatta nella tua sovrascrittura del contenutoNotazione: 'configurer.ignoreAcceptHeader (true)' –

+1

Penso che ci sia un errore minore qui - il tuo modoRichiedi il controller per funzionare, dovresti impostare favorPathExtension per essere vero, piuttosto che favoreParameter. – user31415

+0

può essere fatto per un URI specifico? –

Problemi correlati