如何获取Spring中@PathVariable注解包含点的全部参数值?

2026-05-25 19:451阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1472个文字,预计阅读时间需要6分钟。

如何获取Spring中@PathVariable注解包含点的全部参数值?

通过URL的扩展发现,Spring中出现了`useSuffixPatternMatch`这个参数。以下是关于这个参数的一些背景、原因、解决方案和参考资料:

如何获取Spring中@PathVariable注解包含点的全部参数值?

背景:`useSuffixPatternMatch`是Spring框架中用于URL匹配的参数,它控制Spring是否使用后缀模式匹配来解析控制器方法。

原因:在Spring 5.1及之前版本中,默认值为`true`,这意味着Spring会检查请求路径是否以特定后缀匹配。然而,这种做法可能会导致一些潜在的问题,例如无法正确处理带有参数的URL。

解决方案:要解决这个问题,可以将`useSuffixPatternMatch`设置为`false`,这样Spring就不会使用后缀模式匹配。

示例:java@Configuration@Import(WebMvcAutoConfiguration.class)public class WebConfig { @Bean public WebMvcConfigurer webMvcConfigurer() { return webMvcConfigurer -> webMvcConfigurer.setUseSuffixPatternMatch(false); }}

参考资料:- [Spring 5.1官方文档](https://docs.spring.io/spring-framework/docs/5.1.6.RELEASE/reference//web.#mvc-ann-config)- [Spring Boot 2.1.4官方文档](https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/single/#boot-features-spring-mvc)

通过URL的后缀发现了Spring中的useSuffixPatternMatch这个参数

目录
  • 背景
  • 原因
  • 解决
  • 参考

背景

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

启动一下,访问127.0.0.1:8080/param/hehe127.0.0.1:8080/param/hehe.hehe都返回hehe

如果访问127.0.0.1:8080/param/hehe.hehe.hehe,它会返回hehe.hehe

所以会发现它把最后一个小数点后面的字符给截掉了,那如果我们想要获取完整的字符串,该怎么办呢?

原因

下面的例子都是根据127.0.0.1:8080/param/hehe.hehe这个url来调试的

  1. 参数怎么来的

入口在InvocableHandlerMethod.invokeForRequest,如下:

是根据PathVariableMethodArgumentResolver.resolveName得来的,如下:

HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";

什么时候放进attributes里的?,在RequestMappingInfoHandlerMapping.handleMatch,如下:

  1. 参数怎么解析的

程序定义的:/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里没有.,会在后缀自动增加.*

  1. 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(); } } 解决

  1. 修改WebConfiggetRequestMappingHandlerMapping

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

  1. 增加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); } }

  1. 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; } }

访问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; } }

访问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; } }

访问127.0.0.1:8080/param/hehe.heh返回hehe

  1. 修改参数

@RestController public class ParamController { @GetMapping(value = "/param/{param1:.+}") public String param(@PathVariable("param1") String param1) { return param1; } }

访问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; } } } 参考

www.cnblogs.com/yougatei/p/12812906.html

本文共计1472个文字,预计阅读时间需要6分钟。

如何获取Spring中@PathVariable注解包含点的全部参数值?

通过URL的扩展发现,Spring中出现了`useSuffixPatternMatch`这个参数。以下是关于这个参数的一些背景、原因、解决方案和参考资料:

如何获取Spring中@PathVariable注解包含点的全部参数值?

背景:`useSuffixPatternMatch`是Spring框架中用于URL匹配的参数,它控制Spring是否使用后缀模式匹配来解析控制器方法。

原因:在Spring 5.1及之前版本中,默认值为`true`,这意味着Spring会检查请求路径是否以特定后缀匹配。然而,这种做法可能会导致一些潜在的问题,例如无法正确处理带有参数的URL。

解决方案:要解决这个问题,可以将`useSuffixPatternMatch`设置为`false`,这样Spring就不会使用后缀模式匹配。

示例:java@Configuration@Import(WebMvcAutoConfiguration.class)public class WebConfig { @Bean public WebMvcConfigurer webMvcConfigurer() { return webMvcConfigurer -> webMvcConfigurer.setUseSuffixPatternMatch(false); }}

参考资料:- [Spring 5.1官方文档](https://docs.spring.io/spring-framework/docs/5.1.6.RELEASE/reference//web.#mvc-ann-config)- [Spring Boot 2.1.4官方文档](https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/single/#boot-features-spring-mvc)

通过URL的后缀发现了Spring中的useSuffixPatternMatch这个参数

目录
  • 背景
  • 原因
  • 解决
  • 参考

背景

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

启动一下,访问127.0.0.1:8080/param/hehe127.0.0.1:8080/param/hehe.hehe都返回hehe

如果访问127.0.0.1:8080/param/hehe.hehe.hehe,它会返回hehe.hehe

所以会发现它把最后一个小数点后面的字符给截掉了,那如果我们想要获取完整的字符串,该怎么办呢?

原因

下面的例子都是根据127.0.0.1:8080/param/hehe.hehe这个url来调试的

  1. 参数怎么来的

入口在InvocableHandlerMethod.invokeForRequest,如下:

是根据PathVariableMethodArgumentResolver.resolveName得来的,如下:

HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";

什么时候放进attributes里的?,在RequestMappingInfoHandlerMapping.handleMatch,如下:

  1. 参数怎么解析的

程序定义的:/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里没有.,会在后缀自动增加.*

  1. 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(); } } 解决

  1. 修改WebConfiggetRequestMappingHandlerMapping

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

  1. 增加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); } }

  1. 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; } }

访问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; } }

访问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; } }

访问127.0.0.1:8080/param/hehe.heh返回hehe

  1. 修改参数

@RestController public class ParamController { @GetMapping(value = "/param/{param1:.+}") public String param(@PathVariable("param1") String param1) { return param1; } }

访问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; } } } 参考

www.cnblogs.com/yougatei/p/12812906.html