Spring MVC @PathVariable被截断了

时间:2010-08-19 21:44:56

标签: java spring rest spring-mvc get

我有一个控制器,提供对信息的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 个答案:

答案 0 :(得分:144)

尝试@RequestMapping参数的正则表达式:

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

答案 1 :(得分:55)

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

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

答案 2 :(得分:29)

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 project issue

如果你想保持扩展管理,从Spring 3.2开始,你也可以设置RequestMappingHandlerMapping bean的useRegisteredSuffixPatternMatch属性,以保持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)(参见https://jira.springsource.org/browse/SPR-7632)。

因此,您仍然必须覆盖所有mvc:annotation驱动的配置。我打开了一张Spring的票,要求自定义RequestMappingHandlerMapping:https://jira.springsource.org/browse/SPR-11253。如果您有兴趣,请投票。

在覆盖时,请注意自定义执行管理覆盖。否则,所有自定义异常映射都将失败。您必须将messageCoverters与list 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/fileshttps://github.com/resthub/resthub-spring-stack/issues/217

答案 3 :(得分: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>

现在,您的@PathVariable blahName(以及其他所有其他内容)应包含全名,包括所有点。

编辑:这是link to the spring api

答案 4 :(得分:7)

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

  

请注意包含“.xxx”后缀或以“/”结尾的路径   在任何情况下都不会使用默认后缀模式进行转换。

我尝试在我的RESTful URL中添加“/ end”,问题就消失了。我不满意解决方案,但确实有效。

顺便说一下,我不知道Spring设计师在添加这个“功能”时会想到什么,然后默认打开它。恕我直言,它应该被删除。

答案 5 :(得分:7)

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

答案 6 :(得分:4)

我通过这个黑客解决了

1)在@PathVariable中添加了HttpServletRequest,如下所示

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

2)在请求中直接获取URL(在此级别没有截断)

request.getPathInfo() 

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

答案 7 :(得分:3)

我刚刚碰到了这个,这里的解决方案通常不像我预期的那样工作。

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

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

答案 8 :(得分:3)

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

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

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

一切都会好起来的 -

答案 9 :(得分:3)

如果您可以编辑发送请求的地址,那么简单的修复就是向它们添加一个尾部斜杠(以及@RequestMapping值):

/path/{variable}/

所以映射看起来像:

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

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

答案 10 :(得分: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>       

答案 11 :(得分:3)

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

value = {"/username/{id:.+}"}无效

value = "/username/{id:.+}"有效

希望我能帮助某人:]

答案 12 :(得分: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

<强>更新

当我使用上述方法时,我意识到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);
    }
}

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

答案 13 :(得分:2)

如果您确定自己的文字与以下代码中的任何默认扩展名都不匹配,则可以使用

Started by user anonymous
Building in workspace C:\Users\Uday\.jenkins\workspace\MavenProj
FSSCM.checkout D:\FrameworkDemos\MavenHAF to C:\Users\Uday\.jenkins\workspace\MavenProj
FSSCM.check completed in 62 milliseconds
Parsing POMs
Discovered a new module MavenWebHAF:MavenWebHAF MavenWebHAF
Modules changed, recalculating dependency graph
[MavenProj] $ "C:\Program Files\Java\jdk1.8.0_60/bin/java" -cp C:\Users\Uday\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-agent-1.5.jar;E:\Softwares\apache-maven-3.3.3\boot\plexus-classworlds-2.5.2.jar;E:\Softwares\apache-maven-3.3.3/conf/logging jenkins.maven3.agent.Maven31Main E:\Softwares\apache-maven-3.3.3 C:\Users\Uday\.jenkins\war\WEB-INF\lib\remoting-2.52.jar C:\Users\Uday\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven31-interceptor-1.5.jar C:\Users\Uday\.jenkins\plugins\maven-plugin\WEB-INF\lib\maven3-interceptor-commons-1.5.jar 52877
<===[JENKINS REMOTING CAPACITY]===>channel started

Executing Maven:  -B -f C:\Users\Uday\.jenkins\workspace\MavenProj\pom.xml test -Dtest=TestSuite.TestAutomationDriver

