Понимание того, как работает сообщение Spring MVC @RequestMapping
у меня есть простой контроллер, который выглядит так:-
@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
) не вызывает ли здесь исключение" нет сопоставления найдено"? На самом деле, это почти похоже на любой пост с URI, начинающийся с /groups (например: /groups/bla/1 POST
) также будет обрабатываться путем сопоставления #3.
может кто-то обеспечить ясность объясните мне это? Спасибо.
уточнение
я понимаю, что могу использовать более подходящие методы (например, GET, POST, PUT или DELETE)... или я могу создать еще одно сопоставление запросов для обработки /groups/{id} POST
.
однако, что я действительно хочу знать...
.... "почему отображение #3 ручки /groups/1 POST
тоже?"
рассуждения о "ближайшем матче", похоже, не верны потому что, если я удалю mapping #2, то я думаю, что mapping #1 будет обрабатывать /groups/1 GET
, но это не так, и это вызывает исключение" нет сопоставления найдено".
я просто немного в тупике.
4 ответов
это сложно, я думаю, что лучше прочитать код.
весной 3.0 магия делается методом public Method resolveHandlerMethod(HttpServletRequest request)
внутренний класс ServletHandlerMethodResolver
of org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
.
экземпляр этого класса существует для каждого класса контроллера запросов и имеет поле handlerMethods
, который содержит список всех методов запроса.
но позвольте мне подытожить, как я это понимаю
- Spring сначала проверяет, соответствует ли хотя бы один метод обработчика (это может содержат ложные негативы)
- затем он создает карту всех действительно соответствующих методов обработчика
- затем он сортирует карту по пути запроса:
RequestSpecificMappingInfoComparator
- и один
сортировка работает следующим образом:RequestSpecificMappingInfoComparator
сначала сравнивает путь с помощью AntPathMatcher
, если два метода равны в соответствии с этим, то другие метрики (например, количество параметров, количество заголовков и т. д.) принимаются во внимание в отношении запрос.
Spring пытается найти отображение, которое соответствует ближайшему.
следовательно, в вашем случае любого запроса POST единственной картой, найденной для типа запроса, является Mapping# 3.
Ни одно из сопоставлений 1 или 2 не соответствует вашему типу запроса и, следовательно, игнорируется.
Может быть, вы можете попробовать удалить отображение #3 и увидеть, что весна выдает ошибку времени выполнения, так как она не находит совпадения!
Я бы добавил отображение PUT для /groups / {id}. Я думаю, что POST тоже будет работать, но не строго корректно с точки зрения HTTP.
добавление @RequestMapping ("/{id}", POST) должно покрыть его?