带有点(.)的Spring MVC @PathVariable被截断了

Kan*_*mar 345 rest spring spring-mvc spring-annotations

这是Spring MVC @PathVariable被截断的问题的延续

Spring论坛声明它已修复(3.2版本)作为ContentNegotiationManager的一部分.见下面的链接.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632

在我的应用程序中,带有.com的requestParameter被截断.

谁能解释我如何使用这个新功能?它是如何在xml中配置的?

注意:spring论坛 - #1带有点(.)的Spring MVC @PathVariable正在被截断

Mar*_*rey 466

据我所知,此问题仅出现在请求映射结束时的path变量上.

我们能够通过在请求映射中定义正则表达式插件来解决这个问题.

 /somepath/{variable:.+}
Run Code Online (Sandbox Code Playgroud)

  • @Mariusz,语法是``variable_name:regular_expression}`,所以这里我们有一个名为`variable`的变量,该值将使用正则表达式匹配.+`(其中`.`表示'任何字符'和`+`表示'一次或多次'). (9认同)
  • @martin`"变量:.+"`当变量中有多个点时不起作用.例如,将电子邮件放在休息路径的末尾,例如`/ path/abc @ server.com.au`.控制器甚至没有被调用,但只有一个点`/ path/abc @ server.com`时它才有效.知道为什么和/或解决方法吗? (9认同)
  • 这是我在Spring 3.0.5中解决问题的方法`<! - Spring配置需要避免使用点截断的URI - > <bean class ="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" > <property name ="useDefaultSuffixPattern"value ="false"/> </ bean>` (4认同)
  • @StefanHaberl如果你以常规的方式匹配`variable`,Spring会使用它的后缀检测功能并在点之后截断所有内容.使用正则表达式匹配时,不使用这些功能 - 变量仅与您提供的正则表达式匹配. (3认同)

小智 236

Spring认为最后一个点后面的任何内容都是一个文件扩展名,例如.jsonor .xml,并将其设置为检索参数.

所以如果你有/somepath/{variable}:

  • /somepath/param,/somepath/param.json,/somepath/param.xml/somepath/param.anything将导致具有值的PARAMparam
  • /somepath/param.value.json,/somepath/param.value.xml/somepath/param.value.anything将导致有价值的参数param.value

如果您/somepath/{variable:.+}按照建议更改映射,则任何点(包括最后一个点)都将被视为参数的一部分:

  • /somepath/param 将导致一个有价值的参数 param
  • /somepath/param.json 将导致一个有价值的参数 param.json
  • /somepath/param.xml 将导致一个有价值的参数 param.xml
  • /somepath/param.anything 将导致一个有价值的参数 param.anything
  • /somepath/param.value.json 将导致一个有价值的参数 param.value.json
  • ...

如果您不关心扩展程序识别,可以通过覆盖mvc:annotation-drivenautomagic 来禁用它:

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useSuffixPatternMatch" value="false"/>
</bean>
Run Code Online (Sandbox Code Playgroud)

所以,如果你有/somepath/{variable}:

  • /somepath/param,/somepath/param.json,/somepath/param.xml/somepath/param.anything将导致具有值的PARAMparam
  • /somepath/param.value.json,/somepath/param.value.xml/somepath/param.value.anything将导致有价值的参数param.value

注意:只有当你有一个映射时,与默认配置的区别才是可见的somepath/something.{variable}.请参阅Resthub项目问题

如果你想保持扩展管理,从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>
Run Code Online (Sandbox Code Playgroud)

请注意,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>
Run Code Online (Sandbox Code Playgroud)

我实现了,在开源项目Resthub,我的,一组关于这些问题的测试部分:看https://github.com/resthub/resthub-spring-stack/pull/219/fileshttps://开头github.com/resthub/resthub-spring-stack/issues/217


Dav*_*yer 93

Spring 4的更新:从4.0.1开始,您可以使用PathMatchConfigurer(通过您的WebMvcConfigurer),例如

@Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {

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

}
Run Code Online (Sandbox Code Playgroud)

