问题
我在修改了程序中的登录请求连接之后,从 /login.do
修改成为了/login
,发现我访问登录页面(/login.html
)的时候 总会去请求/login
。
起初,我以为是新加的shiro
造成的,因为设置的登录连接就是/login
。但是我的/login.html
设置的访问权限是anon
,不 应该进行拦截啊。
通过网上查找资料,也没找到跟我一样的问题,看来只能靠自己了。
原因
通过对程序进行调试,发现spring在对url链接进行匹配的时候,如果没有直接匹配到对应的@RequestMapping
,同时@RequestMapping
对应的url不包含字符.
会在url(这里是指@RequestMapping
对应的url)后面添加.*
进行匹配。所以就悲剧了,/login.html
匹配 到了/login.*
,就去访问/login
对应的Controller
,没有去访问对应的页面。
对应的代码是在org.springframework.web.servlet.mvc.condition.PatternsRequestCondition
这个类中,这个类是在spring-webmvc-4.3.3.RELEASE.jar
中。
相关的代码如下,在getMatchingPattern
方法中进行了匹配的操作:
/**
* Checks if any of the patterns match the given request and returns an instance
* that is guaranteed to contain matching patterns, sorted via
* {@link PathMatcher#getPatternComparator(String)}.
* <p>A matching pattern is obtained by making checks in the following order:
* <ul>
* <li>Direct match
* <li>Pattern match with ".*" appended if the pattern doesn't already contain a "."
* <li>Pattern match
* <li>Pattern match with "/" appended if the pattern doesn't already end in "/"
* </ul>
* @param request the current request
* @return the same instance if the condition contains no patterns;
* or a new condition with sorted matching patterns;
* or {@code null} if no patterns match.
*/
@Override
public PatternsRequestCondition getMatchingCondition(HttpServletRequest request) {
if (this.patterns.isEmpty()) {
return this;
}
String lookupPath = this.pathHelper.getLookupPathForRequest(request);
List<String> matches = getMatchingPatterns(lookupPath);
return matches.isEmpty() ? null :
new PatternsRequestCondition(matches, this.pathHelper, this.pathMatcher, this.useSuffixPatternMatch,
this.useTrailingSlashMatch, this.fileExtensions);
}
/**
* Find the patterns matching the given lookup path. Invoking this method should
* yield results equivalent to those of calling
* {@link #getMatchingCondition(javax.servlet.http.HttpServletRequest)}.
* This method is provided as an alternative to be used if no request is available
* (e.g. introspection, tooling, etc).
* @param lookupPath the lookup path to match to existing patterns
* @return a collection of matching patterns sorted with the closest match at the top
*/
public List<String> getMatchingPatterns(String lookupPath) {
List<String> matches = new ArrayList<String>();
for (String pattern : this.patterns) {
String match = getMatchingPattern(pattern, lookupPath);
if (match != null) {
matches.add(match);
}
}
Collections.sort(matches, this.pathMatcher.getPatternComparator(lookupPath));
return matches;
}
/**
*pattern 是使用注解`@RequestMapping`配置的url 比如:@RequestMapping("/login")
*lookupPath 是请求的url 比如:"/login.html"
*/
private String getMatchingPattern(String pattern, String lookupPath) {
if (pattern.equals(lookupPath)) {
return pattern;
}
if (this.useSuffixPatternMatch) {
if (!this.fileExtensions.isEmpty() && lookupPath.indexOf('.') != -1) {
for (String extension : this.fileExtensions) {
if (this.pathMatcher.match(pattern + extension, lookupPath)) {
return pattern + extension;
}
}
}
else {
boolean hasSuffix = pattern.indexOf('.') != -1;
if (!hasSuffix && this.pathMatcher.match(pattern + ".*", lookupPath)) {
return pattern + ".*";
}
}
}
if (this.pathMatcher.match(pattern, lookupPath)) {
return pattern;
}
if (this.useTrailingSlashMatch) {
if (!pattern.endsWith("/") && this.pathMatcher.match(pattern + "/", lookupPath)) {
return pattern +"/";
}
}
return null;
}
如有问题,欢迎留言交流