389

This is continuation of question Spring MVC @PathVariable getting truncated

Spring forum states that it has fixed(3.2 version) as part of ContentNegotiationManager. see the below link.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632

In my application requestParameter with .com is truncated.

Could anyone explain me how to use this new feature? how is it configurable at xml?

Note: spring forum- #1 Spring MVC @PathVariable with dot (.) is getting truncated

4

18 回答 18

506

据我所知,此问题仅出现在请求映射末尾的路径变量中。

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

 /somepath/{variable:.+}
于 2013-05-02T08:04:29.033 回答
251

Spring 认为最后一个点后面的任何内容都是文件扩展名,例如.jsonor.xml并对其进行 trucate 以检索您的参数。

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

  • /somepath/param, /somepath/param.json, /somepath/param.xmlor/somepath/param.anything将产生一个带值的参数param
  • /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>

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

  • /somepath/param, /somepath/param.json, /somepath/param.xmlor/somepath/param.anything将产生一个带值的参数param
  • /somepath/param.value.json,/somepath/param.value.xml或者/somepath/param.value.anything会产生一个带值的参数param.value

注意:与默认配置的差异只有在您有类似somepath/something.{variable}. 请参阅Resthub 项目问题

如果要保持扩展管理,从 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-driven 配置。我向 Spring 开了一张票,要求提供自定义 RequestMappingHandlerMapping :https ://jira.springsource.org/browse/SPR-11253 。如果您有兴趣,请投票。

在覆盖时,要小心考虑自定义执行管理覆盖。否则,您的所有自定义异常映射都将失败。您将不得不重用带有列表 bean 的 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

于 2013-12-23T12:48:06.620 回答
97

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

@Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {

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

}


@Configuration
public class WebConfig implements WebMvcConfigurer {

   @Override
   public void configurePathMatch(PathMatchConfigurer configurer) {
       configurer.setUseSuffixPatternMatch(false);
   }
}

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

<mvc:annotation-driven>
    [...]
    <mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>
于 2014-05-29T17:03:01.120 回答
88

除了 Martin Frey 的回答,这也可以通过在 RequestMapping 值中添加斜杠来解决:

/path/{variable}/

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

于 2013-08-22T11:11:50.993 回答
36

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

休息控制器:

@GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(@PathVariable(value = "email") String email){
  //code
}

从休息客户端:

Get http://mywebhook.com/statusByEmail/abc.test@gmail.com/
于 2017-11-03T07:13:18.067 回答
27

添加“:。+”对我有用,但直到我删除了外大括号。

value = { "/username/{id:.+}" } 没用

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

希望我帮助了某人:)

于 2016-01-15T11:58:56.073 回答
16

/somepath/{variable:.+}在 JavarequestMapping标记中工作。

于 2015-12-30T17:17:54.517 回答
15

这是一种完全依赖于 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;
    }
}
于 2016-05-14T10:56:13.400 回答
12

解决此问题的一种非常简单的方法是附加斜杠...

例如:

利用 :

/somepath/filename.jpg/

代替:

/somepath/filename.jpg
于 2015-10-07T17:50:04.057 回答
11

在 Spring Boot 中,正则表达式解决了类似的问题

@GetMapping("/path/{param1:.+}")
于 2017-09-05T13:57:12.943 回答
6

spring 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>

将此添加到 application-xml

于 2016-01-03T02:32:01.880 回答
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;
    }
}

然后把它放在你的 MVC 配置 xml 中:

<bean class="spring.DoNotTruncateMyUrls" />
于 2013-05-29T18:38:16.987 回答
5

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

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

 useSuffixPatternMatching(false), see PathMatchConfigurer

 favorPathExtension(false), see ContentNegotiationConfigurer

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

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

@Override
public void configurePathMatch(PathMatchConfigurer matcher) {
    matcher.setUseSuffixPatternMatch(false);
}
于 2018-10-26T12:02:23.720 回答
5

对我来说

@GetMapping(path = "/a/{variableName:.+}")

确实有效,但前提是您还将请求 url 中的“点”编码为“%2E”,然后它才有效。但是要求所有的 URL 都是……这不是“标准”编码,尽管有效。感觉像是一个错误:|

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

@GetMapping(path = "/{variableName}/a")

现在所有点都将被保留,无需修改。

于 2018-09-20T22:16:33.987 回答
3

If you write both back and frontend, another simple solution is to attach a "/" at the end of the URL at front. If so, you don't need to change your backend...

somepath/myemail@gmail.com/

Be happy!

于 2020-10-27T18:52:55.033 回答
3

从 Spring 5.2.4 (Spring Boot v2.2.6.RELEASE) 开始PathMatchConfigurer.setUseSuffixPatternMatchContentNegotiationConfigurer.favorPathExtension已被弃用 ( https://spring.io/blog/2020/03/24/spring-framework-5-2-5-available-nowhttps://github.com/spring-projects/spring-framework/issues/24179)。

真正的问题是客户端请求特定的媒体类型(如 .com),而 Spring 默认添加了所有这些媒体类型。在大多数情况下,您的 REST 控制器只会生成 JSON,因此它不支持请求的输出格式 (.com)。为了克服这个问题,你应该通过更新你的休息控制器(或特定方法)来支持“输出”格式(@RequestMapping(produces = MediaType.ALL_VALUE))并且当然允许像点({username:.+})这样的字符。

例子:

@RequestMapping(value = USERNAME, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class UsernameAPI {

    private final UsernameService service;

    @GetMapping(value = "/{username:.+}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.ALL_VALUE)
    public ResponseEntity isUsernameAlreadyInUse(@PathVariable(value = "username") @Valid @Size(max = 255) String username) {
        log.debug("Check if username already exists");
        if (service.doesUsernameExist(username)) {
            return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
        }
        return ResponseEntity.notFound().build();
    }
}

Spring 5.3 及更高版本将仅匹配已注册的后缀(媒体类型)。

于 2020-04-03T15:48:26.690 回答
0

简单的解决方案修复:在 @RequestMapping 中添加正则表达式 {q:.+}

@RequestMapping("medici/james/Site")
public class WebSiteController {

    @RequestMapping(value = "/{site:.+}", method = RequestMethod.GET)
    public ModelAndView display(@PathVariable("site") String site) {
        return getModelAndView(site, "web site");

    }
}

现在,对于输入 /site/jamesmedice.com,“site”将显示正确的 james'site

于 2021-03-10T15:12:07.543 回答
0

如果您使用的是 Spring 3.2+,那么以下解决方案将有所帮助。这将处理所有 url,因此肯定比在请求 URI 映射中应用正则表达式模式来允许更好。喜欢 /somepath/{variable:.+}

在xml文件中定义一个bean

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="useSuffixPatternMatch" value="false"/>
        <property name="useRegisteredSuffixPatternMatch" value="true"/>
    </bean>

标志的用法可以在文档中找到。我剪断来解释

据说 useRegisteredSuffixPatternMatch 的解释正在解决这个问题。来自类中的 java doc

如果启用,映射到“/users”的控制器方法也匹配“/users.json”,假设“.json”是使用提供的 {@link #setContentNegotiationManager(ContentNegotiationManager) contentNegotiationManager} 注册的文件扩展名。这对于只允许使用特定的 URL 扩展名以及使用“.”的情况很有用。在 URL 路径中可能导致对路径变量内容的模糊解释(例如,给定“/users/{user}”和传入的 URL,例如“/users/john.j.joe”和“/users/john.j.joe” .json”)。

于 2020-11-11T16:55:59.083 回答