在xml中,它将是(https://jira.spring.io/browse/SPR-10163):

<mvc:annotation-driven>
    [...]
    <mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>
Run Code Online (Sandbox Code Playgroud)

  • 这是迄今为止最干净的解决方案:关闭导致它的功能,而不是黑客攻击它.我们还没有使用这个功能,所以问题解决了 - 完美! (11认同)
  • 使用`matcher.setUseSuffixPatternMatch(false)`来完全禁用后缀匹配. (5认同)

Mic*_*bak 85

除了Martin Frey的回答之外,还可以通过在RequestMapping值中添加尾部斜杠来解决此问题:

/path/{variable}/
Run Code Online (Sandbox Code Playgroud)

请记住,此修复程序不支持可维护性.它现在要求所有URI都有一个尾部斜杠 - 这对API用户/新开发人员来说可能并不明显.因为可能并非所有参数都包含.在其中,所以它也可能会产生间歇性错误

  • 但它与AngularJS的默认行为相冲突,以自动删除尾部斜杠.这可以在最新的Angular版本中进行配置,但如果你不知道发生了什么,它可以追踪几个小时. (7认同)
  • 这甚至是更清洁的解决方案.我必须找出IE根据后缀设置接受标头的困难方式.所以我想发布一些.doc请求映射,我总是下载而不是新的html页面.这种方法解决了这一点 (2认同)

Gou*_*amS 30

在Spring Boot Rest Controller中,我通过以下步骤解决了这些问题:

RestController:

@GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(@PathVariable(value = "email") String email){
  //code
}
Run Code Online (Sandbox Code Playgroud)

来自Rest客户:

Get http://mywebhook.com/statusByEmail/abc.test@gmail.com/
Run Code Online (Sandbox Code Playgroud)

  • 这个答案取决于尾部斜杠以便工作. (2认同)
  • 就像一个魅力(也没有尾随斜杠)。谢谢! (2认同)

Mar*_*jka 26

添加":.+"为我工作,但直到我删除外部花括号.

value = { "/ username/{ id:.+}" } 无法正常工作

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

希望我能帮助别人:)


小智 15

/somepath/{variable:.+}适用于Java requestMapping标记.

  • @8bitjunkie 像 `"/{code:.+}"` 适用于许多点,而不是一个,即 `61.12.7`,它也适用于 `kap@oin` (2认同)

Bru*_*ier 13

这是一种纯粹依赖于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 MvcConfig extends WebMvcConfigurationSupport{

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
        handlerMapping.setUseSuffixPatternMatch(false);
        handlerMapping.setUseTrailingSlashMatch(false);
        return handlerMapping;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 10

解决这个问题的一个非常简单的方法是附加一个尾部斜杠......

例如:

使用 :

/somepath/filename.jpg/
Run Code Online (Sandbox Code Playgroud)

代替:

/somepath/filename.jpg
Run Code Online (Sandbox Code Playgroud)


Dap*_*Dan 10

在Spring Boot中,正则表达式解决了这个问题

@GetMapping("/path/{param1:.+}")
Run Code Online (Sandbox Code Playgroud)


小智 6

包含弹簧4.2路径名中的电子邮件地址的完整解决方案是

<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
    content-negotiation-manager="contentNegotiationManager">
    <mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" />
</mvc:annotation-driven>
Run Code Online (Sandbox Code Playgroud)

将其添加到application-xml


Juk*_*kka 5

如果您使用的是Spring 3.2.x和<mvc:annotation-driven />,请创建以下代码BeanPostProcessor

package spring;

public final class DoNotTruncateMyUrls implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof RequestMappingHandlerMapping) {
            ((RequestMappingHandlerMapping)bean).setUseSuffixPatternMatch(false);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其放在您的MVC配置xml中:

<bean class="spring.DoNotTruncateMyUrls" />
Run Code Online (Sandbox Code Playgroud)

  • 这很旧,但是您实际上不需要`BeanPostProcessor`。如果您使用WebMvcConfigurationSupport,则可以重写@Bean的requestMappingHandlerMapping方法。如果使用XML配置,则可以声明自己的`RequestMappingHandlerMapping` bean并声明该属性。 (2认同)

rog*_*ack 5

对我来说

@GetMapping(path = "/a/{variableName:.+}")
Run Code Online (Sandbox Code Playgroud)

确实有效,但仅当您还将请求 url 中的“点”编码为“%2E”时,它才有效。但要求 URL 全部为...虽然有效,但它不是“标准”编码。感觉像个错误:|

另一种解决方法,类似于“尾部斜杠”方式是移动将具有点“内联”例如的变量:

@GetMapping(path = "/{变量名}/a")

现在所有的点都将被保留,不需要修改。


lub*_*nac 5

最后我在Spring Docs 中找到了解决方案:

要完全禁用文件扩展名,您必须设置以下两项:

 useSuffixPatternMatching(false), see PathMatchConfigurer

 favorPathExtension(false), see ContentNegotiationConfigurer
Run Code Online (Sandbox Code Playgroud)

将此添加到我的WebMvcConfigurerAdapter实现中解决了问题:

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

@Override
public void configurePathMatch(PathMatchConfigurer matcher) {
    matcher.setUseSuffixPatternMatch(false);
}
Run Code Online (Sandbox Code Playgroud)