32 votes

Comprendre comment fonctionne le POST @RequestMapping de Spring MVC

J'ai un contrôleur simple 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) {
        ...
    }
}

En gros, 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 mappings de requête GET fonctionnent ici. Le mappage n°2 est défini, sinon ( /groups/1 GET ) provoquera une exception "No mapping found".

Ce que j'essaie de comprendre ici, c'est pourquoi le mapping n°3 gère les deux ( /groups POST ) et ( /groups/1 POST ) ? Il est logique qu'il gère ( /groups POST ) ici puisque le mappage de la demande correspond à l'URI. Pourquoi ( /groups/1 POST ) n'est pas à l'origine de l'exception "No mapping found" ? En fait, il semble presque que tout POST dont l'URI commence par /groups (ex : /groups/bla/1 POST ) seront également traités par le mapping n°3.

Quelqu'un peut-il me fournir une explication claire à ce sujet ? 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 encore un autre mappage de requête à gérer... /groups/{id} POST .

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

.... "Pourquoi la cartographie n°3 gère-t-elle /groups/1 POST aussi ?"

Le raisonnement de la "correspondance la plus proche" ne semble pas être valable, car si je supprime le mappage n° 2, je pense que le mappage n° 1 s'en chargera. /groups/1 GET mais ce n'est pas le cas et cela provoque une exception "No mapping found".

Je suis juste un peu perplexe ici.

19voto

Ralph Points 42744

C'est compliqué, je pense qu'il est préférable de lire le code.

Dans Spring 3.0, la magie est faite 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 requêtes, et possède un champ handlerMethods qui contient une liste de toutes les méthodes de demande.

Mais laissez-moi résumer comment je le comprends

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

Le tri fonctionne de la manière suivante : le RequestSpecificMappingInfoComparator compare d'abord le chemin avec l'aide d'un AntPathMatcher Si deux méthodes sont égales selon ce critère, d'autres mesures (comme le nombre de paramètres, le nombre d'en-têtes, etc.) sont prises en compte pour la demande.

2voto

PaiS Points 427

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

1voto

Eric Winter Points 488

J'ajouterais un mappage PUT pour /groups/{id}. Je suppose que POST fonctionnerait aussi, mais ce n'est pas tout à fait correct d'un point de vue HTTP.

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

-3voto

Blitzkr1eg Points 650

Ajouter @PathVariable au paramètre Long id dans le mapping #2

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X