2008-12-10 21 views
19

से मैं तरह दिखता है कि एक डेटाबेस तालिका में मेरी FreeMarker टेम्पलेट्स स्टोर करने के लिए करना चाहते हैं:लोड FreeMarker टेम्पलेट्स डेटाबेस

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

एक अनुरोध एक विशेष नाम के साथ एक टेम्पलेट के लिए प्राप्त होता है, यह एक प्रश्न का कारण होना चाहिए निष्पादित करने के लिए, जो प्रासंगिक टेम्पलेट सामग्री लोड करता है। यह टेम्पलेट सामग्री, डेटा मॉडल (उपर्युक्त उदाहरणों में 'उपयोगकर्ता' चर के मूल्य) के साथ, फिर फ्रीमार्कर को पास की जानी चाहिए।

हालांकि, FreeMarker API मानते हैं कि प्रत्येक टेम्पलेट नाम फ़ाइल सिस्टम की किसी विशेष निर्देशिका के भीतर एक ही नाम की फ़ाइल से मेल खाता है। क्या कोई तरीका है कि मैं आसानी से फाइल सिस्टम के बजाय डीबी से अपने टेम्पलेट लोड कर सकता हूं?

संपादित करें: मैंने कहा जाना चाहिए था कि मैं जबकि आवेदन चल रहा है डेटाबेस के लिए टेम्पलेट्स जोड़ने में सक्षम होना चाहते हैं, तो मैं बस (नीचे के रूप में सुझाव दिया एक नया StringTemplateLoader में स्टार्टअप पर सभी टेम्पलेट लोड नहीं कर सकता)।

चीयर्स, डॉन

उत्तर

18

तरीकों में से एक जोड़े:

  • TemplateLoader की एक नई कार्यान्वयन बनाएं टेम्पलेट्स डेटाबेस से प्रत्यक्ष लोड करने के लिए, और यह setTemplateLoader() पहले लोडिंग के का उपयोग कर अपने Configuration उदाहरण के लिए पारित कोई टेम्पलेट्स

  • StringTemplateLoader का उपयोग करें जिसे आप अपने डेटाबेस से कॉन्फ़िगर करते समय अपने डेटाबेस से कॉन्फ़िगर करते हैं। इसे उपरोक्त के रूप में कॉन्फ़िगरेशन में जोड़ें। प्रश्नकर्ता के संपादन के आलोक में

संपादित, TemplateLoader का अपना स्वयं का कार्यान्वयन रास्ते जाने के लिए की तरह लग रहा है। जावाडोक here देखें, यह केवल चार तरीकों के साथ एक साधारण छोटा इंटरफ़ेस है, और इसका व्यवहार अच्छी तरह से प्रलेखित है।

26

हम एक StringTemplateLoader का उपयोग हमारे tempates जो हम डाटाबेस से मिल गया है (जैसा कि दान Vinton सुझाव)

यहाँ एक उदाहरण है लोड करने के लिए:

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); 

संपादित आप की जरूरत नहीं है स्टार्टअप पर सभी टेम्पलेट लोड करें। जब भी हम टेम्पलेट तक पहुंचेंगे, हम इसे डीबी से लाएंगे और स्ट्रिंगलोडर के माध्यम से लोड करेंगे और टेम्पलेट.प्रोसेस() को कॉल करके (हमारे मामले में) एक्सएमएल आउटपुट उत्पन्न करेंगे।

1

कुछ कोड ढूंढने वालों के लिए, यहां यह है। बेहतर समझ के लिए कोड में टिप्पणियों पर एक नज़र डालें।

DBTemplate:

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... 
    } 

} 

सेटअप विन्यास वर्ग:

... 
TemplateLoaderImpl loader = new TemplateLoaderImpl(); 

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

और अंत में, इसका इस्तेमाल

@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 कार्यान्वयन (ईएमएफ एक EntityManagerFactory का एक उदाहरण है):

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

यह अच्छा काम करता है, और आप आयात की तरह Freemarker की सभी सुविधाओं का उपयोग करने के लिए अनुमति देता है, भी शामिल है, आदि निम्न उदाहरण को देखो:

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

या में:

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

मैं का उपयोग यह लोडर मेरे अपने सीएमएस (दालचीनी फ्रेमवर्क) पर और एक आकर्षण की तरह काम करता है।

बेस्ट,