diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java index 6253cb8020..45d33469cb 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java @@ -39,6 +39,17 @@ public interface HandlerMapping { */ String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern"; + /** + * Name of the {@link ServerWebExchange} attribute that contains the path + * within the handler mapping, in case of a pattern match, or the full + * relevant URI (typically within the DispatcherServlet's mapping) else. + *

Note: This attribute is not required to be supported by all + * HandlerMapping implementations. URL-based HandlerMappings will + * typically support it, but handlers should not necessarily expect + * this request attribute to be present in all scenarios. + */ + String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping"; + /** * Name of the {@link ServerWebExchange} attribute that contains the URI * templates map, mapping variable names to values. diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java new file mode 100644 index 0000000000..1711e43af2 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java @@ -0,0 +1,257 @@ +/* + * Copyright 2002-2016 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 + * + * http://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.reactive.handler; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import reactor.core.publisher.Mono; + +import org.springframework.beans.BeansException; +import org.springframework.util.Assert; +import org.springframework.web.server.ServerWebExchange; + +/** + * Abstract base class for URL-mapped + * {@link org.springframework.web.reactive.HandlerMapping} implementations. + * + *

Supports direct matches, e.g. a registered "/test" matches "/test", and + * various Ant-style pattern matches, e.g. a registered "/t*" pattern matches + * both "/test" and "/team", "/test/*" matches all paths under "/test", + * "/test/**" matches all paths below "/test". For details, see the + * {@link org.springframework.util.AntPathMatcher AntPathMatcher} javadoc. + * + *

Will search all path patterns to find the most exact match for the + * current request path. The most exact match is defined as the longest + * path pattern that matches the current request path. + * + * @author Rossen Stoyanchev + */ +public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { + + private boolean useTrailingSlashMatch = false; + + private boolean lazyInitHandlers = false; + + private final Map handlerMap = new LinkedHashMap<>(); + + + /** + * Whether to match to URLs irrespective of the presence of a trailing slash. + * If enabled a URL pattern such as "/users" also matches to "/users/". + *

The default value is {@code false}. + */ + public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) { + this.useTrailingSlashMatch = useTrailingSlashMatch; + } + + /** + * Whether to match to URLs irrespective of the presence of a trailing slash. + */ + public boolean useTrailingSlashMatch() { + return this.useTrailingSlashMatch; + } + + /** + * Set whether to lazily initialize handlers. Only applicable to + * singleton handlers, as prototypes are always lazily initialized. + * Default is "false", as eager initialization allows for more efficiency + * through referencing the controller objects directly. + *

If you want to allow your controllers to be lazily initialized, + * make them "lazy-init" and set this flag to true. Just making them + * "lazy-init" will not work, as they are initialized through the + * references from the handler mapping in this case. + */ + public void setLazyInitHandlers(boolean lazyInitHandlers) { + this.lazyInitHandlers = lazyInitHandlers; + } + + /** + * Return the registered handlers as an unmodifiable Map, with the registered path + * as key and the handler object (or handler bean name in case of a lazy-init handler) + * as value. + */ + public final Map getHandlerMap() { + return Collections.unmodifiableMap(this.handlerMap); + } + + + @Override + public Mono getHandler(ServerWebExchange exchange) { + String lookupPath = getPathHelper().getLookupPathForRequest(exchange); + Object handler = null; + try { + handler = lookupHandler(lookupPath, exchange); + } + catch (Exception ex) { + return Mono.error(ex); + } + + if (handler != null && logger.isDebugEnabled()) { + logger.debug("Mapping [" + lookupPath + "] to " + handler); + } + else if (handler == null && logger.isTraceEnabled()) { + logger.trace("No handler mapping found for [" + lookupPath + "]"); + } + + return Mono.justOrEmpty(handler); + } + + /** + * Look up a handler instance for the given URL path. + * + *

Supports direct matches, e.g. a registered "/test" matches "/test", + * and various Ant-style pattern matches, e.g. a registered "/t*" matches + * both "/test" and "/team". For details, see the AntPathMatcher class. + * + *

Looks for the most exact pattern, where most exact is defined as + * the longest path pattern. + * + * @param urlPath URL the bean is mapped to + * @param exchange the current exchange + * @return the associated handler instance, or {@code null} if not found + * @see org.springframework.util.AntPathMatcher + */ + protected Object lookupHandler(String urlPath, ServerWebExchange exchange) throws Exception { + // Direct match? + Object handler = this.handlerMap.get(urlPath); + if (handler != null) { + return handleMatch(handler, urlPath, urlPath, exchange); + } + // Pattern match? + List matches = new ArrayList<>(); + for (String pattern : this.handlerMap.keySet()) { + if (getPathMatcher().match(pattern, urlPath)) { + matches.add(pattern); + } + else if (useTrailingSlashMatch()) { + if (!pattern.endsWith("/") && getPathMatcher().match(pattern + "/", urlPath)) { + matches.add(pattern +"/"); + } + } + } + String bestMatch = null; + Comparator comparator = getPathMatcher().getPatternComparator(urlPath); + if (!matches.isEmpty()) { + Collections.sort(matches, comparator); + if (logger.isDebugEnabled()) { + logger.debug("Matching patterns for request [" + urlPath + "] are " + matches); + } + bestMatch = matches.get(0); + } + if (bestMatch != null) { + handler = this.handlerMap.get(bestMatch); + if (handler == null) { + Assert.isTrue(bestMatch.endsWith("/")); + handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1)); + } + String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath); + return handleMatch(handler, bestMatch, pathWithinMapping, exchange); + } + // No handler found... + return null; + } + + private Object handleMatch(Object handler, String bestMatch, String pathWithinMapping, + ServerWebExchange exchange) throws Exception { + + // Bean name or resolved handler? + if (handler instanceof String) { + String handlerName = (String) handler; + handler = getApplicationContext().getBean(handlerName); + } + + validateHandler(handler, exchange); + + exchange.getAttributes().put(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping); + exchange.getAttributes().put(BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatch); + + return handler; + } + + /** + * Validate the given handler against the current request. + *

The default implementation is empty. Can be overridden in subclasses, + * for example to enforce specific preconditions expressed in URL mappings. + * @param handler the handler object to validate + * @param exchange current exchange + * @throws Exception if validation failed + */ + @SuppressWarnings("UnusedParameters") + protected void validateHandler(Object handler, ServerWebExchange exchange) throws Exception { + } + + /** + * Register the specified handler for the given URL paths. + * @param urlPaths the URLs that the bean should be mapped to + * @param beanName the name of the handler bean + * @throws BeansException if the handler couldn't be registered + * @throws IllegalStateException if there is a conflicting handler registered + */ + protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { + Assert.notNull(urlPaths, "URL path array must not be null"); + for (String urlPath : urlPaths) { + registerHandler(urlPath, beanName); + } + } + + /** + * Register the specified handler for the given URL path. + * @param urlPath the URL the bean should be mapped to + * @param handler the handler instance or handler bean name String + * (a bean name will automatically be resolved into the corresponding handler bean) + * @throws BeansException if the handler couldn't be registered + * @throws IllegalStateException if there is a conflicting handler registered + */ + protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { + Assert.notNull(urlPath, "URL path must not be null"); + Assert.notNull(handler, "Handler object must not be null"); + Object resolvedHandler = handler; + + // Eagerly resolve handler if referencing singleton via name. + if (!this.lazyInitHandlers && handler instanceof String) { + String handlerName = (String) handler; + if (getApplicationContext().isSingleton(handlerName)) { + resolvedHandler = getApplicationContext().getBean(handlerName); + } + } + + Object mappedHandler = this.handlerMap.get(urlPath); + if (mappedHandler != null) { + if (mappedHandler != resolvedHandler) { + throw new IllegalStateException( + "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + + "]: There is already " + getHandlerDescription(mappedHandler) + " mapped."); + } + } + else { + this.handlerMap.put(urlPath, resolvedHandler); + if (logger.isInfoEnabled()) { + logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); + } + } + } + + private String getHandlerDescription(Object handler) { + return "handler " + (handler instanceof String ? "'" + handler + "'" : "of type [" + handler.getClass() + "]"); + } + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java index 0f1709ad85..fc96cbe07e 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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,41 +16,116 @@ package org.springframework.web.reactive.handler; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.web.reactive.HandlerMapping; -import org.springframework.web.server.ServerWebExchange; +import org.springframework.beans.BeansException; +import org.springframework.util.CollectionUtils; /** + * Implementation of the {@link org.springframework.web.reactive.HandlerMapping} + * interface to map from URLs to request handler beans. Supports both mapping + * to bean instances and mapping to bean names; the latter is required for + * non-singleton handlers. + * + *

The "urlMap" property is suitable for populating the handler map with + * bean instances. Mappings to bean names can be set via the "mappings" + * property, in a form accepted by the {@code java.util.Properties} class, + * like as follows: + * + *

+ * /welcome.html=ticketController
+ * /show.html=ticketController
+ * 
+ * + *

The syntax is {@code PATH=HANDLER_BEAN_NAME}. If the path doesn't begin + * with a slash, one is prepended. + * + *

Supports direct matches, e.g. a registered "/test" matches "/test", and + * various Ant-style pattern matches, e.g. a registered "/t*" pattern matches + * both "/test" and "/team", "/test/*" matches all paths under "/test", + * "/test/**" matches all paths below "/test". For details, see the + * {@link org.springframework.util.AntPathMatcher AntPathMatcher} javadoc. + * * @author Rossen Stoyanchev */ -public class SimpleUrlHandlerMapping implements HandlerMapping { +public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { - private final Map handlerMap = new HashMap<>(); + private final Map urlMap = new LinkedHashMap<>(); - public void setHandlers(Map handlers) { - this.handlerMap.clear(); - if (handlers != null) { - this.handlerMap.putAll(handlers); + /** + * Map URL paths to handler bean names. + * This is the typical way of configuring this HandlerMapping. + *

Supports direct URL matches and Ant-style pattern matches. For syntax + * details, see the {@link org.springframework.util.AntPathMatcher} javadoc. + * @param mappings properties with URLs as keys and bean names as values + * @see #setUrlMap + */ + public void setMappings(Properties mappings) { + CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap); + } + + /** + * Set a Map with URL paths as keys and handler beans (or handler bean names) + * as values. Convenient for population with bean references. + *

Supports direct URL matches and Ant-style pattern matches. For syntax + * details, see the {@link org.springframework.util.AntPathMatcher} javadoc. + * @param urlMap map with URLs as keys and beans as values + * @see #setMappings + */ + public void setUrlMap(Map urlMap) { + this.urlMap.putAll(urlMap); + } + + /** + * Allow Map access to the URL path mappings, with the option to add or + * override specific entries. + *

Useful for specifying entries directly, for example via "urlMap[myKey]". + * This is particularly useful for adding or overriding entries in child + * bean definitions. + */ + public Map getUrlMap() { + return this.urlMap; + } + + + /** + * Calls the {@link #registerHandlers} method in addition to the + * superclass's initialization. + */ + @Override + public void initApplicationContext() throws BeansException { + super.initApplicationContext(); + registerHandlers(this.urlMap); + } + + /** + * Register all handlers specified in the URL map for the corresponding paths. + * @param urlMap Map with URL paths as keys and handler beans or bean names as values + * @throws BeansException if a handler couldn't be registered + * @throws IllegalStateException if there is a conflicting handler registered + */ + protected void registerHandlers(Map urlMap) throws BeansException { + if (urlMap.isEmpty()) { + logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping"); + } + else { + for (Map.Entry entry : urlMap.entrySet()) { + String url = entry.getKey(); + Object handler = entry.getValue(); + // Prepend with slash if not already present. + if (!url.startsWith("/")) { + url = "/" + url; + } + // Remove whitespace from handler bean name. + if (handler instanceof String) { + handler = ((String) handler).trim(); + } + registerHandler(url, handler); + } } } - - @Override - public Mono getHandler(ServerWebExchange exchange) { - return Flux.create(subscriber -> { - String path = exchange.getRequest().getURI().getPath(); - Object handler = this.handlerMap.get(path); - if (handler != null) { - subscriber.onNext(handler); - } - subscriber.onComplete(); - }).next(); - } - } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMappingTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMappingTests.java new file mode 100644 index 0000000000..eccda562f6 --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMappingTests.java @@ -0,0 +1,155 @@ +/* + * Copyright 2002-2016 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 + * + * http://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.reactive.handler; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.junit.Test; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.MockServerHttpRequest; +import org.springframework.http.server.reactive.MockServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.reactive.HandlerMapping; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.adapter.DefaultServerWebExchange; +import org.springframework.web.server.session.WebSessionManager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.mock; +import static org.springframework.web.reactive.HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE; + +/** + * Unit tests for {@link SimpleUrlHandlerMapping}. + * + * @author Rossen Stoyanchev + */ +public class SimpleUrlHandlerMappingTests { + + @Test + public void handlerMappingJavaConfig() throws Exception { + AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext(); + wac.register(WebConfig.class); + wac.refresh(); + + HandlerMapping handlerMapping = (HandlerMapping) wac.getBean("handlerMapping"); + Object mainController = wac.getBean("mainController"); + Object otherController = wac.getBean("otherController"); + + testUrl("/welcome.html", mainController, handlerMapping, "/welcome.html"); + testUrl("/welcome.x", otherController, handlerMapping, "welcome.x"); + testUrl("/welcome/", otherController, handlerMapping, "welcome"); + testUrl("/show.html", mainController, handlerMapping, "/show.html"); + testUrl("/bookseats.html", mainController, handlerMapping, "/bookseats.html"); + } + + @Test + public void handlerMappingXmlConfig() throws Exception { + ClassPathXmlApplicationContext wac = new ClassPathXmlApplicationContext("map.xml", getClass()); + wac.refresh(); + + HandlerMapping handlerMapping = wac.getBean("mapping", HandlerMapping.class); + Object mainController = wac.getBean("mainController"); + + testUrl("/pathmatchingTest.html", mainController, handlerMapping, "pathmatchingTest.html"); + testUrl("welcome.html", null, handlerMapping, null); + testUrl("/pathmatchingAA.html", mainController, handlerMapping, "pathmatchingAA.html"); + testUrl("/pathmatchingA.html", null, handlerMapping, null); + testUrl("/administrator/pathmatching.html", mainController, handlerMapping, "pathmatching.html"); + testUrl("/administrator/test/pathmatching.html", mainController, handlerMapping, "test/pathmatching.html"); + testUrl("/administratort/pathmatching.html", null, handlerMapping, null); + testUrl("/administrator/another/bla.xml", mainController, handlerMapping, "/administrator/another/bla.xml"); + testUrl("/administrator/another/bla.gif", null, handlerMapping, null); + testUrl("/administrator/test/testlastbit", mainController, handlerMapping, "test/testlastbit"); + testUrl("/administrator/test/testla", null, handlerMapping, null); + testUrl("/administrator/testing/longer/bla", mainController, handlerMapping, "bla"); + testUrl("/administrator/testing/longer2/notmatching/notmatching", null, handlerMapping, null); + testUrl("/shortpattern/testing/toolong", null, handlerMapping, null); + testUrl("/XXpathXXmatching.html", mainController, handlerMapping, "XXpathXXmatching.html"); + testUrl("/pathXXmatching.html", mainController, handlerMapping, "pathXXmatching.html"); + testUrl("/XpathXXmatching.html", null, handlerMapping, null); + testUrl("/XXpathmatching.html", null, handlerMapping, null); + testUrl("/show12.html", mainController, handlerMapping, "show12.html"); + testUrl("/show123.html", mainController, handlerMapping, "/show123.html"); + testUrl("/show1.html", mainController, handlerMapping, "show1.html"); + testUrl("/reallyGood-test-is-this.jpeg", mainController, handlerMapping, "reallyGood-test-is-this.jpeg"); + testUrl("/reallyGood-tst-is-this.jpeg", null, handlerMapping, null); + testUrl("/testing/test.jpeg", mainController, handlerMapping, "testing/test.jpeg"); + testUrl("/testing/test.jpg", null, handlerMapping, null); + testUrl("/anotherTest", mainController, handlerMapping, "anotherTest"); + testUrl("/stillAnotherTest", null, handlerMapping, null); + testUrl("outofpattern*ye", null, handlerMapping, null); + testUrl("/test%26t%20est/path%26m%20atching.html", null, handlerMapping, null); + + } + + private void testUrl(String url, Object bean, HandlerMapping handlerMapping, String pathWithinMapping) + throws URISyntaxException { + + ServerWebExchange exchange = createExchange(url); + Object actual = handlerMapping.getHandler(exchange).get(); + if (bean != null) { + assertNotNull(actual); + assertSame(bean, actual); + //noinspection OptionalGetWithoutIsPresent + assertEquals(pathWithinMapping, exchange.getAttribute(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).get()); + } + else { + assertNull(actual); + } + } + + private ServerWebExchange createExchange(String path) throws URISyntaxException { + ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI(path)); + WebSessionManager sessionManager = mock(WebSessionManager.class); + return new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager); + } + + + @Configuration + static class WebConfig { + + @Bean @SuppressWarnings("unused") + public SimpleUrlHandlerMapping handlerMapping() { + SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping(); + hm.setUseTrailingSlashMatch(true); + hm.registerHandler("/welcome*", otherController()); + hm.registerHandler("/welcome.html", mainController()); + hm.registerHandler("/show.html", mainController()); + hm.registerHandler("/bookseats.html", mainController()); + return hm; + } + + @Bean + public Object mainController() { + return new Object(); + } + + @Bean + public Object otherController() { + return new Object(); + } + } + +} diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java index 49d4aa1e26..dc9a56baf3 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java @@ -39,10 +39,8 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.ResponseStatusExceptionHandler; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; -import org.springframework.web.reactive.result.SimpleResultHandler; -import org.springframework.web.reactive.result.WebHandlerHandlerAdapter; -import org.springframework.web.server.WebHandler; import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebHandler; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import static org.junit.Assert.assertArrayEquals; @@ -138,7 +136,7 @@ public class WebHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTe map.put("/foo", new FooHandler()); map.put("/bar", new BarHandler()); map.put("/header", new HeaderSettingHandler()); - setHandlers(map); + setUrlMap(map); } } diff --git a/spring-web-reactive/src/test/resources/org/springframework/web/reactive/handler/map.xml b/spring-web-reactive/src/test/resources/org/springframework/web/reactive/handler/map.xml new file mode 100644 index 0000000000..be0f6f067f --- /dev/null +++ b/spring-web-reactive/src/test/resources/org/springframework/web/reactive/handler/map.xml @@ -0,0 +1,40 @@ + + + + + + + + welcome.html=mainController + /**/pathmatchingTest.html=mainController + /**/pathmatching??.html=mainController + /**/path??matching.html=mainController + /**/??path??matching.html=mainController + /**/*.jsp=mainController + /administrator/**/pathmatching.html=mainController + /administrator/**/testlast*=mainController + /administrator/another/bla.xml=mainController + /administrator/testing/longer/**/**/**/**/**=mainController + /administrator/testing/longer2/**/**/bla/**=mainController + /*test*.jpeg=mainController + /*/test.jpeg=mainController + /outofpattern*yeah=mainController + /anotherTest*=mainController + /stillAnotherTestYeah=mainController + /shortpattern/testing=mainController + /show123.html=mainController + /sho*=mainController + /bookseats.html=mainController + /reservation.html=mainController + /payment.html=mainController + /confirmation.html=mainController + /test%26t%20est/path%26m%20atching.html=mainController + + + + + + +