it-swarm.com.de

Spring MVC: Bitte erläutern Sie den Unterschied zwischen @RequestParam und @ModelAttribute

Ich bin neu bei Spring MVC. Bitte helfen Sie mir beim Auspacken der Dokumentation.

Dokumentation

Spring MVC Documentation Staaten (Schwerpunkt Mine):

  • @ModelAttribute für ein Methodenargument gibt an, dass das Argument aus dem Modell abgerufen werden soll. Wenn das Argument nicht im Modell vorhanden ist, sollte es zuerst instanziiert und dann zum Modell hinzugefügt werden. Sobald im Modell vorhanden, sollte das Feld des Arguments mit allen Anforderungsparametern gefüllt sein, die übereinstimmende Namen haben . Die WebDataBinder-Klasse vergleicht Anforderungsparameternamen - einschließlich Abfragezeichenfolgenparametern und Formularfeldern -, um Attributfelder nach Namen zu modellieren.

  • @RequestParam bindet Anforderungsparameter an einen Methodenparameter in Ihrem Controller.

Disclaimer/Clarifier

Ich weiß, dass @ModelAttribute und @RequestParam nicht dasselbe sind, sich nicht gegenseitig ausschließen, nicht dieselbe Rolle spielen und gleichzeitig verwendet werden können, wie in diese Frage - tatsächlich kann @RequestParam verwendet werden, um Felder von @ModelAttribute auszufüllen. . Meine Frage ist mehr auf den Unterschied zwischen ihren internen Abläufen ausgerichtet.

Frage:

Was ist der Unterschied zwischen @ModelAttribute (wird für ein Methodenargument und nicht für eine Methode verwendet) und @RequestParam? Speziell:

  • Quelle: Haben @RequestParam und @ModelAttribute dieselbe Informationsquelle/Grundgesamtheit, d. H. Anforderungsparameter in URL, die möglicherweise als Elemente eines Formulars/Modells angegeben wurden, das POSTed war?
  • Verwendung: Ist es richtig, dass mit @RequestParam abgerufene Variablen verworfen werden (sofern sie nicht an ein Modell übergeben werden), während mit @ModelAttribute abgerufene Variablen automatisch in das zurückzugebende Modell eingegeben werden?

Oder was ist in sehr einfachen Codierungsbeispielen der wirkliche funktionierende Unterschied zwischen diesen beiden Beispielen?

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

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

Mein aktuelles Verständnis:

Sowohl @ModelAttribute als auch @RequestParam fragen die Anforderungsparameter nach Informationen ab, verwenden diese Informationen jedoch unterschiedlich:

  • @RequestParam füllt nur eigenständige Variablen (die natürlich Felder in einer @ModelAttribute-Klasse sein können). Diese Variablen werden verworfen, wenn der Controller fertig ist, sofern sie nicht in das Modell eingespeist wurden.

  • @ModelAttribute füllt die Felder einer Klasse, die dann ein Attribut des Modells auffüllt, das an die Ansicht zurückgegeben werden soll

Ist das richtig?

43
Lydia Ralph

@RequestParam füllt nur eigenständige Variablen (dies können natürlich Felder in einer @ModelAttribute-Klasse sein). Diese Variablen werden verworfen, wenn der Controller fertig ist, es sei denn, sie wurden in das Modell eingegeben.

Verwechseln Sie nicht das Word-Modell mit der Sitzung. Die http-Konversation lautet im Allgemeinen: HTTP.GET, Serverantwort, dann HTTP.POST. Wenn Sie die @ModelAttribute-Annotation verwenden, erstellen Sie immer eine Instanz dessen, was Sie kommentiert haben. Dies lässt Sie glauben, dass durch das Zuführen von Dingen in das Modell möglicherweise Variablen erhalten bleiben. Dies ist nicht korrekt, sobald die Variable HttpServletRequest beendet ist, sollten diese Variablen nicht mehr Teil der Browser-/Server-Konversation sein, es sei denn, sie wurden in einer Sitzung gespeichert.

@ModelAttribute füllt die Felder einer Klasse aus, die dann ein Attribut des Modells auffüllt, das an die Ansicht zurückgegeben wird

