Package org.springframework.web.servlet.mvc.method.annotation

Source Code of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

/*
* Copyright 2002-2014 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.servlet.mvc.method.annotation;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.util.StringValueResolver;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.condition.AbstractRequestCondition;
import org.springframework.web.servlet.mvc.condition.CompositeRequestCondition;
import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;

/**
* Creates {@link RequestMappingInfo} instances from type and method-level
* {@link RequestMapping @RequestMapping} annotations in
* {@link Controller @Controller} classes.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
*/
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
    implements EmbeddedValueResolverAware {

  private boolean useSuffixPatternMatch = true;

  private boolean useRegisteredSuffixPatternMatch = false;

  private boolean useTrailingSlashMatch = true;

  private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();

  private final List<String> fileExtensions = new ArrayList<String>();

  private StringValueResolver embeddedValueResolver;


  /**
   * Whether to use suffix pattern match (".*") when matching patterns to
   * requests. If enabled a method mapped to "/users" also matches to "/users.*".
   * <p>The default value is {@code true}.
   * <p>Also see {@link #setUseRegisteredSuffixPatternMatch(boolean)} for
   * more fine-grained control over specific suffixes to allow.
   */
  public void setUseSuffixPatternMatch(boolean useSuffixPatternMatch) {
    this.useSuffixPatternMatch = useSuffixPatternMatch;
  }

  /**
   * Whether to use suffix pattern match for registered file extensions only
   * when matching patterns to requests.
   * <p>If enabled, a controller method mapped to "/users" also matches to
   * "/users.json" assuming ".json" is a file extension registered with the
   * provided {@link #setContentNegotiationManager(ContentNegotiationManager)
   * contentNegotiationManager}. This can be useful for allowing only specific
   * URL extensions to be used as well as in cases where a "." in the URL path
   * can lead to ambiguous interpretation of path variable content, (e.g. given
   * "/users/{user}" and incoming URLs such as "/users/john.j.joe" and
   * "/users/john.j.joe.json").
   * <p>If enabled, this flag also enables
   * {@link #setUseSuffixPatternMatch(boolean) useSuffixPatternMatch}. The
   * default value is {@code false}.
   */
  public void setUseRegisteredSuffixPatternMatch(boolean useRegisteredSuffixPatternMatch) {
    this.useRegisteredSuffixPatternMatch = useRegisteredSuffixPatternMatch;
    this.useSuffixPatternMatch = (useRegisteredSuffixPatternMatch || this.useSuffixPatternMatch);
  }

  /**
   * Whether to match to URLs irrespective of the presence of a trailing slash.
   * If enabled a method mapped to "/users" also matches to "/users/".
   * <p>The default value is {@code true}.
   */
  public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
    this.useTrailingSlashMatch = useTrailingSlashMatch;
  }

  /**
   * Set the {@link ContentNegotiationManager} to use to determine requested media types.
   * If not set, the default constructor is used.
   */
  public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) {
    Assert.notNull(contentNegotiationManager, "ContentNegotiationManager must not be null");
    this.contentNegotiationManager = contentNegotiationManager;
  }

  @Override
  public void setEmbeddedValueResolver(StringValueResolver resolver) {
    this.embeddedValueResolver  = resolver;
  }

  @Override
  public void afterPropertiesSet() {
    if (this.useRegisteredSuffixPatternMatch) {
      this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
    }
    super.afterPropertiesSet();
  }



  /**
   * Whether to use suffix pattern matching.
   */
  public boolean useSuffixPatternMatch() {
    return this.useSuffixPatternMatch;
  }

  /**
   * Whether to use registered suffixes for pattern matching.
   */
  public boolean useRegisteredSuffixPatternMatch() {
    return this.useRegisteredSuffixPatternMatch;
  }

  /**
   * Whether to match to URLs irrespective of the presence of a trailing slash.
   */
  public boolean useTrailingSlashMatch() {
    return this.useTrailingSlashMatch;
  }

  /**
   * Return the configured {@link ContentNegotiationManager}.
   */
  public ContentNegotiationManager getContentNegotiationManager() {
    return this.contentNegotiationManager;
  }

  /**
   * Return the file extensions to use for suffix pattern matching.
   */
  public List<String> getFileExtensions() {
    return this.fileExtensions;
  }


  /**
   * {@inheritDoc}
   * Expects a handler to have a type-level @{@link Controller} annotation.
   */
  @Override
  protected boolean isHandler(Class<?> beanType) {
    return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
        (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
  }

  /**
   * Uses method and type-level @{@link RequestMapping} annotations to create
   * the RequestMappingInfo.
   * @return the created RequestMappingInfo, or {@code null} if the method
   * does not have a {@code @RequestMapping} annotation.
   * @see #getCustomMethodCondition(Method)
   * @see #getCustomTypeCondition(Class)
   */
  @Override
  protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    RequestMappingInfo info = null;
    RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
    if (methodAnnotation != null) {
      RequestCondition<?> methodCondition = getCustomMethodCondition(method);
      info = createRequestMappingInfo(methodAnnotation, methodCondition);
      RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
      if (typeAnnotation != null) {
        RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
        info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
      }
    }
    return info;
  }

  /**
   * Provide a custom type-level request condition.
   * The custom {@link RequestCondition} can be of any type so long as the
   * same condition type is returned from all calls to this method in order
   * to ensure custom request conditions can be combined and compared.
   * <p>Consider extending {@link AbstractRequestCondition} for custom
   * condition types and using {@link CompositeRequestCondition} to provide
   * multiple custom conditions.
   * @param handlerType the handler type for which to create the condition
   * @return the condition, or {@code null}
   */
  protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
    return null;
  }

  /**
   * Provide a custom method-level request condition.
   * The custom {@link RequestCondition} can be of any type so long as the
   * same condition type is returned from all calls to this method in order
   * to ensure custom request conditions can be combined and compared.
   * <p>Consider extending {@link AbstractRequestCondition} for custom
   * condition types and using {@link CompositeRequestCondition} to provide
   * multiple custom conditions.
   * @param method the handler method for which to create the condition
   * @return the condition, or {@code null}
   */
  protected RequestCondition<?> getCustomMethodCondition(Method method) {
    return null;
  }

  /**
   * Created a RequestMappingInfo from a RequestMapping annotation.
   */
  protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
    String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
    return new RequestMappingInfo(
        annotation.name(),
        new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
            this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
        new RequestMethodsRequestCondition(annotation.method()),
        new ParamsRequestCondition(annotation.params()),
        new HeadersRequestCondition(annotation.headers()),
        new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
        new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager),
        customCondition);
  }

  /**
   * Resolve placeholder values in the given array of patterns.
   * @return a new array with updated patterns
   */
  protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) {
    if (this.embeddedValueResolver == null) {
      return patterns;
    }
    else {
      String[] resolvedPatterns = new String[patterns.length];
      for (int i = 0; i < patterns.length; i++) {
        resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]);
      }
      return resolvedPatterns;
    }
  }

}
TOP

Related Classes of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.