简体   繁体   English

Spring MVC @PathVariable被截断

[英]Spring MVC @PathVariable getting truncated

I have a controller that provides RESTful access to information: 我有一个控制器,可提供对信息的RESTful访问:

@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 例如: http:// localhost:8080 / blah-server / blah / get / blah2010.08.19-02:25:47

The parameter blahName will be blah2010.08 参数blahName将为blah2010.08

However, the call to request.getRequestURI() contains all the information passed in. 但是,对request.getRequestURI()的调用包含所有传入的信息。

Any idea how to prevent Spring from truncating the @PathVariable? 任何想法如何防止Spring截断@PathVariable?

尝试为@RequestMapping参数使用正则表达式:

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")

This is probably closely related to SPR-6164 . 这可能与SPR-6164密切相关。 Briefly, the framework tries to apply some smarts to the URI interpretation, removing what it thinks are file extensions. 简而言之,该框架尝试将一些技巧应用到URI解释中,以消除其认为的文件扩展名。 This would have the effect of turning blah2010.08.19-02:25:47 into blah2010.08 , since it thinks the .19-02:25:47 is a file extension. 这会导致将blah2010.08.19-02:25:47变成blah2010.08 ,因为它认为.19-02:25:47是文件扩展名。

As described in the linked issue, you can disable this behaviour by declaring your own DefaultAnnotationHandlerMapping bean in the app context, and setting its useDefaultSuffixPattern property to false . 如链接的问题中所述,可以通过在应用程序上下文中声明自己的DefaultAnnotationHandlerMapping bean并将其useDefaultSuffixPattern属性设置为false来禁用此行为。 This will override the default behaviour, and stop it molesting your data. 这将覆盖默认行为,并阻止它破坏您的数据。

Spring considers that anything behind the last dot is a file extension such as .json or .xml and truncate it to retrieve your parameter. Spring认为最后一个点后面的任何东西都是文件扩展名(例如.json.xml然后将其截断以检索您的参数。

So if you have /{blahName} : 因此,如果您有/{blahName}

  • /param , /param.json , /param.xml or /param.anything will result in a param with value param /param/param /param.json/param /param.xml/param.anything会导致参数值为param
  • /param.value.json , /param.value.xml or /param.value.anything will result in a param with value param.value /param.value.json/param.value.json/param.value.xml /param.value.anything都将导致参数值为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: 如果按照建议将映射更改为/{blahName:.+} ,则任何点(包括最后一个点)都将被视为参数的一部分:

  • /param will result in a param with value param /param将产生带有值param
  • /param.json will result in a param with value param.json /param.json将产生一个值为param.json的参数
  • /param.xml will result in a param with value param.xml /param.xml将产生一个值为param.xml的参数
  • /param.anything will result in a param with value param.anything /param.anything会产生带有值param.anything的param
  • /param.value.json will result in a param with value param.value.json /param.value.json将导致参数值为param.value.json
  • ... ...

If you don't care of extension recognition, you can disable it by overriding mvc:annotation-driven automagic: 如果您不关心扩展识别,则可以通过重写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} : 因此,再次,如果您有/{blahName}

  • /param , /param.json , /param.xml or /param.anything will result in a param with value param /param/param /param.json/param /param.xml/param.anything会导致参数值为param
  • /param.value.json , /param.value.xml or /param.value.anything will result in a param with value param.value /param.value.json/param.value.json/param.value.xml /param.value.anything都将导致参数值为param.value的参数

Note: the difference from the default config is visible only if you have a mapping like /something.{blahName} . 注意:仅当您具有/something.{blahName}类的映射时,与默认配置的区别才可见。 See Resthub project issue . 请参阅Resthub项目问题

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. 如果要保留扩展管理,从Spring 3.2开始,还可以设置RequestMappingHandlerMapping bean的useRegisteredSuffixPatternMatch属性,以保持激活suffixPattern识别,但仅限于已注册的扩展。

Here you define only json and xml extensions: 在这里,您仅定义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>

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 ). 请注意,mvc:annotation-driven现在接受contentNegotiation选项以提供自定义bean,但必须将RequestMappingHandlerMapping的属性更改为true(默认为false)(参见https://jira.springsource.org/browse/SPR-7632 )。

For that reason, you still have to override all the mvc:annotation-driven configuration. 因此,您仍然必须覆盖所有mvc:annotation驱动的配置。 I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253 . 我开了一张去Spring的票,要求自定义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. 否则,所有自定义Exception映射将失败。 You will have to reuse messageCoverters with a list bean: 您将必须使用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>

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 我在我参与的开源项目Resthub中实现了针对这些主题的一系列测试:请参阅https://github.com/resthub/resthub-spring-stack/pull/219/fileshttps:// github.com/resthub/resthub-spring-stack/issues/217

Everything after the last dot is interpreted as file extension and cut off by default. 最后一个点之后的所有内容均被解释为文件扩展名,并且默认情况下已切断。
In your spring config xml you can add DefaultAnnotationHandlerMapping and set useDefaultSuffixPattern to false (default is true ). 在您的spring config xml中,您可以添加DefaultAnnotationHandlerMapping并将useDefaultSuffixPattern设置为false (默认为true )。

So open your spring xml mvc-config.xml (or however it is called) and add 因此,打开您的spring xml mvc-config.xml (或调用它)并添加

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="useDefaultSuffixPattern" value="false" />
</bean>

Now your @PathVariable blahName (and all other, too) should contain the full name including all dots. 现在,您的@PathVariable blahName (以及其他所有名称)应包含全名,包括所有点。

EDIT: Here is a link to the spring api 编辑:这是到Spring API链接

I also ran into the same issue, and setting the property to false didn't help me either. 我也遇到了同样的问题,并且将该属性设置为false也没有帮助。 However, the API says : 但是, API表示

Note that paths which include a ".xxx" suffix or end with "/" already will not be transformed using the default suffix pattern in any case. 请注意,在任何情况下,都不会使用默认的后缀模式来转换包含“ .xxx”后缀或以“ /”结尾的路径。

I tried adding "/end" to my RESTful URL, and the problem went away. 我尝试将“ / end”添加到我的RESTful URL中,问题消失了。 I'm not please with the solution, but it did work. 我对解决方案不满意,但确实有效。

BTW, I don't know what the Spring designers were thinking when they added this "feature" and then turned it on by default. 顺便说一句,我不知道Spring设计师在添加此“功能”然后默认将其打开时的想法。 IMHO, it should be removed. 恕我直言,应将其删除。

Using the correct Java configuration class : 使用正确的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);
    }
}

