【问题标题】:How to implement @RequestMapping custom properties如何实现@RequestMapping 自定义属性
【发布时间】:2012-05-05 22:21:51
【问题描述】:

作为示例,以子域映射为例。

本文:Managing multiple Domain and Sub Domain on Google App Engine for Same Application 建议在 Filter 上解析子域并将变量分配给 ServletRequest 标头。

那么映射将如下所示:

@RequestMapping(value = "/path", headers="subdomain=www")
 public String subsiteIndexPage(Model model,HttpServletRequest request) { ... }

如果我们想创建自定义@RequestMapping 属性,例如子域,例如。像这样创建映射:

@RequestMapping(value = "/some/action", subdomain = "www")
public String handlerFunction(){ ... }

我们应该用我们自己的实现覆盖@RequestMapping @interface 定义和覆盖RequestMappingHandlerMapping受保护的方法
(如 JIRA 中所述:“Allow custom request mapping conditions SPR-7812”)。

对吗?谁能提供一个提示,如何实现这个功能?


想法 1
正如原始 jira 线程所建议的那样,是创建自己的 RequestCondition 实现

github上有一个使用此解决方案的项目:https://github.com/rstoyanchev/spring-mvc-31-demo/

以及相关的 SO 问题:Adding custom RequestCondition's in Spring mvc 3.1

也许类型和方法都像@Subdomain("www") 这样的映射,是可能的解决方案吗?


Link to same question on forum.springsource.com

【问题讨论】:

    标签: java spring servlets spring-mvc


    【解决方案1】:

    我已经根据引用的spring-mvc-31-demo 创建了解决方案

    到目前为止,此解决方案仅可用于映射单个 RequestCondition。我创建了两个要通知的问题,应该更改:
    https://github.com/rstoyanchev/spring-mvc-31-demo/issues/5
    https://jira.springsource.org/browse/SPR-9350

    此解决方案使用 Spring 3.1.1.RELEASE 平台的自定义 @RequestCondition 功能

    用法

    示例 1:

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

    示例 2:

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

    我们需要三个文件

    • 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<SubdomainRequestCondition> {
    
        private final Set<String> subdomains;
        private final String tld;
    
        public SubdomainRequestCondition(String tld, String... subdomains) {
            this(tld, Arrays.asList(subdomains));
        }
    
        public SubdomainRequestCondition(String tld, Collection<String> subdomains) {
            this.subdomains = Collections.unmodifiableSet(new HashSet<String>(
                    subdomains));
            this.tld = tld;
        }
    
        @Override
        public SubdomainRequestCondition combine(SubdomainRequestCondition other) {
            Set<String> allRoles = new LinkedHashSet<String>(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;
        }
    
    }
    

    安装

    重要提示:到目前为止,无法将此解决方案与 XML 元素一起使用
    ,请参阅 JIRA https://jira.springsource.org/browse/SPR-9344 了解说明

    • 你必须注册自定义 MappingHandler bean,指向这个自定义实现 SubdomainRequestMappingHandlerMapping
    • 您必须将其顺序设置为低于默认值RequestMappingHandlerMapping

      替换已注册的RequestMappingHandlerMapping(可能在 order=0 上)

    有关实施此解决方案的更广泛说明,请参阅相关的 github 项目

    【讨论】:

    • 要解决的问题,可以通过扩展WebMvcConfigurationSupport替换为基于java的配置(阅读@EnableWebMvc中的javadoc,直接跳到最后一个案例)跨度>
    • 对于 的基于 xml 的替代方案,请检查这个 SO 问题:stackoverflow.com/questions/3693397/…
    • 我可以根据请求正文的条件使用这种方法进行请求映射吗?
    • @WakaWaka 你应该可以使用类似的方法
    • 我已经实现了同样的东西,@Vituel 你有没有使用 XML 实现注释的例子。当前直接在类中定义注释效果很好。
    【解决方案2】:

    没错,但这太复杂了。您最好检查Host 标头,它是否包含给定的子域。

    但是你不应该真的需要超过一次或两次,所以你也可以在方法体中手动完成。如果你真的在很多地方都需要它,那将是一个奇怪的要求。

    【讨论】:

    • 奇数在哪?它给了我可能比许多 Url Rewrite 规则更好的控制。比如如果你有一个平台,你需要根据认证角色(管理员、经理、用户)来区分操作,你可以有/admin/*/manager/*等映射。或者你可以有admin.domain.tld/*manager.domain.tld/*, ...
    • 请参阅有问题的建议 1。也许这可能是一个优雅的解决方案
    • 你能想出比扩展 RequestMappingHandlerMapping 更好的@RequestCondition 实现吗?
    • 据我所知,没有。尽管我认为您应该能够将您的实现插入到一些列表中。但我找不到它
    • 我已经对这个问题提出了自己的解决方案,请考虑对我的代码进行任何更新和/或改进。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2011-05-02
    • 2015-05-11
    • 1970-01-01
    • 2012-05-28
    • 2016-08-21
    相关资源
    最近更新 更多