Ja! Um korrekt zu sein, @ModelAttribute weist Spring an, seine Standard-Webdatenbindung zu verwenden, um eine Instanz von etwas mit Daten aus der HttpServletRequest zu füllen. Die Entscheidung, diese Daten wieder an die Ansicht zu übergeben, liegt beim Programmierer. Wenn Sie über eine Methode verfügen, die mit @ModelAttribute kommentiert ist, wird sie jedes Mal aufgerufen, wenn Code auf dieses Servlet trifft. Wenn Sie @ModelAttribute als Parameter der Methode festgelegt haben, handelt es sich um eingehende HTTP-Form-Datenbindungen.

Das Aufrufen von @RequestParam ist eine Abkürzung, um request.getParameter("foo") zu sagen. Unter der Haube können Sie mit Javas HttpServletRequest Werte vom Anforderungsobjekt abrufen, indem Sie einen Schlüssel-> Wert nachschlagen. Der zurückgegebene Wert ist vom Typ Object. Dies ist, was Sie häufig eingeben würden, wenn Sie Spring nicht in Ihrer Webanwendung verwenden würden.

Spring führt diese Abstraktion dann einen Schritt weiter, wenn Sie @ModelAttribute verwenden. Diese Anmerkung verwendet das Konzept der Datenbindung. Das Ziel der Datenbindung besteht darin, dass der Code in Ihrem Controller nicht für jedes Formularelement request.getParameter("foo1") aufgerufen werden muss. Stellen Sie sich vor, Sie haben ein Webformular mit 5 Feldern. Ohne Datenbindung muss der Programmierer jedes dieser Felder manuell abrufen und überprüfen. Der Programmierer muss sicherstellen, dass die Anforderung die Eigenschaft enthält, dass der Wert der Eigenschaft vorhanden ist und dass der Wert der Eigenschaft dem für jedes Feld erwarteten Typ entspricht. Durch Verwendung von @ModelAttribute kann Spring diese Arbeit für Sie erledigen. 

Wenn Sie eine Methode in Ihrem Controller mit @ModelAttribute("fooBar") FooBar fooBar annotieren, wird eine Instanz von FooBar always von Spring erstellt und Ihrer Methode zur Verfügung gestellt. Wenn die Datenbindung ins Spiel kommt, dann wird diese Anmerkung in den Parametern einer Methode verwendet. Spring betrachtet die Instanz von HttpServletRequest und prüft, ob sie die Daten in der Anforderung mit der richtigen Eigenschaft in einer Instanz von FooBar abgleichen kann. Dies basiert auf der Java-Eigenschaftenkonvention, in der Sie ein Feld wie foo und öffentliche Getter und Setter mit dem Namen getFoo und setFoo haben. Dies mag magisch erscheinen, aber wenn Sie die Konvention brechen würden, würde Ihre Spring-Datenbindung nicht mehr funktionieren, da sie wo die Daten aus Ihrer HttpServletRequest nicht binden könnte. Sie würden trotzdem eine Instanz von FooBar erhalten Für die Eigenschaften werden keine Werte aus der Anforderung festgelegt.

34
zmf

@ModelAttribute: bindet ein gesamtes Java-Objekt (wie Employee). unterstützt mehrere Anforderungsparameter

@RequestParam: bindet einen einzelnen Anforderungsparameter (wie firstName)

Im Algemeinen, 
@RequestParam eignet sich am besten zum Lesen einer kleinen Anzahl von Parametern. 

@ModelAttribute wird verwendet, wenn Sie ein Formular mit einer großen Anzahl von Feldern haben. 

und

@ModelAttribute bietet Ihnen zusätzliche Funktionen wie Datenbindung, Validierung und Formularvorbereitung. 

3
Harinath

@ModelAttribute annotierte Parameter werden von registrierten ServletModelAttributeMethodProcessor (oder ModelAttributeMethodProcessor) und @RequestParam annotierten Parametern behandelt, und zwar je nach Parametertyp von registrierten RequestParamMethodArgumentResolver oder RequestParamMapMethodArgumentResolver.

Im Folgenden wird erläutert, wie Spring diese HandlerMethodArgumentResolvers verwendet, um Argumente für Ihre Handler-Methoden aufzulösen:

