Post要求およびContent-Type application/x-www-form-urlencodedでHTTP devクライアントを使用する
1)@RequestBodyのみ
リクエスト-localhost:8080/SpringMVC/welcome In Body-name = abc
コード-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestBody String body, Model model) {
model.addAttribute("message", body);
return "hello";
}
//本体を期待どおり 'name = abc'として提供します
2)@RequestParamのみ
リクエスト-localhost:8080/SpringMVC/welcome In Body-name = abc
コード-
@RequestMapping(method = RequestMethod.POST)
public String printWelcome(@RequestParam String name, Model model) {
model.addAttribute("name", name);
return "hello";
}
//期待どおりに「abc」として名前を付けます
3)両方一緒
リクエスト-localhost:8080/SpringMVC/welcome In Body-name = abc
コード-
@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エラーコード400-クライアントから送信されたリクエストは構文的に間違っていました。
4)paramsの位置を変更した上
リクエスト-localhost:8080/SpringMVC/welcome In Body-name = abc
コード-
@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";
}
//エラーなし。名前は「abc」です。体は空です
5)一緒に、タイプurlパラメーターを取得
リクエスト-localhost:8080/SpringMVC/welcome?name = xyz In Body-name = abc
コード-
@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";
}
//名前は「xyz」、本体は「name = abc」
6)5)と同じですが、パラメーターの位置が変更されています
コード-
@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 is empty
誰かがこの行動を説明できますか?
@RequestBody
javadocの状態
メソッドパラメータを示す注釈は、Web要求の本文にバインドする必要があります。
HttpMessageConverter
の登録済みインスタンスを使用して、リクエストの本文を注釈付きパラメータータイプのオブジェクトに逆シリアル化します。
そして@RequestParam
メソッドパラメーターをWeb要求パラメーターにバインドする必要があることを示す注釈。
Springは、リクエストの本文を@RequestBody
アノテーションが付けられたパラメーターにバインドします。
Springは、リクエストボディ(urlエンコードされたパラメーター)からのリクエストパラメーターをメソッドパラメーターにバインドします。 Springはパラメーターの名前を使用します。 name
、パラメーターをマップします。
パラメータは順番に解決されます。 @RequestBody
が最初に処理されます。 SpringはすべてのHttpServletRequest
InputStream
を消費します。次に、デフォルトでrequired
である@RequestParam
を解決しようとすると、クエリ文字列にリクエストパラメータがないか、リクエスト本文に残っているものがありません。何もない。そのため、ハンドラメソッドでリクエストを正しく処理できないため、400で失敗します。
@RequestParam
のハンドラーが最初に動作し、HttpServletRequest
InputStream
の機能を読み取って要求パラメーターをマップします。クエリ文字列/ URLエンコードされたパラメータ全体。そうすると、パラメータabc
にマップされた値name
を取得します。 @RequestBody
のハンドラーが実行されると、リクエスト本文に何も残っていないため、使用される引数は空の文字列です。
@RequestBody
のハンドラーは、本体を読み取り、パラメーターにバインドします。 @RequestParam
のハンドラーは、URLクエリ文字列からリクエストパラメーターを取得できます。
@RequestParam
のハンドラーは、本体とURLクエリ文字列の両方から読み取ります。通常はMap
に入れられますが、パラメーターはString
型であるため、SpringはMap
をコンマ区切り値としてシリアル化します。 @RequestBody
のハンドラーには、本体から読み取るものが何もありません。
この質問に答えるのは遅すぎますが、新しい読者には役立つかもしれません。バージョンの問題のようです。これらすべてのテストをSpring 4.1.4で実行しましたが、@RequestBody
と@RequestParam
の順序は関係ないことがわかりました。
body= "name=abc"
とname = "abc"
を与えましたbody ="name=abc"
、name = "xyz,abc"
これは、サーブレットの仕様がそれほど単純ではないために発生します。ネイティブHttpServletRequest
実装を使用している場合、URLエンコード本体とパラメーターの両方を取得することはできません。 Springはいくつかの回避策を実行し、それによりさらに奇妙で不透明になります。
そのような場合、Spring(バージョン3.2.4)は、getParameterMap()
メソッドからのデータを使用して、ボディを再レンダリングします。 GETパラメーターとPOSTパラメーターを混合し、パラメーターの順序を崩します。カオスの原因となるクラスはServletServerHttpRequest
です。残念ながら置き換えることはできませんが、クラスStringHttpMessageConverter
は置き換えることができます。
残念ながら、クリーンなソリューションは単純ではありません。
StringHttpMessageConverter
を置き換えます。元のクラス調整メソッドreadInternal()
をコピー/上書きします。HttpServletRequest
メソッドのラッピングgetInputStream()
、getReader()
、およびgetParameter*()
メソッド。メソッドStringHttpMessageConverter#readInternalでは、次のコードを使用する必要があります。
if (inputMessage instanceof ServletServerHttpRequest) {
ServletServerHttpRequest oo = (ServletServerHttpRequest)inputMessage;
input = oo.getServletRequest().getInputStream();
} else {
input = inputMessage.getBody();
}
次に、コンバーターをコンテキストに登録する必要があります。
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true/false">
<bean class="my-new-converter-class"/>
</mvc:message-converters>
</mvc:annotation-driven>
手順2については、次のとおりです。 Httpサーブレットリクエストは、一度読み取った後、POST本文からパラメータを失います
HTTP要求のステータスコード400が生成されないように、@ RequestParamのデフォルトの必須ステータスをfalseに変更することもできます。これにより、好きな順序で注釈を配置できます。
@RequestParam(required = false)String name