33
33
import org .springframework .core .annotation .AnnotationAwareOrderComparator ;
34
34
import org .springframework .http .server .reactive .PathContainer ;
35
35
import org .springframework .http .server .reactive .ServerHttpRequest ;
36
- import org .springframework .lang .Nullable ;
37
- import org .springframework .util .Assert ;
38
36
import org .springframework .util .StringUtils ;
39
37
import org .springframework .web .reactive .handler .SimpleUrlHandlerMapping ;
40
38
import org .springframework .web .server .ServerWebExchange ;
@@ -57,50 +55,49 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
57
55
private static final Log logger = LogFactory .getLog (ResourceUrlProvider .class );
58
56
59
57
60
- private final PathPatternParser patternParser ;
58
+ private final PathPatternParser patternParser = new PathPatternParser () ;
61
59
62
60
private final Map <PathPattern , ResourceWebHandler > handlerMap = new LinkedHashMap <>();
63
61
64
- private boolean autodetect = true ;
65
-
66
-
67
- public ResourceUrlProvider () {
68
- this (new PathPatternParser ());
69
- }
70
-
71
- public ResourceUrlProvider (PathPatternParser patternParser ) {
72
- Assert .notNull (patternParser , "'patternParser' is required." );
73
- this .patternParser = patternParser ;
74
- }
75
-
76
62
77
63
/**
78
64
* Return a read-only view of the resource handler mappings either manually
79
- * configured or auto-detected when the Spring {@code ApplicationContext}
80
- * is refreshed.
65
+ * configured or auto-detected from Spring configuration.
81
66
*/
82
67
public Map <PathPattern , ResourceWebHandler > getHandlerMap () {
83
68
return Collections .unmodifiableMap (this .handlerMap );
84
69
}
85
70
71
+
86
72
/**
87
- * Return {@code false} if resource mappings were manually configured,
88
- * {@code true} otherwise.
73
+ * Manually configure resource handler mappings.
74
+ * <p><strong>Note:</strong> by default resource mappings are auto-detected
75
+ * from the Spring {@code ApplicationContext}. If this property is used,
76
+ * auto-detection is turned off.
89
77
*/
90
- public boolean isAutodetect () {
91
- return this .autodetect ;
78
+ public void registerHandlers (Map <String , ResourceWebHandler > handlerMap ) {
79
+ this .handlerMap .clear ();
80
+ handlerMap .forEach ((rawPattern , resourceWebHandler ) -> {
81
+ rawPattern = prependLeadingSlash (rawPattern );
82
+ PathPattern pattern = this .patternParser .parse (rawPattern );
83
+ this .handlerMap .put (pattern , resourceWebHandler );
84
+ });
92
85
}
93
86
87
+ private static String prependLeadingSlash (String pattern ) {
88
+ if (StringUtils .hasLength (pattern ) && !pattern .startsWith ("/" )) {
89
+ return "/" + pattern ;
90
+ }
91
+ else {
92
+ return pattern ;
93
+ }
94
+ }
94
95
95
96
@ Override
96
97
public void onApplicationEvent (ContextRefreshedEvent event ) {
97
- if (isAutodetect ()) {
98
- this .handlerMap .clear ();
98
+ if (this .handlerMap .isEmpty ()) {
99
99
detectResourceHandlers (event .getApplicationContext ());
100
- if (!this .handlerMap .isEmpty ()) {
101
- this .autodetect = false ;
102
- }
103
- else if (logger .isDebugEnabled ()) {
100
+ if (logger .isDebugEnabled ()) {
104
101
logger .debug ("No resource handling mappings found" );
105
102
}
106
103
}
@@ -110,10 +107,10 @@ private void detectResourceHandlers(ApplicationContext context) {
110
107
logger .debug ("Looking for resource handler mappings" );
111
108
112
109
Map <String , SimpleUrlHandlerMapping > map = context .getBeansOfType (SimpleUrlHandlerMapping .class );
113
- List <SimpleUrlHandlerMapping > handlerMappings = new ArrayList <>(map .values ());
114
- AnnotationAwareOrderComparator .sort (handlerMappings );
110
+ List <SimpleUrlHandlerMapping > mappings = new ArrayList <>(map .values ());
111
+ AnnotationAwareOrderComparator .sort (mappings );
115
112
116
- handlerMappings .forEach (mapping -> {
113
+ mappings .forEach (mapping -> {
117
114
mapping .getHandlerMap ().forEach ((pattern , handler ) -> {
118
115
if (handler instanceof ResourceWebHandler ) {
119
116
ResourceWebHandler resourceHandler = (ResourceWebHandler ) handler ;
@@ -128,85 +125,45 @@ private void detectResourceHandlers(ApplicationContext context) {
128
125
});
129
126
}
130
127
131
- /**
132
- * Manually configure the resource mappings.
133
- * <p><strong>Note:</strong> by default resource mappings are auto-detected
134
- * from the Spring {@code ApplicationContext}. However if this property is
135
- * used, the auto-detection is turned off.
136
- */
137
- public void registerHandlers (@ Nullable Map <String , ResourceWebHandler > handlerMap ) {
138
- if (handlerMap == null ) {
139
- return ;
140
- }
141
- this .handlerMap .clear ();
142
- handlerMap .forEach ((rawPattern , resourceWebHandler ) -> {
143
- rawPattern = prependLeadingSlash (rawPattern );
144
- PathPattern pattern = this .patternParser .parse (rawPattern );
145
- this .handlerMap .put (pattern , resourceWebHandler );
146
- });
147
- this .autodetect = false ;
148
- }
149
-
150
- private static String prependLeadingSlash (String pattern ) {
151
- if (StringUtils .hasLength (pattern ) && !pattern .startsWith ("/" )) {
152
- return "/" + pattern ;
153
- }
154
- else {
155
- return pattern ;
156
- }
157
- }
158
-
159
128
160
129
/**
161
- * A variation on {@link #getForLookupPath(PathContainer)} that accepts a
162
- * full request URL path and returns the full request URL path to expose
163
- * for public use.
130
+ * Get the public resource URL for the given URI string.
131
+ * <p>The URI string is expected to be a path and if it contains a query or
132
+ * fragment those will be preserved in the resulting public resource URL.
133
+ * @param uriString the URI string to transform
164
134
* @param exchange the current exchange
165
- * @param requestUrl the request URL path to resolve
166
- * @return the resolved public URL path, or empty if unresolved
135
+ * @return the resolved public resource URL path, or empty if unresolved
167
136
*/
168
- public final Mono <String > getForRequestUrl ( ServerWebExchange exchange , String requestUrl ) {
137
+ public final Mono <String > getForUriString ( String uriString , ServerWebExchange exchange ) {
169
138
if (logger .isTraceEnabled ()) {
170
- logger .trace ("Getting resource URL for request URL \" " + requestUrl + "\" " );
139
+ logger .trace ("Getting resource URL for request URL \" " + uriString + "\" " );
171
140
}
172
141
ServerHttpRequest request = exchange .getRequest ();
173
- int queryIndex = getQueryIndex (requestUrl );
174
- String lookupPath = requestUrl .substring (0 , queryIndex );
175
- String query = requestUrl .substring (queryIndex );
142
+ int queryIndex = getQueryIndex (uriString );
143
+ String lookupPath = uriString .substring (0 , queryIndex );
144
+ String query = uriString .substring (queryIndex );
176
145
PathContainer parsedLookupPath = PathContainer .parseUrlPath (lookupPath );
177
- return getForLookupPath (parsedLookupPath ).map (resolvedPath ->
146
+ if (logger .isTraceEnabled ()) {
147
+ logger .trace ("Getting resource URL for lookup path \" " + lookupPath + "\" " );
148
+ }
149
+ return resolveResourceUrl (parsedLookupPath ).map (resolvedPath ->
178
150
request .getPath ().contextPath ().value () + resolvedPath + query );
179
151
}
180
152
181
- private int getQueryIndex (String lookupPath ) {
182
- int suffixIndex = lookupPath .length ();
183
- int queryIndex = lookupPath .indexOf ("?" );
153
+ private int getQueryIndex (String path ) {
154
+ int suffixIndex = path .length ();
155
+ int queryIndex = path .indexOf ("?" );
184
156
if (queryIndex > 0 ) {
185
157
suffixIndex = queryIndex ;
186
158
}
187
- int hashIndex = lookupPath .indexOf ("#" );
159
+ int hashIndex = path .indexOf ("#" );
188
160
if (hashIndex > 0 ) {
189
161
suffixIndex = Math .min (suffixIndex , hashIndex );
190
162
}
191
163
return suffixIndex ;
192
164
}
193
165
194
- /**
195
- * Compare the given path against configured resource handler mappings and
196
- * if a match is found use the {@code ResourceResolver} chain of the matched
197
- * {@code ResourceHttpRequestHandler} to resolve the URL path to expose for
198
- * public use.
199
- * <p>It is expected that the given path is what Spring uses for
200
- * request mapping purposes.
201
- * <p>If several handler mappings match, the handler used will be the one
202
- * configured with the most specific pattern.
203
- * @param lookupPath the lookup path to check
204
- * @return the resolved public URL path, or empty if unresolved
205
- */
206
- public final Mono <String > getForLookupPath (PathContainer lookupPath ) {
207
- if (logger .isTraceEnabled ()) {
208
- logger .trace ("Getting resource URL for lookup path \" " + lookupPath + "\" " );
209
- }
166
+ private Mono <String > resolveResourceUrl (PathContainer lookupPath ) {
210
167
return this .handlerMap .entrySet ().stream ()
211
168
.filter (entry -> entry .getKey ().matches (lookupPath ))
212
169
.sorted (Comparator .comparing (Map .Entry ::getKey ))
0 commit comments