Можно ли в freemarker проверить, существует ли файл, прежде чем включать его? - PullRequest
7 голосов
/ 13 апреля 2010

Мы пытаемся построить систему в freemarker, в которой при желании можно добавить файлы расширения для замены блоков стандартного шаблона.

Мы дошли до этой точки

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

Итак - если файл extension.ftl существует, он будет использован, иначе будет выведена часть внутри блока восстановления.

Проблема в том, что freemarker всегда регистрирует ошибку, которая вызвала срабатывание блока восстановления.

Итак, нам нужна одна из двух вещей:

  1. Не вызывайте include, если файл не существует - таким образом, необходимо проверить наличие файла.

-ИЛИ-

  1. Способ предотвращения регистрации ошибки внутри блока восстановления без изменения регистрации, чтобы предотвратить появление ВСЕХ ошибок freemarker.

Ответы [ 5 ]

2 голосов
/ 27 сентября 2012

более простым решением будет:

<#attempt>
    <#import xyz.ftl>
    your_code_here
<#recover>
</#attempt>
0 голосов
/ 02 декабря 2017

Вы также можете использовать метод Java для проверки наличия файла.

Java-метод-

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

Код бесплатного маркера-

<#assign fileExists = (Static["ClassName"].checkFileExistance("Filename"))?c/>
<#if fileExists = "true">
    <#include "/home/demo.ftl"/>
    <#else>
        <#include "/home/index.ftl">
</#if>
0 голосов
/ 04 января 2013

Мы написали собственный макрос, который решает это для нас. В начале тестирования это работает хорошо. Чтобы включить его, добавьте что-то вроде этого (где 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());
            }
        }
    }
}
0 голосов
/ 26 января 2012

У меня тоже была такая потребность, но я не хотел использовать ObjectConstructor FreeMarker (на мой вкус это было слишком похоже на скриптлет).

Я написал пользовательский 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 не может быть найден.

0 голосов
/ 21 мая 2010

Попробуйте получить базовый путь:

<#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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...