Java Spring MVC@PathVariable被截断

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

我有一个控制器,提供对信息的RESTful访问:

@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

因此,打开SpringXML
MVCConfig.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;
    }
}