Понимание того, как Spring MVC @RequestMapping POST Works

У меня есть простой контроллер, который выглядит так: -

@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) не вызывает исключение "Отсутствие сопоставления найденных" здесь? На самом деле, похоже, что любой POST с URI, начинающийся с /groups (ex: /groups/bla/1 POST), также будет обрабатываться путем сопоставления # 3.

Может ли кто-нибудь дать мне это ясное объяснение? Большое спасибо.

РАЗЪЯСНЕНИЕ

Я понимаю, что я могу использовать более подходящие методы (например, GET, POST, PUT или DELETE)... или я могу создать еще одно сопоставление запросов для обработки /groups/{id} POST.

Однако, что я хочу знать, это...

.... "Почему отображение # 3 обрабатывает /groups/1 POST тоже?"

"Ближайшее совпадение" аргументации кажется недействительным, потому что, если я удалю сопоставление # 2, я бы подумал, что отображение # 1 будет обрабатывать /groups/1 GET, но это не так, и оно вызывает "Нет сопоставления" "исключение.

Я просто немного здесь.

Ответ 1

Это сложно, я думаю, что лучше прочитать код.

В Spring 3.0 Магия выполняется методом public Method resolveHandlerMethod(HttpServletRequest request) внутреннего класса ServletHandlerMethodResolver org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.

Экземпляр этого класса существует для каждого класса контроллера запросов и имеет поле handlerMethods, которое содержит список всех методов запроса.

Но позвольте мне подвести итог тому, как я это понимаю

  • Spring сначала проверяет, соответствует ли хотя бы один метод обработчика (это может содержать ложные негативы)
  • Затем он создает карту всех действительно соответствующих методов-обработчиков
  • Затем он сортирует карту по пути запроса: RequestSpecificMappingInfoComparator
  • и берет первый

Сортировка работает следующим образом: RequestSpecificMappingInfoComparator сначала сравнивает путь с помощью AntPathMatcher, если в соответствии с этим два метода равны, затем другие показатели (например, количество параметров, количество заголовков и т.д. ) учитываются в отношении запроса.

Ответ 2

Spring пытается найти сопоставление, которое соответствует ближайшему.
Следовательно, в вашем случае любого запроса POST единственной картой, найденной для типа запроса, является Mapping # 3. Ни одно из сопоставлений 1 или сопоставление 2 не соответствует типу вашего запроса и, следовательно, игнорируется. Может быть, вы можете попробовать удалить карту # 3 и увидеть, что Spring выдает ошибку времени выполнения, так как не находит соответствия!

Ответ 3

Я бы добавил отображение PUT для /groups/ {id}. Я думаю, что POST будет работать, но не строго корректно с точки зрения HTTP.

добавление @RequestMapping ( "/{id}", POST) должно покрывать его?

Ответ 4

добавить @PathVariable в параметр Long id в отображении # 2