什么是 FreeMarker?
FreeMarker 是一款模板引擎:一种基于模板的、用来生成输出文本(任何来自于 HTML格式的文本用来
自动生成源代码)的通用工具。它是为 Java 程序员提供的一个开发包或者说是类库。它不是面向最终用户,
而是为程序员提供的可以嵌入他们开发产品的一款应用程序。
搭建SpringMVC+FreeMarker环境
springmvc.xml 此处只贴出了配置FreeMarker的代码,hibernate配置等省略。
<!--对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<property name="prefix" value="/" />
<property name="suffix" value=".html" />
<property name="contentType" value="text/html;charset=utf-8" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
<!-- 定义freemarker参数文件并载入 -->
<bean id="freemarkerConfiguration"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:freemarker.properties" />
</bean>
<!-- 定义freemarker配置,包括模板根路径、参数 -->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 注意: templateLoaderPath必须设置,否则freemarker找不到模板位置 -->
<property name="templateLoaderPath" value="/WEB-INF" />
<property name="freemarkerSettings" ref="freemarkerConfiguration" />
</bean>
web.xml就照标准的springmvc配置就行了
当然别忘了配置freemaker.properties
freemaker.properties
template_update_delay=0
defaultEncoding=UTF-8
url_escaping_charset=UTF-8
locale=zh_CN
boolean_format=true,false
datetime_format=yyyy-MM-dd HH:mm:ss
date_format=yyyy-MM-dd
time_format=HH:mm:ss
number_format=0.######
whitespace_stripping=true
注释
<#-- 此处是注释 -->
注释freemaker代码,不要用html的注释,没有效果。
打印值
字符串
<#assign name="hello">
${name}
<!-- 输出hello -->
数值
<#assign number=10>
${number}
<!--输出10 -->
<#assign number2=2.5>
${number2}
<!--输出2.5 -->
<#assign avg = number/number2>
${avg}
<!--输出4 -->
boolean
<#assign flag = true>
${flag}
<!-- 输出true -->
<#assign flag2 = false>
${flag2}
<!-- 什么也没有输出 为空字符串-->
<#assign flag3 = "true">
${flag3}
<!-- 输出为true -->
<#assign flag4 = "false">
${flag4}
<#if flag3> 为真 </#if> <!-- 打印为真,freemarker将字符串"true"转换为boolean -->
运算符
<#assign x=2>
${100-2}
<!-- 减 打印98 -->
${10/2}
<!-- 除 打印5 -->
${10*2}
<!-- 乘 打印20 -->
${9%2}
<!-- 取余 打印1 -->
流程控制
<#assign x2 = 1>
<#assign x3 = 5>
<#assign x4 =6>
<#if (x2<x3) >
A
</#if>
<!-- 打印A,注意此处一定要加括号 -->
<#if (x2>x3)>
B
<#else>
C
</#if>
<!-- 打印C -->
<#if (x2>x3)>
A
<#elseif (x2>x4)>
B
<#elseif (x2<x4)>
C
</#if>
<!-- 打印C -->
<#assign x5 =5>
<#switch x5>
<#case 10>
A
<#break>
<#case 5>
B
<#break>
<#default>
C
</#switch>
<!-- 打印5 -->
遍历
List,Set
后台传入一个uerList的list或者Set
<#list userList as user>
${user.name}
</#list>
<!--打印出用户名列表-->
Map
map为后台传入的Map集合
<#list map?keys as k>
${k}
<!-- 键 -->
${map[k]}
<!-- 值 -->
</#list>
处理空值
可在freemarker.properties中加一句classic_compatible=true如果对象为空将不会报错
<#if user??>
</#if>
<!-- 判断user对象是否为空,如果不为空执行if语句中的代码-->
<!-- 在变量后面加!处理变量值为空的情况-->
${user.name!}
<!-- 判断name是否为空 如果为空将什么也不显示-->
${(user.name)!}
<!-- 判断user和name是否都为空,如果有任意一个为空什么都不显示 如果你有多个对象连环调用属性请一定要加()不然freemarker只会判断最后一个变量,否则报错-->
${(user.name)!"您还没有登录"}
<!-- 如果变量为空的情况下,将显示默认值-->
内置函数
集合
userList 为后台传入的对象集合
<#list userList?reverse as li>
${li.name}
</#list>
<!-- ?reverse 将对象集合顺序反转 -->
${(userList?first).name}
<!-- ?first 打印集合中第一个user对象的name -->
${(userList?last).name}
<!-- ?last 打印集合中最后一个user对象的name -->
${userList?size}
<!-- ?size 打印集合的长度 -->
<#list userList?sort as li>
${li.name}
</#list><br>
<!-- 将对象转换为字符串 顺序排序 -->
<#list userList?sort_by("id") as li>
${li.name}
</#list><br>
<!-- 将对象中的属性值进行排序, 当前为user中的id排序 -->
字符串
${"string"?substring(0)}
<!-- 从索引0开始截取字符串 为string -->
${"string"?substring(1)}
<!-- 从索引1开始截取字符串 为tring -->
${"string"?substring(0,1)}
<!-- 从索引0到1截取字符串 为 s -->
${"string"?substring(1,2)}
<!-- 从索引1到2截取字符串为 t -->
${"string"?cap_first}
<!-- 将字符串首字母变为大写 String-->
${"String"?uncap_first}
<!-- 将字符串首字母变为小写 string-->
${"string"?upper_case}
<!-- 将字符串全部转换为大写 -->
${"STRINg"?lower_case}
<!-- 将字符串全部转换为小写 -->
${"2014-11-11 9:0:0"?date("yyyy-MM-dd")}
<!-- 输出为2014-11-11 -->
${"string"?ends_with("ing")}
<!-- 判断字符串 是否已某段字符串结尾 打印true -->
${"string"?index_of("tr")}
<!-- 判断某段字符串在一段字符串中出现的索引位置,如果没有返回-1 打印1 -->
${"string"?contains('ing')}
<!-- 判断一个字符串中是否包含某段字符串 返回true或false -->
${"strabgab"?replace("ab","in")}
<!-- 将字符串总包含的某段字符串全部替换掉 结果为stringin-->
<#list "this,is,freemaker"?split(",") as s>
${s}
</#list>
<!-- 使用指定的符号将字符串分割为数组 -->
${" String "?trim}
<!-- 去掉首位空格 -->
<#assign num = 1>
${num?string.number}
<!-- 转换为数字格式 1 -->
${num?string.currency}
<!-- 转换为货币格式 ¥1.00 -->
${num?string. percent}
<!-- 转换为百分比格式 100% -->
<#assign flag = true>
${flag?string("yes","no")}
<!-- 根据boolean类型的真假值来输出相应的字符串 -->
freemarker宏定义
宏定义的语法为:<#macro 宏名称 参数1 参数2 参数3 。。。></#macro>
首先我们新建一个freemarker的ftl文件
此处为spring.ftl
<#macro hello>
<h1>hello,World!</h1>
</#macro>
<#-- 定义了一个名为hello的宏,在宏中我们可以写任意的html代码 -->
然后在我的html页面引入
<#import "../../page/spring.ftl" as h />
<!--引入文件 -->
<@h.hello />
<!-- 调用名为hello的宏 -->
然后运行项目打印的为
hello,World!
下面再来个带参数的
<#macro welcome name age>
<span>欢迎您, ${age} 岁的 ${name} 先生,来到freemarker的世界</span>
</#macro>
页面调用宏
<@h.welcome "小李" 22/>
打印为
欢迎您, 22 岁的 小李 先生,来到freemarker的世界
宏嵌套 <#nested>,表示我们可以在宏的标签内加入任意的内容,包括宏
<#macro go>
<#nested>
</#macro>
页面调用
<#import "../../page/spring.ftl" as h />
<@h.go>
大家好!
</@h.go>
此处打印的是:大家好!
我们再来试试嵌套的,这里我定义了两个宏
<#macro go2>
<#nested>
</#macro>
<#macro go3 name>
${name}
</#macro>
页面调用
<#import "../../page/spring.ftl" as h />
<@h.go2>
<@h.go3 "你好"/>,你今天过得快乐吗?
</@h.go2>
此处打印的为:你好,你今天过得快乐吗?
使用宏做一个freemarker分页
首先我们的写个分页的ftl文件
pager.ftl
<#-- 自定义的分页指令
属性:
pageNo 当前页号(int类型)
pageSize 每页要显示的记录数(int类型)
pageCount 总页数
toURL 点击分页标签时要跳转到的目标URL(string类型)
-->
<#macro pager pageNo pageSize toURL pageCount>
<#-- 输出分页表单 -->
<div class="page">
<form method="post" action="${toURL}" name="qPagerForm">
<#--用于记录当前的页数 -->
<input type='hidden' name ='page' />
<#-- 上一页处理 -->
<#if (pageNo == 1)>
<span class="disabled"><a >上一页</a></span>
<#else>
<span ><a href="javascript:page(${pageNo - 1})">上一页</a></span>
</#if>
<#-- 如果前面页数过多,显示... -->
<#assign start=1>
<#if (pageNo > 4)>
<#assign start=(pageNo - 2)>
<a href="javascript:page(1)">1</a>
<span style='color:#444693;'>...</span>
</#if>
<#-- 显示当前页号和它附近的页号 -->
<#assign end=(pageNo + 2)>
<#if (end > pageCount)>
<#assign end=pageCount>
</#if>
<#list start..end as i>
<#if (pageNo==i)>
<span ><a class="dq">${i}</a></span>
<#else>
<span><a href="javascript:page(${i})">${i}</a></span>
</#if>
</#list>
<#-- 如果后面页数过多,显示... -->
<#if (end < pageCount - 1)>
<span style='color:#444693;'>...</span>
</#if>
<#if (end < pageCount)>
<a href="javascript:page(${pageCount})">${pageCount}</a>
</#if>
<#-- 下一页处理 -->
<#if (pageNo == pageCount)>
<span class="disabled"><a >下一页</a></span>
<#else>
<span>
<a href="javascript:page(${pageNo + 1})">下一页</a>
</span>
</#if>
</form>
<script language="javascript">
function page(no){
var $qForm=$("form[name='qPagerForm']");
$qForm.find("input[name='page']").val(no);
$qForm.submit();
}
</script>
</div>
</#macro>
我们只需将分页的结果对象传入页面,分页对象包括:分页的结果数据,当前页号,每页要显示的条数,总页数。
@RequestMapping(value="userList")
public String userList(ModelMap modelMap,@RequestParam(defaultValue="1") int page){
int pageSize = 8;
Pagination p = userDmn.find(page, pageSize, "from User");
modelMap.put("p", p);
return "page/userList";
}
然后将数据循环在页面,页面调用分页宏
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../js/jquery-1.7.1.min.js"></script>
<style type="text/css">
.page{height:30px; line-height:30px; margin:20px 0; clear:both;}
.page a{color:#444693; font-size:14px; border:1px solid #eeeeee; padding:5px 8px;text-decoration: none}
.page a.dq{background:#444693; padding:5px 8px; color:#fff;}
</style>
</head>
<body>
<table>
<tr>
<th>ID</th>
<th>用户名</th>
<th>密码</th>
</tr>
<#list p.list as user>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.pwd}</td>
</tr>
</#list>
</table>
<#import "../../page/pager.ftl" as page/>
<@page.pager pageNo=p.pageNo pageSize = p.pageSize toURL="../user/userList" pageCount=p.getTotalPage()/>
</body>
</html>
效果图:
当我们在进行开发是,页面要引入许多js和css,特别是一些公用的文件,在此我们可以将这些代码写到一个宏中,要用的话就直接调用宏。
<#macro frontJs>
<script type="text/javascript" src="../js/jquery-1.7.1.min.js"></script>
</#macro>
在页面上调用宏
<#import "../../page/spring.ftl" as spring/>
<@spring.frontJs />
就这样我们在页面中引入了js文件。
当然我们在每个页面中都去写一个<#import />确实有点不爽,freemarker配置中有个属性叫 auto_import,, 叫做自动导入,
auto_import=spring.ftl as spring
在此我们就不用引入spring.ftl文件了,因为已经自动导入了,现在我们在每个页面都可以直接使用,我们可以写一些常用的宏在ftl文件中,再自动导入。
<@spring.frontJs />
在页面中往往有相同的主菜单和左菜单,脚部,我们都可以用这种方式来包含html代码。
当然我们也可以用
<#include />
来包含相同的html页面
freemarker获取request对象
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<property name="prefix" value="/" />
<property name="suffix" value=".html" />
<property name="contentType" value="text/html;charset=utf-8" />
<property name="requestContextAttribute" value="rc" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
在配置文件中加入一句
<property name="requestContextAttribute" value="rc" />
这样就可以在页面中使用request对象了
${rc.contextPath}
获取Session
User user = new User();
user.setId(1);
user.setName("li");
user.setPwd("pwd");
session.setAttribute("user",user );
${Session["user"].name}
获取Session中user对象中的name值
来源:oschina
链接:https://my.oschina.net/u/2435940/blog/638330