Понимание того, как работает сообщение 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) должно покрыть его?


добавить @PathVariable к параметру Long id в сопоставлении #2