web-dev-qa-db-fra.com

Comprendre comment @RequestMapping de Spring MVC POST Works

J'ai un simple contrôleur qui ressemble à ceci: -

@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) {
        ...
    }
}

Fondamentalement, cette page a les fonctionnalités suivantes: -

  • L'utilisateur visite la page principale (/groups GET).
  • L'utilisateur crée un nouveau groupe (/groups POST) Ou sélectionne un groupe spécifique (/groups/1 GET).
  • L'utilisateur modifie un groupe existant (/groups/1 POST).

Je comprends comment les deux mappages de requêtes GET fonctionnent ici. Le mappage # 2 est défini, sinon (/groups/1 GET) Provoquera une exception "Aucun mappage trouvé".

Ce que j'essaie de comprendre ici, c'est pourquoi le mappage # 3 gère à la fois (/groups POST) Et (/groups/1 POST)? Il est logique qu'il doive gérer (/groups POST) Ici car le mappage de requête correspond à l'URI. Pourquoi (/groups/1 POST) Ne provoque pas une exception "Aucun mappage trouvé" ici? En fait, il semble presque que tout POST avec URI commençant par/groups (ex: /groups/bla/1 POST) Sera également géré par le mappage # 3.

Quelqu'un peut-il me l'expliquer clairement? Merci beaucoup.

CLARIFICATION

Je comprends le fait que je peux utiliser des méthodes plus appropriées (comme GET, POST, PUT ou DELETE) ... ou je peux créer un autre mappage de demande pour gérer /groups/{id} POST.

Cependant, ce que je veux vraiment savoir, c'est ...

.... "Pourquoi le mappage # 3 gère-t-il aussi /groups/1 POST?"

Le raisonnement de la "correspondance la plus proche" ne semble pas vrai, car si je supprime le mappage n ° 2, je pense que le mappage n ° 1 gérera /groups/1 GET, Mais il ne le fait pas et provoque un "Aucun mappage trouvé "exception.

Je suis juste un peu perplexe ici.

32
limc

C'est compliqué, je pense qu'il vaut mieux lire le code.

Au printemps 3.0 La magie se fait par la méthode public Method resolveHandlerMethod(HttpServletRequest request) de la classe interne ServletHandlerMethodResolver de org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.

Une instance de cette classe existe pour chaque classe de contrôleur de demande et possède un champ handlerMethods qui contient une liste de toutes les méthodes de demande.

Mais permettez-moi de résumer comment je le comprends

  • Spring vérifie d'abord si au moins une méthode de gestionnaire correspond (cela peut contenir de faux négatifs)
  • Ensuite, il crée une carte de toutes les méthodes de gestionnaire vraiment correspondantes
  • Ensuite, il trie la carte par chemin de requête: RequestSpecificMappingInfoComparator
  • et prend le premier

Le tri fonctionne de cette façon: le RequestSpecificMappingInfoComparator compare d'abord le chemin à l'aide d'un AntPathMatcher, si deux méthodes sont égales selon cela, alors d'autres métriques (comme le nombre de paramètres, le nombre d'en-têtes , etc.) sont pris en compte pour la demande.

19
Ralph

Spring essaie de trouver le mappage qui correspond le plus.
Par conséquent, dans le cas de toute demande POST, la seule carte trouvée pour le type de demande est Mappage n ° 3. Ni le mappage 1 ni le mappage 2 ne correspond à votre type de demande, et sont donc ignorés . Peut-être que vous pouvez essayer de supprimer le mappage # 3 et voir que Spring lance une erreur d'exécution car il ne trouve pas de correspondance!

2
PaiS

J'ajouterais un mappage PUT pour/groups/{id}. Je suppose que POST fonctionnerait aussi mais pas strictement correct du point de vue HTTP.

l'ajout de @RequestMapping ("/ {id}", POST) devrait le couvrir?

1
Eric Winter