2010-08-19 107 views
124

我有一个控制器,提供信息的RESTful访问:Spring MVC的@PathVariable越来越截断

@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()包含在传递的所有信息

不知道如何预防春季从截断。 @PathVariable?

+0

看来这已经在Spring解决了3.2-M2:参见[允许内容协商有效的文件扩展名的路径(https://jira.springsource.org/browse/SPR-7632)和[其文件](http://static.springsource.org/spring/docs/3.2.0.M2/reference/htmlsingle) /#MVC-配置内容协商)。 – Arjan 2012-10-17 19:59:40

回答

137

拉升@RequestMapping争论正则表达式:

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

感谢您的回答,这帮助我解决了用户名被修剪的情况。( - : 'useDefaultSuffixPattern'的其他选项不是一个选项,因为我们使用的是@Configuration弹簧类而不是XML。 – evandongen 2011-10-20 13:46:10

+3

这可以工作,但冒号在正则表达式中的意义是什么? – 2012-11-02 17:43:35

+6

Noah, t很久以前就用过了,但我认为冒号将正则表达式与参数名称分开来绑定它。 – earldouglas 2012-11-02 18:18:57

54

这可能是密切相关的SPR-6164。简而言之,框架试图将一些智能应用于URI解释,去除它认为是文件扩展名的东西。这可能会将blah2010.08.19-02:25:47转换为blah2010.08,因为它认为.19-02:25:47是文件扩展名。

如链接问题中所述,您可以通过在应用上下文中声明自己的DefaultAnnotationHandlerMapping bean并将其useDefaultSuffixPattern属性设置为false来禁用此行为。这将覆盖默认行为,并停止它骚扰您的数据。

+2

默认情况下打开基于扩展的内容协商似乎是一个很奇怪的选择。有多少系统在实践中真正以不同的格式显示相同的资源? – Affe 2010-08-19 23:23:10

+0

我早上试过这个,仍然有截断路径变量。 – phogel 2010-08-20 14:55:21

+1

这对我有类似的问题。谢谢,skaffman。 – AHungerArtist 2010-10-18 16:44:07

15

最后一个点之后的所有内容都被解释为文件扩展名并在默认情况下被截断。
在您的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> 

现在你@PathVariableblahName(和所有其他的,太)应包含全名,包括所有的点。

编辑:这里是一个link to the spring api

+0

我还没有尝试,但[其他人声称](http://stackoverflow.com/questions/4135329/how-to-change-spring-mvcs-behavior-in-handling-url-dot-character/11141184#11141184)如果适用,您还需要删除''。 – Arjan 2012-10-17 18:05:36

3

我只是碰到了这个和解决方案,在这里一般不工作,我的预期。

我建议使用SpEL表达式和多个映射,例如

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

我也遇到了同样的问题,并将属性设置为false也没有帮助我。然而,the API says

注意,路径,其包括一个“.XXX”后缀或结尾‘/’已经 将不使用在任何情况下的默认后缀模式进行转化。

我尝试在我的RESTful URL中添加“/ end”,问题就消失了。我不喜欢这个解决方案,但它确实有效。顺便说一下,我不知道Spring设计者在添加这个“功能”时想到了什么,然后默认打开它。恕我直言,它应该被删除。

+0

我同意。我最近被这个比较了一点。 – llambda 2014-09-09 23:16:57

4

我这个黑客

1)增加的HttpServletRequest在@PathVariable像下面

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

2)直接将URL(在Request这个级别没有截断)解决

request.getPathInfo() 

Spring MVC @PathVariable with dot (.) is getting truncated

3

仅当参数位于URL的最后部分时才存在文件扩展名问题。更改

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

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

和一切都会好起来再次 -

3

如果您可以编辑请求发送到该地址,简单的解决将是一个加上尾部斜杠他们(以及在@RequestMapping值):

/path/{variable}/ 

这样的映射将如下所示:

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

另请参阅Spring MVC @PathVariable with dot (.) is getting truncated

27

Spring认为最后一个点后面的任何内容都是文件扩展名,例如.json.xml,并截断它以检索您的参数。

所以,如果你有/{blahName}

  • /param/param.json/param.xml/param.anything将导致PARAM值为param
  • /param.value.json/param.value.xml/param.value.anything将导致PARAM值为param.value

如果您将映射更改为/{blahName:.+}的建议,任何点,包括最后一个,将被视为您参数的一部分:

  • /param将导致与价值设置了一个param param
  • /param.json将导致PARAM值为param.json
  • /param.xml将产生具有值的PARAM param.xml
  • /param.anything将导致与PARAM值param.anything
  • /param.value.json将导致与价值param.value.json
  • 设置了一个param ...

如果你不在乎扩展的认可,你可以通过重写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
  • /param.value.json/param.value.xml/param.value.anything会导致与价值设置了一个param param.value

注:从默认的配置不同的是仅可见,如果你有一个映射如/something.{blahName}。见Resthub project issue

如果您想保留扩展管理,自Spring 3.2以来,您还可以设置RequestMappingHandlerMapping bean的useRegisteredSuffixPatternMatch属性,以保持后缀模式识别已激活但仅限于已注册的扩展名。

在这里,你只定义了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选项提供自定义的bean,但RequestMappingHandlerMapping的财产已被更改为true(默认假)(参见https://jira.springsource.org/browse/SPR-7632)。

因此,您仍然必须覆盖所有mvc:注释驱动的配置。我打开了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/fileshttps://github.com/resthub/resthub-spring-stack/issues/217

3
//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>  
2

基于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; 
    } 
} 

Source: http://www.javacodegeeks.com/2013/01/spring-mvc-customizing-requestmappinghandlermapping.html

UPDATE:

我实现具有同春开机自动配置的一些问题,当我使用上述(一些自动配置并没有得到有效的)的办法。

取而代之,我开始使用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); 
    } 
} 

Inspired from: http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html

4

使用正确的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); 
    } 
} 
2

,如果你确信你的文本将不会匹配任何默认的功能扩展,你可以使用下面的代码:

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void configurePathMatch(PathMatchConfigurer configurer) { 
     configurer.setUseRegisteredSuffixPatternMatch(true); 
    } 
} 
3

添加“:。+”为我工作,但直到我删除ou大花括号。

value = {"/username/{id:.+}"}没有工作

value = "/username/{id:.+}"工作

希望我帮助别人:]

+0

这解决了我的问题,谢谢。 – demdem 2016-06-17 06:58:55

1

我最好的解决方案,以防止Spring MVC的@PathVariable获得截断是在末尾添加斜线的路径变量。

例如:

@RequestMapping(value ="/email/{email}/") 

因此,请求将是这样的:

http://localhost:8080/api/email/[email protected]/