I resolved by this hack 我通过此黑客解决了

1) Added HttpServletRequest in @PathVariable like below 1)在@PathVariable中添加了HttpServletRequest,如下所示

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

2) Get the URL directly (At this level no truncation) in the request 2)直接在请求中获取URL(在此级别,不截断)

request.getPathInfo() 

Spring MVC @PathVariable with dot (.) is getting truncated 带有点(。)的Spring MVC @PathVariable被截断

The file extension problem only exists if the parameter is in the last part of the URL. 仅当参数位于URL的最后一部分时,文件扩展名问题才会存在。 Change 更改

@RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}")

to

@RequestMapping(
   method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/safe")

and all will be well again- 一切都会好起来的-

If you can edit the address that requests are sent to, simple fix would be to add a trailing slash to them (and also in the @RequestMapping value): 如果您可以编辑请求发送到的地址,则简单的解决方法是在请求末尾添加斜杠(也可以在@RequestMapping值中):

/path/{variable}/

so the mapping would look like: 因此映射看起来像:

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName}/")

See also Spring MVC @PathVariable with dot (.) is getting truncated . 另请参阅带有点(。)的Spring MVC @PathVariable被截断

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

adding the ":.+" worked for me, but not until I removed outer curly brackets. 添加“:。+”对我有用,但是直到我移除了外部花括号为止。

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

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

Hope I helped someone :] 希望我能帮助一个人:]

I just ran into this and the solutions here didn't generally work as I expected. 我只是碰到了这一点,这里的解决方案通常无法按我预期的那样工作。

I suggest using a SpEL expression and multiple mappings, eg 我建议使用SpEL表达式和多个映射,例如

@RequestMapping(method = RequestMethod.GET, 
    value = {Routes.BLAH_GET + "/{blahName:.+}", 
             Routes.BLAH_GET + "/{blahName}/"})

Java based configuration solution to prevent truncation (using a not-deprecated class): 基于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;
    }
}

Source: http://www.javacodegeeks.com/2013/01/spring-mvc-customizing-requestmappinghandlermapping.html 来源:http://www.javacodegeeks.com/2013/01/spring-mvc-customizing-requestmappinghandlermapping.html

UPDATE: 更新:

I realized having some problems with Spring Boot auto-configuration when I used the approach above (some auto-configuration doesn't get effective). 当我使用上述方法时,我意识到Spring Boot自动配置存在一些问题(某些自动配置没有效果)。

Instead, I started to use the BeanPostProcessor approach. 相反,我开始使用BeanPostProcessor方法。 It seemed to be working better. 它似乎工作得更好。

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);
    }
}

Inspired from: http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html 灵感来源:http://ronaldxq.blogspot.com/2014/10/spring-mvc-setting-alwaysusefullpath-on.html

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);
    }
}

My preferable solution to prevent the Spring MVC @PathVariable to get truncated is to add trailing slash at the end of the path variable. 为了防止Spring MVC @PathVariable被截断,我更可取的解决方案是在path变量的末尾添加斜杠。

For example: 例如:

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

So, the request will look like: 因此,请求将如下所示:

http://localhost:8080/api/email/test@test.com/

The problem that you are facing is due to spring interpreting the last part of the uri after the dot (.) as a file extension like .json or .xml . 您面临的问题是由于Spring点(。) 之后的uri的最后部分解释为.json或.xml之类的文件扩展名 So when spring tries to resolve the path variable it simply truncates the rest of the data after it encounters a dot (.) at the end of the uri. 因此,当spring尝试解析path变量时,它会在uri末尾遇到点(。)之后,将截断其余数据。 Note: also this happens only if you keep the path variable at the end of the uri. 注意:仅当您将路径变量保留在uri的末尾时,也会发生这种情况。

For example consider uri : https://localhost/example/gallery.df/link.ar 例如考虑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) {
        // ...  
    }
}

In the above url firstValue = "gallery.df" and secondValue="link" , the last bit after the . 在上面的网址firstValue =“ gallery.df”和secondValue =“ link”中,。之后的最后一位。 gets truncated when the path variable gets interpreted. 在解释路径变量时被截断。

So, to prevent this there is two possible ways: 因此,为防止这种情况,有两种可能的方法:

1.) Using a regexp mapping 1.)使用正则表达式映射

Use a regex at the end part of mapping 在映射的末尾使用正则表达式

@GetMapping("/example/{firstValue}/{secondValue:.+}")   
public void example(
  @PathVariable("firstValue") String firstValue,
  @PathVariable("secondValue") String secondValue) {
    //...
}

By using + , we indicate any value after the dot will also be part of the path variable. 通过使用+,我们指示点后的任何值也将成为path变量的一部分。

2.) Adding a slash at the end of our @PathVariable 2.)在@PathVariable的末尾添加一个斜杠

@GetMapping("/example/{firstValue}/{secondValue}/")
public void example(
  @PathVariable("firstValue") String firstValue,
  @PathVariable("secondValue") String secondValue) {
    //...
}

This will enclose our second variable protecting it from Spring's default behavior. 这将包含我们的第二个变量,以保护它免受Spring的默认行为的影响。

3) By overriding Spring's default webmvc configuration 3)通过覆盖Spring的默认webmvc配置

Spring provides ways to override the default configurations that gets imported by using the annotations @EnableWebMvc .We can customize the Spring MVC configuration by declaring our own DefaultAnnotationHandlerMapping bean in the application context and setting its useDefaultSuffixPattern property to false. Spring提供了一些方法来覆盖通过使用@EnableWebMvc注释导入的默认配置。我们可以通过在应用程序上下文中声明我们自己的DefaultAnnotationHandlerMapping bean并将其useDefaultSuffixPattern属性设置为false来自定义Spring MVC配置。 Example: 例:

@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {

    @Bean
    public RequestMappingHandlerMapping 
      requestMappingHandlerMapping() {

        RequestMappingHandlerMapping handlerMapping
          = super.requestMappingHandlerMapping();
        handlerMapping.setUseSuffixPatternMatch(false);
        return handlerMapping;
    }
}

Keep in mind that overriding this default configuration, affects all urls. 请记住,覆盖此默认配置会影响所有url。

Note : here we are extending the WebMvcConfigurationSupport class to override the default methods. 注意:这里我们扩展了WebMvcConfigurationSupport类以覆盖默认方法。 There is one more way to override the deault configurations by implementing the WebMvcConfigurer interface. 通过实现WebMvcConfigurer接口,还有另一种方法来覆盖默认配置。 For more details on this read : https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html 有关此内容的更多信息,请阅读: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM