struts2的路径检索策略

16 篇文章 0 订阅
10 篇文章 0 订阅
对于动态页面程序,由于请求路径已经不再是一眼可以看出的页面资源,所以往往会给程序开发人员带来很多的困扰,控制层的框架不同,请求虚拟路径的地址的规则也各不相同,在众多的控制层框架中struts2请求路径有时就让程序感到无所适从,在struts2中后台服务资源名称是通过命名空间规范进行组织的,关于这一规范众说纷纭,今天我决定来一探究竟,在众多的说法中最流行的一种就是当前空间优先查找,如果没有找到,就到默认空间进行查找,如果还没找到请抛异常(action or result没找到),这应该是strut2开发过程中,最常见的一种错误.上面所说的当前空间优先,而默认空间次之是什么意思呢?
<package name="默认空间" extends="struts-default">
		<!-- 这是一个默认空间中的aciton,主要提供验证码图形服务 -->
		<action name="captchaImage" class="captchaImageAction">
			<result type="captchaImage" />
		</action>
	</package>
	<package name="/public/login" namespace="/public/login" extends="risen-default">
		<!-- 这是一个默认空间中的aciton,主要提供验证码图形服务 -->
		<action name="login" class="captchaImageAction">
			<result type="captchaImage" />
		</action>
	</package>


可以从上面两个配置进行说起,上面第一个包是默认空间配置,第二个包的命名空间是/public/login,如果你从前台访问地址/xx/public/login/captchaImage.action如果在当前空间/public/login没有找到captchaImage配置,则系统会到默认空间中去查找,

事实并不是如此的简单,要弄清这个问题,你必须要去仔细阅读一个类源代码,这个类就是org.apache.struts2.dispatcher.mapper.DefaultActionMapper,这个类的主要功能就是将前请台的就求转换成与后台匹配一个action配置,这实际就是解决上面这个问题的关键,其中有一个关键的方法如下:

    protected void parseNameAndNamespace(String uri, ActionMapping mapping,
                                         ConfigurationManager configManager) {
        String namespace, name;
        int lastSlash = uri.lastIndexOf("/");
        if (lastSlash == -1) {
            namespace = "";
            name = uri;
        } else if (lastSlash == 0) {
            // ww-1046, assume it is the root namespace, it will fallback to
            // default
            // namespace anyway if not found in root namespace.
            namespace = "/";
            name = uri.substring(lastSlash + 1);
        } else if (alwaysSelectFullNamespace) {
            // Simply select the namespace as everything before the last slash
            namespace = uri.substring(0, lastSlash);
            name = uri.substring(lastSlash + 1);
        } else {
            // Try to find the namespace in those defined, defaulting to ""
            Configuration config = configManager.getConfiguration();
            String prefix = uri.substring(0, lastSlash);
            namespace = "";
            boolean rootAvailable = false;
            // Find the longest matching namespace, defaulting to the default
            for (Object cfg : config.getPackageConfigs().values()) {
                String ns = ((PackageConfig) cfg).getNamespace();
                if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {
                    if (ns.length() > namespace.length()) {
                        namespace = ns;
                    }
                }
                if ("/".equals(ns)) {
                    rootAvailable = true;
                }
            }

            name = uri.substring(namespace.length() + 1);

            // Still none found, use root namespace if found
            if (rootAvailable && "".equals(namespace)) {
                namespace = "/";
            }
        }

        if (!allowSlashesInActionNames && name != null) {
            int pos = name.lastIndexOf('/');
            if (pos > -1 && pos < name.length() - 1) {
                name = name.substring(pos + 1);
            }
        }

        mapping.setNamespace(namespace);
        mapping.setName(name);
    }

如果你仔细阅读上面的方法就会发现实际先前所谈论的解析策略,上面方法的倒数第二种情况,alwaysSelectFullNamespace=true是符合的,它总是获取命名空间的最长名称,余下的部分作为action的名称,但事实是alwaysSelectFullNamespace在默认情况下的取值是false,所以正常情况系统所采用的策略是最后一种情况,是采用逐级解析策略,即尽可能长的获取命名空间名称,而不是总是取全名称,对于这种策略上,针对上面的action配置,如果请求的路径是/xx/public/login/a/b/c/captchaImage.action同样可以找到空间/public/login下的captchaImage配置,所以在出现了action or result找不到的异常是你需要查看一个alwaysSelectFullNamespace是何种配置,以及allowSlashesInActionNames 是何种配置,实在没有办法,可以将断点调试,将断点设置在此方法中,进行查看

另外,还有一点你必须得明白,系统到默认空间中去查找只是一种说法,而不是实际情况,实际情况下,系统会将默认空间下的所有action配置复制到所有非默认空间下去,造成了,在当前空间下没能找到就到默认空间下去找的假象,如果你仔细去体会这两种逻辑,它们是有差别的,你可以仔细去体会.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值