【问题标题】:In freemarker is it possible to check to see if a file exists before including it?在 freemarker 中是否可以在包含文件之前检查文件是否存在?
【发布时间】:2010-04-13 15:38:43
【问题描述】:

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

我们已经到了这一点

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

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

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

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

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

-或-

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

【问题讨论】:

  • 这并不能直接回答您的问题,但您是否考虑过使用自定义 TemplateLoader 来代替?例如freemarker.org/docs/api/freemarker/template/…
  • 由Freemarker的[用户定义指令][1]解决,你可以试试。 [1]:stackoverflow.com/questions/13908848/…
  • 我希望我能结束这个问题 - 我不能接受任何答案,因为我不再参与这个项目,所以我不知道它们是否有效。对此感到抱歉。

标签: freemarker


【解决方案1】:

更简单的解决方案是:

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

【讨论】:

    【解决方案2】:

    我们编写了一个自定义宏来解决这个问题。在早期测试中,它运行良好。要包含它,请添加如下内容(其中 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());
                }
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      我也有这个确切的需求,但我不想使用 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。

      【讨论】:

        【解决方案4】:

        您也可以使用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>
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • 这个解决方案无法解析文件路径,总是落入else分支
          猜你喜欢
          • 2011-02-07
          • 2012-12-04
          • 2019-03-07
          • 2023-03-05
          • 2012-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-15
          相关资源
          最近更新 更多