32

私は次のような単純なコントローラーを持っています:-

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

誰かが私にこれについて明確な説明を提供できますか? どうもありがとう。

明確化

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

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

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

「最も近い一致」の推論は当てはまらないようです。なぜなら、マッピング #2 を削除すると、マッピング #1 が を処理すると思うからです/groups/1 GETが、そうではなく、「マッピングが見つかりません」という例外が発生します。

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

4

4 に答える 4

19

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

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

このクラスのインスタンスは、リクエスト コントローラ クラスごとに存在しhandlerMethods、すべてのリクエスト メソッドのリストを含むフィールドがあります。

しかし、私がそれをどのように理解しているかを要約させてください

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

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

于 2012-03-16T14:45:05.620 に答える
2

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

于 2012-03-16T13:57:20.653 に答える
1

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

@RequestMapping("/{id}", POST) を追加すると、それをカバーする必要がありますか?

于 2012-03-16T14:25:24.467 に答える
-3

add @PathVariable to the Long id parameter in mapping #2

于 2012-03-16T14:10:54.870 に答える