[英]Spring MVC @PathVariable getting truncated
我有一个控制器,可提供对信息的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?
尝试为@RequestMapping
参数使用正则表达式:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")
这可能与SPR-6164密切相关。 简而言之,该框架尝试将一些技巧应用到URI解释中,以消除其认为的文件扩展名。 这会导致将blah2010.08.19-02:25:47
变成blah2010.08
,因为它认为.19-02:25:47
是文件扩展名。
如链接的问题中所述,可以通过在应用程序上下文中声明自己的DefaultAnnotationHandlerMapping
bean并将其useDefaultSuffixPattern
属性设置为false
来禁用此行为。 这将覆盖默认行为,并阻止它破坏您的数据。
Spring认为最后一个点后面的任何东西都是文件扩展名(例如.json
或.xml
然后将其截断以检索您的参数。
因此,如果您有/{blahName}
:
/param
, /param
/param.json
, /param
/param.xml
或/param.anything
会导致参数值为param
/param.value.json
或/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 /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
/param.json
, /param
/param.xml
或/param.anything
会导致参数值为param
/param.value.json
或/param.value.json
。 /param.value.xml
/param.value.anything
都将导致参数值为param.value
的参数 注意:仅当您具有/something.{blahName}
类的映射时,与默认配置的区别才可见。 请参阅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映射将失败。 您将必须使用list 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
最后一个点之后的所有内容均被解释为文件扩展名,并且默认情况下已切断。
在您的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
(以及其他所有名称)应包含全名,包括所有点。
编辑:这是到Spring API的链接
我也遇到了同样的问题,并且将该属性设置为false也没有帮助。 但是, API表示 :
请注意,在任何情况下,都不会使用默认的后缀模式来转换包含“ .xxx”后缀或以“ /”结尾的路径。
我尝试将“ / end”添加到我的RESTful URL中,问题消失了。 我对解决方案不满意,但确实有效。
顺便说一句,我不知道Spring设计师在添加此“功能”然后默认将其打开时的想法。 恕我直言,应将其删除。
使用正确的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);
}
}
我通过此黑客解决了
1)在@PathVariable中添加了HttpServletRequest,如下所示
@PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception {
2)直接在请求中获取URL(在此级别,不截断)
request.getPathInfo()
仅当参数位于URL的最后一部分时,文件扩展名问题才会存在。 更改
@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
至
@RequestMapping(
method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/safe")
一切都会好起来的-
如果您可以编辑请求发送到的地址,则简单的解决方法是在请求末尾添加斜杠(也可以在@RequestMapping
值中):
/path/{variable}/
因此映射看起来像:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")
//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>
添加“:。+”对我有用,但是直到我移除了外部花括号为止。
value = {"/username/{id:.+}"}
无效
value = "/username/{id:.+}"
有效
希望我能帮助一个人:]
我只是碰到了这一点,这里的解决方案通常无法按我预期的那样工作。
我建议使用SpEL表达式和多个映射,例如
@RequestMapping(method = RequestMethod.GET,
value = {Routes.BLAH_GET + "/{blahName:.+}",
Routes.BLAH_GET + "/{blahName}/"})
基于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;
}
}
来源: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);
}
}
灵感来源:http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html
如果您确定您的文字与任何默认扩展名都不匹配,则可以使用以下代码:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseRegisteredSuffixPatternMatch(true);
}
}
为了防止Spring MVC @PathVariable被截断,我更可取的解决方案是在path变量的末尾添加斜杠。
例如:
@RequestMapping(value ="/email/{email}/")
因此,请求将如下所示:
http://localhost:8080/api/email/test@test.com/
您面临的问题是由于Spring将点(。) 之后的uri的最后部分解释为.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) {
//...
}
通过使用+,我们指示点后的任何值也将成为path变量的一部分。
2.)在@PathVariable的末尾添加一个斜杠
@GetMapping("/example/{firstValue}/{secondValue}/")
public void example(
@PathVariable("firstValue") String firstValue,
@PathVariable("secondValue") String secondValue) {
//...
}
这将包含我们的第二个变量,以保护它免受Spring的默认行为的影响。
3)通过覆盖Spring的默认webmvc配置
Spring提供了一些方法来覆盖通过使用@EnableWebMvc注释导入的默认配置。我们可以通过在应用程序上下文中声明我们自己的DefaultAnnotationHandlerMapping bean并将其useDefaultSuffixPattern属性设置为false来自定义Spring MVC配置。 例:
@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {
@Bean
public RequestMappingHandlerMapping
requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping
= super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
return handlerMapping;
}
}
请记住,覆盖此默认配置会影响所有url。
注意:这里我们扩展了WebMvcConfigurationSupport类以覆盖默认方法。 通过实现WebMvcConfigurer接口,还有另一种方法来覆盖默认配置。 有关此内容的更多信息,请阅读: https : //docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.