Question Spring MVC: veuillez expliquer la différence entre @RequestParam et @ModelAttribute


Je suis nouveau sur Spring MVC. Aidez-moi à décompresser la documentation.

Documentation

Documentation Spring MVC États (emphase mien):

  • @ModelAttribute sur un argument de méthode indique que l'argument doit être extrait du modèle. S'il n'est pas présent dans le modèle, l'argument doit être instancié d'abord, puis ajouté au modèle. Une fois présent dans le modèle, les champs de l'argument doivent être renseignés à partir de tous les paramètres de requête qui ont des noms correspondants. La classe WebDataBinder met en correspondance les noms de paramètres de requête - y compris les paramètres de chaîne de requête et les champs de formulaire - pour modéliser les champs d'attribut par nom.

  • @RequestParam  lie les paramètres de requête à un paramètre de méthode dans votre contrôleur

Disclaimer / Clarifier

je le sais @ModelAttribute et @RequestParam ne sont pas la même chose, ne s'excluent pas mutuellement, ne remplissent pas le même rôle et peuvent être utilisés simultanément, comme dans cette question - effectivement, @RequestParam peut être utilisé pour remplir les champs de @ModelAttribute. Ma question est plus orientée vers la différence entre leur fonctionnement interne.

Question:

Quelle est la différence entre @ModelAttribute (utilisé sur un argument de méthode, pas de méthode) et @RequestParam? Plus précisément:

  • La source: Faire @RequestParam et @ModelAttribute avoir la même source de information / population, c’est-à-dire les paramètres de requête dans l’URL, qui peuvent avoir été fournis en tant qu’éléments d’un formulaire / modèle POSTed?
  • Usage: Est-il correct que les variables récupérées avec @RequestParam sont jetés (sauf s'ils sont passés dans un modèle), alors que les variables récupérées avec @ModelAttribute sont automatiquement introduits dans le modèle à retourner?

Ou, dans des exemples de codage très basiques, quelle est la véritable différence entre ces deux exemples?

Exemple 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
  }

Exemple 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
}

Ma compréhension actuelle:

@ModelAttribute et @RequestParam les deux interrogent les paramètres de la requête pour information, mais ils utilisent cette information différemment:

  • @RequestParam ne remplit que les variables autonomes (qui peuvent bien entendu être des champs dans un @ModelAttribute classe). Ces variables seront rejetées lorsque le contrôleur est terminé, sauf si elles ont été introduites dans le modèle.

  • @ModelAttribute remplit les champs d'une classe, qui remplit ensuite un attribut du modèle à renvoyer à la vue

Est-ce correct?


37
2018-03-31 14:07


origine


Réponses:


@RequestParam ne remplit que les variables autonomes (qui peuvent bien entendu être des champs dans un @ModelAttribute classe). Ces variables seront rejetées lorsque le contrôleur est terminé, sauf si elles ont été introduites dans le modèle.

Ne confondez pas le mot "modèle" avec la session. La conversation http est généralement: HTTP.GET, réponse du serveur, puis HTTP.POST. Quand tu as le @ModelAttribute annotation en cours d'utilisation vous construisez toujours une instance de ce que vous avez annoté, c'est ce qui vous fait penser que «nourrir les choses avec le modèle» peut faire en sorte que les variables restent présentes. Ce n'est pas correct, une fois le HttpServletRequest a terminé ces variables ne devraient plus faire partie de la conversation navigateur / serveur à moins d’avoir été enregistrées dans une session.

@ModelAttribute remplit les champs d'une classe, qui remplit ensuite un attribut du modèle à renvoyer à la vue

Oui! Être correct, @ModelAttribute dit à Spring d'utiliser son classeur de données Web par défaut pour remplir une instance de quelque chose avec des données du HttpServletRequest. Le choix de transmettre ces données à la vue revient au programmeur. Lorsque vous avez une méthode annotée avec @ModelAttribute, il est appelé à chaque fois que le code frappe cette servlet. Lorsque vous avez @ModelAttribute En tant que paramètre de la méthode, nous parlons de la liaison de données au format HTTP entrant.

Appel @RequestParam est un raccourci pour dire request.getParameter("foo"); sous le capot, les java HttpServletRequest vous permet d’obtenir des valeurs à partir de l’objet de requête en effectuant une recherche par clé> valeur. La valeur renvoyée est de type Object. C'est ce que vous taperiez beaucoup si vous n'utilisiez pas Spring dans votre application Web.

Printemps prend alors cette abstraction un peu plus loin quand vous commencez à utiliser @ModelAttribute. Cette annotation utilise le concept de liaison de données. L’objectif de la liaison de données est que le code de votre contrôleur n’ait pas à appeler request.getParameter("foo1"), pour chaque élément de forme. Imaginez que vous avez un formulaire Web avec 5 champs. Sans liaison de données, le programmeur doit récupérer et valider manuellement chacun de ces champs. Le programmeur doit s'assurer que la demande contient la propriété, que la valeur de la propriété existe et que la valeur de la propriété est du type attendu pour chaque champ. En utilisant @ModelAttribute dit à Spring de faire ce travail pour vous.

