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被截断
#1 楼
据我所知,这个问题只出现在requestmapping末尾的pathvariable中。我们能够通过在requestmapping中定义regex插件来解决此问题。
/somepath/{variable:.+}
#2 楼
Spring认为最后一个点后面的任何东西都是文件扩展名,例如.json
或.xml
,并对其进行结构化以检索您的参数。因此,如果您具有
/somepath/{variable}
:/somepath/param
,/somepath/param.json
,/somepath/param.xml
或/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-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>
因此,如果您有
/somepath/{variable}
,请再次使用它:/somepath/param
,/somepath/param.json
,/somepath/param.xml
或/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驱动的配置。我开了一张去Spring的票,要求自定义RequestMappingHandlerMapping:https://jira.springsource.org/browse/SPR-11253。如果您有兴趣,请投票。
覆盖时,请谨慎考虑自定义执行管理覆盖。否则,所有自定义Exception映射将失败。您将必须使用带列表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/files和https://github.com/resthub/resthub-spring-stack/issues/217
评论
原谅我是新手,所以您将Bean配置放在哪里?它适用于什么春季版本?
–飞溅
2014年9月13日下午2:51
@Splash:您必须将这些bean定义到“标准” Spring applicationContext.xml文件中。这至少适用于Spring 3.2。大概(至少部分)之前
– bmeurant
2014年9月19日于21:07
我认为这是正确的答案。似乎参数“ useRegisteredSuffixPatternMatch”正是针对OP问题引入的。
–lrxw
17年4月19日在8:45
这对我来说只是解决方案的一半。请参阅@Paul Aerer的答案。
– 8bitjunkie
18年7月26日在14:13
#3 楼
春季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>
评论
到目前为止,这是最干净的解决方案:关闭导致它的功能,而不是对其进行破解。我们仍然没有使用此功能,因此问题已解决-完美!
–大卫·拉文德(David Lavender)
15年3月26日在12:58
AllResources类去哪儿了?
– irl_irl
16年7月4日在19:34
@ste_irl在与您的main相同的包中添加一个Java类。
– kometen
16 Dec 4'在22:36
使用matcher.setUseSuffixPatternMatch(false)完全禁用后缀匹配。
–吉安·马可(Gian Marco)
17年1月3日在16:23
这对我来说只是解决方案的一半。请参阅@Paul Aerer的答案。
– 8bitjunkie
18年7月26日在14:13
#4 楼
除了Martin Frey的答案之外,还可以通过在RequestMapping值中添加尾斜杠来解决此问题:/path/{variable}/
请记住,此修复程序不支持可维护性。现在,它要求所有URI都带有斜线-对于API用户/新开发人员而言,这可能并不明显。因为可能并非所有参数中都有一个
.
,所以它还可能会造成间歇性错误评论
那甚至是一个更干净的解决方案。我不得不找出IE根据后缀设置接受标头的困难方式。所以我想在一些.doc requestmapping上发布,我总是得到下载而不是新的html页面。这种方法解决了这一问题。
–马丁·弗雷(Martin Frey)
2014年1月31日19:02
这是我解决问题的最简单的方法; regexp在许多情况下似乎有些过大
–Riccardo Cossu
2014年8月1日上午9:50
但它会与AngularJS的默认行为发生冲突,从而自动删除尾随的斜杠。可以在最新的Angular版本中进行配置,但是如果您不知道发生了什么,就需要跟踪数小时。
– dschulten
2014年9月1日下午6:38
@dschulten您刚刚节省了我几个小时的调试工作,谢谢!但是,您应该在答案中提到HTPP请求中将要求使用斜杠。
–霍夫曼
2014年11月7日15:58
这非常危险!我当然不会推荐它,因为任何实现该API的人都不会期望它。非常不可维护。
–sparkyspider
16年4月19日在19:39
#5 楼
在Spring Boot Rest Controller中,我已通过以下步骤解决了这些问题:RestController:
@GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(@PathVariable(value = "email") String email){
//code
}
从Rest Client:
Get http://mywebhook.com/statusByEmail/abc.test@gmail.com/
评论
该答案取决于斜杠才能起作用。
– 8bitjunkie
18年7月26日在14:07
就像吊饰一样工作(也没有斜线)。谢谢!
–afe
18/12/20在13:19
#6 楼
添加“:。+”对我有用,但是直到我移除了外部花括号。value = {“ /username/{id:.+}”}无效
值=“ /用户名/{id:.+}”起作用
希望我帮助了某人:)
评论
那是因为大括号评估了RegEx,并且您已经有了一些id
– 8bitjunkie
18年7月26日在14:06
#7 楼
/somepath/{variable:.+}
可在Java requestMapping
标签中使用。评论
我喜欢这个答案,因为它没有显示出什么无效的方法。
– johnnieb
17-10-30在16:54
不适用于带有多个点的电子邮件地址。
– 8bitjunkie
18年7月26日在14:03
@ 8bitjunkie Sth像“ /{code:.+}”一样适用于许多点,而不是61.12.7,也适用于k.a.p@o.i.n
–tryingHard
18年8月30日在9:50
#8 楼
这是一种完全依赖于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;
}
}
评论
谢谢,为我解决了。另外,它非常干净明确。 +1
– bkis
19年7月8日在12:08
#9 楼
解决此问题的一种非常简单的方法是在末尾添加斜杠...例如:
use:
/somepath/filename.jpg/
而不是:
/somepath/filename.jpg
#10 楼
在Spring Boot中,正则表达式解决了类似@GetMapping("/path/{param1:.+}")
的问题
评论
请注意,这仅适用于一个点。它不适用于电子邮件地址。
– 8bitjunkie
18年7月26日在14:07
@ 8bitjunkie Sth像“ /{code:.+}”一样适用于许多点,而不是61.12.7,也适用于k.a.p@o.i.n
–tryingHard
18年8月30日在9:46
@ 8bitjunkie我已经使用IP地址对其进行了测试。它运作良好。因此,这意味着它适用于多个点。
– Dapper Dan
18-09-6在19:33
#11 楼
包括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
评论
Upvote-这是唯一的答案,明确表明ContentNegotiationManagerFactoryBean和contentNegotiationManager配置项都是必需的
– 8bitjunkie
18年7月26日在14:12
#12 楼
如果您使用的是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" />
评论
它与ContentNegotiationManager有关吗?
–卡纳加韦卢·苏古玛(Kanagavelu Sugumar)
13年5月31日在9:18
我的代码仅配置RequestMappingHandlerMapping,以便URL不会被截断。 ContentNegotiationManager是另一种野兽。
– Jukka
13年5月31日在14:26
这很旧,但是您实际上不需要BeanPostProcessor。如果使用WebMvcConfigurationSupport,则可以重写requestMappingHandlerMapping @Bean方法。如果使用XML配置,则可以声明自己的RequestMappingHandlerMapping bean并声明该属性。
– Sotirios Delimanolis
13-10-29在21:06
非常感谢您,我针对同一问题尝试了多种解决方案,仅此一种对我有用。 :-)
–我们是博格
2014年11月24日10:05
#13 楼
最后,我在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);
}
#14 楼
对我来说,@GetMapping(path = "/a/{variableName:.+}")
有效,但仅当您还将请求URL中的“点”也编码为“%2E”时,它才有效。但要求URL全部都是……虽然有效,但这不是“标准”编码。感觉像是一个bug:|
另一个解决方法,类似于“ trailing slash”,是移动将带有点“ inline”的变量,例如:
@GetMapping(path =“ / {variableName} / a“)
现在将保留所有点,无需进行任何修改。
#15 楼
从Spring 5.2.4(Spring Boot v2.2.6.RELEASE)开始,不推荐使用PathMatchConfigurer.setUseSuffixPatternMatch
和ContentNegotiationConfigurer.favorPathExtension
(https://spring.io/blog/2020/03/24/spring-framework-5-2- 5-available-now和https://github.com/spring-projects/spring-framework/issues/24179)。真正的问题是客户端请求特定的媒体类型(例如。 com),默认情况下,Spring添加了所有这些媒体类型。在大多数情况下,您的REST控制器只会生成JSON,因此不支持请求的输出格式(.com)。
要克服此问题,您应该通过更新rest控制器(或特定方法)以支持'输出'格式(
@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及更高版本将仅匹配注册的后缀(媒体类型)。
#16 楼
如果同时写后端和前端,则另一个简单的解决方案是在URL的末尾附加一个“ /”。如果是这样,则无需更改后端...somepath/myemail@gmail.com/
请开心!
#17 楼
如果您使用的是Spring 3.2+,则以下解决方案将有所帮助。这样处理所有URL绝对比在请求URI映射中允许使用regex模式更好。像/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文档中,
如果启用,则映射到“ / users”的控制器方法也将匹配到“
” /users.json”,并假设“ .json”是在
提供了{@link #setContentNegotiationManager(ContentNegotiationManager)
contentNegotiationManager}。这对于仅允许使用特定的
URL扩展名以及“。”的情况很有用。 URL路径中的
可能导致路径变量内容的模棱两可(例如,给定的
“ / users / {user}”以及传入的URL,例如“ /users/john.j.joe”和
"/users/john.j.joe.json“)。
评论
谢谢,我认为此修复程序还可以在3.2V之前使用吗?但是,我不喜欢此修复程序。因为在我的应用程序中必须要处理的所有URL都需要它...并且将来的URL实现也要注意这一点...
–卡纳加韦卢·苏古玛(Kanagavelu Sugumar)
13年5月2日在8:35
这是我在Spring 3.0.5中解决此问题的方法<!-Spring配置需要避免使用点被截断的URI->
–轮渡
13年5月29日在18:43
@Mariusz,语法为{variable_name:regular_expression},因此这里有一个名为variable的变量,该值将使用regex。+(其中。表示“任意字符”,+表示“一次或多次”)进行匹配。
–MichałRybak
13-10-17在9:23
@StefanHaberl如果您以常规方式匹配变量,Spring将使用其后缀检测功能并将点后的所有内容都截断。使用regexp匹配时,不会使用这些功能-变量仅与您提供的regexp匹配。
–MichałRybak
2014年2月11日在11:49
如果变量中有多个点,则@martin“ variable:。+”不起作用。例如,将电子邮件放在诸如/path/abc@server.com.au之类的宁静路径的末尾。控制器甚至没有被调用,但是当只有一个点/path/abc@server.com时,它就可以工作。知道为什么和/或解决方法吗?
–波西米亚风格♦
16年4月11日在5:45