java - método - Spring MVC: por favor explique la diferencia entre @RequestParam y @ModelAttribute
spring boot model attribute (5)
@RequestParam
solo rellena variables independientes (que pueden ser, por supuesto, campos en una clase@ModelAttribute
). Estas variables se descartarán cuando el controlador termine, a menos que hayan sido alimentadas al modelo.
No confunda la palabra "modelo" con la sesión. La conversación http generalmente es: HTTP.GET
, respuesta del servidor, luego HTTP.POST
. Cuando tiene la anotación @ModelAttribute
en uso, siempre está construyendo una instancia de lo que ha anotado, esto es lo que le hace pensar que "alimentar al modelo" podría hacer que las variables permanezcan. Esto no es correcto, una vez que HttpServletRequest
ha terminado, esas variables ya no deben formar parte de la conversación entre el navegador y el servidor a menos que se hayan guardado en una sesión.
@ModelAttribute
rellena los campos de una clase, que luego rellena un atributo del modelo que se pasará a la vista
¡Sí! Para ser correcto, @ModelAttribute
le dice a Spring que use su carpeta de datos web predeterminada para llenar una instancia de algo con datos de HttpServletRequest
. La elección de pasar esta información a la vista depende del programador. Cuando tiene un método anotado con @ModelAttribute
, se @ModelAttribute
cada vez que el código golpea ese servlet. Cuando tiene @ModelAttribute
como uno de los parámetros del método, estamos hablando del enlace de datos del formulario Http entrante.
Llamar a @RequestParam
es un atajo para decir request.getParameter("foo")
; bajo el capó, HttpServletRequest
de Java HttpServletRequest
permite obtener valores del objeto de solicitud haciendo una HttpServletRequest
de HttpServletRequest
> valor. El valor devuelto es de tipo Object. Esto es lo que escribirías mucho si no estuvieras usando Spring en tu aplicación web.
Spring luego lleva esta abstracción un paso más allá cuando comienzas a usar @ModelAttribute
. Esta anotación emplea el concepto de enlace de datos. El objetivo del enlace de datos es que el código en su controlador no tendrá que llamar a request.getParameter("foo1")
, para cada elemento del formulario. Imagine que tiene un formulario web con 5 campos. Sin vinculación de datos, el programador debe recuperar manualmente y validar cada uno de esos campos. El programador debe asegurarse de que la solicitud contenga la propiedad, que el valor de la propiedad exista y que el valor de la propiedad sea del tipo esperado para cada campo. Usar @ModelAttribute
le dice a Spring que haga este trabajo por usted.
Si anota un método en su controlador con @ModelAttribute("fooBar") FooBar fooBar
Una instancia de FooBar
siempre será construida por Spring, y se suministrará a su método. Donde el enlace de datos entra en juego, es cuando esta anotación se usa en los parámetros de un Método; Spring observa la instancia de HttpServletRequest
y ve si puede hacer coincidir los datos en la solicitud con la propiedad correcta en una instancia de FooBar
. Esto se basa en la convención de propiedades de Java, donde tiene un campo como foo
y public getters y setters llamados getFoo
y setFoo
. Esto podría parecer mágico, pero si rompiera la convención, su enlace de datos de Spring dejaría de funcionar porque no podría saber dónde vincular los datos de su HttpServletRequest
Todavía tendría una instancia de FooBar
, pero las propiedades no establecerse en cualquier valor de la solicitud.
Soy nuevo en Spring MVC. Por favor, ayúdame a desempaquetar la documentación.
Documentación
Spring MVC Documentation states (el énfasis es mío):
@ModelAttribute
en un argumento de método indica que el argumento debe recuperarse del modelo. Si no está presente en el modelo, el argumento debe crearse una instancia primero y luego agregarse al modelo. Una vez que estén presentes en el modelo, los campos del argumento se deben llenar de todos los parámetros de solicitud que tengan nombres coincidentes . La clase WebDataBinder coincide con los nombres de parámetros de solicitud, incluidos los parámetros de cadena de consulta y los campos de formulario, para modelar los campos de atributo por nombre.@RequestParam
vincula los parámetros de solicitud a un parámetro de método en su controlador.
Descargo de responsabilidad / clarificador
Sé que @ModelAttribute
y @RequestParam
no son lo mismo, no son mutuamente excluyentes, no realizan el mismo rol y se pueden usar simultáneamente, como en esta pregunta ; de hecho, @RequestParam
se puede usar para rellenar campos de @ModelAttribute
. Mi pregunta está más orientada a la diferencia entre su funcionamiento interno.
Pregunta:
¿Cuál es la diferencia entre @ModelAttribute
(usado en un argumento de método, no en un método) y @RequestParam
? Específicamente:
- Fuente: ¿
@RequestParam
y@ModelAttribute
tienen la misma fuente de información / población, es decir, parámetros de solicitud en URL, que pueden haber sido suministrados como elementos de un formulario / modelo que sePOST
? - Uso: ¿Es correcto que las variables recuperadas con
@RequestParam
se@RequestParam
(a menos que se pasen a un modelo), mientras que las variables recuperadas con@ModelAttribute
se introducen automáticamente en el modelo que se devolverá?
O en ejemplos de codificación muy básicos, ¿cuál es la diferencia de trabajo real entre estos dos ejemplos?
Ejemplo 1: @RequestParam
:
// foo and bar are thrown away, and are just used (e.g.) to control flow?
@RequestMapping(method = RequestMethod.POST)
public String testFooBar(@RequestParam("foo") String foo,
@RequestParam("bar") String bar, ModelMap model) {
try {
doStuff(foo, bar);
}
// other code
}
Ejemplo 2: @ModelAttribute
:
// FOOBAR CLASS
// Fields could of course be explicitly populated from parameters by @RequestParam
public class FooBar{
private String foo;
private String bar;
// plus set() and get() methods
}
// CONTROLLER
// Foo and Bar become part of the model to be returned for the next view?
@RequestMapping(method = RequestMethod.POST)
public String setupForm(@ModelAttribute("fooBar") FooBar foobar) {
String foo = fooBar.getFoo();
String bar = fooBar.getBar();
try {
doStuff(foo, bar);
}
// other code
}
Mi comprensión actual:
@ModelAttribute
y @RequestParam
interrogan los parámetros de solicitud para obtener información, pero usan esta información de manera diferente:
@RequestParam
solo rellena variables independientes (que pueden ser, por supuesto, campos en una clase@ModelAttribute
). Estas variables se descartarán cuando el controlador termine, a menos que hayan sido alimentadas al modelo.@ModelAttribute
rellena los campos de una clase, que luego rellena un atributo del modelo que se pasará a la vista
¿Es esto correcto?
@ModelAttribute
: enlaza un objeto de Java completo (como Employee). admite múltiples parámetros de solicitud
@RequestParam
: enlaza un solo parámetro de solicitud (como firstName)
En general,
@RequestParam
es mejor para leer un pequeño número de params.
@ModelAttribute
se usa cuando tiene un formulario con una gran cantidad de campos.
y
@ModelAttribute
le brinda funciones adicionales como el enlace de datos, la validación y la prepoblación de formularios.
@ModelAttribute
(parámetro) carga un atributo de modelo de @SessionAttributes
o de @ModelAttribute
(método) .
No lo necesita solo para enlazar valores de una solicitud, pero lo hará después de cargar desde @SessionAttributes
.
@RequestParam
vincula un parámetro de solicitud a un objeto.
@ModelAttribute
parámetros anotados son manejados por un ServletModelAttributeMethodProcessor
registrado (o ModelAttributeMethodProcessor
) y los parámetros anotados @RequestParam
son manejados por un RequestParamMethodArgumentResolver
o RequestParamMapMethodArgumentResolver
registrado según el tipo de parámetro.
Aquí hay una explicación de cómo Spring usa estos HandlerMethodArgumentResolvers
para resolver argumentos para sus métodos de HandlerMethodArgumentResolvers
:
En ambos casos, @ModelAttribute
y @RequestParam
, los valores a vincular se recuperan de los parámetros de ServletRequest
.
Puede ver el código fuente de los tipos mencionados anteriormente, pero aquí están los detalles simples.
Para @ModelAttribute
, Spring creará una instancia del tipo de parámetro. Inspeccionará los campos de esa instancia e intentará enlazar valores de parámetros a ellos en función de una estrategia de denominación / alias compuesta por el nombre @ModelAttribute
y los nombres de campo. Por lo general, utiliza un grupo de instancias de Converter
para convertir de String
(los valores de los parámetros son siempre valores de String
) a cualquier tipo de campo de destino Integer
, Date
, etc. También puede registrar sus propios Tipos de Converter
para conversiones personalizadas. También puedes anidar POJO tipos.
Para @RequestParam
, Spring utilizará las mismas instancias de Converter
para convertir los valores de los parámetros directamente al tipo de parámetro anotado.
Tenga en cuenta que los valores de los parámetros no son "desechados". Se almacenan en HttpServletRequest
durante el ciclo de procesamiento de solicitud del contenedor. Siempre puede acceder a ellos a través de los métodos apropiados .
- En el nivel de método
Cuando la anotación se utiliza en el nivel del método, indica que el propósito de ese método es agregar uno o más atributos del modelo. Dichos métodos admiten los mismos tipos de argumentos que los métodos @RequestMapping
, pero no se pueden asignar directamente a las solicitudes.
@ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("msg", "Welcome to the Netherlands!");
}
Un método que agrega un atributo llamado msg a todos los modelos definidos en la clase de controlador.
Spring-MVC siempre hará una llamada primero a ese método, antes de llamar a cualquier método de controlador de solicitud. Es decir, se invocan los métodos @ModelAttribute antes de invocar los métodos del controlador anotados con @RequestMapping. La lógica detrás de la secuencia es que, el objeto modelo debe ser creado antes de que comience cualquier procesamiento dentro de los métodos del controlador.
También es importante que anote la clase respectiva como @ControllerAdvice. Por lo tanto, puede agregar valores en el modelo que se identificará como global. Esto realmente significa que para cada solicitud existe un valor predeterminado, para cada método en la parte de respuesta.
- Como argumento del método
Cuando se usa como un argumento de método, indica que el argumento debe recuperarse del modelo. si no está presente, primero se debe crear una instancia y luego agregar al modelo y, una vez presente en el modelo, los campos de argumentos se deben llenar de todos los parámetros de solicitud que tengan nombres coincidentes.
En el fragmento de código que sigue al atributo de modelo de usuario se rellena con datos de un formulario enviado al punto final addUser. Spring MVC hace esto detrás de escena antes de invocar el método de envío:
**@RequestMapping**(value = "/addUser", method = RequestMethod.POST)
public String submit(@ModelAttribute("user") User user) {
return "userView";
}
Por lo tanto, vincula los datos del formulario con un bean. El controlador anotado con @RequestMapping puede tener argumento (s) de clase personalizados anotados con @ModelAttribute.
Esto es lo que comúnmente se conoce como enlace de datos en Spring-MVC, un mecanismo común que le evita tener que analizar cada campo de formulario individualmente.