У меня есть контроллер, обеспечивающий 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?
Ответы:
Попробуйте использовать регулярное выражение для
@RequestMapping
аргумента:RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")
источник
Вероятно, это тесно связано с SPR-6164 . Вкратце, фреймворк пытается применить некоторые хитрости к интерпретации URI, удаляя то, что он считает расширениями файлов. Это приведет к превращению
blah2010.08.19-02:25:47
вblah2010.08
, поскольку он думает, что.19-02:25:47
это расширение файла.Как описано в связанной проблеме, вы можете отключить это поведение, объявив свой собственный
DefaultAnnotationHandlerMapping
bean-компонент в контексте приложения и установив для егоuseDefaultSuffixPattern
свойства значениеfalse
. Это переопределит поведение по умолчанию и предотвратит нарушение ваших данных.источник
RequestMappingHandlerMapping
вместо этого вы используете новый , устанавливаемое свойствоuseSuffixPatternMatch
(такжеfalse
). @Ted: в связанной проблеме упоминается, что в 3.2 они надеются добавить немного больше контроля, чтобы не было все или ничего.WebMvcConfigurationSupport
которые предоставляют простой крючок:public void configurePathMatch(PathMatchConfigurer configurer)
- просто переопределите это и настройте путь, соответствующий вашему желанию.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
автоматическую магию:<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 bean-компонента 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: с управлением аннотациями теперь принимает параметр contentNegotiation для предоставления настраиваемого компонента, но свойство RequestMappingHandlerMapping должно быть изменено на true (по умолчанию false) (см. Https://jira.springsource.org/browse/SPR-7632 ).
По этой причине вам все равно придется переопределить всю конфигурацию, управляемую mvc: annotation. Я открыл билет в Spring, чтобы попросить пользовательский RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253 . Пожалуйста, проголосуйте, если вам интересно.
При переопределении не забудьте также рассмотреть возможность переопределения настраиваемого управления выполнением. В противном случае все ваши настраиваемые сопоставления исключений завершатся ошибкой. Вам придется повторно использовать messageCoverters со списковым компонентом:
<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
источник
Все, что находится после последней точки, интерпретируется как расширение файла и по умолчанию обрезается.
В вашей весне конфигурации 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
(как и все остальные) должно содержать полное имя, включая все точки.EDIT: вот ссылка на весенний api
источник
<mvc:annotation-driven />
если это возможно.Я также столкнулся с той же проблемой, и установка свойства на false мне тоже не помогла. Однако API говорит :
Я попытался добавить «/ end» к моему URL-адресу RESTful, и проблема исчезла. Я не доволен решением, но оно сработало.
Кстати, я не знаю, о чем думали дизайнеры Spring, когда добавляли эту «функцию», а затем включали ее по умолчанию. ИМХО, его надо удалить.
источник
Используя правильный класс конфигурации 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); } }
источник
Я решил этим взломом
1) Добавлен HttpServletRequest в @PathVariable, как показано ниже
@PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception {
2) Получить URL напрямую (на этом уровне без усечения) в запросе
Spring MVC @PathVariable с точкой (.) Усекается
источник
Я только что столкнулся с этим, и решения здесь в целом не работали, как я ожидал.
Я предлагаю использовать выражение SpEL и несколько сопоставлений, например
@RequestMapping(method = RequestMethod.GET, value = {Routes.BLAH_GET + "/{blahName:.+}", Routes.BLAH_GET + "/{blahName}/"})
источник
Проблема с расширением файла существует, только если параметр находится в последней части URL-адреса. + Изменить
@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
к
@RequestMapping( method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/safe")
И снова все будет хорошо -
источник
Если вы можете редактировать адрес, на который отправляются запросы, простым исправлением будет добавление к ним завершающей косой черты (а также в
@RequestMapping
значении):поэтому отображение будет выглядеть так:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")
См. Также Spring MVC @PathVariable с точкой (.) Усекается .
источник
//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>
источник
добавление ":. +" сработало для меня, но только после того, как я удалил внешние фигурные скобки.
value = {"/username/{id:.+}"}
не сработалоvalue = "/username/{id:.+}"
работаетНадеюсь, я кому-то помог:]
источник
Решение для конфигурации на основе Java для предотвращения усечения (с использованием нерекомендуемого класса):
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @Configuration public class PolRepWebConfig extends WebMvcConfigurationSupport { @Override @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { final RequestMappingHandlerMapping handlerMapping = super .requestMappingHandlerMapping(); // disable the truncation after . handlerMapping.setUseSuffixPatternMatch(false); // disable the truncation after ; handlerMapping.setRemoveSemicolonContent(false); return handlerMapping; } }
Источник: http://www.javacodegeeks.com/2013/01/spring-mvc-customizing-requestmappinghandlermapping.html
ОБНОВИТЬ:
Я понял, что у меня есть некоторые проблемы с автоконфигурацией Spring Boot, когда я использовал подход, описанный выше (некоторые автоконфигурации не работают).
Вместо этого я начал использовать этот
BeanPostProcessor
подход. Вроде получилось лучше.import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { private static final Logger logger = LoggerFactory .getLogger(MyBeanPostProcessor.class); @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof RequestMappingHandlerMapping) { setRemoveSemicolonContent((RequestMappingHandlerMapping) bean, beanName); setUseSuffixPatternMatch((RequestMappingHandlerMapping) bean, beanName); } return bean; } private void setRemoveSemicolonContent( RequestMappingHandlerMapping requestMappingHandlerMapping, String beanName) { logger.info( "Setting 'RemoveSemicolonContent' on 'RequestMappingHandlerMapping'-bean to false. Bean name: {}", beanName); requestMappingHandlerMapping.setRemoveSemicolonContent(false); } private void setUseSuffixPatternMatch( RequestMappingHandlerMapping requestMappingHandlerMapping, String beanName) { logger.info( "Setting 'UseSuffixPatternMatch' on 'RequestMappingHandlerMapping'-bean to false. Bean name: {}", beanName); requestMappingHandlerMapping.setUseSuffixPatternMatch(false); } }
На основе: http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html
источник
если вы уверены, что ваш текст не будет соответствовать ни одному из расширений по умолчанию, вы можете использовать следующий код:
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configurePathMatch(PathMatchConfigurer configurer) { configurer.setUseRegisteredSuffixPatternMatch(true); } }
источник
Моим предпочтительным решением для предотвращения усечения Spring MVC @PathVariable является добавление завершающей косой черты в конце переменной пути.
Например:
@RequestMapping(value ="/email/{email}/")
Итак, запрос будет выглядеть так:
http://localhost:8080/api/email/test@test.com/
источник
Проблема , с которой вы столкнулись из - за весны интерпретирования последней части Ури после с точки (.) В качестве расширения файла , как .json или .xml. Поэтому, когда spring пытается разрешить переменную пути, он просто обрезает остальные данные после того, как встречает точку (.) В конце uri. Примечание: также это происходит, только если вы сохраняете переменную пути в конце uri.
Например, рассмотрим uri: https: //localhost/example/gallery.df/link.ar
@RestController public class CustomController { @GetMapping("/example/{firstValue}/{secondValue}") public void example(@PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { // ... } }
В указанном выше URL firstValue = "gallery.df" и secondValue = "link" последний бит после. усекается при интерпретации переменной пути.
Итак, предотвратить это можно двумя способами:
1.) Использование отображения регулярного выражения
Используйте регулярное выражение в конце сопоставления
@GetMapping("/example/{firstValue}/{secondValue:.+}") public void example( @PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { //... }
Используя +, мы указываем, что любое значение после точки также будет частью переменной пути.
2.) Добавление косой черты в конце нашей @PathVariable
@GetMapping("/example/{firstValue}/{secondValue}/") public void example( @PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { //... }
Это закроет нашу вторую переменную, защищающую ее от поведения Spring по умолчанию.
3) Путем переопределения конфигурации Spring по умолчанию webmvc
Spring предоставляет способы переопределить конфигурации по умолчанию, которые импортируются с помощью аннотаций @EnableWebMvc. Мы можем настроить конфигурацию Spring MVC, объявив наш собственный bean- компонент DefaultAnnotationHandlerMapping в контексте приложения и установив для его свойства useDefaultSuffixPattern значение false. Пример:
@Configuration public class CustomWebConfiguration extends WebMvcConfigurationSupport { @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping(); handlerMapping.setUseSuffixPatternMatch(false); return handlerMapping; } }
Имейте в виду, что переопределение этой конфигурации по умолчанию влияет на все URL-адреса.
Примечание: здесь мы расширяем класс WebMvcConfigurationSupport, чтобы переопределить методы по умолчанию. Есть еще один способ переопределить конфигурации по умолчанию, реализовав интерфейс WebMvcConfigurer. Подробнее об этом читайте: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html
источник