spring - postmapping - MĂșltiples escenarios @RequestMapping produce JSON/XML junto con Accept o ResponseEntity
spring consumes json example (3)
He preferido usar el filtro params para el tipo de contenido centrado en parámetros. Creo que debería funcionar junto con el atributo produce.
@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
}
Estoy trabajando con Spring 4.0.7
Acerca de Spring MVC, con fines de investigación, tengo lo siguiente:
@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();
}
Cada uno funciona bien, observe ambos para JSON, con y sin extensión:
- / getjsonperson
- /getperson.json
Lo mismo para 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();
}
Cada uno funciona bien, observe ambos para XML, con y sin extensión:
- / getxmlperson
- /getperson.xml
Ahora, sobre Restful , tengo lo siguiente:
@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
}
Observe el MediaType
, está mezclado, para JSON y XML
A través de RestTemplate puedo indicar el valor de 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
);
Hasta aquí, por lo tanto, puedo usar una URL / URI para obtener datos en formatos XML o JSON. Funciona bien
Mi problema es con Spring MVC ... solo considera
@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);
}
Puedo llamar o activar ese método de manejo ( @RequestMapping
) a través de:
- jQuery trabajando con Ajax, puedo indicar el valor de
Accept
(JSON, por ejemplo) - Poster , a través del botón
Headers
, puedo configurarAccept
Pregunta uno:
¿Pero para un enlace común? cómo puedo configurar el valor de Accept
? ¿es posible?
Pensé de otra manera en resolver este problema.
-
http://localhost:8080/spring-utility/person/getpersonformat?format=json
-
http://localhost:8080/spring-utility/person/getpersonformat?format=xml
Observar:
-
?format
Por lo tanto
@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);
}
Pregunta dos:
¿Qué código para el método mostrado arriba se debe agregar para personalizar el formato del tipo de devolución? Quiero decir, JSON o XML, ¿es posible?
Pensé en lo siguiente:
@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);
}
Pero:
Si ejecuto la URL:
-
http://localhost:8080/spring-utility/person/getpersonformataltern?format=json
yo obtengo
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<id>1</id>
<firstName>Manuel</firstName>
<lastName>Jordan</lastName>
…
</person>
¡Sí en XML !
Nota : Puedo confirmar que la consola imprime Ok JSON
Si ejecuto la URL:
-
http://localhost:8080/spring-utility/person/getpersonformataltern?format=xml
yo obtengo
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>
Pregunta tres
¿Qué código para el método mostrado arriba se debe agregar para corregir la salida JSON? No sé lo que está mal o falta.
Hay tres preguntas
Gracias
Alfa
@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);
}
Todos sus problemas son que está mezclando la negociación del tipo de contenido con el paso de parámetros. Son cosas en diferentes niveles. Más específico, para su pregunta 2, construyó el encabezado de respuesta con el tipo de medio que desea devolver. La negociación de contenido real se basa en el tipo de medio aceptado en el encabezado de su solicitud, no en el encabezado de respuesta. En el momento en que la ejecución llega a la implementación del método getPersonFormat, no estoy seguro de si la negociación del contenido se ha realizado o no. Depende de la implementación. Si no es así y desea que la cosa funcione, puede sobrescribir el tipo de aceptación del encabezado de solicitud con lo que desea devolver.
return new ResponseEntity <> (PersonFactory.createPerson (), httpHeaders, HttpStatus.OK);
Usar el encabezado Aceptar es realmente fácil de obtener el formato json o xml del servicio REST.
Este es mi controlador, eche un vistazo a la sección de producción.
@RequestMapping(value = "properties", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.GET)
public UIProperty getProperties() {
return uiProperty;
}
Para consumir el servicio REST, podemos usar el siguiente código donde el encabezado puede ser MediaType.APPLICATION_JSON_VALUE o 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();
Editar 01:
Para trabajar con application/xml
, agregue esta dependencia
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>