2008-12-10 9 views
19

Ich mag würde meine Freemarker Vorlagen in einer Datenbanktabelle speichern, dass etwas wie folgt aussieht:laden Freemarker Vorlagen aus der Datenbank

template_name | template_content 
--------------------------------- 
hello   |Hello ${user} 
goodbye  |So long ${user} 

Wenn eine Anfrage für eine Vorlage mit einem bestimmten Namen empfangen wird, diese eine Abfrage führen soll ausgeführt werden, der den relevanten Vorlageninhalt lädt. Dieser Vorlageninhalt sollte zusammen mit dem Datenmodell (der Wert der Variable 'user' in den obigen Beispielen) an FreeMarker übergeben werden. Die FreeMarker API scheint jedoch anzunehmen, dass jeder Vorlagenname einer Datei desselben Namens in einem bestimmten Verzeichnis des Dateisystems entspricht. Gibt es eine Möglichkeit, wie ich meine Vorlagen einfach aus der Datenbank anstatt aus dem Dateisystem laden kann?

EDIT: ich erwähnt habe, sollte, dass ich mag in der Lage sein, Vorlagen zur Datenbank hinzufügen, während die Anwendung ausgeführt wird, so kann ich nicht einfach alle Vorlagen in einen neuen StringTemplateLoader beim Start geladen werden (wie unten vorgeschlagen).

Cheers, Don

Antwort

18

Ein paar Möglichkeiten: mit setTemplateLoader() vor dem Laden

  • eine neue Implementierung von TemplateLoader Erstellen von Vorlagen aus der Datenbank direkt zu laden, und es zu Ihrer Configuration Instanz übergibt irgendwelche Vorlagen.

  • Verwenden Sie eine StringTemplateLoader, die Sie beim Start der Anwendung in Ihrer Datenbank konfigurieren. Fügen Sie es der Konfiguration wie oben hinzu.

bearbeiten im Licht der Bearbeitung des Fragestellers, sieht eine eigene Implementierung von TemplateLoader wie der Weg zu gehen. Überprüfen Sie die Javadoc here, es ist eine einfache kleine Schnittstelle mit nur vier Methoden, und das Verhalten ist gut dokumentiert.

26

Wir verwenden eine StringTemplateLoader unsere tempates zu laden, die wir aus der db bekam (wie Dan Vinton vorgeschlagen)

Hier ist ein Beispiel:

StringTemplateLoader stringLoader = new StringTemplateLoader(); 
String firstTemplate = "firstTemplate"; 
stringLoader.putTemplate(firstTemplate, freemarkerTemplate); 
// It's possible to add more than one template (they might include each other) 
// String secondTemplate = "<#include \"greetTemplate\"><@greet/> World!"; 
// stringLoader.putTemplate("greetTemplate", secondTemplate); 
Configuration cfg = new Configuration(); 
cfg.setTemplateLoader(stringLoader); 
Template template = cfg.getTemplate(firstTemplate); 

bearbeiten Sie haben noch zu Laden Sie alle Vorlagen beim Start. Wann immer wir auf die Vorlage zugreifen, holen wir sie aus der DB und laden sie über den StringLoader und durch Aufruf von template.process() erzeugen wir (in unserem Fall) die XML-Ausgabe.

1

Für diejenigen, die nach Code suchen, hier ist es. Sehen Sie sich die Kommentare im Code zum besseren Verständnis an.

DBTemplate:

@Entity 
public class DBTemplate implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    private long templateId; 

    private String content; // Here's where the we store the template 

    private LocalDateTime modifiedOn; 

} 

TemplateLoader Implementierung (EMF ist eine Instanz eines EntityManagerFactory):

public class TemplateLoaderImpl implements TemplateLoader { 

    public TemplateLoaderImpl() { } 

    /** 
    * Retrieves the associated template for a given id. 
    * 
    * When Freemarker calls this function it appends a locale 
    * trying to find a specific version of a file. For example, 
    * if we need to retrieve the layout with id = 1, then freemarker 
    * will first try to load layoutId = 1_en_US, followed by 1_en and 
    * finally layoutId = 1. 
    * That's the reason why we have to catch NumberFormatException 
    * even if it is comes from a numeric field in the database. 
    * 
    * @param layoutId 
    * @return a template instance or null if not found. 
    * @throws IOException if a severe error happens, like not being 
    * able to access the database. 
    */ 
    @Override 
    public Object findTemplateSource(String templateId) throws IOException { 

     EntityManager em = null; 

     try { 
      long id = Long.parseLong(templateId); 
      em = EMF.getInstance().getEntityManager(); 
      DBTemplateService service = new DBTemplateService(em); 
      Optional<DBTemplate> result = service.find(id); 
      if (result.isPresent()) { 
       return result.get(); 
      } else { 
       return null; 
      } 
     } catch (NumberFormatException e) { 
      return null; 
     } catch (Exception e) { 
      throw new IOException(e); 
     } finally { 
      if (em != null && em.isOpen()) { 
       em.close(); 
      } 
     } 
    } 


    /** 
    * Returns the last modification date of a given template. 
    * If the item does not exist any more in the database, this 
    * method will return Long's MAX_VALUE to avoid freemarker's 
    * from recompiling the one in its cache. 
    * 
    * @param templateSource 
    * @return 
    */ 
    @Override 
    public long getLastModified(Object templateSource) { 
     EntityManager em = null; 
     try { 
      em = EMF.getInstance().getEntityManager(); 
      DBTemplateService service = new DBTemplateService(em); 
      // Optimize to only retrieve the date 
      Optional<DBTemplate> result = service.find(((DBTemplate) templateSource).getTemplateId()); 
      if (result.isPresent()) { 
       return result.get().getModifiedOn().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); 
      } else { 
       return Long.MAX_VALUE; 
      } 
     } finally { 
      if (em != null && em.isOpen()) { 
       em.close(); 
      } 
     } 
    } 

    /** 
    * Returns a Reader from a template living in Freemarker's cache. 
    */ 
    @Override 
    public Reader getReader(Object templateSource, String encoding) throws IOException { 
     return new StringReader(((DBTemplate) templateSource).getContent()); 
    } 

    @Override 
    public void closeTemplateSource(Object templateSource) throws IOException { 
     // Nothing to do here... 
    } 

} 

-Setup die Konfigurationsklasse:

... 
TemplateLoaderImpl loader = new TemplateLoaderImpl(); 

templateConfig = new Configuration(Configuration.VERSION_2_3_25); 
templateConfig.setTemplateLoader(loader); 
... 

Und schließlich, es verwenden:

... 
long someId = 3L; 
Template template = templateConfig.getTemplate("" + someId); 
... 

Dies funktioniert gut, und ermöglicht es Ihnen, alle Freemarker-Funktionen wie Importe zu verwenden, schließt ein, usw. Schauen Sie sich die folgenden Beispiele:

<#import "1" as layout> <!-- Use a template id. --> 
<@layout.mainLayout> 
... 

Oder:

<#include "3"> <!-- Use a template id. --> 
... 

Ich benutze Dieser Loader auf meinem eigenen CMS (CinnamonFramework) und funktioniert wie ein Zauber.

Beste,

Verwandte Themen