struts2中模板路径的不常用策略

在模板路径的构建策略一文中谈到模板的最终路径是由三个参量 templateDir(模板目录),theme(主题),template(模板名称)所决定的,例如:

<@rs.nav templateDir='template' theme='ajax' template="nav" />

上面的一个自定义组件nav它的模板路径就为/template/ajax/nav,如果模板引擎选择freemarker则最终的路径应该为/template/ajax/nav.ftl,在进行路径配置的时候其中有很重要的条就是除了在template参数中可以带一个扩展名称外其它任何地方都不可以使用小数点,这是因为在struts2中路径中的点是非常敏感的,它决定了对模板引擎的选择问题,具体可以查看TemplateEngineManager中的代码,其中关键源代码如下:

    public TemplateEngine getTemplateEngine(Template template, String templateTypeOverride) {
        String templateType = DEFAULT_TEMPLATE_TYPE;
        String templateName = template.toString();
        if (templateName.indexOf(".") > 0) {
            templateType = templateName.substring(templateName.indexOf(".") + 1);
        } else if (templateTypeOverride !=null && templateTypeOverride.length() > 0) {
            templateType = templateTypeOverride;
        } else {
            String type = defaultTemplateType;
            if (type != null) {
                templateType = type;
            }
        }
        return templateEngines.get(templateType).create();
    }

从这个地方的源代码可以看出此方法实现有些不好,至少要用一个lastIndexOf方法,使得开发者对路径的控制可以更灵活一些,根据上面的代码可以看出开发者不能在templateDir(模板目录),theme(主题),中添加任何小数点符号,也不能在template(模板名称)中添加两个或两个以上的小数点符号,

假如我们可以在theme中使用小数点则可以如些设计:

<@rs.nav templateDir='template' theme='.' template="nav" />

此时的路径就会变成/template/./nav.ftl而实际最终的路径为:/template/nav.ftl这样可以使得用开发者对默认模板有更灵活的控制.

另外还有几种怪异的符符号/与*如果程序为如下的形式:

<@rs.nav templateDir='template/ajax' theme='/' template="nav" />

假设在template/ajax路径下有一个模板nav.ftl那么上面的配置是否可以成功呢?答案是肯定的这是因为在一个文件路径中多几个/是可以忽略的,上面生成的最终路径是:template/ajax///nav.ftl但是加载器任何可以查找到相关的资源.

如果程序配置为如下形式:

<@rs.nav templateDir='template/ajax/a/b' theme='*' template="nav" />

是否可以查看到相关的资源,答案也是肯定的,上面的那个*是有特别含义的,此逻辑是freemarker框架中的TemplateCache对象提供的其关键源代码如下:

    private Object acquireTemplateSource(String path) throws IOException
    {
        int asterisk = path.indexOf(ASTERISK);
        // Shortcut in case there is no acquisition
        if(asterisk == -1)
        {
            return mainLoader.findTemplateSource(path);
        }
        StringTokenizer tok = new StringTokenizer(path, "/");
        int lastAsterisk = -1;
        List tokpath = new ArrayList();
        while(tok.hasMoreTokens())
        {
            String pathToken = tok.nextToken();
            if(pathToken.equals(ASTERISKSTR))
            {
                if(lastAsterisk != -1)
                {
                    tokpath.remove(lastAsterisk);
                }
                lastAsterisk = tokpath.size();
            }
            tokpath.add(pathToken);
        }
        String basePath = concatPath(tokpath, 0, lastAsterisk);
        String resourcePath = concatPath(tokpath, lastAsterisk + 1, tokpath.size());
        if(resourcePath.endsWith("/"))
        {
            resourcePath = resourcePath.substring(0, resourcePath.length() - 1);
        }
        StringBuffer buf = new StringBuffer(path.length()).append(basePath);
        int l = basePath.length();
        boolean debug = logger.isDebugEnabled();
        for(;;)
        {
            String fullPath = buf.append(resourcePath).toString();
            if(debug)
            {
                logger.debug("Trying to find template source " + fullPath);
            }
            Object templateSource = mainLoader.findTemplateSource(fullPath);
            if(templateSource != null)
            {
                return templateSource;
            }
            if(l == 0)
            {
                return null;
            }
            l = basePath.lastIndexOf(SLASH, l - 2) + 1;
            buf.setLength(l);
        }
    }

从上面的代码可以看出它会按*左侧的路径逐次查找:第一次查找template/ajax/a/b/nav.ftl;第二次查找template/ajax/a/nav.ftl;第三次查找template/ajax/nav.ftl(此时将会查找成功)

 

你可能感兴趣的:(struts2中模板路径的不常用策略)