8

我们正在尝试在 freemarker 中构建一个系统,可以选择添加扩展文件来替换标准模板的块。

我们已经到了这个地步

<#attempt>
    <#include "extension.ftl">
<#recover>
    Standard output
</#attempt>

所以 - 如果 extension.ftl 文件存在,它将被使用,否则恢复块内部的部分将被输出。

这样做的问题是 freemarker 总是记录导致恢复块触发的错误。

所以我们需要两件事之一:

  1. 如果文件不存在,请不要调用包含 - 因此需要检查文件是否存在。

-或者-

  1. 一种在不更改日志记录的情况下防止在恢复块内记录错误以防止出现所有 freemarker 错误的方法。
4

5 回答 5

2

更简单的解决方案是:

<#attempt>
    <#import xyz.ftl>
    your_code_here
<#recover>
</#attempt>
于 2012-09-27T09:44:18.863 回答
1

我们编写了一个自定义宏来为我们解决这个问题。在早期测试中,它运行良好。要包含它,请添加如下内容(其中 mm 是 Spring ModelMap):

mm.addAttribute(IncludeIfExistsMacro.MACRO_NAME, new IncludeIfExistsMacro());
import java.io.IOException;
import java.util.Map;

import org.apache.commons.io.FilenameUtils;

import freemarker.cache.TemplateCache;
import freemarker.cache.TemplateLoader;
import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;


/**
 * This macro optionally includes the template given by path.  If the template isn't found, it doesn't
 * throw an exception; instead it renders the nested content (if any).
 * 
 * For example: 
 * <@include_if_exists path="module/${behavior}.ftl">
 * <#include "default.ftl">
 * </@include_if_exists>
 * 
 * @param path the path of the template to be included if it exists
 * @param nested (optional) body could be include directive or any other block of code
 */
public class IncludeIfExistsMacro implements TemplateDirectiveModel {

    private static final String PATH_PARAM = "path";
    public static final String MACRO_NAME = "include_if_exists";

    @Override
    public void execute(Environment environment, Map map, TemplateModel[] templateModel,
            TemplateDirectiveBody directiveBody) throws TemplateException, IOException {

        if (! map.containsKey(PATH_PARAM)) {
            throw new RuntimeException("missing required parameter '" + PATH_PARAM + "' for macro " + MACRO_NAME);
        }

        // get the current template's parent directory to use when searching for relative paths
        final String currentTemplateName = environment.getTemplate().getName();
        final String currentTemplateDir = FilenameUtils.getPath(currentTemplateName);

        // look up the path relative to the current working directory (this also works for absolute paths)
        final String path = map.get(PATH_PARAM).toString();
        final String fullTemplatePath = TemplateCache.getFullTemplatePath(environment, currentTemplateDir, path);

        TemplateLoader templateLoader = environment.getConfiguration().getTemplateLoader();
        if (templateLoader.findTemplateSource(fullTemplatePath) != null) {
            // include the template for the path, if it's found
            environment.include(environment.getTemplateForInclusion(fullTemplatePath, null, true));
        } else {
            // otherwise render the nested content, if there is any
            if (directiveBody != null) {
                directiveBody.render(environment.getOut());
            }
        }
    }
}
于 2013-01-04T04:01:20.203 回答
0

我也有这个确切的需求,但我不想使用 FreeMarker ObjectConstructor(我觉得它太像脚本了)。

我写了一个自定义FileTemplateLoader

public class CustomFileTemplateLoader 
    extends FileTemplateLoader {

    private static final String STUB_FTL = "/tools/empty.ftl";

    public CustomFileTemplateLoader(File baseDir) throws IOException {
        super(baseDir);
    }


    @Override
    public Object findTemplateSource(String name) throws IOException {
        Object result = null;
        if (name.startsWith("optional:")) {
            result = super.findTemplateSource(name.replace("optional:", ""));
            if (result == null) {
                result = super.findTemplateSource(STUB_FTL);
            }
        }

        if (result == null) {
            result = super.findTemplateSource(name);
        }

        return result;
    }

}

还有我对应的 FreeMarker 宏:

<#macro optional_include name>
    <#include "/optional:" + name>
</#macro>

需要一个空的 FTL 文件 ( /tools/empty.ftl),其中仅包含解释其存在的注释。

结果是,如果无法找到请求的 FTL,“可选”包含将仅包含此空 FTL。

于 2012-01-26T18:08:13.797 回答
0

您也可以使用 Java 方法检查文件是否存在。

Java方法-

public static boolean checkFileExistance(String filePath){
            File tmpDir = new File(filePath);
        boolean exists = tmpDir.exists();
        return exists;
    }

Freemarker代码-

<#assign fileExists = (Static["ClassName"].checkFileExistance("Filename"))?c/>
<#if fileExists = "true">
    <#include "/home/demo.ftl"/>
    <#else>
        <#include "/home/index.ftl">
</#if>
于 2017-12-02T07:00:27.180 回答
-2

试试这个来获得基本路径:

<#assign objectConstructor = "freemarker.template.utility.ObjectConstructor"?new()>
<#assign file = objectConstructor("java.io.File","")>
<#assign path = file.getAbsolutePath()>
<script type="text/javascript">
alert("${path?string}");
</script>

然后这个走目录结构:

<#assign objectConstructor = "freemarker.template.utility.ObjectConstructor"?new()>
<#assign file = objectConstructor("java.io.File","target/test.ftl")>
<#assign exist = file.exists()>
<script type="text/javascript">
alert("${exist?string}");
</script>
于 2010-05-21T09:09:47.907 回答