Spring MVC @PathVariable становится усеченным - PullRequest
132 голосов
/ 20 августа 2010

У меня есть контроллер, который обеспечивает RESTful доступ к информации:

@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
public ModelAndView getBlah(@PathVariable String blahName, HttpServletRequest request,
                            HttpServletResponse response) {

Проблема, с которой я сталкиваюсь, заключается в том, что, если я попадаю на сервер с переменной пути специальными символами, он усекается.Например: http://localhost:8080/blah-server/blah/get/blah2010.08.19-02:25:47

Параметр blahName будет blah2010.08

Однако вызов request.getRequestURI () содержит всю передаваемую информацию.

ЛюбойИдея, как запретить Spring усекать @PathVariable?

Ответы [ 16 ]

144 голосов
/ 20 августа 2010

Попробуйте использовать регулярное выражение для аргумента @RequestMapping:

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")
55 голосов
/ 20 августа 2010

Это, вероятно, тесно связано с SPR-6164 .Вкратце, фреймворк пытается применить некоторые смарты к интерпретации URI, удаляя то, что считает расширениями файлов.Это может привести к превращению blah2010.08.19-02:25:47 в blah2010.08, поскольку он считает, что .19-02:25:47 является расширением файла.

Как описано в связанной проблеме, вы можете отключить это поведение, объявив свой собственный DefaultAnnotationHandlerMapping bean в контексте приложения и установив для его свойства useDefaultSuffixPattern значение false.Это переопределит поведение по умолчанию и прекратит приставать к вашим данным.

29 голосов
/ 23 декабря 2013

Spring считает, что все, что находится за последней точкой, является расширением файла, например .json или .xml, и усекает его для получения вашего параметра.

Так что если у вас есть /{blahName}:

  • /param, /param.json, /param.xml или /param.anything приведет к параметру со значением param
  • /param.value.json, /param.value.xml или /param.value.anything приведет кпараметр со значением param.value

Если вы измените отображение на /{blahName:.+}, как предложено, любая точка, включая последнюю, будет считаться частью вашего параметра:

  • /param приведет к параметру со значением param
  • /param.json приведет к параметру со значением param.json
  • /param.xml приведет к параметрусо значением param.xml
  • /param.anything приведет к параметру со значением param.anything
  • /param.value.json приведет к параметру со значением param.value.json
  • ...

Если вам не нужно распознавание расширений, вы можете отключить его, переопределив mvc:annotation-driven automagic:

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useSuffixPatternMatch" value="false"/>
</bean>

Итак, еще раз, если у вас есть /{blahName}:

  • /param, /param.json, /param.xml или /param.anything приведет к параметру со значением param
  • /param.value.json, /param.value.xml или /param.value.anything приведет к параметрусо значением param.value

Примечание: отличие от конфигурации по умолчанию видно только в том случае, если у вас есть сопоставление типа /something.{blahName}.См. Проблема проекта Resthub .

Если вы хотите сохранить управление расширениями, начиная с Spring 3.2, вы также можете установить свойство useRegisteredSuffixPatternMatch компонента RequestMappingHandlerMapping, чтобы сохранить активацию распознавания суффикса Паттерн, но ограниченную зарегистрированным расширением..

Здесь вы определяете только расширения json и xml:

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false"/>
    <property name="favorParameter" value="true"/>
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

Обратите внимание, что mvc: annotation-driven теперь принимает опцию contentNegotiation для предоставления пользовательского компонента, но свойство RequestMappingHandlerMapping должно бытьизменено на true (по умолчанию false) (ср. https://jira.springsource.org/browse/SPR-7632).

По этой причине вам все равно придется переопределить всю конфигурацию, управляемую аннотациями mvc :. Я открыл билет в Spring, чтобы запросить пользовательский RequestMappingHandlerMapping:https://jira.springsource.org/browse/SPR-11253. Пожалуйста, проголосуйте, если вы заинтересованы.

При переопределении, будьте осторожны, чтобы учесть также переопределение пользовательского управления выполнением. В противном случае все ваши пользовательские сопоставления исключений потерпят неудачу. Вам придется повторно использовать messageCoverters со списком bean:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />

<util:list id="messageConverters">
    <bean class="your.custom.message.converter.IfAny"></bean>
    <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>

<bean name="exceptionHandlerExceptionResolver"
      class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
    <property name="order" value="0"/>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean name="handlerAdapter"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="conversionService" ref="conversionService" />
            <property name="validator" ref="validator" />
        </bean>
    </property>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>

Я реализовал в проекте с открытым исходным кодом Resthub , частью которого я являюсь, набор тестов по этим предметам: см. https://github.com/resthub/resthub-spring-stack/pull/219/files и https://github.com/resthub/resthub-spring-stack/issues/217

15 голосов
/ 22 октября 2010

Все после последней точки по умолчанию интерпретируется как расширение файла и обрезается.
В вашей весенней конфигурации xml вы можете добавить DefaultAnnotationHandlerMapping и установить useDefaultSuffixPattern на false (по умолчанию true).

Итак, откройте ваш xml mvc-config.xml пружины (или как он называется) и добавьте

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="useDefaultSuffixPattern" value="false" />
</bean>

Теперь ваш @PathVariable blahName (и все остальные тоже) должен содержатьполное имя, включая все точки.

РЕДАКТИРОВАТЬ: Вот ссылка на пружину API

7 голосов
/ 05 марта 2015

Использование правильного класса конфигурации Java:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter
{

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer)
    {
        configurer.favorPathExtension(false);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer)
    {
        configurer.setUseSuffixPatternMatch(false);
    }
}
7 голосов
/ 06 апреля 2012

Я тоже столкнулся с той же проблемой, и установка свойства в false также мне не помогла.Однако API говорит :

Обратите внимание, что пути, содержащие суффикс ".xxx" или заканчивающиеся на "/", уже не будут преобразованы с использованием шаблона суффикса по умолчанию в любомcase.

Я попытался добавить "/ end" к своему RESTful URL, и проблема исчезла.Мне не нравится решение, но оно сработало.

Кстати, я не знаю, о чем думали дизайнеры Spring, когда добавляли эту «функцию», а затем включали по умолчанию.ИМХО, это надо убрать.

4 голосов
/ 26 февраля 2013

Я решил этот хак

1) Добавлен HttpServletRequest в @PathVariable, как показано ниже

 @PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception { 

2) Получить URL напрямую (на этом уровне без усечения) в запросе

request.getPathInfo() 

Spring MVC @PathVariable с точкой (.) Усекается

3 голосов
/ 15 января 2016

добавление «:. +» Работало для меня, но не до тех пор, пока я не снял внешние фигурные скобки.

value = {"/username/{id:.+}"} не сработало

value = "/username/{id:.+}" работает

Надеюсь, я помог кому-то:]

3 голосов
/ 25 марта 2014
//in your xml dispatcher  add this property to your default annotation mapper bean as follow
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="alwaysUseFullPath" value="true"></property>
</bean>       
3 голосов
/ 28 ноября 2013

Если вы можете отредактировать адрес, на который отправляются запросы, простым исправлением было бы добавить косую черту к ним (а также значение @RequestMapping):

/path/{variable}/

, чтобы сопоставлениевыглядит так:

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")

См. также Spring MVC @PathVariable с точкой (.) усекается .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...