In beiden Fällen, @ModelAttribute und @RequestParam, werden die zu bindenden Werte aus ServletRequest parameters abgerufen.

Sie können sich den Quellcode der oben genannten Typen ansehen, aber hier sind die einfachen Details. 

Für @ModelAttribute erstellt Spring eine Instanz des Parametertyps. Er prüft die Felder dieser Instanz und versucht, Parameterwerte an sie zu binden, basierend auf einer Namens-/Aliasing-Strategie, die sich aus dem @ModelAttribute-Namen und den Feldnamen zusammensetzt. Normalerweise verwendet es eine Gruppe von Converter-Instanzen, um von String (Parameterwerte sind immer String-Werte) in den Zielfeldtyp Integer, Date usw. zu konvertieren. Sie können auch eigene Converter-Typen für benutzerdefinierte Konvertierungen registrieren. Sie können auch POJO-Typen verschachteln.

Für @RequestParam verwendet Spring dieselben Converter-Instanzen, um die Parameterwerte direkt in den mit Annotationen versehenen Parametertyp zu konvertieren.

Beachten Sie, dass Parameterwerte nicht "weggeworfen" werden. Sie werden für die Dauer des Anforderungsverarbeitungszyklus des Containers in der Variablen HttpServletRequest gespeichert. Sie können immer über die entsprechenden Methoden darauf zugreifen.

@ModelAttribute (Parameter) lädt ein Modellattribut aus @SessionAttributes oder aus @ModelAttribute (Methode) .

Sie brauchen es nicht nur, um Werte aus einer Anfrage zu binden, sondern tun dies nach dem Laden von @SessionAttributes.

@RequestParam bindet einen Anforderungsparameter an ein Objekt.

0
Neil McGuigan
  • Auf der Methodenebene

Wenn die Annotation auf Methodenebene verwendet wird, bedeutet dies, dass der Zweck dieser Methode darin besteht, ein oder mehrere Modellattribute hinzuzufügen. Solche Methoden unterstützen dieselben Argumenttypen wie @RequestMapping-Methoden, die jedoch nicht direkt Anforderungen zugeordnet werden können.

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

Eine Methode, die allen in der Controller-Klasse definierten Modellen ein Attribut namens msg hinzufügt.

Spring-MVC ruft immer zuerst diese Methode auf, bevor Request-Handler-Methoden aufgerufen werden. Das heißt, @ModelAttribute-Methoden werden aufgerufen, bevor die mit @RequestMapping annotierten Controller-Methoden aufgerufen werden. Die Logik hinter der Sequenz ist, dass das Modellobjekt erstellt werden muss, bevor eine Verarbeitung innerhalb der Controller-Methoden beginnt.

Es ist auch wichtig, dass Sie die jeweilige Klasse als @ControllerAdvice kommentieren. Daher können Sie in Model Werte hinzufügen, die als global gekennzeichnet werden. Dies bedeutet tatsächlich, dass für jede Anforderung ein Standardwert für jede Methode im Antwortteil vorhanden ist.

  • Als Methodenargument

Bei Verwendung als Methodenargument bedeutet es, dass das Argument aus dem Modell abgerufen werden soll. Wenn es nicht vorhanden ist, sollte es zuerst instanziiert und dann zum Modell hinzugefügt werden. Sobald die Argumentfelder in dem Modell vorhanden sind, sollten sie aus allen Anforderungsparametern mit übereinstimmenden Namen gefüllt werden.

In dem folgenden Codefragment wird das Benutzermodellattribut mit Daten aus einem an den addUser-Endpunkt gesendeten Formular gefüllt. Spring MVC führt dies im Hintergrund aus, bevor die Submit-Methode aufgerufen wird:

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

Es bindet also die Formulardaten mit einer Bean. Der mit @RequestMapping kommentierte Controller kann über benutzerdefinierte Klassenargumente verfügen, die mit @ModelAttribute versehen sind.

Dies ist das, was in Spring-MVC allgemein als Datenbindung bekannt ist. Dies ist ein allgemeiner Mechanismus, durch den Sie nicht jedes Formularfeld einzeln analysieren müssen.

0
Kumar Abhishek