Spring переменные с несколькими путями

В моем контроллере Spring я пытаюсь получить 3 переменные пути:

@RequestMapping("{language}/{country}/{term}/catalogue") - @PathVariable String language, @PathVariable String country, @PathVariable String term

К сожалению, это не будет распознано сервлетом.

Существуют способы привязки URI, например,
@RequestMapping("**/catalogue"), а также @RequestMapping("{language}/{country}/catalogue") будут работать, но с третьей переменной пути она перестанет работать.

Сам контроллер также привязан к определенному пути.

Есть ли ограничение для переменных пути? Возможно ли, что другие подстановочные знаки (например, @RequestMapping("**"))) будут оцениваться выше? Например, 2 подстановочных знака более специфичны, чем 3 определенных значения. Но на практике подстановочные знаки должны быть последним совпадающим вариантом.

Относительно появившейся ошибки:
Во-первых, сопоставления с подстановочными знаками будут сопоставляться. Когда я отключаю сопоставления подстановочных знаков, возникает ошибка org.springframework.web.HttpRequestMethodNotSupportedException.

15:42:53,881  DEBUG [http-bio-18091-exec-31] (org.springframework.web.servlet.DispatcherServlet) - Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'errors/exception'; model is null
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodResolver.resolveHandlerMethod(AnnotationMethodHandlerAdapter.java:665)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:431)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at [device detection filter]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)

Метод контроллера:

