web-dev-qa-db-fra.com

Plusieurs scénarios @RequestMapping produit JSON / XML avec Accept ou ResponseEntity

Je travaille avec Spring 4.0.7

À propos de Spring MVC, à des fins de recherche, j’ai les compétences suivantes:

@RequestMapping(value="/getjsonperson", 
                method=RequestMethod.GET, 
                produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Person getJSONPerson(){
    logger.info("getJSONPerson - getjsonperson");
    return PersonFactory.createPerson();
}

@RequestMapping(value="/getperson.json", method=RequestMethod.GET)
public @ResponseBody Person getPersonJSON(){
    logger.info("getPerson - getpersonJSON");
    return PersonFactory.createPerson();
}

Chacun fonctionne bien, observez les deux pour JSON, avec et sans extension:

  • / getjsonperson
  • /getperson.json

Pareil pour XML

@RequestMapping(value="/getxmlperson",
                method=RequestMethod.GET,
                produces=MediaType.APPLICATION_XML_VALUE
                )
public @ResponseBody Person getXMLPerson(){
    logger.info("getXMLPerson - getxmlperson");
    return PersonFactory.createPerson();
}

@RequestMapping(value="/getperson.xml", method=RequestMethod.GET)
@ResponseBody
public Person getPersonXML(){
    logger.info("getPerson - getpersonXML");
    return PersonFactory.createPerson();
}

Chacun fonctionne bien, observez les deux formats XML, avec et sans extension:

  • / getxmlperson
  • /getperson.xml

Maintenant à propos de reposant , j'ai les éléments suivants:

@RequestMapping(value="/person/{id}/", 
                method=RequestMethod.GET,
                produces={MediaType.APPLICATION_JSON_VALUE, 
                          MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<Person> getPersonCustomizedRestrict(@PathVariable Integer id){
    Person person = personMapRepository.findPerson(id);
    return new ResponseEntity<>(person, HttpStatus.FOUND);//302     
}

Observez le MediaType, il est mélangé, pour JSON et XML

Avec RestTemplate je peux indiquer la valeur Accept

    if(type.equals("JSON")){
        logger.info("JSON");
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    }
    else if(type.equals("XML")){
        logger.info("XML");
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
    }
    ….

    ResponseEntity<Person> response =
                restTemplate.exchange("http://localhost:8080/spring-utility/person/{id}/customizedrestrict",
                                      HttpMethod.GET,
                                      new HttpEntity<Person>(headers),  
                                      Person.class,
                                       id
                                     ); 

Jusqu'ici, je peux donc utiliser une URL/URI pour obtenir des données aux formats XML ou JSON. Ça fonctionne bien

Mon problème est avec Spring MVC… il suffit de considérer

@RequestMapping(value="/{id}/person", 
                method=RequestMethod.GET,
                produces={MediaType.APPLICATION_JSON_VALUE,  
                          MediaType.APPLICATION_XML_VALUE})
public @ResponseBody Person getPerson(@PathVariable Integer id){
    return personMapRepository.findPerson(id);
}

Je peux appeler ou activer cette méthode de gestionnaire (@RequestMapping) par:

  1. jQuery travaillant avec Ajax, je peux indiquer la valeur Accept (JSON par exemple)
  2. Poster , via le bouton Headers, je peux régler le Accept

Première question:

Mais pour un lien commun? Comment puis-je définir la valeur Accept? est possible?

J'ai pensé d'une autre manière à résoudre ce problème.

  • http://localhost:8080/spring-utility/person/getpersonformat?format=json
  • http://localhost:8080/spring-utility/person/getpersonformat?format=xml

Observer:

  • ?format

Donc

@RequestMapping(value="/getpersonformat", 
                method=RequestMethod.GET,
                produces={MediaType.APPLICATION_JSON_VALUE,  
                          MediaType.APPLICATION_XML_VALUE})
public @ResponseBody Person getPerson(@RequestParam String format){
    return personMapRepository.findPerson(id);
}

Deuxième question:

Quel code pour la méthode présentée ci-dessus doit être ajouté pour personnaliser le format du type de retour? Je veux dire, JSON ou XML, est possible?

J'ai pensé dans ce qui suit:

@RequestMapping(value="/getpersonformataltern",
        method=RequestMethod.GET
        produces={MediaType.APPLICATION_JSON_VALUE, 
                  MediaType.APPLICATION_XML_VALUE}
        )
public ResponseEntity<Person> getPersonFormat(@RequestParam String format){
    logger.info("getPersonFormat - format: {}", format);
    HttpHeaders httpHeaders = new HttpHeaders();
    if(format.equals("json")){
        logger.info("Ok JSON");
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    }
    else{
        logger.info("Ok XML");
        httpHeaders.setContentType(MediaType.APPLICATION_XML);
    }
    return new ResponseEntity<>(PersonFactory.createPerson(), httpHeaders, HttpStatus.OK);
}

Mais:

Si j'exécute l'URL:

  • http://localhost:8080/spring-utility/person/getpersonformataltern?format=json

Je reçois

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
    <id>1</id>
    <firstName>Manuel</firstName>
    <lastName>Jordan</lastName>
…
</person>

Oui dans [~ # ~] xml [~ # ~] !

Remarque : Je peux confirmer l'impression de la console Ok JSON

Si j'exécute l'URL:

  • http://localhost:8080/spring-utility/person/getpersonformataltern?format=xml

Je reçois

This XML file does not appear to have any style information associated with it. 
The document tree is shown below.

<person>
    <id>1</id>
    <firstName>Manuel</firstName>
    <lastName>Jordan</lastName> 
    …
</person>

Troisième question

Quel code pour la méthode ci-dessus doit être ajouté pour corriger la sortie JSON? Je ne sais pas ce qui ne va pas ou manque.

Il y a trois questions.

Merci

Alpha

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    Map<String,MediaType> mediaTypes = new LinkedHashMap<>();
    mediaTypes.put("json", MediaType.APPLICATION_JSON);
    mediaTypes.put("xml", MediaType.APPLICATION_XML);
    configurer.mediaTypes(mediaTypes);
    configurer.defaultContentType(MediaType.TEXT_HTML);
}
34
Manuel Jordan

L'utilisation de l'en-tête Accept est très facile à obtenir au format json ou xml à partir du service REST.

Ceci est mon contrôleur, jetez un oeil produit section.

@RequestMapping(value = "properties", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.GET)
    public UIProperty getProperties() {
        return uiProperty;
    }

Afin de consommer le service REST, nous pouvons utiliser le code ci-dessous où l'en-tête peut être MediaType.APPLICATION_JSON_VALUE ou MediaType.APPLICATION_XML_VALUE

HttpHeaders headers = new HttpHeaders();
headers.add("Accept", header);

HttpEntity entity = new HttpEntity(headers);

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange("http://localhost:8080/properties", HttpMethod.GET, entity,String.class);
return response.getBody();

Edit 01:

Afin de travailler avec application/xml, ajoute cette dépendance

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>
36
Eddú Meléndez

Tous vos problèmes sont que vous mélangez la négociation du type de contenu avec la transmission de paramètres. Ce sont des choses à différents niveaux. Plus précisément, pour votre question 2, vous avez construit l’en-tête de la réponse avec le type de support que vous souhaitez renvoyer. La négociation de contenu réelle est basée sur le type de support accepté dans l'en-tête de votre demande, pas dans l'en-tête de la réponse. Au moment où l'exécution atteint l'implémentation de la méthode getPersonFormat, je ne sais pas si la négociation de contenu a été effectuée ou non. Dépend de la mise en œuvre. Si ce n'est pas le cas et que vous souhaitez faire fonctionner l'objet, vous pouvez écraser le type d'acceptation de l'en-tête de demande avec ce que vous voulez renvoyer.

return new ResponseEntity <> (PersonFactory.createPerson (), httpHeaders, HttpStatus.OK);

2
jljl

J'ai préféré utiliser le filtre params pour le type de contenu centré sur les paramètres. Je pense que cela devrait fonctionner en conjonction avec l'attribut de produit.

@GetMapping(value="/person/{id}/", 
            params="format=json",
            produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> getPerson(@PathVariable Integer id){
    Person person = personMapRepository.findPerson(id);
    return ResponseEntity.ok(person);
} 
@GetMapping(value="/person/{id}/", 
            params="format=xml",
            produces=MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<Person> getPersonXML(@PathVariable Integer id){
    return GetPerson(id); // delegate
}
0
M. Maraist