freemarker入门part2

freemarker part2

前一篇简单的介绍了FreeMarker的用法和特性,这一篇介绍一些开发相关的核心组件

快速开始

创建Configuration实例

Configuration是FreeMarker对应应用基本配置的封装,同时它也处理模板的创建和缓存等

// cfg最好是单例,因为cfg创建成本高
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
// 路径
cfg.setDirectoryForTemplateLoading(new File("/ftl"));
// 编码
cfg.setDefaultEncoding("UTF-8");
// 异常处理
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
创建data-model

数据模型即模板渲染所需的数据

// 数据
Map<String,Object> dataModel = Maps.newHashMap();
dataModel.put("user", "FreeMarker");
dataModel.put("product", Product.builder()
        .name("testName")
        .url("http://test/url")
        .build());
获取Template&渲染数据

Template即FreeMarker对模板的封装,通过process方法将渲染后的文件放到由文件流处理

// 获取模板
cfg.getTemplate("test.ftl");

// 渲染
try (Writer writer = new OutputStreamWriter(System.out)){
    template.process(dataModel, writer);
}

数据模型

基础TemplateModel

所有Java的变量都会转为TemplateModel。可以理解为FreeMarker会将传进来的数据类型都包装一次,便于统一处理。

标准Scalars

Template{type}Model

Boolean: TemplateBooleanModel
Number: TemplateNumberModel (默认实现为SimpleNumber)
String: TemplateScalarModel(因为历史原因String对应的不叫TemplateStringModel,而是TemplateScalarModel,且默认实现为SimpleScalar)
Date-like: TemplateDateModel(比较麻烦因为Java用不用类来表示日期、时间和日期时间)
容器Containers

hashes、sequences和collections

hashes: TemplateHashModel、TemplateHashModelEx(默认实现SimpleHash)
sequences: TemplateSequenceModel(默认实现SimpleSequence)
collections: TemplateCollectionModel(默认实现SimpleCollection)

方法

同理数据模型的方法FreeMarker也会封装一层TemplateMethodModel、TemplateMethodModelEx

自定义方法实现

public class IndexOfMethod implements TemplateMethodModel {

    public TemplateModel exec(List args) throws TemplateModelException {
        if (args.size() != 2) {
            throw new TemplateModelException("Wrong arguments");
        }
        return new SimpleNumber(
            ((String) args.get(1)).indexOf((String) args.get(0)));
    }
}

模型设置

root.put("indexOf", new IndexOfMethod());

使用

<#assign x = "something">
${indexOf("met", x)}
${indexOf("foo", x)}

指令

所有指令由TemplateDirectiveModel封装,用户自定义指令也需要实现TemplateDirectiveModel接口

例子(大写命令范围所有字符)

UpperDirective

public class UpperDirective implements TemplateDirectiveModel {
    @Override
    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
            throws TemplateException, IOException {
        if (!params.isEmpty()){
            throw new TemplateModelException("This directive doesn't allow parameters.");
        }
        
        if (loopVars.length != 0){
            throw new TemplateModelException("This directive doesn't allow loop variables.");
        }
        
        if (body == null){
            throw new RuntimeException("missing body");
        }
    
        body.render(new UpperCaseFilterWriter(env.getOut()));
    }
    
    private static class UpperCaseFilterWriter extends Writer {
        
        private final Writer out;
        
        public UpperCaseFilterWriter(Writer out){
            this.out = out;
        }
    
        @Override
        public void write(char[] cbuf, int off, int len) throws IOException {
            // 将所有字符转为大写
            char[] transformChars = new char[len];
            for (int i=0; i<len; i++){
                transformChars[i] = Character.toUpperCase(cbuf[i + off]);
            }
            out.write(transformChars);
        }
    
        @Override
        public void flush() throws IOException {
            out.flush();
        }
    
        @Override
        public void close() throws IOException {
            out.close();
        }
    }
}

加入DataModel或加入cfg

// 仅此dataModel可用
dataModel.put("upper", new UpperDirective());

// 全局都可用
cfg.setSharedVariable("up", new UpperDirective())

ftl使用

<@upper>
    Kkkkk
    ${user}
    Wwwww
</@upper>

节点

节点就是类似树的数据类型。FreeMarker用TemplateNodeModel统一封装。处理XML结构需要用TemplateNodeModel.

常用方法

String getNodeName():节点名称
String getNodeType():节点类型
String getNamespaceURI():资源路径

配置

基础配置

Configuration一般是应用级别的(单例),一个Configuration绑定多个Template。特殊场景也会存在多个Configuration。

共享变量

所有绑定同一Configuration的Template共享的变量。

// 共享变量
cfg.setSharedVariable("up", new UpperDirective());

内置的共享变量

capture_output: freemarker.template.utility.CaptureOutput
compress: freemarker.template.utility.StandardCompress
html_escape: freemarker.template.utility.HtmlEscape
normalize_newlines: freemarker.template.utility.NormalizeNewlines
xml_escape: freemarker.template.utility.XmlEscape
Settings

比如:locale、number_format、default_encoding等,完整的可参考https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#setSetting-java.lang.String-java.lang.String-

cfg.setSetting(...);
模板相关
模板加载

通过文件、数据库或者内存等进行加载至Template

内置加载方法
void setDirectoryForTemplateLoading(File dir): 文件流
void setClassForTemplateLoading(Class cl, String basePackagePath): 类加载
void setServletContextForTemplateLoading(Object servletContext, String path):web资源

也可以自定义TemplateLoader,然后设置到cfg即可

组合加载

可以从多个地方加载模板

FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates"));
FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates"));
ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), "/com/example/templates");

MultiTemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[] { ftl1, ftl2, ctl });
cfg.setTemplateLoader(mtl);
其他加载

如URLTemplateLoader加载等

模板缓存

通过cfg.getTemplate是获取缓存的模板,如果你改变了模板,会在下次获取时生效(默认5s)。
注意有些加载器(基于classloader的)不支持刷新。我们也可以实现TemplateLoader来自定义。

错误处理

FreeMarker在处理模板时可能会发生异常,默认有以下几种处理器。

TemplateExceptionHandler.DEBUG_HANDLER: 打日志然后抛异常
TemplateExceptionHandler.HTML_DEBUG_HANDLER: 同上,不过日志格式为HTML
TemplateExceptionHandler.IGNORE_HANDLER: 忽略异常,不会抛
TemplateExceptionHandler.RETHROW_HANDLER: 重新抛异常

可以实现TemplateExceptionHandler实现自定义错误处理

-- 自定义错误处理器
class MyTemplateExceptionHandler implements TemplateExceptionHandler {
    public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out)
            throws TemplateException {
        try {
            out.write("[ERROR: " + te.getMessage() + "]");
        } catch (IOException e) {
            throw new TemplateException("Failed to print error message. Cause: " + e, env);
        }
    }
}

-- 配置错误处理器
cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());
模板配置
TemplateConfiguration tcUTF8XML = new TemplateConfiguration();
tc.setEncoding("utf-8");
tc.setOutputFormat(XMLOutputFormat.INSTANCE);

cfg.setTemplateConfigurations(
        new ConditionalTemplateConfigurationFactory(
                new FileExtensionMatcher("xml"),
                tcUTF8XML));

其他

整合Servlet

见https://freemarker.apache.org/docs/pgui_misc_servlet.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值