I have a simple Controller that looks like this:-
@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) {
...
}
}
Basically, this page has the following functionalities:-
/groups GET
)./groups POST
) or selects a specific group (/groups/1 GET
)./groups/1 POST
).I understand how both GET request mappings work here. Mapping #2 is defined, otherwise (/groups/1 GET
) will cause a "No mapping found" exception.
What I'm trying to understand here is why mapping #3 handles both (/groups POST
) and (/groups/1 POST
)? It makes sense that it should handle (/groups POST
) here since the request mapping matches the URI. Why (/groups/1 POST
) isn't causing a "No mapping found" exception being thrown here? In fact, it almost seems like any POST with URI beginning with /groups (ex: /groups/bla/1 POST
) will also be handled by mapping #3.
Can someone provide a clear explanation of this to me? Thanks much.
CLARIFICATION
I understand the fact that I can use more appropriate methods (like GET, POST, PUT or DELETE)... or I can create yet another request mapping to handle /groups/{id} POST
.
However, what I want to really know is...
.... "Why does mapping #3 handle /groups/1 POST
too?"
The "closest match" reasoning don't seem to hold true because if I remove mapping #2, then I would think mapping #1 will handle /groups/1 GET
, but it doesn't and it causes a "No mapping found" exception.
I'm just a little stumped here.
This is complicated, I think it is better to read the code.
In Spring 3.0 The magic is done by method public Method resolveHandlerMethod(HttpServletRequest request)
of the inner class ServletHandlerMethodResolver
of org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
.
An instance of this class exists for every Request Controller Class, and has a field handlerMethods
that contains a list of all the request methods.
But let me summarize how I understand it
RequestSpecificMappingInfoComparator
The sorting works this way: the RequestSpecificMappingInfoComparator
first compares the path with the help of an AntPathMatcher
, if two methods are equal according to this, then other metrics (like number of parameters, number of headers, etc.) are taken into account with respect to the request.