背景
spring-boot的版本是2.1.4.RELEASE,spring的版本是5.1.6.RELEASE
一个例子如下:
@Configuration
@Import(WebMvcAutoConfiguration.EnableWebMvcConfiguration.class)
@SuppressWarnings(\"unchecked\")
public class WebConfig implements WebMvcConfigurer, WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
}
@RestController
public class ParamController {
@GetMapping(value = \"/param/{param1}\")
public String param(@PathVariable(\"param1\") String param1) {
return param1;
}
}
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
启动一下,访问http://127.0.0.1:8080/param/hehe
和http://127.0.0.1:8080/param/hehe.hehe
都返回hehe
如果访问http://127.0.0.1:8080/param/hehe.hehe.hehe
,它会返回hehe.hehe
所以会发现它把最后一个小数点后面的字符给截掉了,那如果我们想要获取完整的字符串,该怎么办呢?
探索
- 参数怎么来的
入口在InvocableHandlerMethod.invokeForRequest
,如下:
是根据PathVariableMethodArgumentResolver.resolveName
得来的,如下:
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + \".uriTemplateVariables\";
什么时候放进attributes
里的?,在RequestMappingInfoHandlerMapping.handleMatch
,如下:
- 参数怎么解析的
程序定义的:/param/{param1} -> /param/{param1}.*
接口传过来的:/param/hehe.hehe
以/分割,第一个字符串param里没有参数,所以会跳过,直接看第二个字符串:
{param1}.* -> pattern=(.*)\\Q.\\E.*
hehe.hehe
param1=hehe
我们定义的是/param/{param1}
,怎么就变成了/param/{param1}.*
?在PatternsRequestCondition.getMatchingPattern
可以看到如果useSuffixPatternMatch为true,并且指定的url里没有.,会在后缀自动增加.*
- useSuffixPatternMatch是在哪里设置的?
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
implements MatchableHandlerMapping, EmbeddedValueResolverAware {
private boolean useSuffixPatternMatch = true;
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch); // 这里设置了
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
}
解决
- 修改
WebConfig
的getRequestMappingHandlerMapping
@Configuration
@Import(WebMvcAutoConfiguration.EnableWebMvcConfiguration.class)
@SuppressWarnings(\"unchecked\")
public class WebConfig implements WebMvcConfigurer, WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
return requestMappingHandlerMapping;
}
}
- 增加
configurePathMatch
方法
@Configuration
@Import(WebMvcAutoConfiguration.EnableWebMvcConfiguration.class)
@SuppressWarnings(\"unchecked\")
public class WebConfig implements WebMvcConfigurer, WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
- url中增加点
a. 中间的参数是不受影响的
@RestController
public class ParamController {
@GetMapping(value = \"/param/{param1}/{param2}\")
public String param(@PathVariable(\"param1\") String param1, @PathVariable(\"param2\") String param2) {
return param1 + \" \" + param2;
}
}
访问http://127.0.0.1:8080/param/hehe.hehe/hehe.hee
返回hehe.hehe hehe
b. 增加点
@RestController
public class ParamController {
//@GetMapping(value = \"/param/{param1}\")
//public String param(@PathVariable(\"param1\") String param1) {
// return param1;
//}
@GetMapping(value = \"/param/{param1}.{param2}\")
public String param(@PathVariable(\"param1\") String param1, @PathVariable(\"param2\") String param2) {
return param1 + \" \" + param2;
}
}
访问http://127.0.0.1:8080/param/hehe.hehe
返回hehe hehe
注意第一个方法和第二个方法不要同时出现,如果同时出现的话,则会访问第一个方法
@RestController
public class ParamController {
@GetMapping(value = \"/param/{param1}\")
public String param(@PathVariable(\"param1\") String param1) {
return param1;
}
@GetMapping(value = \"/param/{param1}.{param2}\")
public String param(@PathVariable(\"param1\") String param1, @PathVariable(\"param2\") String param2) {
return param1 + \" \" + param2;
}
}
访问http://127.0.0.1:8080/param/hehe.heh
返回hehe
- 修改参数
@RestController
public class ParamController {
@GetMapping(value = \"/param/{param1:.+}\")
public String param(@PathVariable(\"param1\") String param1) {
return param1;
}
}
访问http://127.0.0.1:8080/param/hehe.hehe
,返回hehe.hehe
原因如下:
/param/{param1:.+} -> /param/{param1:.+}
/param/hehe.hehe
{param1:.+} -> pattern=(.+)
hehe.hehe
param1=hehe.hehe
得到pattern以及提取参数的类 AntPathStringMatcher
protected static class AntPathStringMatcher {
private static final Pattern GLOB_PATTERN = Pattern.compile(\"\\\\?|\\\\*|\\\\{((?:\\\\{[^/]+?\\\\}|[^/{}]|\\\\\\\\[{}])+?)\\\\}\");
private static final String DEFAULT_VARIABLE_PATTERN = \"(.*)\";
private final Pattern pattern;
private final List<String> variableNames = new LinkedList<>();
public AntPathStringMatcher(String pattern) {
this(pattern, true);
}
public AntPathStringMatcher(String pattern, boolean caseSensitive) {
StringBuilder patternBuilder = new StringBuilder();
Matcher matcher = GLOB_PATTERN.matcher(pattern);
int end = 0;
while (matcher.find()) {
patternBuilder.append(quote(pattern, end, matcher.start()));
String match = matcher.group();
if (\"?\".equals(match)) {
patternBuilder.append(\'.\');
}
else if (\"*\".equals(match)) {
patternBuilder.append(\".*\");
}
else if (match.startsWith(\"{\") && match.endsWith(\"}\")) {
int colonIdx = match.indexOf(\':\');
if (colonIdx == -1) {
patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
this.variableNames.add(matcher.group(1));
}
else {
String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
patternBuilder.append(\'(\');
patternBuilder.append(variablePattern);
patternBuilder.append(\')\');
String variableName = match.substring(1, colonIdx);
this.variableNames.add(variableName);
}
}
end = matcher.end();
}
patternBuilder.append(quote(pattern, end, pattern.length()));
this.pattern = (caseSensitive ? Pattern.compile(patternBuilder.toString()) :
Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE));
}
private String quote(String s, int start, int end) {
if (start == end) {
return \"\";
}
return Pattern.quote(s.substring(start, end));
}
/**
* Main entry point.
* @return {@code true} if the string matches against the pattern, or {@code false} otherwise.
*/
public boolean matchStrings(String str, @Nullable Map<String, String> uriTemplateVariables) {
Matcher matcher = this.pattern.matcher(str);
if (matcher.matches()) {
if (uriTemplateVariables != null) {
// SPR-8455
if (this.variableNames.size() != matcher.groupCount()) {
throw new IllegalArgumentException(\"The number of capturing groups in the pattern segment \" +
this.pattern + \" does not match the number of URI template variables it defines, \" +
\"which can occur if capturing groups are used in a URI template regex. \" +
\"Use non-capturing groups instead.\");
}
for (int i = 1; i <= matcher.groupCount(); i++) {
String name = this.variableNames.get(i - 1);
String value = matcher.group(i);
uriTemplateVariables.put(name, value);
}
}
return true;
}
else {
return false;
}
}
}
来源:https://www.cnblogs.com/eaglelihh/p/16273654.html
本站部分图文来源于网络,如有侵权请联系删除。