5

我对 Freemarker 和 Restlet 的 freemarker 扩展的文档中所写的内容有点困惑。

情况如下:restlet 引擎提供资源的 HTML 表示(例如 www.mysite.com/{user}/updates)。为这个 URI 返回的资源是一个包含所有更新的 HTML 页面,它是使用 freemarker 模板创建的。此应用程序托管在 Glassfish v3 服务器上

问题):

  • 根据 freemarker 文档,freemarker 配置只能加载一次:

        /* You should do this ONLY ONCE in the whole application life-cycle:Create and adjust the configuration */
        Configuration cfg = new Configuration();
        cfg.setDirectoryForTemplateLoading(
                new File("/where/you/store/templates"));
        cfg.setObjectWrapper(new DefaultObjectWrapper());
    

    在 Java EE 应用程序中执行此操作的最佳位置是什么?我正在考虑将它作为 web.xml 中的上下文参数并使用 ServletContextListener - 但我不确定如何去做。

  • 根据 freemarker 的文档,我们还可以添加一个 freemarkerservlet 并将.ftl url-patterns 映射到它。但这已经由 Restlet servlet 映射(即“/ ”的 url 模式)。因此,为 *.ftl 设置另一个是没有意义的(或者是吗?)

所以问题基本上是关于如何最好地与 Freemarker 的“配置”集成,以便它只发生一次,以及那段代码的“入口点”是什么(谁调用它)。有没有人在 Java EE 环境中成功使用过 Freemarker + restlet?有任何想法吗?

谢谢!

4

1 回答 1

6

这是一个棘手的问题——确实如此。要求我执行 org.restlet.ext.Freemarker 包中的源文件 - 唷!

这是你可以做到的

  1. 如果您需要创建自己的配置对象,请将“templateLoader”设置为使用,然后在其上使用 TemplateRepresentation 进行渲染:

    Configuration cfg = new Configuration();
    
    ContextTemplateLoader loader = new ContextTemplateLoader(getContext(),"war:///WEB-INF");
    
    cfg.setTemplateLoader(loader);
    
    TemplateRepresentation rep = null;
    
    Mail mail = new Mail(); //The data object you wish to populate - example from Restlet itself
        mail.setStatus("received");
        mail.setSubject("Message to self");
        mail.setContent("Doh!");
        mail.setAccountRef(new Reference(getReference(), "..").getTargetRef()
                .toString());
    
      Map<String, Object> data = new HashMap<String, Object>();
      data.put("status", mail.getStatus());
      data.put("subject", mail.getSubject());
      data.put("content", mail.getContent());
      data.put("accountRef", mail.getAccountRef());
    
      rep = new TemplateRepresentation("Mail.ftl", cfg, data, MediaType.TEXT_HTML);
    
      return rep;
    
  2. 如果您对默认设置感到满意并希望使用基于类加载器的方式来加载模板

    //Load the FreeMarker template
        Representation mailFtl = new ClientResource(
                LocalReference.createClapReference(getClass().getPackage())
                        + "/Mail.ftl").get(); 
      //Wraps the bean with a FreeMarker representation
    return new TemplateRepresentation(mailFtl, mail, MediaType.TEXT_HTML);
    
  3. 如果您想初始化一次配置对象并通过调用配置对象上的 setServletContextForTemplateLoading(...) 方法来设置模板。您总是可以在 ServletContextListener 中执行此操作


public class Config implements ServletContextListener {
    private static Configuration cfg = new Configuration();

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext sc = sce.getServletContext();
        cfg.setServletContextForTemplateLoading(sc, "/WEB-INF");        
    }
    public static Configuration getFMConfig()
    {
        return cfg;
    }
}

然后调用静态 getFMConfig() 并将其传递给 TemplateRepresentation,如 1

注意事项:

  • 如果您确实获得了协议不受支持的异常,则会出现在案例 2 中。这意味着 ServerResource 不知道使用什么协议来访问文件 - 这将是 Restlet 的 CLAP 协议。您可能必须在 web.xml 文件中为 RestletServlet 设置 init-params 并将 CLAP 作为参数值之一
  • TemplateRepresentation 有很多构造函数——如果你在实例化过程中不传入配置对象(使用另一个重载的构造函数),它将为你创建一个新的 Configuration()。因此,您不必像 2 中那样进行任何配置设置(这可能会让您觉得很明显,但我认为您仍然需要设置配置,否则它会“从某处获取”)
  • 如果您确实希望设置自己的配置,则必须将其传递给构造函数之一
  • 看看 1 中 ContextTemplateLoader 的构造函数中的“war:///”字符串。这很重要没有提到这个baseUri引用应该是什么,甚至在文档中也没有。我试了好久才发现它应该是“war:///”,后跟存储模板的文件夹名称。
  • 对于案例 2,您可能必须将模板存储在与访问此代码的类文件相同的包中。如果您仔细观察,您会注意到 LocalReference 参数作为 ClientResource 的参数,表示资源应该在本地存在,因此您需要使用自定义 CLAP 协议(​​类加载器访问协议)

个人挫折点-为什么在文档或任何地方都没有澄清这一切:)

希望它对偶然发现这篇文章的人有所帮助!呸!

于 2011-03-22T21:34:58.457 回答