Java Spring MVC@PathVariable被截断
我有一个控制器,提供对信息的RESTful访问:Java Spring MVC@PathVariable被截断,java,spring,rest,spring-mvc,get,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 respo
@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
public ModelAndView getBlah(@PathVariable String blahName, HttpServletRequest request,
HttpServletResponse response) {
我遇到的问题是,如果我使用带有特殊字符的path变量访问服务器,它会被截断。例如:
参数blahName将为blah2010.08
但是,对request.getRequestURI()的调用包含传入的所有信息
知道如何防止Spring截断@PathVariable吗?尝试使用正则表达式作为
@RequestMapping
参数:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")
这很可能与此密切相关。简单地说,该框架尝试将一些智能应用于URI解释,删除它认为是文件扩展名的内容。这将产生将
blah2010.08.19-02:25:47
转换为blah2010.08
的效果,因为它认为.19-02:25:47
是文件扩展名
如链接问题中所述,您可以通过在应用程序上下文中声明自己的
DefaultAnnotationHandlerMapping
bean,并将其UseDefaultSuffExpattern
属性设置为false
来禁用此行为。这将覆盖默认行为,并阻止它干扰您的数据。最后一个点之后的所有内容都将被解释为文件扩展名,并在默认情况下被切断。在spring配置xml中,可以添加
DefaultAnnotationHandlerMapping
并将UseDefaultSuffExpattern
设置为false
(默认值为true
)
因此,打开SpringXMLMVCConfig.xml
(或者它的名称)并添加
现在,您的@PathVariable
blahName
(以及所有其他)应该包含包括所有点的全名
编辑:这里有一个我刚刚遇到了这个问题,这里的解决方案通常没有像我预期的那样有效 我建议使用一个SpEL表达式和多个映射,例如
@RequestMapping(method = RequestMethod.GET,
value = {Routes.BLAH_GET + "/{blahName:.+}",
Routes.BLAH_GET + "/{blahName}/"})
我也遇到了同样的问题,将属性设置为false也没有帮助。然而: 请注意,包含“.xxx”后缀或以“/”结尾的路径已经存在 在任何情况下都不会使用默认后缀模式进行转换 我尝试将“/end”添加到我的RESTful URL中,问题消失了。我不喜欢这个解决方案,但它确实奏效了
顺便说一句,我不知道Spring设计师在添加这个“特性”并默认打开它时是怎么想的。嗯,应该把它取下来 我解决了这个问题
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
值中):
因此,映射将如下所示:
RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")
http://localhost:8080/api/email/test@test.com/
另请参见。Spring认为最后一个点后面的任何内容都是文件扩展名,如
.json
或.xml
,并将其截断以检索参数
所以如果你有/{blahName}
:
,/param
,/param.json
或/param.xml
都将生成值为/param。任何
param
,/param.value.json
或/param.value.xml
都将生成一个值为/param.value。任何
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
automatic:
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
</bean>
请注意,mvc:annotation-driven现在接受contentNegotiation选项以提供自定义bean,但RequestMappingHandlerMapping的属性必须更改为true(默认为false)(参见)
因此,您仍然必须覆盖所有mvc:annotation驱动的配置。我打开了一张到Spring的票据,请求定制RequestMappingHandlerMapping:。如果你有兴趣,请投票
重写时,要谨慎考虑自定义执行管理。否则,所有自定义异常映射都将失败。您必须将MessageConverter与列表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>
在我所参与的开源项目中,我对这些主题实现了一组测试:请参见和//在xml dispatcher中,将此属性添加到默认注释映射器bean中,如下所示
防止截断的基于Java的配置解决方案(使用未弃用的类):
更新:
当我使用上述方法时,我意识到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);
}
}
使用正确的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);
}
}
如果您确定文本与任何默认扩展名都不匹配,则可以使用以下代码:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseRegisteredSuffixPatternMatch(true);
}
}
添加“:.+”对我来说很有效,但直到我去掉了外部的花括号
<代码
//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>
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;
}
}
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);
}
}
@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);
}
}
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseRegisteredSuffixPatternMatch(true);
}
}
@RequestMapping(value ="/email/{email}/")
http://localhost:8080/api/email/test@test.com/
@RestController
public class CustomController {
@GetMapping("/example/{firstValue}/{secondValue}")
public void example(@PathVariable("firstValue") String firstValue,
@PathVariable("secondValue") String secondValue) {
// ...
}
}
@GetMapping("/example/{firstValue}/{secondValue:.+}")
public void example(
@PathVariable("firstValue") String firstValue,
@PathVariable("secondValue") String secondValue) {
//...
}
@GetMapping("/example/{firstValue}/{secondValue}/")
public void example(
@PathVariable("firstValue") String firstValue,
@PathVariable("secondValue") String secondValue) {
//...
}
@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {
@Bean
public RequestMappingHandlerMapping
requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping
= super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
return handlerMapping;
}
}