Использование Freemarker с Restlet 2.0 на сервере Java EE

Я немного смущен тем, что написано в документации (ах) для Freemarker и расширения 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? Я думаю о том, чтобы использовать его как context-param в web.xml и использовать ServletContextListener, но я не уверен, как это сделать.

  • В соответствии с документацией freemarker мы также можем добавить freemarkerservlet и сопоставить ему url-шаблоны .ftl. Но это уже отображается сервлетом Restlet (т. Е. URL-шаблоном "/"). Так что иметь еще один для * .ftl не имеет смысла (или нет?)

Таким образом, вопрос в основном заключается в том, как лучше всего интегрироваться с «конфигурацией» Freemarker, чтобы это происходило только один раз, и какова «точка входа» для этого фрагмента кода (кто его вызывает). Кто-нибудь успешно использовал Freemarker + restlet в среде Java EE? Любые идеи?

Спасибо!


person PhD    schedule 21.03.2011    source источник


Ответы (1)


Это был действительно сложный вопрос. Требовал от меня пройти реализацию исходных файлов в пакете 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

На заметку:

  • Если вы получите протокол, который не поддерживается, Exception, это будет в случае 2. Подразумевается, что ServerResource не знает, какой протокол использовать для доступа к файлу - это будет протокол CLAP Restlet. Возможно, вам придется настроить параметры инициализации для RestletServlet в файле web.xml и указать CLAP в качестве одного из значений параметров.
  • TemplateRepresentation имеет довольно много конструкторов - если вы НЕ передаете объект конфигурации во время создания экземпляра (с использованием другого перегруженного конструктора), он создаст для вас новый Configuration (). Таким образом, вам не нужно настраивать какую-либо конфигурацию, как в пункте 2 (это может показаться вам очевидным, но я предполагал, что вам все равно нужно настроить конфигурацию, иначе она `` заберет ее откуда-то '')
  • Если вы хотите, чтобы ваша СОБСТВЕННАЯ конфигурация была настроена, вы ДОЛЖНЫ передать ее одному из конструкторов.
  • Взгляните на строку «war: ///» в конструкторе ContextTemplateLoader в 1. это важно. Ни где не упоминается, какой должна быть эта ссылка baseUri, даже в документации. Я долго пытался, прежде чем сообразил, что это должно быть «war: ///», за которым следует имя папки, в которой хранятся шаблоны.
  • Для случая 2 вам, вероятно, придется хранить шаблоны в том же пакете, что и файл класса, из которого осуществляется доступ к этому коду. Если вы внимательно посмотрите, вы заметите параметр LocalReference в качестве аргумента для ClientResource, говорящий, что ресурс должен присутствовать локально, и, следовательно, вам необходимо использовать настраиваемый протокол CLAP (протокол доступа classLoader)

Личное разочарование - почему все это даже не разъясняется в документации или НИГДЕ :)

Надеюсь, это поможет кому-то, кто наткнется на этот пост! Фух!

person PhD    schedule 22.03.2011
comment
Вариант 2 у меня работает. Я хотел бы использовать вариант 1, но всегда получаю сообщение об ошибке «Шаблон не найден». Не могли бы вы объяснить мне структуру каталогов для этого? - person bvamos; 03.03.2014
comment
@bvamos - Должно работать. Мой пример кода работает для всех шаблонов, находящихся в папке WEB-INF на корневом уровне. Если у вас есть вложенные папки, путь нужно указать соответствующим образом. Где ваши шаблоны и как вы вызываете конструктор ContextTemplateLoader? - person PhD; 04.03.2014
comment
@PhD - Спасибо за ответ. Я решил это с помощью cfg.setTemplateLoader (новый ClassTemplateLoader (getClass (), templates /)) и cfg.getTemplate (filename), который идеально мне подходит и работает с военным пакетом. - person bvamos; 04.03.2014