web-dev-qa-db-fra.com

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

Je suis nouveau à Spring MVC. S'il vous plaît aidez-moi à décompresser la documentation.

Documentation

Documentation MVC de printemps états (c'est moi qui souligne):

  • @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 d'abord être instancié puis ajouté au modèle. Une fois présents dans le modèle, les champs de l'argument doivent être renseignés à partir de tous les paramètres de requête ayant des noms correspondants. La classe WebDataBinder correspond aux noms de paramètre 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. 

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

Disclaimer/Clarifier

Je sais que @ModelAttribute et @RequestParam ne sont pas la même chose, ne s'excluent pas mutuellement, ne jouent pas le même rôle et peuvent être utilisés simultanément, comme dans cette question - en effet, @RequestParam peut être utilisé pour renseigner les champs de @ModelAttribute . Ma question est davantage axée sur la différence entre leurs rouages ​​internes.

Question:

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

  • Source: Est-ce que @RequestParam et @ModelAttribute ont la même source d'informations/population .__, c'est-à-dire des paramètres de requête dans une URL, qui peuvent avoir été fournis en tant qu'éléments d'un formulaire/modèle POSTed? 
  • Usage: Est-il exact que les variables extraites avec @RequestParam sont supprimées (sauf si elles sont passées dans un modèle), alors que les variables extraites avec @ModelAttribute sont automatiquement introduites dans le modèle à renvoyer?

Ou dans des exemples de codage très basiques, quelle est la différence de travail réelle 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 interrogent les paramètres de la requête pour obtenir des informations, mais ils utilisent ces informations différemment:

  • @RequestParam ne remplit que les variables autonomes (qui peuvent bien sûr être des champs dans une classe @ModelAttribute). Ces variables seront supprimées une fois le contrôleur terminé, sauf si elles ont été introduites dans le modèle.

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

Est-ce correct?

43
Lydia Ralph

@RequestParam ne remplit que les variables autonomes (qui peuvent bien sûr être des champs dans une classe @ModelAttribute). Ces variables seront supprimées une fois le contrôleur terminé, sauf si elles ont été introduites dans le modèle.

Ne confondez pas le mot "modèle" avec session. La conversation http est généralement: HTTP.GET, réponse du serveur, puis HTTP.POST. Lorsque vous utilisez l'annotation @ModelAttribute, vous construisez toujours une instance de tout ce que vous avez annoté. C'est ce qui vous fait penser que "l'insertion d'éléments dans le modèle" peut laisser des variables persister. Ce n'est pas correct, une fois que la variable HttpServletRequest a terminé, ces variables ne doivent plus faire partie de la conversation navigateur/serveur, sauf si elles ont été enregistrées dans une session.

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

Oui! Pour être correct, @ModelAttribute indique à Spring d'utiliser son classeur de données Web par défaut pour renseigner une instance de quelque chose avec les données de la variable HttpServletRequest. Le choix de transmettre ces données à la vue revient au programmeur. Quand vous avez une méthode annotée avec @ModelAttribute, elle est appelée à chaque fois que le code entre en contact avec ce servlet. Lorsque vous avez @ModelAttribute comme l'un des paramètres de la méthode, nous parlons de la liaison de données de formulaire HTTP entrante.

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

Spring prend ensuite cette abstraction encore plus loin lorsque 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 ne doit pas appeler request.getParameter("foo1"), pour chaque élément de formulaire. Imaginez que vous ayez un formulaire Web avec 5 champs. Sans liaison de données, le programmeur doit extraire 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. Utiliser @ModelAttribute indique à 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 sera toujours construite par Spring et fournie à 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; Spring examine l'instance de HttpServletRequest et voit si elle peut faire correspondre les données de la requête à la propriété correcte 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 des getters et setters publics appelés getFoo et setFoo. Cela peut sembler magique, mais si vous respectiez la convention, votre liaison de données Spring cesserait de fonctionner car elle ne pourrait pas savoirpour lier les données de votre HttpServletRequest Vous obtiendriez tout de même une instance de FooBar, mais les propriétés ne seraient définies sur aucune valeur de la demande.

34
zmf

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

@RequestParam: lie un paramètre de requête unique (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 le pré-remplissage de formulaires. 

3
Harinath

Les paramètres annotés @ModelAttribute sont gérés par une variable ServletModelAttributeMethodProcessor (ou ModelAttributeMethodProcessor) enregistrée, tandis que les paramètres annotés @RequestParam sont gérés par une variable RequestParamMethodArgumentResolver ou RequestParamMapMethodArgumentResolver enregistrée, en fonction du type de paramètre.

Voici une explication de la façon dont Spring utilise ces 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 parameters .

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

Pour @ModelAttribute, Spring créera une instance du type de paramètre. Il inspectera les champs de cette instance et tentera de leur lier des valeurs de paramètres en fonction d'une stratégie de nommage/aliasing composée du nom @ModelAttribute et des noms de champs. Il utilise généralement un groupe d'instances Converter pour convertir de String (les valeurs de paramètre sont toujours des valeurs String) en tout type de champ cible Integer, Date, etc. Vous pouvez également enregistrer vos propres types Converter pour des conversions personnalisées. Vous pouvez également imbriquer des types POJO.

Pour @RequestParam, Spring utilisera les mêmes instances Converter pour convertir les valeurs de paramètre directement en type de paramètre annoté.

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

2

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

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

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

0
Neil McGuigan
  • 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 les méthodes @RequestMapping mais ne peuvent pas être mappées directement sur des 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 de contrôleur.

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

Il est également important que vous annotiez la classe respective en tant que @ControllerAdvice. Ainsi, vous pouvez ajouter des valeurs dans Model qui seront identifiées comme globales. Cela signifie en fait que pour chaque demande, une valeur par défaut existe, pour chaque méthode de la partie réponse.

  • En tant qu'argument de méthode

Lorsqu'il est 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, puis une fois présent dans le modèle, les champs d'arguments doivent être renseignés à partir de tous les paramètres de requête portant des noms correspondants.

Dans l'extrait de code qui suit, l'attribut de modèle utilisateur est rempli avec les données d'un formulaire soumis au noeud final addUser. Spring MVC fait cela en coulisse 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 un ou plusieurs 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
Kumar Abhishek