1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.web.servlet.mvc.method.annotation;
18
19 import java.lang.reflect.Method;
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.springframework.context.EmbeddedValueResolverAware;
24 import org.springframework.core.annotation.AnnotationUtils;
25 import org.springframework.stereotype.Controller;
26 import org.springframework.util.Assert;
27 import org.springframework.util.StringValueResolver;
28 import org.springframework.web.accept.ContentNegotiationManager;
29 import org.springframework.web.bind.annotation.RequestMapping;
30 import org.springframework.web.servlet.mvc.condition.AbstractRequestCondition;
31 import org.springframework.web.servlet.mvc.condition.CompositeRequestCondition;
32 import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
33 import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
34 import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
35 import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
36 import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
37 import org.springframework.web.servlet.mvc.condition.RequestCondition;
38 import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
39 import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
40 import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
41
42
43
44
45
46
47
48
49
50
51 public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
52 implements EmbeddedValueResolverAware {
53
54 private boolean useSuffixPatternMatch = true;
55
56 private boolean useRegisteredSuffixPatternMatch = false;
57
58 private boolean useTrailingSlashMatch = true;
59
60 private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
61
62 private final List<String> fileExtensions = new ArrayList<String>();
63
64 private StringValueResolver embeddedValueResolver;
65
66
67
68
69
70
71
72
73
74 public void setUseSuffixPatternMatch(boolean useSuffixPatternMatch) {
75 this.useSuffixPatternMatch = useSuffixPatternMatch;
76 }
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 public void setUseRegisteredSuffixPatternMatch(boolean useRegisteredSuffixPatternMatch) {
94 this.useRegisteredSuffixPatternMatch = useRegisteredSuffixPatternMatch;
95 this.useSuffixPatternMatch = (useRegisteredSuffixPatternMatch || this.useSuffixPatternMatch);
96 }
97
98
99
100
101
102
103 public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
104 this.useTrailingSlashMatch = useTrailingSlashMatch;
105 }
106
107
108
109
110
111 public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) {
112 Assert.notNull(contentNegotiationManager, "ContentNegotiationManager must not be null");
113 this.contentNegotiationManager = contentNegotiationManager;
114 }
115
116 @Override
117 public void setEmbeddedValueResolver(StringValueResolver resolver) {
118 this.embeddedValueResolver = resolver;
119 }
120
121 @Override
122 public void afterPropertiesSet() {
123 if (this.useRegisteredSuffixPatternMatch) {
124 this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
125 }
126 super.afterPropertiesSet();
127 }
128
129
130
131
132
133
134 public boolean useSuffixPatternMatch() {
135 return this.useSuffixPatternMatch;
136 }
137
138
139
140
141 public boolean useRegisteredSuffixPatternMatch() {
142 return this.useRegisteredSuffixPatternMatch;
143 }
144
145
146
147
148 public boolean useTrailingSlashMatch() {
149 return this.useTrailingSlashMatch;
150 }
151
152
153
154
155 public ContentNegotiationManager getContentNegotiationManager() {
156 return this.contentNegotiationManager;
157 }
158
159
160
161
162 public List<String> getFileExtensions() {
163 return this.fileExtensions;
164 }
165
166
167
168
169
170
171 @Override
172 protected boolean isHandler(Class<?> beanType) {
173 return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
174 (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
175 }
176
177
178
179
180
181
182
183
184
185 @Override
186 protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
187 RequestMappingInfo info = null;
188 RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
189 if (methodAnnotation != null) {
190 RequestCondition<?> methodCondition = getCustomMethodCondition(method);
191 info = createRequestMappingInfo(methodAnnotation, methodCondition);
192 RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
193 if (typeAnnotation != null) {
194 RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
195 info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
196 }
197 }
198 return info;
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212 protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
213 return null;
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227 protected RequestCondition<?> getCustomMethodCondition(Method method) {
228 return null;
229 }
230
231
232
233
234 protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
235 String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
236 return new RequestMappingInfo(
237 annotation.name(),
238 new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
239 this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
240 new RequestMethodsRequestCondition(annotation.method()),
241 new ParamsRequestCondition(annotation.params()),
242 new HeadersRequestCondition(annotation.headers()),
243 new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
244 new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager),
245 customCondition);
246 }
247
248
249
250
251
252 protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) {
253 if (this.embeddedValueResolver == null) {
254 return patterns;
255 }
256 else {
257 String[] resolvedPatterns = new String[patterns.length];
258 for (int i = 0; i < patterns.length; i++) {
259 resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]);
260 }
261 return resolvedPatterns;
262 }
263 }
264
265 }