添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在Web开发中,我们经常需要动态生成网页(HTML文件)以便在响应中包含与请求有关的信息(如用户名、 搜索结果)。这时我们有两种方法:

  • 硬编码代码生成的规则。例如: "亲爱的"+user.getName()+"上午好" 。这种方法对于生成简单的文本时可能比较方便,但当规模变大后就容易失控,而且用于生成HTML或SQL代码时往往成为注入攻击的温床。
  • 套用模板。例如: java.text.MessageFormat.format("亲爱的{0}上午好",user.getName()) 。这里 "亲爱的{0}上午好" 就是一个模板,而 user.getName() 则是模型,这种方法体现了MVC(模型-视图-控制器)模式的原则,有利于分离关注点并容许专门人员分别负责展现什么和怎么展示,提高了可维护性。当然 java.text.MessageFormat 的模板语言表达力对于许多用途而言太弱,但freemarker之类的模板引擎克服了这个局限性。JVM平台上其它通用模板引擎包括:
  • Apache Velocity
  • Thymeleaf
  • StringTemplate
  • 然后我们编写一个简单的模板 src/main/resources/com/github/chungkwong/template/example.ftl

    亲爱的${name}上午好
    

    接着我们演示如何在java程序src/main/java/com/github/chungkwong/template/Main.java中使用上述模板:

    package com.github.chungkwong.template;
    import freemarker.template.*;
    import java.io.*;
    import java.util.*;
    public class Main{
    	public static void main(String[] args) throws IOException,TemplateException{
    		//创建配置类,配置类应尽可能重用,不必再创建以提高性能
    		Configuration configuration=new Configuration(Configuration.getVersion());
    		//设置模板所在目录,另外可改为
    		// setDirectoryForTemplateLoading(File)
    		// setClassLoaderForTemplateLoading(ClassLoader, String)
    		configuration.setClassForTemplateLoading(Main.class,"");
    		//取得模板  
    		Template template=configuration.getTemplate("example.ftl");
    		//准备模型
    		Map<String,Object> model=new HashMap<>();
    		model.put("name","陈大文");
    		//套用模板并把结果输出到一个流
    		template.process(model,new OutputStreamWriter(System.out));
    

    运行上述程序应该得到输出亲爱的陈大文上午好

    模型在内部表示为TemplateModel子类型的对象。幸运的是,freemarker.template.DefaultObjectWrapperTemplateModel handleUnknownType(final Object obj) throws TemplateModelException方法通常能把Java模型对象自动转换为内部对象,我们很少要清晰区分内部对象。不过如果有兴趣也可以通过TemplateModel的子接口了解其类型系统:

  • AdapterTemplateModel包装动态类型语言的对象
  • TemplateBooleanModel对应于布尔值
  • TemplateCollectionModel对应于集合,它的子接口TemplateCollectionModelEx支持查询元素数
  • TemplateDateModel对应于日期和/或时间
  • TemplateDirectiveModel对应于模板可使用的指令,在需要自定义指令时可覆盖方法void execute(Environment env,Map params, TemplateModel[] loopVars,TemplateDirectiveBody body) throws TemplateException, IOException
  • TemplateHashModel对应于哈希表,它的子接口TemplateHashModelExTemplateHashModelEx2提供迭代键值对的方法
  • TemplateMarkupOutputModel对于于不应再转义就能输出的代码
  • TemplateMethodModel对应于模板可调用的方法,它的子接口TemplateMethodModelEx要求实参以TemplateModel而非String传入方法由TemplateModel exec(List args) throws TemplateModelException给出的自定义方法
  • TemplateModelWithAPISupport
  • TemplateNodeModel对应于XML文档中的结点,它的子接口TemplateNodeModelEx支持查找相邻兄弟结点
  • TemplateNumberModel对应于数值
  • TemplateScalarModel对应于字符串
  • TemplateSequenceModel对应于序列
  • WrapperTemplateModel包装其它Java对象
  • 模板中形如<#-- 注释内容 -->的是注释(注释内容中不能含-->),会被忽略。注意注释也可以出现在表达式或指令中。

    模板中其余部分由以下构造连接而成:

    输出变量的值,其中变量名只可以包含字母(也可以是非拉丁文)、 数字(也可以是非拉丁数字)、 下划线 、 美元符号、 at符号,且首个字符不能为ASCII数字,变量名不能是保留字:truefalsegtgteltlteasinusing <#指令名 参数> </#指令名> 结束指令(不是所有指令都需要结束) <#ftl 参数1=值1 参数2=值2 ... 参数N=值N> 设置参数为常量表达式,其中encoding值为字符串、 strip_whitespace值为布尔值、 strip_text值为布尔值、 strict_syntax值为布尔值、 ns_prefixes值为把命名空间前缀到位置的哈希表、 attributes值为模板属性的哈希表 <#function 名字 参数1 参数2 ... 参数N>其它<#return 返回表达式>其它</#function> 声明一个值为方法的变量 <#function 名字 参数1 参数2 ... 参数N...>其它<#return 返回表达式>其它</#function> 声明一个值为方法的变量,方法最后一个参数接收余下实参组成的序列 <#global 变量名1=值1 变量名2=值2 ... 变量名N=值N> 定义全局变量 <#global 变量名>块</#global> 定义全局变量 <#if 条件表达式>块<#elseif 条件表达式>块...<#else>块</#if> 分支,elseifelse可选 <#import 路径 as 名字空间> 把指定路径的库引入到指定名字空间 <#include 路径 选项...> 把指定路径的文件插入到当前位置,其中选项可以为encoding=字符串表达式parse=布尔值表达式ignore_missing=布尔值表达式 <#list 序列 as 项>循环体<sep>分隔<#else>序列空时用的块</#list> 迭代列表,sepelse可选,其中可用<#break>跳出迭代 <#list 序列>序列非空时用的块<#items as 项目>循环体<sep>分隔</#items>序列非空时用的块<#else>序列空时用的块</#list> 迭代列表,sepelse可选,其中可用<#break>跳出迭代 <#local 变量名1=值1 变量名2=值2 ... 变量名N=值N> 定义局部变量 <#local 变量名>块</#global> 定义局部变量 <#macro 名 参数1 参数2 ... 参数N>块<#nested loopvar1, loopvar2, ..., loopvarN>块<#return>块</#macro> <#noparse>块</#noparse> 忽略块中指令 禁止本行消除空白 <#setting 属性名=值表达式> <#stop> 中止处理模板 <#stop 字符串表达式> 中止处理模板 <#switch 表达式><#case 值1>块<#break>...<#case 值N>块<#break><#default>块</#switch> 按表达式的值分支,其中breakdefault可选 忽略本行首尾所有空白 忽略本行首所有空白 忽略本行尾所有空白 <#visit 结点 using 名字空间> 访问结点,即以它为参数调用同名的指令 <#visit 结点> 访问结点,即以它为参数调用同名的指令 <#recurse 结点 using 名字空间> 访问所有子结点 <#recurse 结点> 访问所有子结点 <#recurse using 名字空间> 访问当前结点的所有子结点 <#recurse> 访问当前结点的所有子结点 <#fallback> 在更多名字空间找结点处理器 <@指令 参数1=值1 参数2=值2 ... 参数N=值N/> 用户定义指令 date_formattime_formatdatetime_format 日期时间格式,可以是SimpleDateFormat中格式,或者shortmediumlongfullxs(XML Schema 格式)、 iso(ISO 8601:2004 格式) time_zone 时区名(同Java) sql_date_and_time_time_zone 为仅日期或仅时间值加上的时区 url_escaping_charset 用于URL转义的字符集 output_encoding 输出编码名 classic_compatible 是否兼容经典模式
  • start..end表示一个范围(包含startend
  • start..<endstart..!end表示一个范围(包含start但不包含end
  • start..*length表示从start开始长度为length绝对值的范围
  • start..表示从start开始的无穷序列
  • 关系表达式
  • 小于检测:表达式<表达式表达式 lt 表达式
  • 小于等于检测:表达式<=表达式表达式 lte 表达式
  • 大于检测:表达式>表达式表达式 gt 表达式
  • 大于等于检测:表达式>=表达式表达式 gte 表达式
  • 相等性表达式
  • 相等检测:表达式==表达式表达式=表达式
  • 不等检测:表达式!=表达式
  • 逻辑与:表达式&&表达式
  • 逻辑与:表达式||表达式
  • is_类型 是否指定类型,其中类型可为stringnumberbooleandatedate_likedate_onlytimedatetimeunknown_date_likemethodtransformmacrohashhash_exsequencecollectioncollection_exenumerableindexabledirectivenode 可选的时区 把日期和或时间转换为字符串 iso_选项 可选的时区 把日期和或时间转换为字符串,其中选项由可选的时区isolocal;精度hmms组成;忽略时区nz,用_分隔 j_string 按Java字符串格式转义字符串 分隔字符串 把序列串接为字符串 js_string 按JavaScript字符串格式转义字符串 json_string 按JSON字符串格式转义字符串 keep_after 子串,可选的标志 仅保留子串首个匹配后的字符串 keep_after_last 子串,可选的标志 仅保留子串最后一个匹配后的字符串 keep_before 子串,可选的标志 仅保留子串首个匹配前的字符串 keep_before_last 子串,可选的标志 仅保留子串最后一个匹配后的字符串 最后一个元素 last_index_of 最后出现位置或-1 last_index_of 子串,起点 最后出现位置或-1 left_pad 用空格在开始处填充字符串到指定长度 left_pad 长度,填充字符 在开始填充字符串到指定长度 length 字符串长度 用long作内部表示 lower_abc 把数字转换为电子表格式的小写列号 lower_case matches 正则表达式,可选的标志 匹配正则表达式 namespace 宏或函数对应的名字空间 构造器参数 创建指定类对象 node_namespace 结点名字空间 node_name node_type 结点类型:"attribute""text""comment""document_fragment""document""document_type""element""entity""entity_reference""notation""pi" number 字符串转换为数字 number_to_date 数字转换为日期 number_to_datetime 数字转换为日期时间 number_to_time 数字转换为时间 parent replace 子串,替换,可选的标志 替换全部指定子串 remove_beginning 移除指定前缀 remove_ending 移除指定后缀 reverse 反序的序列 right_pad 用空格在结束处填充字符串到指定长度 right_pad 长度,填充字符 在结束处填充字符串到指定长度 round RTF转义 short 用short作内部表示 序列元素数 升序排序序列 seq_contains seq_index_of 首次出现的下标或-1 seq_last_index_of 最后出现的下标或-1 sort_by 用于排序的键序列 升序排序哈希表序列 split 分隔,可选的标志 分割字符串 starts_with string 可选的格式 把字符串、 数值、 布尔值、 日期、 日期时间、 时间转换为字符串 string.computer 把数值转换为字符串 string.currency 把数值转换为字符串 string.number 把数值转换为字符串 string.percent 把数值转换为字符串 string.short 把日期时间转换为字符串 string.medium 把日期时间转换为字符串 string.long 把日期时间转换为字符串 string.full 把日期时间转换为字符串 string.xs 把日期时间转换为字符串 string.iso 把日期时间转换为字符串 switch 值1,结果1,…,默认值 按值选结果 真时的值,假时的值 按真值选择 可选的格式 字符串/日期/日期时间/时间转换为时间 time_if_unknown 不确定时定为时间 去除首尾空白 uncap_first 首字母小写 upper_abc 把数字转换为电子表格式的大写列号 upper_case URL转义 URL转义 url_path URL转义(保留/url_path URL转义(保留/values word_list 字符串分割为单词 xhtml XHTML转义 XML转义 void setAttemptExceptionReporter(AttemptExceptionReporter attemptExceptionReporter) 设置#attempt块异常处理器 void setAutoEscapingPolicy(int autoEscapingPolicy) 设置是否按输出格式自动转义 void setCacheStorage(CacheStorage cacheStorage) 设置缓存空间 void setClassForTemplateLoading(java.lang.Class resourceLoaderClass, java.lang.String basePackagePath) 设置模板所在的包 void setClassLoaderForTemplateLoading(java.lang.ClassLoader classLoader, java.lang.String basePackagePath) 设置模板所在的包 void setDefaultEncoding(java.lang.String encoding) 设置默认字符编码 void setDirectoryForTemplateLoading(java.io.File dir) 设置模板所在的目录 void setEncoding(java.util.Locale locale, java.lang.String encoding) 设置用于指定区域的字符编码 void setIncompatibleImprovements(Version incompatibleImprovements) 设置freemarker语法版本 void setInterpolationSyntax(int interpolationSyntax) 设置变量语法(${x}还是[=x]void setLocale(java.util.Locale locale) void setLocalizedLookup(boolean localizedLookup) 设置是否启用本地化模板查找 void setLogTemplateExceptions(boolean value) 设置是否把模板处理中异常记录到日志 void setNamingConvention(int namingConvention) 设置标识符命名规则 void setObjectWrapper(ObjectWrapper objectWrapper) 设置Java对象到freemarker对象的转换器 void setOutputFormat(OutputFormat outputFormat) 设置默认输出格式 void setRecognizeStandardFileExtensions(boolean recognizeStandardFileExtensions) 设置是否用文件扩展名猜测输出格式 void setRegisteredCustomOutputFormats(java.util.Collection<? extends OutputFormat> registeredCustomOutputFormats) 设置输出格式名(参考OutputFormat.getName())集合 void setServletContextForTemplateLoading(java.lang.Object servletContext, java.lang.String path) 设置模板所在位置 void setSetting(java.lang.String name, java.lang.String value) void setSharedVariable(java.lang.String name, java.lang.Object value) 设置共享变量 void setSharedVariable(java.lang.String name, TemplateModel tm) 设置一个共享变量 void setSharedVaribles(java.util.Map map) 设置全部共享变量 void setTabSize(int tabSize) 设置制表符大小(占用列数) void setTagSyntax(int tagSyntax) 设置默认指令格式(<#if x>还是[#if x]void setTemplateConfigurations(TemplateConfigurationFactory templateConfigurations) 设置模板特定的配置选项 void setTemplateExceptionHandler(TemplateExceptionHandler templateExceptionHandler) 设置模板异常处理器 void setTemplateLoader(TemplateLoader templateLoader) 设置模板加载器 void setTemplateLookupStrategy(TemplateLookupStrategy templateLookupStrategy) 设置按名寻找模板的策略 void setTemplateNameFormat(TemplateNameFormat templateNameFormat) 设置模板名格式 void setTemplateUpdateDelayMilliseconds(long millis) 设置检查模板更新的最短时间间隔 void setTimeZone(java.util.TimeZone timeZone) void setWhitespaceStripping(boolean b) 设置是否去除FTL指令两侧的空白 void setWrapUncheckedExceptions(boolean value) 是否把表达式求值或执行指令时的非检查型异常包装为TemplateException