1. 循环变量内建函数counter、has_next、index、is_even_item、is_first、is_last、is_odd_item、item_cycle、item_parity和item_parity_cap只能用于list和items指令的循环变量。
2. index
2.1. 返回当前迭代(由循环变量名称识别)从0开始的索引。
<#list ['a', 'b', 'c', 'd'] as word>
${word?index}: ${word}<br />
</#list>
3. counter
3.1. 返回当前迭代(由循环变量名称识别)从1开始的索引。
3.2. 当list指令不指定循环变量时, 这些内建函数就作用于items指令的循环变量。
<#list ['a', 'b', 'c', 'd']>
<#items as word>
${word?counter}: ${word}<br />
</#items>
</#list>
4. has_next
4.1. 辨别循环项是否是当前迭代(由循环变量名称识别)的最后一项。
5. is_even_item
5.1. 辨别循环项是否是当前迭代(由循环变量名称识别)间隔1的奇数项。
6. is_first
6.1. 辨别循环项是否是当前迭代(由循环变量名称识别)的第一项。
7. is_last
7.1. 辨别循环项是否是当前迭代(由循环变量名称识别)的最后一项。
8. is_odd_item
8.1. 辨别循环项是否是当前迭代(由循环变量名称识别)间隔1的偶数项。
9. item_parity
9.1. 基于当前迭代(由循环变量名称识别)间隔为1的索引的奇偶性, 返回字符串值"odd"或"even"。这通常用于表格中行间的颜色变换。
10. item_parity_cap
10.1. 基于当前迭代(由循环变量名称识别)间隔为1的索引的奇偶性, 返回字符串值"Odd"或"Even"(请注意大写)。
11. item_cycle
11.1. 这是item_parity内建函数更为通用的版本, 这里可以指定何值来代替"odd"和"even"。它也允许多余两个值来循环。
12. switch独立类型内建函数
12.1. 它的通用版本就像matchedValue?switch(case1, result1, case2, result2, ... caseN, resultN, defaultResult), 这里的defaultResult可以被忽略。
12.2. switch会找到第一个case和参数(从左到右)值matchedValue相等, 之后返回直接在case参数后的result参数的值, 如果它没有找到一个相等的case, 那么就返回defaultResult的值, 如果没有defaultResult参数(换言之, 参数的个数是基数), 那么就发生错误中止模板处理。
12.3. matchedValue和case参数值的比较, 就像==操作符。那就只比较标量并且是相同类型的值。
12.4. 对case参数值的类型没有任何限制, 它们可以是字符串, 或数字, 布尔, 或日期等。但因为==操作符的特性, 那么在相同的switch中使用不同类型的case参数是没有意义的。
12.5. case参数表达式不需要是常量值, 它们可以是任意复杂的表达式。当然result, defaultResult和matchedValue也是相同的。
12.6. 不像普通的方法调用, switch(...)的那些参数被评估为确实需要的。比如: 在two()?switch(c1(), r1(), c2(), r2(), c3(), r3())中, 如果two()返回2, c1()返回1, 且c2()返回2, 那么只有下面的函数会被调用, 而且顺序是这样c1(), c2(), r2()。它保证了case参数表达式被从左到右进行评估, 直到第一个匹配项被找到。它也保证了只有属于第一个匹配case的result表达式会被评估。它还保证了如果没有匹配的case参数, 那么defaultResult表达式会被评估。
13. 例子
13.1. 新建一个名为FMBuiltInsForLoop的动态Web工程, 同时添加相关jar包。
13.2. 编写FMFactory.java
package com.fm.util;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;
public class FMFactory {
private final static FMFactory instance = new FMFactory();
private FMFactory() {}
public static FMFactory getInstance() {
return instance;
}
private Map<String, Configuration> map = new ConcurrentHashMap<String, Configuration>();
// 创建单个Configuration实例
public synchronized Configuration getCfg(Object servletContext, String path) {
if(null != map.get(path)) {
return map.get(path);
}
Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
cfg.setServletContextForTemplateLoading(servletContext, path);
cfg.setDefaultEncoding("utf-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
map.put(path, cfg);
return cfg;
}
}
13.3. 编写BuiltInsForLoop.java
package com.fm.action;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fm.util.FMFactory;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class BuiltInsForLoop extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Configuration cfg = FMFactory.getInstance().getCfg(req.getServletContext(), "/WEB-INF/templates");
Template template = cfg.getTemplate("builtinsforloop.html");
Map<String, Object> root = new HashMap<String, Object>();
Writer out = new OutputStreamWriter(resp.getOutputStream());
try {
template.process(root, out);
} catch (TemplateException e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
13.4. 修改web.xml
13.5. 在/WEB-INF/templates下编写builtinsforloop.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>循环变量内建函数</title>
<style type="text/css">
b {
font-size: 32px;
}
.odd {
color: #009688;
}
.even {
color: #FFB800;
}
.Odd {
color: #5FB878;
}
.Even {
color: #FF5722;
}
.first {
color: #393D49;
}
.second {
color: #01AAED;
}
.third {
color: #FFB800;
}
.fourth {
color: #FF5722;
}
</style>
</head>
<body>
<h2>index</h2>
<#list ['a', 'b', 'c', 'd'] as word>
${word?index}: ${word}<br />
</#list>
<h2>counter</h2>
<#list ['a', 'b', 'c', 'd']>
<#items as word>
${word?counter}: ${word}<br />
</#items>
</#list>
<h2>has_next</h2>
<#list ['a', 'b', 'c', 'd'] as word>
${word}
<#if word?has_next>
,
<#else>
.
</#if>
</#list>
<h2>is_even_item</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<#if word?is_even_item>${word?index}: ${word}<br /></#if>
</#list>
<h2>is_first</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<#if word?is_first>${word}</#if>
</#list>
<h2>is_last</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<#if word?is_last>${word}</#if>
</#list>
<h2>is_odd_item</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<#if word?is_odd_item>${word?index}: ${word}<br /></#if>
</#list>
<h2>item_parity</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<b class="${word?item_parity}">${word}</b>
</#list>
<h2>item_parity_cap</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<b class="${word?item_parity_cap}">${word}</b>
</#list>
<h2>item_cycle</h2>
<#list ['a', 'b', 'c', 'd'] as word>
<b class="${word?item_cycle('first', 'second', 'third', 'fourth')}">${word}</b>
</#list>
<h2>switch</h2>
<#list ['r', 'w', 'x', 's'] as flag>
${flag?switch('r', 'readable', 'w' 'writable', 'x', 'executable', 'unknown flag: ' + flag)}<br />
</#list>
</body>
</html>
13.6. 运行项目