|
20 | 20 |
|
21 | 21 | import org.springframework.core.annotation.AnnotationUtils; |
22 | 22 | import org.springframework.stereotype.Controller; |
23 | | -import org.springframework.util.PathMatcher; |
24 | 23 | import org.springframework.web.bind.annotation.RequestMapping; |
25 | 24 | import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition; |
26 | 25 | import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition; |
27 | 26 | import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition; |
28 | 27 | import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; |
29 | 28 | import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition; |
| 29 | +import org.springframework.web.servlet.mvc.condition.RequestCondition; |
30 | 30 | import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition; |
31 | 31 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo; |
32 | 32 | import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; |
|
41 | 41 | */ |
42 | 42 | public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping { |
43 | 43 |
|
| 44 | + private boolean useSuffixPatternMatch = true; |
| 45 | + |
| 46 | + /** |
| 47 | + * Set whether to use a suffix pattern match (".*") when matching patterns to URLs. |
| 48 | + * If enabled a method mapped to "/users" will also match to "/users.*". |
| 49 | + * <p>Default is "true". Turn this convention off if you intend to interpret path mappings strictly. |
| 50 | + */ |
| 51 | + public void setUseSuffixPatternMatch(boolean useSuffixPatternMatch) { |
| 52 | + this.useSuffixPatternMatch = useSuffixPatternMatch; |
| 53 | + } |
| 54 | + |
| 55 | + /** |
| 56 | + * Returns the value of the useSuffixPatternMatch flag, see {@link #setUseSuffixPatternMatch(boolean)}. |
| 57 | + */ |
| 58 | + public boolean isUseSuffixPatternMatch() { |
| 59 | + return useSuffixPatternMatch; |
| 60 | + } |
| 61 | + |
44 | 62 | /** |
45 | | - * {@inheritDoc} The handler determination in this method is made based on the presence of a type-level {@link |
46 | | - * Controller} annotation. |
| 63 | + * {@inheritDoc} |
| 64 | + * The default implementation checks for the presence of a type-level {@link Controller} |
| 65 | + * annotation via {@link AnnotationUtils#findAnnotation(Class, Class)}. |
47 | 66 | */ |
48 | 67 | @Override |
49 | 68 | protected boolean isHandler(Class<?> beanType) { |
50 | 69 | return AnnotationUtils.findAnnotation(beanType, Controller.class) != null; |
51 | 70 | } |
52 | 71 |
|
53 | 72 | /** |
54 | | - * Provides a {@link RequestMappingInfo} for the given method. <p>Only {@link RequestMapping @RequestMapping}-annotated |
55 | | - * methods are considered. Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their |
56 | | - * attributes combined with method-level {@link RequestMapping @RequestMapping} attributes. |
| 73 | + * Determines if the given method is a handler method and creates a {@link RequestMappingInfo} for it. |
| 74 | + * |
| 75 | + * <p>The default implementation expects the presence of a method-level @{@link RequestMapping} |
| 76 | + * annotation via {@link AnnotationUtils#findAnnotation(Class, Class)}. The presence of |
| 77 | + * type-level annotations is also checked and if present a RequestMappingInfo is created for each type- |
| 78 | + * and method-level annotations and combined via {@link RequestMappingInfo#combine(RequestMappingInfo)}. |
57 | 79 | * |
58 | | - * @param method the method to create a mapping for |
| 80 | + * @param method the method to create a RequestMappingInfo for |
59 | 81 | * @param handlerType the actual handler type, possibly a sub-type of {@code method.getDeclaringClass()} |
60 | | - * @return the mapping, or {@code null} |
61 | | - * @see RequestMappingInfo#combine(RequestMappingInfo, PathMatcher) |
| 82 | + * @return the info, or {@code null} |
62 | 83 | */ |
63 | 84 | @Override |
64 | 85 | protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { |
65 | | - RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); |
66 | | - if (methodAnnotation == null) { |
67 | | - return null; |
68 | | - } |
69 | | - RequestMappingInfo methodInfo = createFromRequestMapping(methodAnnotation); |
70 | | - RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); |
71 | | - if (typeAnnotation != null) { |
72 | | - RequestMappingInfo typeInfo = createFromRequestMapping(typeAnnotation); |
73 | | - return typeInfo.combine(methodInfo); |
74 | | - } |
75 | | - else { |
76 | | - return methodInfo; |
| 86 | + RequestMapping methodAnnot = AnnotationUtils.findAnnotation(method, RequestMapping.class); |
| 87 | + if (methodAnnot != null) { |
| 88 | + RequestMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); |
| 89 | + RequestMappingInfo methodInfo = createRequestMappingInfo(methodAnnot, handlerType, method); |
| 90 | + if (typeAnnot != null) { |
| 91 | + RequestMappingInfo typeInfo = createRequestMappingInfo(typeAnnot, handlerType, method); |
| 92 | + return typeInfo.combine(methodInfo); |
| 93 | + } |
| 94 | + else { |
| 95 | + return methodInfo; |
| 96 | + } |
77 | 97 | } |
| 98 | + return null; |
78 | 99 | } |
79 | 100 |
|
80 | | - private RequestMappingInfo createFromRequestMapping(RequestMapping annotation) { |
| 101 | + /** |
| 102 | + * Override this method to create a {@link RequestMappingInfo} from a @{@link RequestMapping} annotation. The main |
| 103 | + * reason for doing so is to provide a custom {@link RequestCondition} to the RequestMappingInfo constructor. |
| 104 | + * |
| 105 | + * <p>This method is invoked both for type- and method-level @{@link RequestMapping} annotations. The resulting |
| 106 | + * {@link RequestMappingInfo}s are combined via {@link RequestMappingInfo#combine(RequestMappingInfo)}. |
| 107 | + * |
| 108 | + * @param annot a type- or a method-level {@link RequestMapping} annotation |
| 109 | + * @param handlerType the handler type |
| 110 | + * @param method the method with which the created RequestMappingInfo will be combined |
| 111 | + * @return a {@link RequestMappingInfo} instance; never {@code null} |
| 112 | + */ |
| 113 | + protected RequestMappingInfo createRequestMappingInfo(RequestMapping annot, Class<?> handlerType, Method method) { |
81 | 114 | return new RequestMappingInfo( |
82 | | - new PatternsRequestCondition(annotation.value(), getUrlPathHelper(), getPathMatcher()), |
83 | | - new RequestMethodsRequestCondition(annotation.method()), |
84 | | - new ParamsRequestCondition(annotation.params()), |
85 | | - new HeadersRequestCondition(annotation.headers()), |
86 | | - new ConsumesRequestCondition(annotation.consumes(), annotation.headers()), |
87 | | - new ProducesRequestCondition(annotation.produces(), annotation.headers()), null); |
| 115 | + new PatternsRequestCondition(annot.value(), getUrlPathHelper(), getPathMatcher(), useSuffixPatternMatch), |
| 116 | + new RequestMethodsRequestCondition(annot.method()), |
| 117 | + new ParamsRequestCondition(annot.params()), |
| 118 | + new HeadersRequestCondition(annot.headers()), |
| 119 | + new ConsumesRequestCondition(annot.consumes(), annot.headers()), |
| 120 | + new ProducesRequestCondition(annot.produces(), annot.headers()), null); |
88 | 121 | } |
89 | | - |
| 122 | + |
90 | 123 | } |
0 commit comments