Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
19dc9816
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
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,发现更多精彩内容 >>
提交
19dc9816
编写于
6月 07, 2018
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Path prefixes for groups of controllers
Issue: SPR-16336
上级
31159a85
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
313 addition
and
33 deletion
+313
-33
spring-webflux/src/main/java/org/springframework/web/reactive/config/PathMatchConfigurer.java
...ingframework/web/reactive/config/PathMatchConfigurer.java
+28
-1
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java
...work/web/reactive/config/WebFluxConfigurationSupport.java
+10
-1
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java
...esult/method/annotation/RequestMappingHandlerMapping.java
+42
-1
spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java
...web/reactive/config/WebFluxConfigurationSupportTests.java
+32
-1
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMappingTests.java
.../method/annotation/RequestMappingHandlerMappingTests.java
+33
-4
spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java
...rk/web/servlet/config/annotation/PathMatchConfigurer.java
+27
-0
spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
...servlet/config/annotation/WebMvcConfigurationSupport.java
+11
-2
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
...t/mvc/method/annotation/RequestMappingHandlerMapping.java
+42
-1
spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java
.../annotation/WebMvcConfigurationSupportExtensionTests.java
+31
-1
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMappingTests.java
.../method/annotation/RequestMappingHandlerMappingTests.java
+31
-6
src/docs/asciidoc/web/webflux.adoc
src/docs/asciidoc/web/webflux.adoc
+20
-11
src/docs/asciidoc/web/webmvc.adoc
src/docs/asciidoc/web/webmvc.adoc
+6
-4
未找到文件。
spring-webflux/src/main/java/org/springframework/web/reactive/config/PathMatchConfigurer.java
浏览文件 @
19dc9816
/*
* Copyright 2002-201
7
the original author or authors.
* Copyright 2002-201
8
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.
...
...
@@ -16,7 +16,11 @@
package
org.springframework.web.reactive.config
;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
org.springframework.lang.Nullable
;
import
org.springframework.web.method.HandlerTypePredicate
;
/**
* Assist with configuring {@code HandlerMapping}'s with path matching options.
...
...
@@ -34,6 +38,9 @@ public class PathMatchConfigurer {
@Nullable
private
Boolean
caseSensitiveMatch
;
@Nullable
private
Map
<
String
,
HandlerTypePredicate
>
pathPrefixes
;
/**
* Whether to match to URLs irrespective of their case.
...
...
@@ -55,6 +62,22 @@ public class PathMatchConfigurer {
return
this
;
}
/**
* Configure a path prefix to apply to matching controller methods.
* <p>Prefixes are used to enrich the mappings of every {@code @RequestMapping}
* method whose controller type is matched by the corresponding
* {@link HandlerTypePredicate}. The prefix for the first matching predicate
* is used.
* @param prefix the path prefix to apply
* @param predicate a predicate for matching controller types
* @since 5.1
*/
public
PathMatchConfigurer
addPathPrefix
(
String
prefix
,
HandlerTypePredicate
predicate
)
{
this
.
pathPrefixes
=
this
.
pathPrefixes
==
null
?
new
LinkedHashMap
<>()
:
this
.
pathPrefixes
;
this
.
pathPrefixes
.
put
(
prefix
,
predicate
);
return
this
;
}
@Nullable
protected
Boolean
isUseTrailingSlashMatch
()
{
return
this
.
trailingSlashMatch
;
...
...
@@ -65,4 +88,8 @@ public class PathMatchConfigurer {
return
this
.
caseSensitiveMatch
;
}
@Nullable
protected
Map
<
String
,
HandlerTypePredicate
>
getPathPrefixes
()
{
return
this
.
pathPrefixes
;
}
}
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java
浏览文件 @
19dc9816
...
...
@@ -44,6 +44,7 @@ import org.springframework.validation.Validator;
import
org.springframework.web.bind.WebDataBinder
;
import
org.springframework.web.bind.support.ConfigurableWebBindingInitializer
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.reactive.DispatcherHandler
;
import
org.springframework.web.reactive.HandlerMapping
;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolver
;
...
...
@@ -119,14 +120,22 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
mapping
.
setCorsConfigurations
(
getCorsConfigurations
());
PathMatchConfigurer
configurer
=
getPathMatchConfigurer
();
Boolean
useTrailingSlashMatch
=
configurer
.
isUseTrailingSlashMatch
();
Boolean
useCaseSensitiveMatch
=
configurer
.
isUseCaseSensitiveMatch
();
if
(
useTrailingSlashMatch
!=
null
)
{
mapping
.
setUseTrailingSlashMatch
(
useTrailingSlashMatch
);
}
Boolean
useCaseSensitiveMatch
=
configurer
.
isUseCaseSensitiveMatch
();
if
(
useCaseSensitiveMatch
!=
null
)
{
mapping
.
setUseCaseSensitiveMatch
(
useCaseSensitiveMatch
);
}
Map
<
String
,
HandlerTypePredicate
>
pathPrefixes
=
configurer
.
getPathPrefixes
();
if
(
pathPrefixes
!=
null
)
{
mapping
.
setPathPrefixes
(
pathPrefixes
);
}
return
mapping
;
}
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java
浏览文件 @
19dc9816
/*
* Copyright 2002-201
7
the original author or authors.
* Copyright 2002-201
8
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.
...
...
@@ -18,6 +18,9 @@ package org.springframework.web.reactive.result.method.annotation;
import
java.lang.reflect.AnnotatedElement
;
import
java.lang.reflect.Method
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
org.springframework.context.EmbeddedValueResolverAware
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
...
...
@@ -25,11 +28,13 @@ import org.springframework.lang.Nullable;
import
org.springframework.stereotype.Controller
;
import
org.springframework.util.Assert
;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.util.StringUtils
;
import
org.springframework.util.StringValueResolver
;
import
org.springframework.web.bind.annotation.CrossOrigin
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolver
;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder
;
...
...
@@ -48,6 +53,8 @@ import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerM
public
class
RequestMappingHandlerMapping
extends
RequestMappingInfoHandlerMapping
implements
EmbeddedValueResolverAware
{
private
final
Map
<
String
,
HandlerTypePredicate
>
pathPrefixes
=
new
LinkedHashMap
<>();
private
RequestedContentTypeResolver
contentTypeResolver
=
new
RequestedContentTypeResolverBuilder
().
build
();
@Nullable
...
...
@@ -56,6 +63,22 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
private
RequestMappingInfo
.
BuilderConfiguration
config
=
new
RequestMappingInfo
.
BuilderConfiguration
();
/**
* Configure path prefixes to apply to controller methods.
* <p>Prefixes are used to enrich the mappings of every {@code @RequestMapping}
* method whose controller type is matched by the corresponding
* {@link HandlerTypePredicate} in the map. The prefix for the first matching
* predicate is used, assuming the input map has predictable order.
* @param prefixes a map with path prefixes as key
* @since 5.1
*/
public
void
setPathPrefixes
(
Map
<
String
,
HandlerTypePredicate
>
prefixes
)
{
this
.
pathPrefixes
.
clear
();
prefixes
.
entrySet
().
stream
()
.
filter
(
entry
->
StringUtils
.
hasText
(
entry
.
getKey
()))
.
forEach
(
entry
->
this
.
pathPrefixes
.
put
(
entry
.
getKey
(),
entry
.
getValue
()));
}
/**
* Set the {@link RequestedContentTypeResolver} to use to determine requested media types.
* If not set, the default constructor is used.
...
...
@@ -80,6 +103,14 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
}
/**
* The configured path prefixes as a read-only, possibly empty map.
* @since 5.1
*/
public
Map
<
String
,
HandlerTypePredicate
>
getPathPrefixes
()
{
return
Collections
.
unmodifiableMap
(
this
.
pathPrefixes
);
}
/**
* Return the configured {@link RequestedContentTypeResolver}.
*/
...
...
@@ -113,6 +144,16 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
if
(
typeInfo
!=
null
)
{
info
=
typeInfo
.
combine
(
info
);
}
for
(
Map
.
Entry
<
String
,
HandlerTypePredicate
>
entry
:
this
.
pathPrefixes
.
entrySet
())
{
if
(
entry
.
getValue
().
test
(
handlerType
))
{
String
prefix
=
entry
.
getKey
();
if
(
this
.
embeddedValueResolver
!=
null
)
{
prefix
=
this
.
embeddedValueResolver
.
resolveStringValue
(
prefix
);
}
info
=
RequestMappingInfo
.
paths
(
prefix
).
build
().
combine
(
info
);
break
;
}
}
}
return
info
;
}
...
...
spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java
浏览文件 @
19dc9816
...
...
@@ -18,8 +18,10 @@ package org.springframework.web.reactive.config;
import
java.lang.reflect.Field
;
import
java.nio.ByteBuffer
;
import
java.security.Principal
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
javax.xml.bind.annotation.XmlRootElement
;
import
org.junit.Test
;
...
...
@@ -47,11 +49,17 @@ import org.springframework.util.MimeTypeUtils;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.validation.Validator
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.support.WebBindingInitializer
;
import
org.springframework.web.bind.support.WebExchangeDataBinder
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolver
;
import
org.springframework.web.reactive.handler.AbstractUrlHandlerMapping
;
import
org.springframework.web.reactive.handler.SimpleUrlHandlerMapping
;
import
org.springframework.web.reactive.result.method.RequestMappingInfo
;
import
org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter
;
import
org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping
;
import
org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler
;
...
...
@@ -67,6 +75,7 @@ import org.springframework.web.server.WebHandler;
import
org.springframework.web.util.pattern.PathPatternParser
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
mockito
.
Mockito
.*;
import
static
org
.
springframework
.
core
.
ResolvableType
.
forClass
;
import
static
org
.
springframework
.
core
.
ResolvableType
.
forClassWithGenerics
;
import
static
org
.
springframework
.
http
.
MediaType
.
APPLICATION_FORM_URLENCODED
;
...
...
@@ -110,7 +119,7 @@ public class WebFluxConfigurationSupportTests {
}
@Test
public
void
customPathMatchConfig
()
throws
Exception
{
public
void
customPathMatchConfig
()
{
ApplicationContext
context
=
loadConfig
(
CustomPatchMatchConfig
.
class
);
final
Field
field
=
ReflectionUtils
.
findField
(
PathPatternParser
.
class
,
"matchOptionalTrailingSeparator"
);
ReflectionUtils
.
makeAccessible
(
field
);
...
...
@@ -123,6 +132,11 @@ public class WebFluxConfigurationSupportTests {
assertNotNull
(
patternParser
);
boolean
matchOptionalTrailingSlash
=
(
boolean
)
ReflectionUtils
.
getField
(
field
,
patternParser
);
assertFalse
(
matchOptionalTrailingSlash
);
Map
<
RequestMappingInfo
,
HandlerMethod
>
map
=
mapping
.
getHandlerMethods
();
assertEquals
(
1
,
map
.
size
());
assertEquals
(
Collections
.
singleton
(
new
PathPatternParser
().
parse
(
"/api/user/{id}"
)),
map
.
keySet
().
iterator
().
next
().
getPatternsCondition
().
getPatterns
());
}
@Test
...
...
@@ -295,6 +309,23 @@ public class WebFluxConfigurationSupportTests {
@Override
public
void
configurePathMatching
(
PathMatchConfigurer
configurer
)
{
configurer
.
setUseTrailingSlashMatch
(
false
);
configurer
.
addPathPrefix
(
"/api"
,
HandlerTypePredicate
.
forAnnotation
(
RestController
.
class
));
}
@Bean
UserController
userController
()
{
return
new
UserController
();
}
}
@RestController
@RequestMapping
(
"/user"
)
static
class
UserController
{
@GetMapping
(
"/{id}"
)
public
Principal
getUser
()
{
return
mock
(
Principal
.
class
);
}
}
...
...
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMappingTests.java
浏览文件 @
19dc9816
/*
* Copyright 2002-201
7
the original author or authors.
* Copyright 2002-201
8
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.
...
...
@@ -21,7 +21,9 @@ import java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
java.lang.reflect.Method
;
import
java.security.Principal
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Set
;
import
org.junit.Before
;
...
...
@@ -37,13 +39,17 @@ import org.springframework.web.bind.annotation.PostMapping;
import
org.springframework.web.bind.annotation.PutMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.context.support.StaticWebApplicationContext
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.reactive.result.method.RequestMappingInfo
;
import
org.springframework.web.util.pattern.PathPattern
;
import
org.springframework.web.util.pattern.PathPatternParser
;
import
static
org
.
junit
.
Assert
.
assertArrayEquals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
mockito
.
Mockito
.*;
/**
* Unit tests for {@link RequestMappingHandlerMapping}.
...
...
@@ -64,9 +70,7 @@ public class RequestMappingHandlerMappingTests {
@Test
public
void
resolveEmbeddedValuesInPatterns
()
{
this
.
handlerMapping
.
setEmbeddedValueResolver
(
value
->
"/${pattern}/bar"
.
equals
(
value
)
?
"/foo/bar"
:
value
);
this
.
handlerMapping
.
setEmbeddedValueResolver
(
value
->
"/${pattern}/bar"
.
equals
(
value
)
?
"/foo/bar"
:
value
);
String
[]
patterns
=
new
String
[]
{
"/foo"
,
"/${pattern}/bar"
};
String
[]
result
=
this
.
handlerMapping
.
resolveEmbeddedValuesInPatterns
(
patterns
);
...
...
@@ -74,6 +78,20 @@ public class RequestMappingHandlerMappingTests {
assertArrayEquals
(
new
String
[]
{
"/foo"
,
"/foo/bar"
},
result
);
}
@Test
public
void
pathPrefix
()
throws
NoSuchMethodException
{
this
.
handlerMapping
.
setEmbeddedValueResolver
(
value
->
"/${prefix}"
.
equals
(
value
)
?
"/api"
:
value
);
this
.
handlerMapping
.
setPathPrefixes
(
Collections
.
singletonMap
(
"/${prefix}"
,
HandlerTypePredicate
.
forAnnotation
(
RestController
.
class
)));
Method
method
=
UserController
.
class
.
getMethod
(
"getUser"
);
RequestMappingInfo
info
=
this
.
handlerMapping
.
getMappingForMethod
(
method
,
UserController
.
class
);
assertNotNull
(
info
);
assertEquals
(
Collections
.
singleton
(
new
PathPatternParser
().
parse
(
"/api/user/{id}"
)),
info
.
getPatternsCondition
().
getPatterns
());
}
@Test
public
void
resolveRequestMappingViaComposedAnnotation
()
throws
Exception
{
RequestMappingInfo
info
=
assertComposedAnnotationMapping
(
"postJson"
,
"/postJson"
,
RequestMethod
.
POST
);
...
...
@@ -191,4 +209,15 @@ public class RequestMappingHandlerMappingTests {
String
[]
value
()
default
{};
}
@RestController
@RequestMapping
(
"/user"
)
static
class
UserController
{
@GetMapping
(
"/{id}"
)
public
Principal
getUser
()
{
return
mock
(
Principal
.
class
);
}
}
}
spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java
浏览文件 @
19dc9816
...
...
@@ -16,8 +16,12 @@
package
org.springframework.web.servlet.config.annotation
;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
org.springframework.lang.Nullable
;
import
org.springframework.util.PathMatcher
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.util.UrlPathHelper
;
/**
...
...
@@ -53,6 +57,9 @@ public class PathMatchConfigurer {
@Nullable
private
PathMatcher
pathMatcher
;
@Nullable
private
Map
<
String
,
HandlerTypePredicate
>
pathPrefixes
;
/**
* Whether to use suffix pattern match (".*") when matching patterns to
...
...
@@ -110,6 +117,22 @@ public class PathMatchConfigurer {
return
this
;
}
/**
* Configure a path prefix to apply to matching controller methods.
* <p>Prefixes are used to enrich the mappings of every {@code @RequestMapping}
* method whose controller type is matched by the corresponding
* {@link HandlerTypePredicate}. The prefix for the first matching predicate
* is used.
* @param prefix the prefix to apply
* @param predicate a predicate for matching controller types
* @since 5.1
*/
public
PathMatchConfigurer
addPathPrefix
(
String
prefix
,
HandlerTypePredicate
predicate
)
{
this
.
pathPrefixes
=
this
.
pathPrefixes
==
null
?
new
LinkedHashMap
<>()
:
this
.
pathPrefixes
;
this
.
pathPrefixes
.
put
(
prefix
,
predicate
);
return
this
;
}
@Nullable
public
Boolean
isUseSuffixPatternMatch
()
{
...
...
@@ -136,4 +159,8 @@ public class PathMatchConfigurer {
return
this
.
pathMatcher
;
}
@Nullable
protected
Map
<
String
,
HandlerTypePredicate
>
getPathPrefixes
()
{
return
this
.
pathPrefixes
;
}
}
spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java
浏览文件 @
19dc9816
...
...
@@ -70,6 +70,7 @@ import org.springframework.web.bind.WebDataBinder;
import
org.springframework.web.bind.support.ConfigurableWebBindingInitializer
;
import
org.springframework.web.context.ServletContextAware
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.method.support.CompositeUriComponentsContributor
;
import
org.springframework.web.method.support.HandlerMethodArgumentResolver
;
import
org.springframework.web.method.support.HandlerMethodReturnValueHandler
;
...
...
@@ -284,15 +285,18 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
mapping
.
setCorsConfigurations
(
getCorsConfigurations
());
PathMatchConfigurer
configurer
=
getPathMatchConfigurer
();
Boolean
useSuffixPatternMatch
=
configurer
.
isUseSuffixPatternMatch
();
Boolean
useRegisteredSuffixPatternMatch
=
configurer
.
isUseRegisteredSuffixPatternMatch
();
Boolean
useTrailingSlashMatch
=
configurer
.
isUseTrailingSlashMatch
();
if
(
useSuffixPatternMatch
!=
null
)
{
mapping
.
setUseSuffixPatternMatch
(
useSuffixPatternMatch
);
}
Boolean
useRegisteredSuffixPatternMatch
=
configurer
.
isUseRegisteredSuffixPatternMatch
();
if
(
useRegisteredSuffixPatternMatch
!=
null
)
{
mapping
.
setUseRegisteredSuffixPatternMatch
(
useRegisteredSuffixPatternMatch
);
}
Boolean
useTrailingSlashMatch
=
configurer
.
isUseTrailingSlashMatch
();
if
(
useTrailingSlashMatch
!=
null
)
{
mapping
.
setUseTrailingSlashMatch
(
useTrailingSlashMatch
);
}
...
...
@@ -307,6 +311,11 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
mapping
.
setPathMatcher
(
pathMatcher
);
}
Map
<
String
,
HandlerTypePredicate
>
pathPrefixes
=
configurer
.
getPathPrefixes
();
if
(
pathPrefixes
!=
null
)
{
mapping
.
setPathPrefixes
(
pathPrefixes
);
}
return
mapping
;
}
...
...
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
浏览文件 @
19dc9816
/*
* Copyright 2002-201
7
the original author or authors.
* Copyright 2002-201
8
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.
...
...
@@ -18,7 +18,10 @@ package org.springframework.web.servlet.mvc.method.annotation;
import
java.lang.reflect.AnnotatedElement
;
import
java.lang.reflect.Method
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.servlet.http.HttpServletRequest
;
...
...
@@ -28,12 +31,14 @@ import org.springframework.lang.Nullable;
import
org.springframework.stereotype.Controller
;
import
org.springframework.util.Assert
;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.util.StringUtils
;
import
org.springframework.util.StringValueResolver
;
import
org.springframework.web.accept.ContentNegotiationManager
;
import
org.springframework.web.bind.annotation.CrossOrigin
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.servlet.handler.MatchableHandlerMapping
;
import
org.springframework.web.servlet.handler.RequestMatchResult
;
...
...
@@ -62,6 +67,8 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
private
boolean
useTrailingSlashMatch
=
true
;
private
final
Map
<
String
,
HandlerTypePredicate
>
pathPrefixes
=
new
LinkedHashMap
<>();
private
ContentNegotiationManager
contentNegotiationManager
=
new
ContentNegotiationManager
();
@Nullable
...
...
@@ -102,6 +109,22 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
this
.
useTrailingSlashMatch
=
useTrailingSlashMatch
;
}
/**
* Configure path prefixes to apply to controller methods.
* <p>Prefixes are used to enrich the mappings of every {@code @RequestMapping}
* method whose controller type is matched by the corresponding
* {@link HandlerTypePredicate} in the map. The prefix for the first matching
* predicate is used, assuming the input map has predictable order.
* @param prefixes a map with path prefixes as key
* @since 5.1
*/
public
void
setPathPrefixes
(
Map
<
String
,
HandlerTypePredicate
>
prefixes
)
{
this
.
pathPrefixes
.
clear
();
prefixes
.
entrySet
().
stream
()
.
filter
(
entry
->
StringUtils
.
hasText
(
entry
.
getKey
()))
.
forEach
(
entry
->
this
.
pathPrefixes
.
put
(
entry
.
getKey
(),
entry
.
getValue
()));
}
/**
* Set the {@link ContentNegotiationManager} to use to determine requested media types.
* If not set, the default constructor is used.
...
...
@@ -151,6 +174,14 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
return
this
.
useTrailingSlashMatch
;
}
/**
* The configured path prefixes as a read-only, possibly empty map.
* @since 5.1
*/
public
Map
<
String
,
HandlerTypePredicate
>
getPathPrefixes
()
{
return
Collections
.
unmodifiableMap
(
this
.
pathPrefixes
);
}
/**
* Return the configured {@link ContentNegotiationManager}.
*/
...
...
@@ -195,6 +226,16 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
if
(
typeInfo
!=
null
)
{
info
=
typeInfo
.
combine
(
info
);
}
for
(
Map
.
Entry
<
String
,
HandlerTypePredicate
>
entry
:
this
.
pathPrefixes
.
entrySet
())
{
if
(
entry
.
getValue
().
test
(
handlerType
))
{
String
prefix
=
entry
.
getKey
();
if
(
this
.
embeddedValueResolver
!=
null
)
{
prefix
=
this
.
embeddedValueResolver
.
resolveStringValue
(
prefix
);
}
info
=
RequestMappingInfo
.
paths
(
prefix
).
build
().
combine
(
info
);
break
;
}
}
}
return
info
;
}
...
...
spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java
浏览文件 @
19dc9816
/*
* Copyright 2002-201
6
the original author or authors.
* Copyright 2002-201
8
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.
...
...
@@ -16,6 +16,7 @@
package
org.springframework.web.servlet.config.annotation
;
import
java.security.Principal
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.List
;
...
...
@@ -48,7 +49,9 @@ import org.springframework.validation.Errors;
import
org.springframework.validation.MessageCodesResolver
;
import
org.springframework.validation.Validator
;
import
org.springframework.web.accept.ContentNegotiationManager
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.support.ConfigurableWebBindingInitializer
;
import
org.springframework.web.context.request.NativeWebRequest
;
import
org.springframework.web.context.request.ServletWebRequest
;
...
...
@@ -56,6 +59,8 @@ import org.springframework.web.context.request.async.CallableProcessingIntercept
import
org.springframework.web.context.request.async.DeferredResultProcessingInterceptor
;
import
org.springframework.web.context.support.StaticWebApplicationContext
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.method.HandlerMethod
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.method.annotation.ModelAttributeMethodProcessor
;
import
org.springframework.web.method.support.HandlerMethodArgumentResolver
;
import
org.springframework.web.method.support.HandlerMethodReturnValueHandler
;
...
...
@@ -70,6 +75,7 @@ import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
;
import
org.springframework.web.servlet.i18n.LocaleChangeInterceptor
;
import
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
;
import
org.springframework.web.servlet.mvc.method.RequestMappingInfo
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
;
import
org.springframework.web.servlet.resource.ResourceHttpRequestHandler
;
...
...
@@ -86,6 +92,7 @@ import static org.junit.Assert.assertEquals;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertSame
;
import
static
org
.
mockito
.
Mockito
.*;
import
static
org
.
springframework
.
http
.
MediaType
.
APPLICATION_ATOM_XML
;
import
static
org
.
springframework
.
http
.
MediaType
.
APPLICATION_JSON
;
import
static
org
.
springframework
.
http
.
MediaType
.
APPLICATION_XML
;
...
...
@@ -114,6 +121,7 @@ public class WebMvcConfigurationSupportExtensionTests {
this
.
context
=
new
StaticWebApplicationContext
();
this
.
context
.
setServletContext
(
new
MockServletContext
(
new
FileSystemResourceLoader
()));
this
.
context
.
registerSingleton
(
"controller"
,
TestController
.
class
);
this
.
context
.
registerSingleton
(
"userController"
,
UserController
.
class
);
this
.
config
=
new
TestWebMvcConfigurationSupport
();
this
.
config
.
setApplicationContext
(
this
.
context
);
...
...
@@ -135,6 +143,15 @@ public class WebMvcConfigurationSupportExtensionTests {
assertEquals
(
ConversionServiceExposingInterceptor
.
class
,
chain
.
getInterceptors
()[
1
].
getClass
());
assertEquals
(
ResourceUrlProviderExposingInterceptor
.
class
,
chain
.
getInterceptors
()[
2
].
getClass
());
Map
<
RequestMappingInfo
,
HandlerMethod
>
map
=
rmHandlerMapping
.
getHandlerMethods
();
assertEquals
(
2
,
map
.
size
());
RequestMappingInfo
info
=
map
.
entrySet
().
stream
()
.
filter
(
entry
->
entry
.
getValue
().
getBeanType
().
equals
(
UserController
.
class
))
.
findFirst
()
.
orElseThrow
(()
->
new
AssertionError
(
"UserController bean not found"
))
.
getKey
();
assertEquals
(
Collections
.
singleton
(
"/api/user/{id}"
),
info
.
getPatternsCondition
().
getPatterns
());
AbstractHandlerMapping
handlerMapping
=
(
AbstractHandlerMapping
)
this
.
config
.
viewControllerHandlerMapping
();
handlerMapping
.
setApplicationContext
(
this
.
context
);
assertNotNull
(
handlerMapping
);
...
...
@@ -402,6 +419,7 @@ public class WebMvcConfigurationSupportExtensionTests {
public
void
configurePathMatch
(
PathMatchConfigurer
configurer
)
{
configurer
.
setPathMatcher
(
new
TestPathMatcher
());
configurer
.
setUrlPathHelper
(
new
TestPathHelper
());
configurer
.
addPathPrefix
(
"/api"
,
HandlerTypePredicate
.
forAnnotation
(
RestController
.
class
));
}
@Override
...
...
@@ -453,4 +471,16 @@ public class WebMvcConfigurationSupportExtensionTests {
private
class
TestPathHelper
extends
UrlPathHelper
{}
private
class
TestPathMatcher
extends
AntPathMatcher
{}
@RestController
@RequestMapping
(
"/user"
)
static
class
UserController
{
@GetMapping
(
"/{id}"
)
public
Principal
getUser
()
{
return
mock
(
Principal
.
class
);
}
}
}
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMappingTests.java
浏览文件 @
19dc9816
/*
* Copyright 2002-201
6
the original author or authors.
* Copyright 2002-201
8
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.
...
...
@@ -21,6 +21,7 @@ import java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
java.lang.reflect.Method
;
import
java.security.Principal
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
...
...
@@ -42,14 +43,13 @@ import org.springframework.web.bind.annotation.PostMapping;
import
org.springframework.web.bind.annotation.PutMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.context.support.StaticWebApplicationContext
;
import
org.springframework.web.method.HandlerTypePredicate
;
import
org.springframework.web.servlet.mvc.method.RequestMappingInfo
;
import
static
org
.
junit
.
Assert
.
assertArrayEquals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
mockito
.
Mockito
.*;
/**
* Tests for {@link RequestMappingHandlerMapping}.
...
...
@@ -140,6 +140,19 @@ public class RequestMappingHandlerMappingTests {
assertArrayEquals
(
new
String
[]
{
"/foo"
,
"/foo/bar"
},
result
);
}
@Test
public
void
pathPrefix
()
throws
NoSuchMethodException
{
this
.
handlerMapping
.
setEmbeddedValueResolver
(
value
->
"/${prefix}"
.
equals
(
value
)
?
"/api"
:
value
);
this
.
handlerMapping
.
setPathPrefixes
(
Collections
.
singletonMap
(
"/${prefix}"
,
HandlerTypePredicate
.
forAnnotation
(
RestController
.
class
)));
Method
method
=
UserController
.
class
.
getMethod
(
"getUser"
);
RequestMappingInfo
info
=
this
.
handlerMapping
.
getMappingForMethod
(
method
,
UserController
.
class
);
assertNotNull
(
info
);
assertEquals
(
Collections
.
singleton
(
"/api/user/{id}"
),
info
.
getPatternsCondition
().
getPatterns
());
}
@Test
public
void
resolveRequestMappingViaComposedAnnotation
()
throws
Exception
{
RequestMappingInfo
info
=
assertComposedAnnotationMapping
(
"postJson"
,
"/postJson"
,
RequestMethod
.
POST
);
...
...
@@ -245,6 +258,7 @@ public class RequestMappingHandlerMappingTests {
}
@RequestMapping
(
method
=
RequestMethod
.
POST
,
produces
=
MediaType
.
APPLICATION_JSON_VALUE
,
consumes
=
MediaType
.
APPLICATION_JSON_VALUE
)
...
...
@@ -256,4 +270,15 @@ public class RequestMappingHandlerMappingTests {
String
[]
value
()
default
{};
}
@RestController
@RequestMapping
(
"/user"
)
static
class
UserController
{
@GetMapping
(
"/{id}"
)
public
Principal
getUser
()
{
return
mock
(
Principal
.
class
);
}
}
}
src/docs/asciidoc/web/webflux.adoc
浏览文件 @
19dc9816
...
...
@@ -2929,16 +2929,8 @@ match to incoming URLs without versions -- e.g. `"/jquery/jquery.min.js"` to
=== Path Matching
[.small]#<<web.adoc#mvc-config-path-matching,Same in Spring MVC>>#
Spring WebFlux uses parsed representation of path patterns -- i.e. `PathPattern`, and also
the incoming request path -- i.e. `RequestPath`, which eliminates the need to indicate
whether to decode the request path, or remove semicolon content, since `PathPattern`
can now access decoded path segment values and match safely.
Spring WebFlux also does not support suffix pattern matching so effectively there are only two
minor options to customize related to path matching -- whether to match trailing slashes
(`true` by default) and whether the match is case-sensitive (`false`).
To customize those options:
Customize options related to path matching. For details on the individual options, see the
{api-spring-framework}/web/reactive/config/PathMatchConfigurer.html[PathMatchConfigurer] Javadoc.
[source,java,indent=0]
[subs="verbatim,quotes"]
...
...
@@ -2949,12 +2941,29 @@ To customize those options:
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// ...
configurer
.setUseCaseSensitiveMatch(true)
.setUseTrailingSlashMatch(false)
.addPathPrefix("/api",
HandlerTypePredicate.forAnnotation(RestController.class));
}
}
----
[TIP]
====
Spring WebFlux relies on a parsed representation of the request path called
`RequestPath` for access to decoded path segment values, with semicolon content removed
(i.e. path/matrix variables). That means, unlike Spring MVC, there is no need to indicate
neither whether to decode the request path, nor whether to remove semicolon content for
path matching purposes.
Spring WebFlux also does not support suffix pattern matching, unlike Spring MVC, where we
also <<web.adoc#mvc-ann-requestmapping-suffix-pattern-match,recommend>> moving away from
reliance on it.
====
[[webflux-config-advanced-java]]
...
...
src/docs/asciidoc/web/webmvc.adoc
浏览文件 @
19dc9816
...
...
@@ -4644,9 +4644,9 @@ Or in XML:
=== Path Matching
[.small]#
<
<
web-reactive.adoc#webflux-config-path-matching
,
Same
in
Spring
WebFlux
>
>#
This allows customizing options related to URL matching
and treatment of the URL.
For details on the individual options
check out
the
{api-spring-framework}/web/servlet/config/annotation/PathMatchConfigurer.html[PathMatchConfigurer]
API
.
Customize options related to path matching,
and treatment of the URL.
For details on the individual options
, see
the
{api-spring-framework}/web/servlet/config/annotation/PathMatchConfigurer.html[PathMatchConfigurer]
Javadoc
.
Example in Java config:
...
...
@@ -4664,7 +4664,9 @@ Example in Java config:
.setUseTrailingSlashMatch(false)
.setUseRegisteredSuffixPatternMatch(true)
.setPathMatcher(antPathMatcher())
.setUrlPathHelper(urlPathHelper());
.setUrlPathHelper(urlPathHelper())
.addPathPrefix("/api",
HandlerTypePredicate.forAnnotation(RestController.class));
}
@Bean
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录