Spring MVC @PathVariable getting truncated

2019-01-01 06:59发布

I have a controller that provides RESTful access to information:

@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")
public ModelAndView getBlah(@PathVariable String blahName, HttpServletRequest request,
                            HttpServletResponse response) {

The problem I am experiencing is that if I hit the server with a path variable with special characters it gets truncated. For example: http://localhost:8080/blah-server/blah/get/blah2010.08.19-02:25:47

The parameter blahName will be blah2010.08

However, the call to request.getRequestURI() contains all the information passed in.

Any idea how to prevent Spring from truncating the @PathVariable?

15条回答
墨雨无痕
2楼-- · 2019-01-01 07:09

adding the ":.+" worked for me, but not until I removed outer curly brackets.

value = {"/username/{id:.+}"} didn't work

value = "/username/{id:.+}" works

Hope I helped someone :]

查看更多
明月照影归
3楼-- · 2019-01-01 07:10

Using the correct Java configuration class :

@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);
    }
}
查看更多
唯独是你
4楼-- · 2019-01-01 07:10

My preferable solution to prevent the Spring MVC @PathVariable to get truncated is to add trailing slash at the end of the path variable.

For example:

@RequestMapping(value ="/email/{email}/")

So, the request will look like:

http://localhost:8080/api/email/test@test.com/
查看更多
何处买醉
5楼-- · 2019-01-01 07:12

if you are sure that your text will not match any of default extensions you can use below code:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setUseRegisteredSuffixPatternMatch(true);
    }
}
查看更多
旧人旧事旧时光
6楼-- · 2019-01-01 07:15

I resolved by this hack

1) Added HttpServletRequest in @PathVariable like below

 @PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception { 

2) Get the URL directly (At this level no truncation) in the request

request.getPathInfo() 

Spring MVC @PathVariable with dot (.) is getting truncated

查看更多
姐姐魅力值爆表
7楼-- · 2019-01-01 07:16

Spring considers that anything behind the last dot is a file extension such as .jsonor .xml and truncate it to retrieve your parameter.

So if you have /{blahName}:

  • /param, /param.json, /param.xml or /param.anything will result in a param with value param
  • /param.value.json, /param.value.xml or /param.value.anything will result in a param with value param.value

If you change your mapping to /{blahName:.+} as suggested, any dot, including the last one, will be considered as part of your parameter:

  • /param will result in a param with value param
  • /param.json will result in a param with value param.json
  • /param.xml will result in a param with value param.xml
  • /param.anything will result in a param with value param.anything
  • /param.value.json will result in a param with value param.value.json
  • ...

If you don't care of extension recognition, you can disable it by overriding 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>

So, again, if you have /{blahName}:

  • /param, /param.json, /param.xml or /param.anything will result in a param with value param
  • /param.value.json, /param.value.xml or /param.value.anything will result in a param with value param.value

Note: the difference from the default config is visible only if you have a mapping like /something.{blahName}. See Resthub project issue.

If you want to keep extension management, since Spring 3.2 you can also set the useRegisteredSuffixPatternMatch property of RequestMappingHandlerMapping bean in order to keep suffixPattern recognition activated but limited to registered extension.

Here you define only json and xml extensions:

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

Note that mvc:annotation-driven accepts now a contentNegotiation option to provide a custom bean but the property of RequestMappingHandlerMapping has to be changed to true (default false) (cf. https://jira.springsource.org/browse/SPR-7632).

For that reason, you still have to override all the mvc:annotation-driven configuration. I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253. Please vote if you are interested in.

While overriding, be careful to consider also custom Execution management overriding. Otherwise, all your custom Exception mappings will fail. You will have to reuse messageCoverters with a list 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>

I implemented, in the open source project Resthub that I am part of, a set of tests on these subjects: see https://github.com/resthub/resthub-spring-stack/pull/219/files and https://github.com/resthub/resthub-spring-stack/issues/217

查看更多
登录 后发表回答