Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Meiracle
spring-framework
提交
8aeae49f
S
spring-framework
项目概览
Meiracle
/
spring-framework
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8aeae49f
编写于
1月 26, 2021
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support for servletPath prefix in ServletRequestPathUtils
Closes gh-26445
上级
f22e2ac5
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
208 addition
and
37 deletion
+208
-37
spring-web/src/main/java/org/springframework/web/util/ServletRequestPathUtils.java
...org/springframework/web/util/ServletRequestPathUtils.java
+130
-20
spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java
...main/java/org/springframework/web/util/UrlPathHelper.java
+2
-2
spring-web/src/test/java/org/springframework/http/server/DefaultRequestPathTests.java
.../springframework/http/server/DefaultRequestPathTests.java
+12
-15
spring-web/src/test/java/org/springframework/web/util/ServletRequestPathUtilsTests.java
...pringframework/web/util/ServletRequestPathUtilsTests.java
+64
-0
未找到文件。
spring-web/src/main/java/org/springframework/web/util/ServletRequestPathUtils.java
浏览文件 @
8aeae49f
...
...
@@ -15,24 +15,29 @@
*/
package
org.springframework.web.util
;
import
java.nio.charset.StandardCharsets
;
import
java.util.List
;
import
javax.servlet.RequestDispatcher
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.http.HttpServletMapping
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.MappingMatch
;
import
org.springframework.http.server.PathContainer
;
import
org.springframework.http.server.RequestPath
;
import
org.springframework.lang.Nullable
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.util.StringUtils
;
/**
* Utility class to parse the path of an {@link HttpServletRequest} to a
* {@link RequestPath} and cache it in a request attribute for further access.
* This can then be used for URL path matching with
* {@link org.springframework.web.util.pattern.PathPattern PathPattern}s.
*
* <p>Also includes helper methods to return either a previously
* {@link UrlPathHelper#resolveAndCacheLookupPath resolved} String lookupPath
* or a previously {@link #parseAndCache parsed} {@code RequestPath} depending
* on which is cached in request attributes.
* Utility class to assist with preparation and access to the lookup path for
* request mapping purposes. This can be the parsed {@link RequestPath}
* representation of the path when use of
* {@link org.springframework.web.util.pattern.PathPattern parsed patterns}
* is enabled or a String path for use with a
* {@link org.springframework.util.PathMatcher} otherwise.
*
* @author Rossen Stoyanchev
* @since 5.3
...
...
@@ -44,20 +49,21 @@ public abstract class ServletRequestPathUtils {
/**
* Parse the {@link HttpServletRequest#getRequestURI() requestURI} of the
* request and its {@code contextPath} to create a {@link RequestPath} and
* cache it in the request attribute {@link #PATH_ATTRIBUTE}.
* Parse the {@link HttpServletRequest#getRequestURI() requestURI} to a
* {@link RequestPath} and save it in the request attribute
* {@link #PATH_ATTRIBUTE} for subsequent use with
* {@link org.springframework.web.util.pattern.PathPattern parsed patterns}.
* The returned {@code RequestPath} will have both the contextPath and any
* servletPath prefix omitted from the {@link RequestPath#pathWithinApplication()
* pathWithinApplication} it exposes.
*
* <p>This method ignores the {@link HttpServletRequest#getServletPath()
* servletPath} and the {@link HttpServletRequest#getPathInfo() pathInfo}.
* Therefore in case of a Servlet mapping by prefix, the
* {@link RequestPath#pathWithinApplication()} will always include the
* Servlet prefix.
* <p>This method is typically called by the {@code DispatcherServlet} to
* if any {@code HandlerMapping} indicates that it uses parsed patterns.
* After that the pre-parsed and cached {@code RequestPath} can be accessed
* through {@link #getParsedRequestPath(ServletRequest)}.
*/
public
static
RequestPath
parseAndCache
(
HttpServletRequest
request
)
{
String
requestUri
=
(
String
)
request
.
getAttribute
(
WebUtils
.
INCLUDE_REQUEST_URI_ATTRIBUTE
);
requestUri
=
(
requestUri
!=
null
?
requestUri
:
request
.
getRequestURI
());
RequestPath
requestPath
=
RequestPath
.
parse
(
requestUri
,
request
.
getContextPath
());
RequestPath
requestPath
=
ServletRequestPath
.
parse
(
request
);
request
.
setAttribute
(
PATH_ATTRIBUTE
,
requestPath
);
return
requestPath
;
}
...
...
@@ -172,4 +178,108 @@ public abstract class ServletRequestPathUtils {
request
.
getAttribute
(
UrlPathHelper
.
PATH_ATTRIBUTE
)
!=
null
);
}
/**
* Simple wrapper around the default {@link RequestPath} implementation that
* supports a servletPath as an additional prefix to be omitted from
* {@link #pathWithinApplication()}.
*/
private
static
class
ServletRequestPath
implements
RequestPath
{
private
final
RequestPath
requestPath
;
private
final
PathContainer
contextPath
;
private
ServletRequestPath
(
String
rawPath
,
@Nullable
String
contextPath
,
String
servletPathPrefix
)
{
Assert
.
notNull
(
servletPathPrefix
,
"`servletPathPrefix` is required"
);
this
.
requestPath
=
RequestPath
.
parse
(
rawPath
,
contextPath
+
servletPathPrefix
);
this
.
contextPath
=
PathContainer
.
parsePath
(
StringUtils
.
hasText
(
contextPath
)
?
contextPath
:
""
);
}
@Override
public
String
value
()
{
return
this
.
requestPath
.
value
();
}
@Override
public
List
<
Element
>
elements
()
{
return
this
.
requestPath
.
elements
();
}
@Override
public
PathContainer
contextPath
()
{
return
this
.
contextPath
;
}
@Override
public
PathContainer
pathWithinApplication
()
{
return
this
.
requestPath
.
pathWithinApplication
();
}
@Override
public
RequestPath
modifyContextPath
(
String
contextPath
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
equals
(
@Nullable
Object
other
)
{
if
(
this
==
other
)
{
return
true
;
}
if
(
other
==
null
||
getClass
()
!=
other
.
getClass
())
{
return
false
;
}
return
(
this
.
requestPath
.
equals
(((
ServletRequestPath
)
other
).
requestPath
));
}
@Override
public
int
hashCode
()
{
return
this
.
requestPath
.
hashCode
();
}
@Override
public
String
toString
()
{
return
this
.
requestPath
.
toString
();
}
public
static
RequestPath
parse
(
HttpServletRequest
request
)
{
String
requestUri
=
(
String
)
request
.
getAttribute
(
WebUtils
.
INCLUDE_REQUEST_URI_ATTRIBUTE
);
if
(
requestUri
==
null
)
{
requestUri
=
request
.
getRequestURI
();
}
if
(
UrlPathHelper
.
servlet4Present
)
{
String
servletPathPrefix
=
Servlet4Delegate
.
getServletPathPrefix
(
request
);
if
(
StringUtils
.
hasText
(
servletPathPrefix
))
{
return
new
ServletRequestPath
(
requestUri
,
request
.
getContextPath
(),
servletPathPrefix
);
}
}
return
RequestPath
.
parse
(
requestUri
,
request
.
getContextPath
());
}
}
/**
* Inner class to avoid a hard dependency on Servlet 4 {@link HttpServletMapping}
* and {@link MappingMatch} at runtime.
*/
private
static
class
Servlet4Delegate
{
@Nullable
public
static
String
getServletPathPrefix
(
HttpServletRequest
request
)
{
HttpServletMapping
mapping
=
(
HttpServletMapping
)
request
.
getAttribute
(
RequestDispatcher
.
INCLUDE_MAPPING
);
if
(
mapping
==
null
)
{
mapping
=
request
.
getHttpServletMapping
();
}
MappingMatch
match
=
mapping
.
getMappingMatch
();
if
(!
ObjectUtils
.
nullSafeEquals
(
match
,
MappingMatch
.
PATH
))
{
return
null
;
}
String
servletPath
=
(
String
)
request
.
getAttribute
(
WebUtils
.
INCLUDE_SERVLET_PATH_ATTRIBUTE
);
servletPath
=
(
servletPath
!=
null
?
servletPath
:
request
.
getServletPath
());
return
UriUtils
.
encodePath
(
servletPath
,
StandardCharsets
.
UTF_8
);
}
}
}
spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java
浏览文件 @
8aeae49f
/*
* Copyright 2002-202
0
the original author or authors.
* Copyright 2002-202
1
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -62,7 +62,7 @@ public class UrlPathHelper {
*/
public
static
final
String
PATH_ATTRIBUTE
=
UrlPathHelper
.
class
.
getName
()
+
".PATH"
;
private
static
final
boolean
servlet4Present
=
static
final
boolean
servlet4Present
=
ClassUtils
.
hasMethod
(
HttpServletRequest
.
class
,
"getHttpServletMapping"
);
/**
...
...
spring-web/src/test/java/org/springframework/http/server/DefaultRequestPathTests.java
浏览文件 @
8aeae49f
/*
* Copyright 2002-202
0
the original author or authors.
* Copyright 2002-202
1
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -26,40 +26,37 @@ import static org.assertj.core.api.Assertions.assertThat;
class
DefaultRequestPathTests
{
@Test
void
requestPath
()
{
void
parse
()
{
// basic
test
RequestPath
(
"/app/a/b/c"
,
"/app"
,
"/a/b/c"
);
test
Parse
(
"/app/a/b/c"
,
"/app"
,
"/a/b/c"
);
// no context path
test
RequestPath
(
"/a/b/c"
,
""
,
"/a/b/c"
);
test
Parse
(
"/a/b/c"
,
""
,
"/a/b/c"
);
// context path only
test
RequestPath
(
"/a/b"
,
"/a/b"
,
""
);
test
Parse
(
"/a/b"
,
"/a/b"
,
""
);
// root path
test
RequestPath
(
"/"
,
""
,
"/"
);
test
Parse
(
"/"
,
""
,
"/"
);
// empty path
test
RequestPath
(
""
,
""
,
""
);
test
RequestPath
(
""
,
"/"
,
""
);
test
Parse
(
""
,
""
,
""
);
test
Parse
(
""
,
"/"
,
""
);
// trailing slash
test
RequestPath
(
"/app/a/"
,
"/app"
,
"/a/"
);
test
RequestPath
(
"/app/a//"
,
"/app"
,
"/a//"
);
test
Parse
(
"/app/a/"
,
"/app"
,
"/a/"
);
test
Parse
(
"/app/a//"
,
"/app"
,
"/a//"
);
}
private
void
testRequestPath
(
String
fullPath
,
String
contextPath
,
String
pathWithinApplication
)
{
private
void
testParse
(
String
fullPath
,
String
contextPath
,
String
pathWithinApplication
)
{
RequestPath
requestPath
=
RequestPath
.
parse
(
fullPath
,
contextPath
);
Object
expected
=
contextPath
.
equals
(
"/"
)
?
""
:
contextPath
;
assertThat
(
requestPath
.
contextPath
().
value
()).
isEqualTo
(
expected
);
assertThat
(
requestPath
.
pathWithinApplication
().
value
()).
isEqualTo
(
pathWithinApplication
);
}
@Test
void
updateRequestPath
()
{
void
modifyContextPath
()
{
RequestPath
requestPath
=
RequestPath
.
parse
(
"/aA/bB/cC"
,
null
);
assertThat
(
requestPath
.
contextPath
().
value
()).
isEqualTo
(
""
);
...
...
spring-web/src/test/java/org/springframework/web/util/ServletRequestPathUtilsTests.java
0 → 100644
浏览文件 @
8aeae49f
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.web.util
;
import
javax.servlet.http.MappingMatch
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.http.server.RequestPath
;
import
org.springframework.web.testfixture.servlet.MockHttpServletMapping
;
import
org.springframework.web.testfixture.servlet.MockHttpServletRequest
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
/**
* Unit tests for {@link ServletRequestPathUtils}.
* @author Rossen Stoyanchev
*/
public
class
ServletRequestPathUtilsTests
{
@Test
void
parseAndCache
()
{
// basic
testParseAndCache
(
"/app/servlet/a/b/c"
,
"/app"
,
"/servlet"
,
"/a/b/c"
);
// contextPath only, servletPathOnly, contextPath and servletPathOnly
testParseAndCache
(
"/app/a/b/c"
,
"/app"
,
""
,
"/a/b/c"
);
testParseAndCache
(
"/servlet/a/b/c"
,
""
,
"/servlet"
,
"/a/b/c"
);
testParseAndCache
(
"/app1/app2/servlet1/servlet2"
,
"/app1/app2"
,
"/servlet1/servlet2"
,
""
);
// trailing slash
testParseAndCache
(
"/app/servlet/a/"
,
"/app"
,
"/servlet"
,
"/a/"
);
testParseAndCache
(
"/app/servlet/a//"
,
"/app"
,
"/servlet"
,
"/a//"
);
}
private
void
testParseAndCache
(
String
requestUri
,
String
contextPath
,
String
servletPath
,
String
pathWithinApplication
)
{
MockHttpServletRequest
request
=
new
MockHttpServletRequest
(
"GET"
,
requestUri
);
request
.
setContextPath
(
contextPath
);
request
.
setServletPath
(
servletPath
);
request
.
setHttpServletMapping
(
new
MockHttpServletMapping
(
pathWithinApplication
,
contextPath
,
"myServlet"
,
MappingMatch
.
PATH
));
RequestPath
requestPath
=
ServletRequestPathUtils
.
parseAndCache
(
request
);
assertThat
(
requestPath
.
contextPath
().
value
()).
isEqualTo
(
contextPath
);
assertThat
(
requestPath
.
pathWithinApplication
().
value
()).
isEqualTo
(
pathWithinApplication
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录