How to implement @RequestMapping custom properties

后端 未结 2 1202
天命终不由人
天命终不由人 2020-12-01 01:25

As an example, take subdomain mapping.

This article: Managing multiple Domain and Sub Domain on Google App Engine for Same Applicat

2条回答
  •  自闭症患者
    2020-12-01 02:05

    I've created solution based on referenced spring-mvc-31-demo

    This solution can be used to map only single RequestCondition as of now. I've created two Issues to notify, this should be changed:
    https://github.com/rstoyanchev/spring-mvc-31-demo/issues/5
    https://jira.springsource.org/browse/SPR-9350

    This solution uses custom @RequestCondition feature of Spring 3.1.1.RELEASE platform

    USAGE

    Example 1:

    @Controller
    @SubdomainMapping(value = "subdomain", tld = ".mydomain.com")
    class MyController1 {
        // Code here will be executed only on address match:
        // subdomain.mydomain.com
    }
    

    Example 2:

    @Controller
    class MyController2 {
    
        @RequestMapping("/index.html")
        @SubdomainMapping("www")
        public function index_www(Map map){
            // on www.domain.com
            // where ".domain.com" is defined in SubdomainMapping.java
        }
    
        @RequestMapping("/index.html")
        @SubdomainMapping("custom")
        public function index_custom(Map map){
            // on custom.domain.com
            // where ".domain.com" is defined in SubdomainMapping.java
        }
    }
    

    We need three files

    • SubdomainMapping.java
    • SubdomainRequestCondition.java
    • SubdomainRequestMappingHandlerMapping.java

    SubdomainMapping.java

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SubdomainMapping {
    
        /**
        * This param defines single or multiple subdomain
        * Where the Method/Type is valid to be called
        */
        String[] value() default {};
        /**
        * This param defines site domain and tld
        * It's important to put the leading dot
        * Not an array, so cannot be used for mapping multiple domains/tld
        */
        String tld() default ".custom.tld";
    }
    

    SubdomainRequestCondition.java

    import java.net.URL;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.LinkedHashSet;
    import java.util.Set;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.web.servlet.mvc.condition.RequestCondition;
    
    public class SubdomainRequestCondition implements
            RequestCondition {
    
        private final Set subdomains;
        private final String tld;
    
        public SubdomainRequestCondition(String tld, String... subdomains) {
            this(tld, Arrays.asList(subdomains));
        }
    
        public SubdomainRequestCondition(String tld, Collection subdomains) {
            this.subdomains = Collections.unmodifiableSet(new HashSet(
                    subdomains));
            this.tld = tld;
        }
    
        @Override
        public SubdomainRequestCondition combine(SubdomainRequestCondition other) {
            Set allRoles = new LinkedHashSet(this.subdomains);
            allRoles.addAll(other.subdomains);
            return new SubdomainRequestCondition(tld, allRoles);
        }
    
        @Override
        public SubdomainRequestCondition getMatchingCondition(
                HttpServletRequest request) {
            try {
                URL uri = new URL(request.getRequestURL().toString());
                String[] parts = uri.getHost().split(this.tld);
                if (parts.length == 1) {
                    for (String s : this.subdomains) {
                        if (s.equalsIgnoreCase(parts[0])) {
                            return this;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace(System.err);
            }
            return null;
        }
    
        @Override
        public int compareTo(SubdomainRequestCondition other,
                HttpServletRequest request) {
            return org.apache.commons.collections.CollectionUtils.removeAll(other.subdomains, this.subdomains).size();
        }
    
    }
    

    SubdomainRequestMappingHandlerMapping.java

    import java.lang.reflect.Method;
    
    import org.springframework.core.annotation.AnnotationUtils;
    import org.springframework.web.servlet.mvc.condition.RequestCondition;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
    
    public class CustomRequestMappingHandlerMapping extends
            RequestMappingHandlerMapping {
    
        @Override
        protected RequestCondition getCustomTypeCondition(Class handlerType) {
            SubdomainMapping typeAnnotation = AnnotationUtils.findAnnotation(
                    handlerType, SubdomainMapping.class);
            return createCondition(typeAnnotation);
        }
    
        @Override
        protected RequestCondition getCustomMethodCondition(Method method) {
            SubdomainMapping methodAnnotation = AnnotationUtils.findAnnotation(
                    method, SubdomainMapping.class);
            return createCondition(methodAnnotation);
        }
    
        private RequestCondition createCondition(SubdomainMapping accessMapping) {
            return (accessMapping != null) ? new SubdomainRequestCondition(
                    accessMapping.tld(), accessMapping.value()) : null;
        }
    
    }
    

    Instalation

    IMPORTANT: So far, it is not possible to use this solution with XML element
    , see JIRA https://jira.springsource.org/browse/SPR-9344 for explanation

    • You have to register custom MappingHandler bean, pointing at this custom implementation SubdomainRequestMappingHandlerMapping class
    • You have to set it's order to be lower than default RequestMappingHandlerMapping
      OR
      Replace the registered RequestMappingHandlerMapping (possibly on order=0)

    For more wide explanation on implementing this solution, see the related github project

提交回复
热议问题