java - restful - spring rest ejemplo
¿Cómo funciona la anotación Spring @ResponseBody en este ejemplo de aplicación RESTful? (4)
Tengo un método que se anota de la siguiente manera:
/**
* Provide a list of all accounts.
*/
// TODO 02: Complete this method. Add annotations to respond
// to GET /accounts and return a List<Account> to be converted.
// Save your work and restart the server. You should get JSON results when accessing
// http://localhost:8080/rest-ws/app/accounts
@RequestMapping(value="/orders", method=RequestMethod.GET)
public @ResponseBody List<Account> accountSummary() {
return accountManager.getAllAccounts();
}
Entonces sé que por esta anotación:
@RequestMapping(value="/orders", method=RequestMethod.GET)
Este método maneja las solicitudes HTTP GET realizadas al recurso representado por la URL / pedidos .
Este método llama a un objeto DAO que devuelve una Lista .
donde Account representa a un usuario en el sistema y tiene algunos campos que representan a este usuario, algo como:
public class Account {
@Id
@Column(name = "ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long entityId;
@Column(name = "NUMBER")
private String number;
@Column(name = "NAME")
private String name;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name = "ACCOUNT_ID")
private Set<Beneficiary> beneficiaries = new HashSet<Beneficiary>();
...............................
...............................
...............................
}
Mi pregunta es:
¿cómo funciona exactamente la anotación
@ResponseBody
?
Está situado antes del objeto
List<Account>
devuelto, por lo que creo que se refiere a esta lista.
La documentación del curso establece que esta anotación cumple la función de:
asegúrese de que el resultado se escriba en la respuesta HTTP mediante un convertidor de mensajes HTTP (en lugar de una vista MVC).
Y también leyendo en la documentación oficial de Spring: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html
parece que toma el objeto
List<Account>
y lo coloca en la
Http Response
.
¿Es esto correcto o estoy malentendido?
Escrito en el comentario del método anterior
accountSummary()
hay:
Debería obtener resultados JSON al acceder a http://localhost:8080/rest-ws/app/accounts
Entonces, ¿qué significa esto exactamente?
¿Significa que el objeto
List<Account>
devuelto por el método
accountSummary()
se convierte automáticamente en formato
JSON
y luego se coloca en la
Http Response
?
¿O que?
Si esta afirmación es verdadera, ¿dónde se especifica que el objeto se convertirá automáticamente en formato
JSON
?
¿Se adopta el formato estándar cuando se
@ResponseBody
anotación
@ResponseBody
o se especifica en otra parte?
Además de esto, el tipo de retorno está determinado por
-
Lo que la solicitud HTTP dice que quiere, en su encabezado Aceptar. Intente mirar la solicitud inicial para ver en qué está configurado Aceptar.
-
Lo que HttpMessageConverters Spring configura. Spring MVC configurará convertidores para XML (usando JAXB) y JSON si las bibliotecas de Jackson están en el classpath.
Si hay una opción, elige una; en este ejemplo, resulta ser JSON.
Esto está cubierto en las notas del curso. Busque las notas sobre Convertidores de mensajes y Negociación de contenido.
Como lo mencionó JB Nizet,
@RequestMapping(value="/orders", method=RequestMethod.GET)
@ResponseBody
public List<Account> accountSummary() {
return accountManager.getAllAccounts();
}
y
@RequestMapping(value="/orders", method=RequestMethod.GET)
public @ResponseBody List<Account> accountSummary() {
return accountManager.getAllAccounts();
}
ambos son lo mismo. como @ResponseBody anota el método, no la lista. @GMsoF - Los convertidores de mensajes instalados aquí se pueden usar de la siguiente manera.
@RequestMapping(value="/orders", method=RequestMethod.GET , produces={"application/json","application/xml"})
@ResponseBody
public List<Account> accountSummary() {
return accountManager.getAllAccounts();
}
Gracias :)
En primer lugar, la anotación no anota la
List
.
RequestMapping
el método, tal como
RequestMapping
hace
RequestMapping
.
Tu código es equivalente a
@RequestMapping(value="/orders", method=RequestMethod.GET)
@ResponseBody
public List<Account> accountSummary() {
return accountManager.getAllAccounts();
}
Ahora, lo que significa la anotación es que el valor devuelto del método constituirá el cuerpo de la respuesta HTTP. Por supuesto, una respuesta HTTP no puede contener objetos Java. Por lo tanto, esta lista de cuentas se transforma a un formato adecuado para aplicaciones REST, generalmente JSON o XML.
La elección del formato depende de los convertidores de mensajes instalados, de los valores del
atributo
produces
de la anotación RequestMapping y del tipo de contenido que acepta el cliente (que está disponible en los encabezados de solicitud HTTP).
Por ejemplo, si la solicitud dice que acepta XML, pero no JSON, y hay un convertidor de mensajes instalado que puede transformar la lista a XML, se devolverá XML.
Lo primero que hay que entender es la diferencia en arquitecturas.
Un extremo tiene la arquitectura MVC, que se basa en su aplicación web normal, que usa páginas web, y el navegador solicita una página:
Browser <---> Controller <---> Model
| |
+-View-+
El navegador realiza una solicitud, el controlador (@Controller) obtiene el modelo (@Entity), crea la vista (JSP) del modelo y la vista se devuelve al cliente. Esta es la arquitectura básica de la aplicación web.
En el otro extremo, tienes una arquitectura RESTful. En este caso, no hay vista. El controlador solo devuelve el modelo (o representación de recursos, en términos más RESTful). El cliente puede ser una aplicación de JavaScript, una aplicación de servidor Java, cualquier aplicación en la que expongamos nuestra API REST. Con esta arquitectura, el cliente decide qué hacer con este modelo. Tomemos por ejemplo Twitter. Twitter como API web (REST), que permite que nuestras aplicaciones utilicen su API para obtener actualizaciones de estado, de modo que podamos usarla para poner esos datos en nuestra aplicación. Esos datos vendrán en algún formato como JSON.
Dicho esto, cuando se trabaja con Spring MVC, primero se creó para manejar la arquitectura básica de la aplicación web.
Hay muchos sabores de firma de métodos diferentes que permiten que se produzca una vista a partir de nuestros métodos.
El método podría devolver un
ModelAndView
donde lo creamos explícitamente, o hay formas implícitas en las que podemos devolver algún objeto arbitrario que se establece en los atributos del modelo.
Pero de cualquier manera, en algún lugar a lo largo del ciclo de solicitud-respuesta, se producirá una vista.
Pero cuando usamos
@ResponseBody
, estamos diciendo que no queremos que se produzca una vista.
Solo queremos enviar el objeto de retorno como el cuerpo, en cualquier formato que especifiquemos.
No queremos que sea un objeto Java serializado (aunque posible).
Entonces, sí, debe convertirse a algún otro tipo común (este tipo normalmente se trata a través de la negociación de contenido; consulte el enlace a continuación).
Honestamente, no trabajo mucho con Spring, aunque juego con eso aquí y allá.
Normalmente uso
@RequestMapping(..., produces = MediaType.APPLICATION_JSON_VALUE)
para establecer el tipo de contenido, pero tal vez JSON es el predeterminado.
No me cite, pero si está obteniendo JSON y no ha especificado los
produces
, entonces tal vez sea el valor predeterminado.
JSON no es el único formato.
Por ejemplo, lo anterior podría enviarse fácilmente en XML, pero necesitaría tener los
produces
en
MediaType.APPLICATION_XML_VALUE
y creo que necesita configurar
HttpMessageConverter
para JAXB.
En cuanto al JSON
MappingJacksonHttpMessageConverter
configurado, cuando tenemos a Jackson en el classpath.
Me tomaría un tiempo aprender sobre la negociación de contenido . Es una parte muy importante de REST. Le ayudará a conocer los diferentes formatos de respuesta y cómo asignarlos a sus métodos.