1. Overview
1.概述
In this short tutorial, we’ll discuss a common problem when working with Spring MVC – when using a Spring @PathVariable with a @RequestMapping to map the end of a request URI that contains a dot, we’ll end up with a partial value in our variable, truncated at the last dot.
在这个简短的教程中,我们将讨论使用Spring MVC时的一个常见问题–当使用Spring @PathVariable与@RequestMapping来映射一个包含点的请求URI的结尾时,我们的变量中最终会出现一个部分值,在最后一个点处被截断。
In the next sections, we’ll focus on why this happens and how to change this behavior.
在接下来的章节中,我们将重点讨论为什么会发生这种情况以及如何改变这种行为。
For an introduction to Spring MVC, please refer to this article.
关于Spring MVC的介绍,请参考到这篇文章。
2. Unwanted Spring Help
2.不需要的Spring的帮助
The framework causes this often unwanted behavior because of the way it interprets the path variable.
该框架导致了这种通常不受欢迎的行为,因为它解释路径变量的方式。
Specifically, Spring considers that anything behind the last dot is a file extension such as .json or .xml.
具体来说,Spring认为最后一个点后面的任何东西都是文件扩展名,如.json或.xml.。
As a result, it truncates the value to retrieve the parameter.
因此,它截断了检索参数的值。
Let’s see an example of using path variables, then analyze the result with different possible values:
让我们看一个使用路径变量的例子,然后分析不同可能值的结果。
@RestController
public class CustomController {
@GetMapping("/example/{firstValue}/{secondValue}")
public void example(@PathVariable("firstValue") String firstValue,
@PathVariable("secondValue") String secondValue) {
// ...
}
}
With the above example, let’s consider the next requests and evaluate our variables:
有了上面的例子,让我们考虑下一个请求并评估我们的变量。
- the URL example/gallery/link results in evaluating firstValue = “gallery” and secondValue = “link”
- when using the example/gallery.df/link.ar URL, we’ll have firstValue = “gallery.df” and secondValue = “link”
- with the example/gallery.df/link.com.ar URL, our variables will be: firstValue = “gallery.df” and secondValue = “link.com”
As we can see, the first variable isn’t affected but the second is always truncated.
我们可以看到,第一个变量不受影响,但第二个变量总是被截断。
3. Solutions
3.解决方案
One way to solve this inconvenience is to modify our @PathVariable definition by adding a regex mapping. Thereby any dot, including the last one, will be considered as part of our parameter:
解决这种不便的方法之一是修改我们的@PathVariable定义,添加一个regex映射。这样,任何一个点,包括最后一个点,都将被视为我们参数的一部分。
@GetMapping("/example/{firstValue}/{secondValue:.+}")
public void example(
@PathVariable("firstValue") String firstValue,
@PathVariable("secondValue") String secondValue) {
//...
}
Another way to avoid this issue is by adding a slash at the end of our @PathVariable. This will enclose our second variable protecting it from Spring’s default behavior:
另一个避免这个问题的方法是:在我们的@PathVariable的末尾添加一个斜线。这将包围我们的第二个变量,保护它不受Spring默认行为的影响。
@GetMapping("/example/{firstValue}/{secondValue}/")
The two solutions above apply to a single request mapping that we’re modifying.
上面的两个解决方案适用于我们要修改的单一请求映射。
If we want to change the behavior at a global MVC level, we need to provide a custom configuration. For this purpose, we can extend the WebMvcConfigurationSupport and override its getPathMatchConfigurer() method to adjust a PathMatchConfigurer.
如果我们想在全局MVC层面上改变行为,我们需要提供一个自定义配置。为此,我们可以扩展WebMvcConfigurationSupport并重载其getPathMatchConfigurer()方法来调整一个PathMatchConfigurer。
@Configuration
public class CustomWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
@Override
protected PathMatchConfigurer getPathMatchConfigurer() {
PathMatchConfigurer pathMatchConfigurer = super.getPathMatchConfigurer();
pathMatchConfigurer.setUseSuffixPatternMatch(false);
return pathMatchConfigurer;
}
}
We have to remember that this approach affects all URLs.
我们必须记住,这种方法会影响所有的URL。
With these three options, we’ ll obtain the same result: when calling the example/gallery.df/link.com.ar URL, our secondValue variable will be evaluated to “link.com.ar”, which is what we want.
使用这三个选项,我们将得到相同的结果:当调用example/gallery.df/link.com.ar URL时,我们的secondValue变量将被评估为 “link.com.ar”,这是我们想要的。
3.1. Deprecation Notice
3.1.弃用通知
As of Spring Framework 5.2.4, the setUseSuffixPatternMatch(boolean) method is deprecated in order to discourage the use of path extensions for request routing and content negotiation. Basically, the current implementation makes it hard to protect web applications against the Reflected File Download (RFD) attack.
从 Spring Framework 5.2.4开始,setUseSuffixPatternMatch(boolean)方法被弃用,以阻止在请求路由和内容协商中使用路径扩展。基本上,当前的实现使 Web 应用程序难以防范反射式文件下载(RFD)攻击。
Also, as of Spring Framework 5.3, the suffix pattern matching will only work for explicitly registered suffixes, to prevent arbitrary extensions.
另外,从Spring Framework 5.3开始,后缀模式匹配将只对明确注册的后缀起作用,以防止任意的扩展。
The bottom line is, as of Spring 5.3, we won’t need to use the setUseSuffixPatternMatch(false) since it’s disabled by default.
底线是,从Spring 5.3开始,我们将不需要使用setUseSuffixPatternMatch(false) ,因为它默认是禁用的。
4. Conclusion
4.结论
In this quick writeup, we’ve explored different ways to solve a common problem when working with @PathVariable and @RequestMapping in Spring MVC and the source of this issue.
在这篇短文中,我们探讨了在Spring MVC中使用@PathVariable和@RequestMapping时解决一个常见问题的不同方法以及这个问题的来源。
As always, the full source code of the examples is available over on GitHub.
一如既往,这些示例的完整源代码可在GitHub上获得over。