Verwenden des HTTP-Dev-Clients mit Post-Request und Content-Type-Anwendung/x-www-form-urlencoded
1) Nur @RequestBody
Anfrage - localhost: 8080/SpringMVC/welcome In Körpername = abc
Code-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestBody String body, Model model) {
model.addAttribute("message", body);
return "hello";
}
// Gibt den Körper wie erwartet als 'name = abc' aus
2) Nur @RequestParam
Anfrage - localhost: 8080/SpringMVC/welcome In Körpername = abc
Code-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestParam String name, Model model) {
model.addAttribute("name", name);
return "hello";
}
// Gibt den Namen wie erwartet als 'abc' aus
3) Beides zusammen
Anfrage - localhost: 8080/SpringMVC/welcome In Körpername = abc
Code-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestBody String body, @RequestParam String name, Model model) {
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// HTTP-Fehlercode 400 - Die vom Client gesendete Anforderung war syntaktisch falsch.
4) Oben mit geänderter Position der Parameter
Anfrage - localhost: 8080/SpringMVC/welcome In Körpername = abc
Code-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestParam String name, @RequestBody String body, Model model) {
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// Kein Fehler. Der Name ist 'abc'. Körper ist leer
5) Geben Sie zusammen aber URL-Parameter ein
Anfrage - localhost: 8080/SpringMVC/welcome? Name = xyz In Body - name = abc
Code-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestBody String body, @RequestParam String name, Model model) {
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// name ist 'xyz' und body ist 'name = abc'
6) Wie 5), jedoch mit geänderter Parameterposition
Code -
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestParam String name, @RequestBody String body, Model model) {
model.addAttribute("name", name);
model.addAttribute("message", body);
return "hello";
}
// name = 'xyz, abc' body ist leer
Kann jemand dieses Verhalten erklären?
Der @RequestBody
- Javadoc gibt an
Anmerkungen, die einen Methodenparameter angeben, sollten an den Hauptteil der Webanforderung gebunden sein.
Es verwendet registrierte Instanzen von HttpMessageConverter
, um den Anforderungshauptteil in ein Objekt des mit Anmerkungen versehenen Parametertyps zu deserialisieren.
Und @RequestParam
Anmerkung, die angibt, dass ein Methodenparameter an einen Webanforderungsparameter gebunden werden soll.
Spring bindet den Body der Anfrage an den mit @RequestBody
Gekennzeichneten Parameter.
Spring bindet Anforderungsparameter aus dem Anforderungshauptteil (url-codierte Parameter) an Ihren Methodenparameter. Spring verwendet den Namen des Parameters, d. H. name
, um den Parameter abzubilden.
Parameter werden der Reihe nach aufgelöst. Der @RequestBody
Wird zuerst verarbeitet. Der Frühling verbraucht alle HttpServletRequest
InputStream
. Wenn es dann versucht, den @RequestParam
Aufzulösen, der standardmäßig required
ist, gibt es keinen Anforderungsparameter in der Abfragezeichenfolge oder was vom Anforderungshauptteil übrig bleibt, d. H. nichts. Daher schlägt es mit 400 fehl, da die Anforderung von der Handlermethode nicht korrekt verarbeitet werden kann.
Der Handler für @RequestParam
Handelt zuerst und liest, was er von HttpServletRequest
InputStream
kann, um den Anforderungsparameter abzubilden, dh. die gesamte Abfragezeichenfolge/URL-codierte Parameter. Dabei wird der Wert abc
dem Parameter name
zugeordnet. Wenn der Handler für @RequestBody
Ausgeführt wird, ist im Anforderungshauptteil nichts mehr vorhanden. Daher wird als Argument die leere Zeichenfolge verwendet.
Der Handler für @RequestBody
Liest den Body und bindet ihn an den Parameter. Der Handler für @RequestParam
Kann dann den Anforderungsparameter aus der URL-Abfragezeichenfolge abrufen.
Der Handler für @RequestParam
Liest sowohl aus dem Text als auch aus der URL-Abfragezeichenfolge. Normalerweise werden sie in ein Map
eingefügt. Da der Parameter jedoch vom Typ String
ist, serialisiert Spring das Map
als durch Kommas getrennte Werte. Der Handler für @RequestBody
Hat dann wiederum nichts mehr, was er aus dem Body lesen könnte.
Es ist zu spät, um diese Frage zu beantworten, aber es könnte für neue Leser helfen. Es scheint, dass es Versionsprobleme gibt. Ich habe all diese Tests mit Spring 4.1.4 durchgeführt und festgestellt, dass die Reihenfolge von @RequestBody
und @RequestParam
spielt keine Rolle.
body= "name=abc"
, und name = "abc"
body ="name=abc"
, name = "xyz,abc"
Dies liegt an der nicht ganz einfachen Servlet-Spezifikation. Wenn Sie mit einer systemeigenen HttpServletRequest
-Implementierung arbeiten, können Sie nicht sowohl den URL-Codierungshauptteil als auch die Parameter abrufen. Spring macht einige Workarounds, die es noch seltsamer und undurchsichtiger machen.
In solchen Fällen rendert Spring (Version 3.2.4) einen Body unter Verwendung von Daten aus der getParameterMap()
-Methode neu. Es mischt die Parameter GET und POST und unterbricht die Parameterreihenfolge. Die Klasse, die für das Chaos verantwortlich ist, ist ServletServerHttpRequest
. Leider kann sie nicht ersetzt werden, aber die Klasse StringHttpMessageConverter
kann sein.
Die saubere Lösung ist leider nicht einfach:
StringHttpMessageConverter
ersetzen. Kopieren/Überschreiben Sie die ursprüngliche Klassenanpassungsmethode readInternal()
.HttpServletRequest
Überschreibungsmethoden getInputStream()
, getReader()
und getParameter*()
.In der Methode StringHttpMessageConverter # readInternal muss folgender Code verwendet werden:
if (inputMessage instanceof ServletServerHttpRequest) {
ServletServerHttpRequest oo = (ServletServerHttpRequest)inputMessage;
input = oo.getServletRequest().getInputStream();
} else {
input = inputMessage.getBody();
}
Dann muss der Konverter im Kontext registriert werden.
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true/false">
<bean class="my-new-converter-class"/>
</mvc:message-converters>
</mvc:annotation-driven>
Der zweite Schritt wird hier beschrieben: HTTP-Servlet-Anforderung verliert Parameter von POST body nach einmaligem Lesen
Sie können auch einfach den voreingestellten Status von @RequestParam in false ändern, damit der HTTP-Antwortstatuscode 400 nicht generiert wird. Auf diese Weise können Sie die Anmerkungen in beliebiger Reihenfolge platzieren.
@RequestParam(required = false)String name