In freemarker is it possible to check to see if a file exists before including it?

梦想与她 提交于 2019-12-07 01:43:31

问题


We are trying to build a system in freemarker where extension files can be optionally added to replace blocks of the standard template.

We have gotten to this point

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

So - if the extension.ftl file exists it will be used otherwise the part inside of the recover block is output.

The problem with this is that freemarker always logs the error that caused the recover block to trigger.

So we need one of two things:

  1. Don't call the include if the file doesn't exist - thus the need to check for file existence.

-OR-

  1. A way to prevent the logging of the error inside the recover block without changing the logging to prevent ALL freemarker errors from showing up.

回答1:


easier solution would be:

<#attempt>
    <#import xyz.ftl>
    your_code_here
<#recover>
</#attempt>



回答2:


We've written a custom macro which solves this for us. In early testing, it works well. To include it, add something like this (where mm is a 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());
            }
        }
    }
}



回答3:


I had this exact need as well but I didn't want to use FreeMarker's ObjectConstructor (it felt too much like a scriptlet for my taste).

I wrote a custom 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;
    }

}

And my corresponding FreeMarker macro:

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

An empty FTL file was required (/tools/empty.ftl) which just contains a comment explaining its existence.

The result is that an "optional" include will just include this empty FTL if the requested FTL cannot be found.




回答4:


You can use also use Java method to check file exist or not.

Java Method-

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

Freemarker Code-

<#assign fileExists = (Static["ClassName"].checkFileExistance("Filename"))?c/>
<#if fileExists = "true">
    <#include "/home/demo.ftl"/>
    <#else>
        <#include "/home/index.ftl">
</#if>



回答5:


Try this to get the base path:

<#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>

Then this to walk the directory structure:

<#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>


来源:https://stackoverflow.com/questions/2630942/in-freemarker-is-it-possible-to-check-to-see-if-a-file-exists-before-including-i

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!