Понимание того, как работает Spring MVC @RequestMapping POST - PullRequest
32 голосов
/ 16 марта 2012

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

@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 (например: /groups/bla/1 POST), также будет обработан отображением # 3.

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

ПОЯСНЕНИЯ

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

Однако, что я действительно хочу знать, это ...

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

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

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

Ответы [ 4 ]

19 голосов
/ 16 марта 2012

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

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

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

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

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

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

2 голосов
/ 16 марта 2012

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

1 голос
/ 16 марта 2012

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

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

0 голосов
/ 16 марта 2012

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

...