Ответ 1
Попробуйте регулярное выражение для аргумента @RequestMapping
:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")
У меня есть контроллер, который предоставляет 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
. Это приведет к переопределению поведения по умолчанию и прекратит его приставать к вашим данным.
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 bean, чтобы поддерживать распознавание suffixPattern, но ограничивается зарегистрированным расширением.
Здесь вы определяете только расширения 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 для предоставления пользовательского bean, но свойство RequestMappingHandlerMapping должно быть изменено на true (по умолчанию false) (cf. https://jira.springsource.org/browse/SPR-7632).
По этой причине вам все равно придется переопределить всю конфигурацию mvc: annotation. Я открыл билет на Spring, чтобы запросить пользовательскую RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253. Пожалуйста, проголосуйте, если вы заинтересованы.
В то время как переопределение, будьте осторожны, чтобы рассмотреть также настраиваемое управление выполнением Execution. В противном случае все ваши пользовательские сопоставления исключений не удастся. Вам придется повторно использовать 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
Все после последней точки интерпретируется как расширение файла и отключено по умолчанию.
В вашем spring config xml вы можете добавить DefaultAnnotationHandlerMapping
и установить useDefaultSuffixPattern
в false
(по умолчанию - true
).
Итак, откройте свой spring xml mvc-config.xml
(или, тем не менее, он вызывается) и добавьте
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
Теперь ваш @PathVariable
blahName
(и все остальные тоже) должен содержать полное имя, включая все точки.
EDIT: ссылка на spring api
Я также столкнулся с одной и той же проблемой, и установка свойства false также не помогла мне. Однако API говорит:
Обратите внимание, что пути, которые включают суффикс ".xxx", или конец с "/" уже не будет преобразовываться с использованием шаблона суффикса по умолчанию в любом случае.
Я попытался добавить "/end" к моему URL RESTful, и проблема исчезла. Я не рад решению, но это действительно сработало.
Кстати, я не знаю, о чем думали дизайнеры Spring, добавив эту "функцию", а затем включил ее по умолчанию. ИМХО, его следует удалить.
Я разрешил этот хак
1) Добавлен HttpServletRequest в @PathVariable, как показано ниже
@PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception {
2) Получите URL-адрес напрямую (на этом уровне нет усечения) в запросе
request.getPathInfo()
Использование правильного класса конфигурации 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);
}
}
Я просто столкнулся с этим, и решения здесь вообще не работали, как я ожидал.
Я предлагаю использовать выражение SpEL и несколько сопоставлений, например
@RequestMapping(method = RequestMethod.GET,
value = {Routes.BLAH_GET + "/{blahName:.+}",
Routes.BLAH_GET + "/{blahName}/"})
Проблема с расширением файла существует только в том случае, если параметр находится в последней части URL-адреса. Изменить
@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
to
@RequestMapping(
method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/safe")
и все будет хорошо снова -
Если вы можете редактировать адрес, на который отправляются запросы, простым исправлением было бы добавить к ним конечную косую черту (а также значение @RequestMapping
):
/path/{variable}/
поэтому отображение будет выглядеть так:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")
//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;
}
}
UPDATE:
Я понял, что у меня возникли проблемы с Spring автоматической настройкой загрузки, когда я использовал описанный выше подход (некоторая автоматическая настройка не работает).
Вместо этого я начал использовать подход 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/[email protected]/