Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从数据库加载FreeMarker模板_Java_Templates_Freemarker - Fatal编程技术网

Java 从数据库加载FreeMarker模板

Java 从数据库加载FreeMarker模板,java,templates,freemarker,Java,Templates,Freemarker,我想将我的FreeMarker模板存储在一个数据库表中,该表类似于: template_name | template_content --------------------------------- hello |Hello ${user} goodbye |So long ${user} 当收到对具有特定名称的模板的请求时,这将导致执行查询,从而加载相关模板内容。该模板内容以及数据模型(上述示例中“user”变量的值)应传递给FreeMarker 但是,似乎假

我想将我的FreeMarker模板存储在一个数据库表中,该表类似于:

template_name | template_content
---------------------------------
hello         |Hello ${user}
goodbye       |So long ${user}
当收到对具有特定名称的模板的请求时,这将导致执行查询,从而加载相关模板内容。该模板内容以及数据模型(上述示例中“user”变量的值)应传递给FreeMarker

但是,似乎假定每个模板名对应于文件系统特定目录中的同名文件。是否有任何方法可以轻松地从DB而不是文件系统加载模板

编辑:我应该提到,我希望能够在应用程序运行时将模板添加到数据库中,因此我不能简单地在启动时将所有模板加载到新的StringTemplateLoader中(如下所示)。

有几种方法:

  • 创建的新实现以直接从数据库加载模板,并在加载任何模板之前使用
    setTemplateLoader()
    将其传递给实例

  • 使用应用程序启动时从数据库配置的。如上所述,将其添加到配置中


编辑根据提问者的编辑,您自己的TemplateLoader实现看起来是一个不错的选择。查看Javadoc,它是一个简单的小接口,只有四种方法,其行为有很好的文档记录。

我们使用StringTemplateLoader来加载我们从db获得的Tempate(正如Dan 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);
StringTemplateLoader stringLoader=新StringTemplateLoader();
字符串firstTemplate=“firstTemplate”;
stringLoader.PuttTemplate(第一个模板,freemarkerTemplate);
//可以添加多个模板(它们可能相互包含)
//String secondTemplate=“World!”;
//stringLoader.PuttTemplate(“greetTemplate”,第二个模板);
Configuration cfg=新配置();
cfg.setTemplateLoader(stringLoader);
模板模板=cfg.getTemplate(firstTemplate);
编辑
您不必在启动时加载所有模板。无论何时访问模板,我们都会从数据库中获取它,并通过StringLoader加载它,并通过调用template.process()生成(在本例中)XML输出。

自2.3.20以来,您只需:


这是一个方便的构造函数。

对于那些寻找一些代码的人来说,它就在这里。请查看代码中的注释,以便更好地理解

数据库模板:

@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实现(EMF是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. -->
...

...
我在自己的CMS(肉桂框架)上使用这个加载程序,工作起来很有魅力


最好,实施配置

例如:

@Configuraton
public class FreemarkerConfig {

@Autowired
TemplateRepository tempRepo;

@Autowired
TemplateUtils tempUtils;

@Primary
@Bean   
public FreeMarkerConfigurationFactoryBean getFreeMarkerConfiguration() {
    // Create new configuration bean
    FreeMarkerConfigurationFactoryBean bean = new FreeMarkerConfigurationFactoryBean();
    // Create template loader
    StringTemplateLoader sTempLoader = new StringTemplateLoader();
    // Find all templates
    Iterable<TemplateDb> ite = tempRepo.findAll();
    ite.forEach((template) -> {
        // Put them in loader
        sTempLoader.putTemplate(template.getFilename(), template.getContent()); 
    });
    // Set loader
    bean.setPreTemplateLoaders(sTempLoader);
    return bean;
}

老问题,但对于任何有相同问题的人,我实现了一个简单的解决方案,无需自定义模板加载器或在启动时加载模板

假设数据库中有动态模板:

数据库:

你好${params.user}

您只需创建一个Freemarker文件(ftlh),该文件解释接收到的字符串(
内容
),并使用以下命令从中生成模板:

dynamic.ftlh:


然后,在java代码中,您只需要从数据库中获取字符串(就像从数据库中检索任何其他数据一样),并使用具有
exploration
的文件来生成模板:

爪哇:

String content=getFromDatabase();
Configuration cfg=getConfiguration();
字符串filePath=“dynamic.ftlh”;
Map params=新的HashMap();
参数put(“用户”、“世界”);
Map root=newhashmap();
root.put(“内容”,content);
root.put(“params”,params);
Template-Template=cfg.getTemplate(文件路径);
尝试(Writer out=new StringWriter()){
模板。进程(根,出);
字符串结果=out.toString();
系统输出打印项次(结果);
}
(将方法
getFromDatabase()
getConfiguration()
分别更改为希望从数据库获取动态内容和获取动态内容的任何方法)

应打印:

你好,世界


然后,您可以更改数据库中的动态内容或创建其他内容、添加新参数等,而无需创建其他Freemarker文件(ftlh)。

我认为您可以设置Configuration.setLocalizedLookup(布尔)以禁用本地化查找,这样您就不必捕获NumberFormatException。
<#import "1" as layout> <!-- Use a template id. -->
<@layout.mainLayout>
...
<#include "3"> <!-- Use a template id. -->
...
@Configuraton
public class FreemarkerConfig {

@Autowired
TemplateRepository tempRepo;

@Autowired
TemplateUtils tempUtils;

@Primary
@Bean   
public FreeMarkerConfigurationFactoryBean getFreeMarkerConfiguration() {
    // Create new configuration bean
    FreeMarkerConfigurationFactoryBean bean = new FreeMarkerConfigurationFactoryBean();
    // Create template loader
    StringTemplateLoader sTempLoader = new StringTemplateLoader();
    // Find all templates
    Iterable<TemplateDb> ite = tempRepo.findAll();
    ite.forEach((template) -> {
        // Put them in loader
        sTempLoader.putTemplate(template.getFilename(), template.getContent()); 
    });
    // Set loader
    bean.setPreTemplateLoaders(sTempLoader);
    return bean;
}
@Autowired
private Configuration freemarkerConfig;

  Template template = freemarkerConfig.getTemplate(templateFilePath);
  String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, mapTemplate);