2008-12-10 13 views
19

me gustaría para almacenar mis plantillas FreeMarker en una tabla de base de datos que se ve algo como:plantillas de carga FreeMarker de la base de datos

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

Cuando se recibe una solicitud de una plantilla con un nombre particular, esto debería hacer una consulta para ser ejecutado, que carga el contenido de plantilla relevante. Este contenido de la plantilla, junto con el modelo de datos (el valor de la variable 'usuario' en los ejemplos anteriores), se debe pasar a FreeMarker.

Sin embargo, el FreeMarker API parece suponer que cada nombre de plantilla corresponde a un archivo del mismo nombre dentro de un directorio particular del sistema de archivos. ¿Hay alguna forma en la que pueda cargar fácilmente mis plantillas desde la base de datos en lugar del sistema de archivos?

EDIT: debería haber mencionado que me gustaría ser capaz de añadir plantillas a la base de datos mientras se ejecuta la aplicación, así que no puedo simplemente cargar todas las plantillas en el inicio a una nueva StringTemplateLoader (como se sugiere a continuación)

Saludos, Don

Respuesta

18

Un par de maneras:

  • Crear una nueva aplicación de TemplateLoader para cargar plantillas directamente desde la base de datos, y pasarlo a su Configuration ejemplo utilizando setTemplateLoader() antes de la carga cualquier plantilla

  • Utilice un StringTemplateLoader que configure desde su base de datos cuando se inicie su aplicación. Agréguelo a la configuración como se indica arriba.

Editar a la luz de la edición de la pregunta, su propia implementación de TemplateLoader parece que el camino a seguir. Compruebe el Javadoc here, es una pequeña interfaz simple con solo cuatro métodos, y su comportamiento está bien documentado.

26

se utiliza un StringTemplateLoader para cargar nuestros tempates que nos dieron desde el db (como sugiere Dan Vinton)

He aquí un ejemplo:

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

Editar Usted no tiene que cargar todas las plantillas al inicio. Cada vez que accedemos a la plantilla, la buscamos desde el DB y la cargamos a través del StringLoader y al llamar a template.process() generamos (en nuestro caso) el resultado XML.

1

Para aquellos que buscan algún código, aquí está. Eche un vistazo a los comentarios en el código para una mejor comprensión.

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; 

} 

aplicación TemplateLoader (EMF es una instancia de un 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... 
    } 

} 

instalación de la clase de configuración:

... 
TemplateLoaderImpl loader = new TemplateLoaderImpl(); 

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

Y, por último, lo utilizan:

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

Esto funciona muy bien, y le permite utilizar todas las funciones de Freemarker como las importaciones, incluye, etc. Mira los siguientes ejemplos:

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

O en:

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

utilizo este cargador en mi propio CMS (CinnamonFramework) y funciona como un encanto.

Mejor,

Cuestiones relacionadas