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.servlet.handler; 018 019import java.util.ArrayList; 020import java.util.LinkedHashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Properties; 024 025import org.springframework.beans.BeansException; 026import org.springframework.util.CollectionUtils; 027 028/** 029 * Implementation of the {@link org.springframework.web.servlet.HandlerMapping} 030 * interface that maps from URLs to request handler beans. Supports both mapping to bean 031 * instances and mapping to bean names; the latter is required for non-singleton handlers. 032 * 033 * <p>The "urlMap" property is suitable for populating the handler map with 034 * bean references, e.g. via the map element in XML bean definitions. 035 * 036 * <p>Mappings to bean names can be set via the "mappings" property, in a form 037 * accepted by the {@code java.util.Properties} class, as follows: 038 * 039 * <pre class="code"> 040 * /welcome.html=ticketController 041 * /show.html=ticketController</pre> 042 * 043 * <p>The syntax is {@code PATH=HANDLER_BEAN_NAME}. If the path doesn't begin 044 * with a slash, one is prepended. 045 * 046 * <p>Supports direct matches (given "/test" -> registered "/test") and "*" 047 * pattern matches (given "/test" -> registered "/t*"). Note that the default 048 * is to map within the current servlet mapping if applicable; see the 049 * {@link #setAlwaysUseFullPath "alwaysUseFullPath"} property. For details on the 050 * pattern options, see the {@link org.springframework.util.AntPathMatcher} javadoc. 051 052 * @author Rod Johnson 053 * @author Juergen Hoeller 054 * @author Sam Brannen 055 * @see #setMappings 056 * @see #setUrlMap 057 * @see BeanNameUrlHandlerMapping 058 */ 059public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { 060 061 private final Map<String, Object> urlMap = new LinkedHashMap<>(); 062 063 064 /** 065 * Create a {@code SimpleUrlHandlerMapping} with default settings. 066 */ 067 public SimpleUrlHandlerMapping() { 068 } 069 070 /** 071 * Create a {@code SimpleUrlHandlerMapping} using the supplied URL map. 072 * @param urlMap map with URL paths as keys and handler beans (or handler 073 * bean names) as values 074 * @since 5.2 075 * @see #setUrlMap(Map) 076 */ 077 public SimpleUrlHandlerMapping(Map<String, ?> urlMap) { 078 setUrlMap(urlMap); 079 } 080 081 /** 082 * Create a {@code SimpleUrlHandlerMapping} using the supplied URL map and order. 083 * @param urlMap map with URL paths as keys and handler beans (or handler 084 * bean names) as values 085 * @param order the order value for this {@code SimpleUrlHandlerMapping} 086 * @since 5.2 087 * @see #setUrlMap(Map) 088 * @see #setOrder(int) 089 */ 090 public SimpleUrlHandlerMapping(Map<String, ?> urlMap, int order) { 091 setUrlMap(urlMap); 092 setOrder(order); 093 } 094 095 096 /** 097 * Map URL paths to handler bean names. 098 * This is the typical way of configuring this HandlerMapping. 099 * <p>Supports direct URL matches and Ant-style pattern matches. For syntax 100 * details, see the {@link org.springframework.util.AntPathMatcher} javadoc. 101 * @param mappings properties with URLs as keys and bean names as values 102 * @see #setUrlMap 103 */ 104 public void setMappings(Properties mappings) { 105 CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap); 106 } 107 108 /** 109 * Set a Map with URL paths as keys and handler beans (or handler bean names) 110 * as values. Convenient for population with bean references. 111 * <p>Supports direct URL matches and Ant-style pattern matches. For syntax 112 * details, see the {@link org.springframework.util.AntPathMatcher} javadoc. 113 * @param urlMap map with URLs as keys and beans as values 114 * @see #setMappings 115 */ 116 public void setUrlMap(Map<String, ?> urlMap) { 117 this.urlMap.putAll(urlMap); 118 } 119 120 /** 121 * Allow Map access to the URL path mappings, with the option to add or 122 * override specific entries. 123 * <p>Useful for specifying entries directly, for example via "urlMap[myKey]". 124 * This is particularly useful for adding or overriding entries in child 125 * bean definitions. 126 */ 127 public Map<String, ?> getUrlMap() { 128 return this.urlMap; 129 } 130 131 132 /** 133 * Calls the {@link #registerHandlers} method in addition to the 134 * superclass's initialization. 135 */ 136 @Override 137 public void initApplicationContext() throws BeansException { 138 super.initApplicationContext(); 139 registerHandlers(this.urlMap); 140 } 141 142 /** 143 * Register all handlers specified in the URL map for the corresponding paths. 144 * @param urlMap a Map with URL paths as keys and handler beans or bean names as values 145 * @throws BeansException if a handler couldn't be registered 146 * @throws IllegalStateException if there is a conflicting handler registered 147 */ 148 protected void registerHandlers(Map<String, Object> urlMap) throws BeansException { 149 if (urlMap.isEmpty()) { 150 logger.trace("No patterns in " + formatMappingName()); 151 } 152 else { 153 urlMap.forEach((url, handler) -> { 154 // Prepend with slash if not already present. 155 if (!url.startsWith("/")) { 156 url = "/" + url; 157 } 158 // Remove whitespace from handler bean name. 159 if (handler instanceof String) { 160 handler = ((String) handler).trim(); 161 } 162 registerHandler(url, handler); 163 }); 164 if (logger.isDebugEnabled()) { 165 List<String> patterns = new ArrayList<>(); 166 if (getRootHandler() != null) { 167 patterns.add("/"); 168 } 169 if (getDefaultHandler() != null) { 170 patterns.add("/**"); 171 } 172 patterns.addAll(getHandlerMap().keySet()); 173 logger.debug("Patterns " + patterns + " in " + formatMappingName()); 174 } 175 } 176 } 177 178}