- 了解模版引擎原理
- 掌握Freemarker常用语法
- Freemarker项目实战
什么是模版引擎: 数据 + 模版 = 结果, 模版引擎将数据与展现有效“解耦”.
在上图中,之前讲述的JSP其实就一个模版引擎,目前主流模版引擎: JSP 、 Freemarker、Beetl.
Freemarker 脚本为:FTL(Freemarker Template Language),Freemarker 提供了大量内建函数来简化开发.
JSP 与 Freemarker 区别
JSP | Freemarker | |
---|---|---|
官方标准 | 是 | 否 |
执行方式 | 编译型 | 解释型 |
执行效率 | 高 | 低 |
开发效率 | 低 | 高 |
扩展能力 | 弱 | 强 |
数据提取 | JSTL + EL | 内置标签 |
Freemarker 快速上手
官方文档 首先我们要在官网上下载或通过maven来安装freemarker
新建一个Java项目,然后将下载的freemarker.jar包导入
Freemarker的使用主要有三步: 1 加载模版、2 创建数据、3 产生输出
public class FreemarkerS1 {
public static void main(String[] args) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
//1 加载模版
//创建核心配置对象
Configuration configuration = new Configuration(Configuration.VERSION_2_3_29);
//设置加载的目录 在这个类所在的包中,加载ftl,第二个参数空字符串相当于当前的包 在当前类的包中查找ftl文件
configuration.setClassForTemplateLoading(FreemarkerS1.class, "");
//得到模版对象
Template template = configuration.getTemplate("smaple.ftl");
//2 创建数据
Map<String,Object> data = new HashMap<String,Object>();
data.put("site", "百度");
data.put("url", "http://www.baidu.com");
//3 产生输出
template.process(data, new OutputStreamWriter(System.out));
}
}
新建FTL文件,可以选择安装插件
${site}
${url}
运行FreemarkerS1 类,得到的结果:
百度
http://www.baidu.com.
可见FTL文件提供模版,FreemarkerS1提供数据,然后通过加载模版 创建数据 就可以在模版中产生输出.
FTL 取值
- ${属性名} 取值,可对属性进行计算
- ${属性名!默认值} 使用默认值
- ${属性名?string(“….”)} 格式化输出
如下代码:获取属性、格式化输出、默认值、对象的属性输出、以及map的输出等
<#-- freemarker取值 -->
${site}
${url}
<#-- freemarker默认值 -->
${author!"不存在的属性默认值:JakePrim"}
<#-- freemarker格式化 -->
${date?string("yyyy-MM-dd HH:mm:ss:SSS")}
${number}
${number?string("0.00")}
<#-- freemarker获取对象及属性 -->
${computer.sn}
${computer.model}
${computer.state}
${computer.user}
${computer.dop?string("yyyy-MM-dd")}
${computer.price?string("0.00")}
<#-- freemarker map的获取 -->
${computer.info["name"]}
分支判断
if 和 switch 语句分支判断,和Java语法没有区别
如下为if的使用:
<#-- 字符串是否相等的判断 直接使用 == -->
<#if computer.sn == "1111111">
重要设备:${computer.sn}
</#if>
${computer.sn}
${computer.model}
<#if computer.state == 1>
状态:正在使用
<#elseif computer.state == 2>
状态:闲置
<#elseif computer.state == 3>
状态:已作废
<#else>
状态:未知
</#if>
${computer.state}
<#-- ?? 代表判断对象是否为空,true不为空,false为空 -->
<#if computer.user??>
用户:${computer.user}
</#if>
如下为switch的使用:
<#switch computer.state>
<#case 1>
状态:正在使用
<#break>
<#case 2>
状态:闲置
<#break>
<#case 3>
状态:已作废
<#break>
<#default>
状态:未知
<#break>
</#switch>
list迭代列表
List<String> list = new ArrayList<String>();
list.add("this1");
list.add("this2");
list.add("this3");
data.put("list", list);
<#list list as c>
序号:${c_index} <#-- 迭代变量_index 保存了循环索引 -->
List:${c}
</#list>
输出:
序号:0
List:this1
序号:1
List:this2
序号:2
List:this3
list迭代Map
Map<String,Object> map = new HashMap<String, Object>();
int i = 0;
for (String string : list) {
i++;
map.put("c_"+i, string);
}
data.put("map", map);
<#list map?keys as k>
${k}-${map[k]}
</#list>
输出:
c_1-this1
c_3-this3
c_2-this2
Freemarker内建函数
内建函数是Freemarker 提供的内部函数. 接下来通过代码来看一下:
public class FreemarkerS2 {
public static void main(String[] args) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
//1 加载模版
//创建核心配置对象
Configuration configuration = new Configuration(Configuration.VERSION_2_3_29);
//设置加载的目录 在这个类所在的包中,加载ftl,第二个参数空字符串相当于当前的包 在当前类的包中查找ftl文件
configuration.setClassForTemplateLoading(FreemarkerS2.class, "");
//得到模版对象
Template template = configuration.getTemplate("smaple2.ftl");
//2 创建数据
Map<String,Object> data = new HashMap<String,Object>();
data.put("name", "jakePrim");
data.put("brand", "bmw");
data.put("words", "first blood");
data.put("n", 878382.1281921);
data.put("date", new Date());
Map<String, Object> infoMap = new HashMap<String, Object>();
infoMap.put("name", "jisdjsd");
data.put("computer", new Computer("1001", "ThinkPad", 3, "JakePrim", new Date(), 5000.1f,infoMap));
List<String> list = new ArrayList<String>();
list.add("this1");
list.add("this2");
list.add("this3");
data.put("list", list);
//3 产生输出
template.process(data, new OutputStreamWriter(System.out));
}
}
${name?cap_first} <#-- 首字母大写 -->
${brand?upper_case} <#-- 全部大写 -->
${brand?length} <#-- 输出字符的长度 -->
${words?replace("blood","******")} <#-- 字符替换 -->
${words?index_of("blood")} <#-- 查找字符 -->
${(words?index_of("blood") != -1)?string("包含敏感词汇","不包含敏感词汇") } <#-- 借助?string可以使用三目运算符操作 -->
${n?round}
${n?floor}
${n?ceiling}
list 共有:${list?size}个
第一个:${list?first}
最后一个:${list?last}
其他的内建函数可以参考中文文档:中文文档
Freemarker 与 Servlet 整合
在上述中,我们通过在Java类中加载模版设置数据,那么Freemarker如何与Servlet整合呢? 这里Freemarker做了处理,可以非常简单和servlet进行整合.
- 首先将freemarker.jar包,放到WEB-INF/lib中
- 在web.xml进行配置
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<!-- 模版文件配置,所有的ftl都要在ftl目录下 -->
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/WEB-INF/ftl</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern> <!-- 请求后缀为.ftl的文件,都会响应FreemarkerServlet -->
</servlet-mapping>
- servlet中配置数据,数据需要添加到request 或 session 或 servletContext的属性中,注意freemarker通过上述的配置会按顺序访问 request - session - servletContext 中设置的属性.
@WebServlet("/list")
public class ListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ListServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee(7731, "张三", "市场部", "客户代表", 8000f));
employees.add(new Employee(7731, "李四", "技术部", "Java工程师", 18000f));
request.setAttribute("employees", employees);//freemarker 会通过 查找request session servletContext
request.getRequestDispatcher("/employee.ftl").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
- 编写ftl文件,可直接访问employees 进行数据设置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>员工列表</title>
<link href="css/bootstrap.css" type="text/css" rel="stylesheet"></link>
<script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<style type="text/css">
.pagination {
margin: 0px
}
.pagination > li > a, .pagination > li > span {
margin: 0 5px;
border: 1px solid #dddddd;
}
.glyphicon {
margin-right: 3px;
}
.form-control[readonly] {
cursor: pointer;
background-color: white;
}
#dlgPhoto .modal-body{
text-align: center;
}
.preview{
max-width: 500px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<h1 style="text-align: center">IMOOC员工信息表</h1>
<div class="panel panel-default">
<div class="clearfix panel-heading ">
<div class="input-group" style="width: 500px;">
</div>
</div>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>序号</th>
<th>员工编号</th>
<th>姓名</th>
<th>部门</th>
<th>职务</th>
<th>工资</th>
<th> </th>
</tr>
</thead>
<tbody>
<#list employees as em>
<tr>
<td>${em_index + 1}</td>
<td>${em.empno?string("0")}</td>
<td>${em.ename}</td>
<td>${em.department}</td>
<td>${em.job}</td>
<td style="color: red;font-weight: bold">¥${em.salary?string("0.00")}</td>
</tr>
</#list>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>