@RequestMapping(value = "{language}/{country}/{term}/catalogue", method = RequestMethod.GET)
public ModelAndView catalogue(HttpServletRequest request, HttpServletResponse response, @PathVariable("language") String language, @PathVariable("country") String country, @PathVariable("term") String term, @RequestParam(value = "d", defaultValue = "") String device, @RequestParam(value = "embedded", defaultValue = "false") String embedded, @RequestParam(value = "id", defaultValue = "") String idString, @RequestParam(value = "nr", defaultValue = "") String nr) {

В качестве запроса, вот все RequestMappings от контроллера (извините, я не могу опубликовать здесь полный код от контроллера):

@Controller
@RequestMapping("xyz/")
public class Controller {

@RequestMapping(value = "{language}/{country}/{term}/catalogue", method = RequestMethod.GET)

@RequestMapping("**")

@RequestMapping("{language}/{country}/product")

@RequestMapping("{language}/{country}/product-detail")

@RequestMapping("{language}/{country}/product-search")

@RequestMapping("{language}/{country}/dealer-search")

@RequestMapping("{language}/{country}/product-finder")

@RequestMapping("{language}/{country}/table")

@RequestMapping("**/languages")

@RequestMapping("**/chooseLanguages")
}    

Спасибо за помощь.


person Noctem    schedule 16.01.2015    source источник
comment
Пожалуйста, предоставьте больше контекста, т. е. задействованный класс контроллера @RequestMapping и другие методы @RequestMapping.   -  person fps    schedule 16.01.2015
comment
@Контроллер @RequestMapping(xyz)   -  person Noctem    schedule 16.01.2015
comment
Что с ошибкой? Когда это происходит? Вы получаете ответ 404 от Spring при отправке запроса или приложение не удалось запустить?   -  person fps    schedule 16.01.2015
comment
проголосуйте за возникшую ошибку, может быть, трассировка стека?   -  person ConMan    schedule 16.01.2015
comment
Аннотация контроллера: @Controller @RequestMapping(xyz). Есть также 2 метода подстановочных знаков, один в корневом контроллере и один в контроллере xyz. Весенняя версия 3.1.0.RELEASE. Другие сопоставления с подстановочными знаками имеют статическое значение в конце (например, **/пример).   -  person Noctem    schedule 16.01.2015
comment
Веб-приложение запускается, только упомянутый метод недоступен и соответствует другим методам или, если подстановочные знаки отключены, отображается страница ошибки и возникает трассировка стека, которую я отредактировал для вопроса.   -  person Noctem    schedule 16.01.2015
comment
Можете ли вы опубликовать свой код вместе с любыми другими методами в том же классе?   -  person ConMan    schedule 16.01.2015
comment
@ user3679981 Прочтите документацию Spring (ссылка здесь). Там написано When a URL matches multiple patterns, a sort is used to find the most specific match. A pattern with a lower count of URI variables and wild cards is considered more specific. Итак, в вашем случае ваше приложение ведет себя так, как ожидалось.   -  person fps    schedule 16.01.2015
comment
@Magnamag, как написано выше, даже если сопоставление подстановочных знаков отключено, шаблон не будет сопоставлен.   -  person Noctem    schedule 16.01.2015
comment
@ user3679981 Вам просто не хватает / (тире) в конце xyz в @RequestMapping контроллера.   -  person fps    schedule 16.01.2015
comment
(я имел в виду косую черту, а не тире :)   -  person fps    schedule 16.01.2015
comment
@Magnamag Спасибо за подсказку. Я отредактировал это в коде, но он все еще не работает.   -  person Noctem    schedule 16.01.2015
comment
@Noctem какова точная подпись метода?   -  person fps    schedule 16.01.2015
comment
@Magnamag Я отредактировал свой пост с полной подписью метода   -  person Noctem    schedule 16.01.2015


Ответы (5)


Это может быть ошибка (исправлена ​​в Spring 4.1): проверьте SPR-6741.

Как описано в проблеме, у вас есть в том же контроллере:

  • отображение с 3 переменными пути
  • «запасное» сопоставление /**
person Brian Clozel    schedule 17.01.2015

Попробуй это. Не забудьте ("lang") в объявлении переменной пути в параметре вашего метода.

@RequestMapping(value = "/{lang}/{count}/{term}", method=RequestMethod.GET)
public ResponseEntity<?> getSomething(@PathVariable("lang") String lang, @PathVariable("count") String count, @PathVariable("term") String term) {
person Susie    schedule 16.01.2015
comment
Можете ли вы объяснить, почему это хорошая идея, и в чем существенная разница с тем, что уже делает ОП? Вы хотите сказать, что язык как-то не подходит для переменной пути? - person Erwin Bolwidt; 16.01.2015

Прежде всего, вам не хватает / (косая черта) в конце xyz в @RequestMapping контроллера (или / в начале каждого метода @RequestMapping). Это основная причина того, что ваш метод с тремя переменными пути никогда не вызывается.

@RequestMapping(value = "{language}/{country}/{term}/catalogue", method = RequestMethod.GET)

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

Когда URL-адрес соответствует нескольким шаблонам, используется сортировка для поиска наиболее точного совпадения.

Шаблон с меньшим количеством переменных URI и подстановочных знаков считается более конкретным.

Это означает, что когда вы включаете сопоставление с подстановочными знаками, даже если вы добавили / в конце @RequestMapping вашего контроллера, ваш метод переменной с тремя путями не будет вызываться, потому что метод с подстановочными знаками считается Spring более конкретным.

Пожалуйста, проверьте все @RequestMapping на наличие отсутствующих косых черт. Я советую вам всегда начинать с косой черты, так будет легче различать сопоставления URL-адресов в вашем коде.

person fps    schedule 16.01.2015

Просто поместите это в свой код, это будет хорошо работать:

@GetMapping(value = "{language}/{country}/{term}/catalogue",produces = {"application/json"})
public @ResponseBody String test(@PathVariable String language,@PathVariable String country,@PathVariable String term) {

        return language+"\t"+country+"\t"+term
    }

Вы должны передать: http://localhost:8080/api/Fran%C3%A7ais/France/fr/catalogue

person Abdellah Abair    schedule 10.05.2020

Попробуй это:

@RequestMapping(value = "/{lang}/{count}/{term}", method=RequestMethod.GET)
public ResponseEntity<?> getSomething(@PathVariable("lang") String lang, @PathVariable("count") String count, @PathVariable("term") String term) {
   // Your code goes here.
}
person AJEET SINGH    schedule 17.12.2016