Si vous annotez une méthode dans votre contrôleur avec @ModelAttribute("fooBar") FooBar fooBar  Une instance de FooBar volonté toujours être construit par le printemps et fourni à votre méthode. Lorsque la liaison de données entre en jeu, c'est lorsque cette annotation est utilisée dans les paramètres d'une méthode; Le printemps regarde l'instance de HttpServletRequest et voit si elle peut faire correspondre les données dans la demande à la bonne propriété sur une instance de FooBar. Ceci est basé sur la convention de propriétés java, où vous avez un champ tel que foo et les receveurs et les organisateurs publics ont appelé getFoo et setFoo. Cela peut sembler magique, mais si vous deviez rompre la convention, votre liaison de données Spring cesserait de fonctionner car elle ne pourrait pas savoir  pour lier les données de votre HttpServletRequest Vous auriez toujours une instance de FooBar, mais les propriétés ne sont définies sur aucune valeur de la demande.


29
2018-03-31 14:42



@ModelAttribute les paramètres annotés sont traités par un enregistrement ServletModelAttributeMethodProcessor (ou ModelAttributeMethodProcessor) et @RequestParam les paramètres annotés sont traités par un enregistrement RequestParamMethodArgumentResolver ou RequestParamMapMethodArgumentResolver en fonction du type de paramètre.

Voici une explication de la façon dont Spring les utilise HandlerMethodArgumentResolvers pour résoudre les arguments de vos méthodes de gestionnaire:

Dans les deux cas, @ModelAttribute et @RequestParam, les valeurs à lier sont extraites de ServletRequest paramètres.

Vous pouvez regarder le code source des types mentionnés ci-dessus, mais voici les détails simples.

Pour @ModelAttributeSpring créera une instance du type de paramètre. Il inspectera les champs de cette instance et tentera de leur associer des valeurs de paramètres en fonction d’une stratégie de nommage / aliasing @ModelAttribute nom et les noms de champs. Il utilise généralement un groupe de Converter instances à convertir à partir de String (les valeurs des paramètres sont toujours String valeurs) quel que soit le type de champ cible Integer, Date, etc. Vous pouvez également enregistrer votre propre Converter types pour les conversions personnalisées. Vous pouvez également imbriquer les types POJO.

Pour @RequestParam, Le printemps utilisera le même Converter instances permettant de convertir directement les valeurs du paramètre en type de paramètre annoté.

Notez que les valeurs des paramètres ne sont pas "jetées". Ils sont stockés dans le HttpServletRequest pour la durée du cycle de traitement des demandes du conteneur. Vous pouvez toujours y accéder via le méthodes appropriées.


2
2018-03-31 16:05



@ModelAttribute: lie un objet Java entier (comme Employee). prend en charge plusieurs paramètres de demande

@RequestParam: lie un seul paramètre de requête (comme firstName)

En général,
@RequestParam est idéal pour lire un petit nombre de paramètres.

@ModelAttribute est utilisé lorsque vous avez un formulaire avec un grand nombre de champs.

et

@ModelAttribute vous offre des fonctionnalités supplémentaires telles que la liaison de données, la validation et la préparation des formulaires.


2
2017-11-03 09:01



@ModelAttribute  (paramètre) charge un attribut de modèle à partir de @SessionAttributes ou de @ModelAttribute  (méthode).

Vous n'en avez pas besoin simplement pour lier les valeurs d'une requête, mais cela le fera après le chargement depuis @SessionAttributes.

@RequestParam lie un paramètre de requête à un objet.


0
2018-03-31 18:27



  • Au niveau de la méthode

Lorsque l'annotation est utilisée au niveau de la méthode, elle indique que le but de cette méthode est d'ajouter un ou plusieurs attributs de modèle. De telles méthodes supportent les mêmes types d'arguments que @RequestMapping méthodes mais qui ne peuvent pas être mappées directement aux requêtes.

@ModelAttribute
public void addAttributes(Model model) {
    model.addAttribute("msg", "Welcome to the Netherlands!");
}

Une méthode qui ajoute un attribut nommé msg à tous les modèles définis dans la classe du contrôleur.

Spring-MVC appellera toujours cette méthode avant d'appeler des méthodes de gestionnaire de requêtes. C'est-à-dire que les méthodes @ModelAttribute sont appelées avant que les méthodes de contrôleur annotées avec @RequestMapping soient appelées. La logique derrière la séquence est la suivante: l'objet modèle doit être créé avant que tout traitement ne commence dans les méthodes du contrôleur.

Il est également important d’annoter la classe respective sous la forme @ControllerAdvice. Ainsi, vous pouvez ajouter des valeurs dans Model qui seront identifiées comme globales. Cela signifie que pour chaque requête, une valeur par défaut existe pour chaque méthode de la partie réponse.

  • Comme argument de méthode

Utilisé comme argument de méthode, il indique que l'argument doit être extrait du modèle. S'il n'est pas présent, il doit d'abord être instancié, puis ajouté au modèle et, une fois présent dans le modèle, les champs d'arguments doivent être remplis à partir de tous les paramètres de requête ayant des noms correspondants.

Dans l'extrait de code qui suit l'attribut de modèle utilisateur est rempli avec des données provenant d'un formulaire soumis au noeud final addUser. Spring MVC le fait en arrière-plan avant d'appeler la méthode submit:

**@RequestMapping**(value = "/addUser", method = RequestMethod.POST)
public String submit(@ModelAttribute("user") User user) {
    return "userView";
}

Ainsi, il lie les données de formulaire avec un bean. Le contrôleur annoté avec @RequestMapping peut avoir des arguments de classe personnalisés annotés avec @ModelAttribute.

C'est ce que l'on appelle communément la liaison de données dans Spring-MVC, un mécanisme commun qui vous évite d'avoir à analyser chaque champ de formulaire individuellement.


0
2018-03-10 18:11