[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for MavenWebHAF:MavenWebHAF:jar:0.0.1-SNAPSHOT
[WARNING] 'dependencies.dependency.systemPath' for com.relevantcodes:extentreports:jar should use a variable instead of a hard-coded path E:\Programming Samples\Selenium Jars\extentreports_Updated.jar @ line 33, column 21
[WARNING] 'dependencies.dependency.systemPath' for org.monte:media:jar should use a variable instead of a hard-coded path E:\Programming Samples\Selenium Jars\MonteScreenRecorder.jar @ line 40, column 21
[WARNING] 'dependencies.dependency.systemPath' for com.sun:tools:jar should use a variable instead of a hard-coded path C:\Program Files\Java\jdk1.8.0_60\lib\tools.jar @ line 52, column 29
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING] 
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building MavenWebHAF 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------

[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ MavenWebHAF ---

[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\Users\Uday\.jenkins\workspace\MavenProj\src\main\resources

[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ MavenWebHAF ---

[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ MavenWebHAF ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\Users\Uday\.jenkins\workspace\MavenProj\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ MavenWebHAF ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 7 source files to C:\Users\Uday\.jenkins\workspace\MavenProj\target\test-classes

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /C:/Users/Uday/.jenkins/workspace/MavenProj/src/test/java/FrameworkLibraries/FunctionLibraries/CommonFunctionLibrary.java:[244,39] strings in switch are not supported in -source 1.5
  (use -source 7 or higher to enable strings in switch)
[ERROR] /C:/Users/Uday/.jenkins/workspace/MavenProj/src/test/java/FrameworkLibraries/FunctionLibraries/CommonFunctionLibrary.java:[287,39] strings in switch are not supported in -source 1.5
  (use -source 7 or higher to enable strings in switch)
[INFO] 2 errors 
[INFO] -------------------------------------------------------------

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17.643 s
[INFO] Finished at: 2015-09-29T23:47:29+05:30
[INFO] Final Memory: 24M/273M
[INFO] ------------------------------------------------------------------------

Waiting for Jenkins to finish collecting data
[JENKINS] Archiving C:\Users\Uday\.jenkins\workspace\MavenProj\pom.xml to MavenWebHAF/MavenWebHAF/0.0.1-SNAPSHOT/MavenWebHAF-0.0.1-SNAPSHOT.pom
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile (default-testCompile) on project MavenWebHAF: Compilation failure: Compilation failure:
[ERROR] /C:/Users/Uday/.jenkins/workspace/MavenProj/src/test/java/FrameworkLibraries/FunctionLibraries/CommonFunctionLibrary.java:[244,39] strings in switch are not supported in -source 1.5
[ERROR] (use -source 7 or higher to enable strings in switch)
[ERROR] /C:/Users/Uday/.jenkins/workspace/MavenProj/src/test/java/FrameworkLibraries/FunctionLibraries/CommonFunctionLibrary.java:[287,39] strings in switch are not supported in -source 1.5
[ERROR] (use -source 7 or higher to enable strings in switch)
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
channel stopped

Finished: FAILURE

答案 14 :(得分:1)

阻止Spring MVC @PathVariable被截断的优选解决方案是在路径变量的末尾添加尾部斜杠。

例如:

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

因此,请求将如下所示:

http://localhost:8080/api/email/test@test.com/

答案 15 :(得分:0)

您面临的问题是由于 spring 解释了点(。)之后的uri的 last 部分。 作为 文件扩展名 ,例如.json或.xml。因此,当spring尝试解析path变量时,它会在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) {
        // ...  
    }
}

在上面的网址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 导入的默认配置。我们可以通过声明我们自己的 DefaultAnnotationHandlerMapping 来定制Spring MVC配置。 Bean,然后将其 useDefaultSuffixPattern 属性设置为false。 示例:

@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {

    @Bean
    public RequestMappingHandlerMapping 
      requestMappingHandlerMapping() {

        RequestMappingHandlerMapping handlerMapping
          = super.requestMappingHandlerMapping();
        handlerMapping.setUseSuffixPatternMatch(false);
        return handlerMapping;
    }
}

请记住,覆盖此默认配置会影响所有网址。

注意::在这里,我们扩展了WebMvcConfigurationSupport类以覆盖默认方法。通过实现WebMvcConfigurer接口,还有另一种方法来覆盖默认配置。 有关更多信息,请阅读:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html