001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.reactive.handler; 018 019import java.util.LinkedHashMap; 020import java.util.Map; 021import java.util.Properties; 022 023import org.springframework.beans.BeansException; 024import org.springframework.util.CollectionUtils; 025 026/** 027 * Implementation of the {@link org.springframework.web.reactive.HandlerMapping} 028 * interface to map from URLs to request handler beans. Supports both mapping 029 * to bean instances and mapping to bean names; the latter is required for 030 * non-singleton handlers. 031 * 032 * <p>The "urlMap" property is suitable for populating the handler map with 033 * bean instances. Mappings to bean names can be set via the "mappings" 034 * property, in a form accepted by the {@code java.util.Properties} class, 035 * as follows: 036 * 037 * <pre class="code"> 038 * /welcome.html=ticketController 039 * /show.html=ticketController</pre> 040 * 041 * <p>The syntax is {@code PATH=HANDLER_BEAN_NAME}. If the path doesn't begin 042 * with a slash, one is prepended. 043 * 044 * <p>Supports direct matches, e.g. a registered "/test" matches "/test", and 045 * various Ant-style pattern matches, e.g. a registered "/t*" pattern matches 046 * both "/test" and "/team", "/test/*" matches all paths under "/test", 047 * "/test/**" matches all paths below "/test". For details, see the 048 * {@link org.springframework.web.util.pattern.PathPattern} javadoc. 049 * 050 * @author Rossen Stoyanchev 051 * @author Sam Brannen 052 * @since 5.0 053 */ 054public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { 055 056 private final Map<String, Object> urlMap = new LinkedHashMap<>(); 057 058 059 /** 060 * Create a {@code SimpleUrlHandlerMapping} with default settings. 061 */ 062 public SimpleUrlHandlerMapping() { 063 } 064 065 /** 066 * Create a {@code SimpleUrlHandlerMapping} using the supplied URL map. 067 * @param urlMap map with URL paths as keys and handler beans (or handler 068 * bean names) as values 069 * @since 5.2 070 * @see #setUrlMap(Map) 071 */ 072 public SimpleUrlHandlerMapping(Map<String, ?> urlMap) { 073 setUrlMap(urlMap); 074 } 075 076 /** 077 * Create a {@code SimpleUrlHandlerMapping} using the supplied URL map and order. 078 * @param urlMap map with URL paths as keys and handler beans (or handler 079 * bean names) as values 080 * @param order the order value for this {@code SimpleUrlHandlerMapping} 081 * @since 5.2 082 * @see #setUrlMap(Map) 083 * @see #setOrder(int) 084 */ 085 public SimpleUrlHandlerMapping(Map<String, ?> urlMap, int order) { 086 setUrlMap(urlMap); 087 setOrder(order); 088 } 089 090 091 /** 092 * Map URL paths to handler bean names. 093 * This is the typical way of configuring this HandlerMapping. 094 * <p>Supports direct URL matches and Ant-style pattern matches. For syntax details, 095 * see the {@link org.springframework.web.util.pattern.PathPattern} javadoc. 096 * @param mappings properties with URLs as keys and bean names as values 097 * @see #setUrlMap 098 */ 099 public void setMappings(Properties mappings) { 100 CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap); 101 } 102 103 /** 104 * Set a Map with URL paths as keys and handler beans (or handler bean names) 105 * as values. Convenient for population with bean references. 106 * <p>Supports direct URL matches and Ant-style pattern matches. For syntax details, 107 * see the {@link org.springframework.web.util.pattern.PathPattern} javadoc. 108 * @param urlMap map with URLs as keys and beans as values 109 * @see #setMappings 110 */ 111 public void setUrlMap(Map<String, ?> urlMap) { 112 this.urlMap.putAll(urlMap); 113 } 114 115 /** 116 * Allow Map access to the URL path mappings, with the option to add or 117 * override specific entries. 118 * <p>Useful for specifying entries directly, for example via "urlMap[myKey]". 119 * This is particularly useful for adding or overriding entries in child 120 * bean definitions. 121 */ 122 public Map<String, ?> getUrlMap() { 123 return this.urlMap; 124 } 125 126 127 /** 128 * Calls the {@link #registerHandlers} method in addition to the 129 * superclass's initialization. 130 */ 131 @Override 132 public void initApplicationContext() throws BeansException { 133 super.initApplicationContext(); 134 registerHandlers(this.urlMap); 135 } 136 137 /** 138 * Register all handlers specified in the URL map for the corresponding paths. 139 * @param urlMap a Map with URL paths as keys and handler beans or bean names as values 140 * @throws BeansException if a handler couldn't be registered 141 * @throws IllegalStateException if there is a conflicting handler registered 142 */ 143 protected void registerHandlers(Map<String, Object> urlMap) throws BeansException { 144 if (urlMap.isEmpty()) { 145 logger.trace("No patterns in " + formatMappingName()); 146 } 147 else { 148 for (Map.Entry<String, Object> entry : urlMap.entrySet()) { 149 String url = entry.getKey(); 150 Object handler = entry.getValue(); 151 // Prepend with slash if not already present. 152 if (!url.startsWith("/")) { 153 url = "/" + url; 154 } 155 // Remove whitespace from handler bean name. 156 if (handler instanceof String) { 157 handler = ((String) handler).trim(); 158 } 159 registerHandler(url, handler); 160 } 161 if (logger.isDebugEnabled()) { 162 logger.debug("Patterns " + getHandlerMap().keySet() + " in " + formatMappingName()); 163 } 164 } 165 } 166 167}