什么是 FreeMarker?javascript
FreeMarker 是一款模板引擎:一种基于模板的、用来生成输出文本(任何来自于 HTML格式的文本用来css
自动生成源代码)的通用工具。它是为 Java 程序员提供的一个开发包或者说是类库。它不是面向最终用户,html
而是为程序员提供的能够嵌入他们开发产品的一款应用程序。java
搭建SpringMVC+FreeMarker环境jquery
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配置就好了web
固然别忘了配置freemaker.propertiesspring
freemaker.propertiesapi
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值