web-dev-qa-db-ja.com

Spring MVCの@RequestMapping POSTの仕組みを理解する

次のようなシンプルなコントローラーがあります:

@Controller
@RequestMapping(value = "/groups")
public class GroupsController {
    // mapping #1
    @RequestMapping(method = RequestMethod.GET)
    public String main(@ModelAttribute GroupForm groupForm, Model model) {
        ...
    }

    // mapping #2
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String changeGroup(@PathVariable Long id, @ModelAttribute GroupForm groupForm, Model model) {
        ...
    }

    // mapping #3
    @RequestMapping(method = RequestMethod.POST)
    public String save(@Valid @ModelAttribute GroupForm groupForm, BindingResult bindingResult, Model model) {
        ...
    }
}

基本的に、このページには次の機能があります。

  • ユーザーがメインページにアクセスします(/groups GET)。
  • ユーザーが新しいグループを作成する(/groups POST)、または特定のグループを選択する(/groups/1 GET)。
  • ユーザーが既存のグループを編集します(/groups/1 POST)。

ここでは、両方のGET要求マッピングがどのように機能するかを理解しています。マッピング#2が定義されている場合、それ以外の場合(/groups/1 GET)は「マッピングが見つかりません」という例外を引き起こします。

ここで理解しようとしているのは、マッピング#3が(/groups POST)と(/groups/1 POST)の両方を処理する理由ですか?要求マッピングがURIと一致するため、ここで(/groups POST)を処理する必要があります。なぜ(/groups/1 POST)が「マッピングが見つかりません」という例外をここでスローしないのですか?実際、/ groups(例:/groups/bla/1 POST)で始まるURIのPOST)もマッピング#3によって処理されるようです。

誰かがこれを明確に説明してもらえますか?どうもありがとう。

[〜#〜]説明[〜#〜]

より適切なメソッド(GET、POST、PUT、DELETEなど)を使用できるという事実を理解しています...または、/groups/{id} POSTを処理するための別の要求マッピングを作成できます。

しかし、私が本当に知りたいのは...

.... "なぜマッピング#3は/groups/1 POSTも処理するのですか?"

マッピング#2を削除すると、マッピング#1が/groups/1 GETを処理すると思うので、「最も近い一致」の推論は当てはまらないようです。例外。

私はここで少し困惑しています。

32
limc

これは複雑です。コードを読む方が良いと思います。

Spring 3.0では、_org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter_の内部クラスServletHandlerMethodResolverのメソッドpublic Method resolveHandlerMethod(HttpServletRequest request)によって魔法が行われます。

このクラスのインスタンスは、すべての要求コントローラークラスに存在し、すべての要求メソッドのリストを含むフィールドhandlerMethodsを持っています。

しかし、私がそれを理解する方法を要約させてください

  • Springはまず、少なくとも1つのハンドラーメソッドが一致するかどうかを確認します(これには、偽陰性が含まれる場合があります)
  • 次に、実際に一致するすべてのハンドラーメソッドのマップを作成します
  • 次に、リクエストパスでマップをソートします:RequestSpecificMappingInfoComparator
  • そして最初のものを取ります

ソートはこのように機能します:RequestSpecificMappingInfoComparatorは最初にAntPathMatcherの助けを借りてパスを比較し、これに従って2つのメソッドが等しい場合、他のメトリック(パラメーターの数、ヘッダーの数など)など)は、リクエストに関して考慮されます。

19
Ralph

Springは、最も近いものに一致するマッピングを見つけようとします。
したがって、POSTリクエストの場合、リクエストタイプに対応する唯一のマップはMapping#3です。マッピング1もマッピング2もリクエストタイプと一致しません。 Mapping#3を削除してみて、Springが一致するものを見つけられないためランタイムエラーをスローすることを確認できます。

2
PaiS

/ groups/{id}のPUTマッピングを追加します。 POSTも動作しますが、HTTPの観点からは厳密には正しくありません。

@RequestMapping( "/ {id}"、POST)を追加することでカバーできますか?

1
Eric Winter