FreeMarker
概述
- FreeMarker是一种模板引擎(基于模板和要改变的数据),主要用于MVC中的view层,生成html展示数据给客户端,可以完全替代jsp
- 它不是面向最终用户的,而是一个Java类库,是一款可以嵌入所开发产品的组件,后缀通常是ftl
- 它是一个基于模板生成文本输出的通用工具,使用纯Java编写,模板中没有业务逻辑,外部java程序通过数据库操作等生成数据传入template中,然后输出页面。它能够生成各种文本:HTML、XML、JSP、RTF、Java源代码等等,而且不需要Servlet环境,并且可以从任何源载入模板,如本地文件、数据库等等
模板文件
- 注释
- <#–注释内容–>
- 文本
- 生成的文件内容,例如java语句或HTML元素等
- 插值
- ${ expr }通用插值
- #{ expr }或#{expr;format}数字格式化插值
避免空值插值
!:指定缺失变量的默认值
${sss!} <#--没有定义这个变量,默认值是空字符串! -->
${sss!"abc"} <#--没有定义这个变量,默认值是字符串abc! -->
??:判断变量是否存在
variable??,如果变量存在,返回true,否则返回false。
插值规则
a) 表达式放置在插值语法${}之中,用于输出表达式的值。
b) 表达式的值的类型可以是:字符串、 数字、布尔、日期时间、序列、Hash结构
c) 表达式支持Java中的所有运算符:
算术运算符:+、-、*、/、%
比较运算符:==(eq)、!=(ne)、>(gt)、>=(gte)、<(lt)、<=(lte)
逻辑运算符:&&(and)、||(or)、!(not)
三目运算符:? :
d) 内置函数:
Ⅰ) 使用方式:表达式?函数名[(实参)]
Ⅱ) 字符串的常用内置函数: substring(from[, to])、html、length、trim、url 示例:<#setting url_escaping_charset="UTF-8"> 、exp?url[("UTF-8")]
Ⅲ) 数字的常用内置函数:c、string[(数字模式串)]、
Ⅳ) 布尔的内置函数:string[("男", "女")]
Ⅴ) 内置的常用日期时间函数:string[("格式模式串")]、datetime、date、time
e) 序列:
在FTL中定义的序列:由方括号包括,各元素用英文逗号分隔如:<#assign seq=["winter", "spring", "summer", "autumn"]>也可以用数字范围(递增、反递增)定义数字序列: <#assign nums=101..105> 或 <#assign nums=105..101> 在数据模型中可以是List对象、Set对象,序列的常用内置函数:size、sort[("指定字段作排序依据")]
f) Hash结构:
在FTL文件中直接定义时:由大括号包括,由逗号分隔键/值列表,键和值之间用冒号分隔。键必须是字符串。如: <#assign scores={"语文":78, "数学":89, "英语":87}> ${scores.语文} 在数据模型中可以是Map对象,Hash结构的内置函数:size、keys、values
-
FTL指令(FreeMarker指令)
- assign 指令:用于为该模板页面创建或替换一个顶层变量
<#--定义变量--> <#assign id=1 name="zhangsan" sex="男"> <#--定义数组--> <#assign hobbyArr=['篮球','足球','排球']> <#--定义Map集合--> <#assign people={"name":"mouse","age":25,"weight":140}>
- if else 指令:用于条件判断
<#--gt:小于 gte:小于等于--> <#assign age=20> <#if age gt 60>老年人 <#elseif age gt 40>中年人 <#elseif age gt 20>青年人 <#else> 少年人 </#if> <#if (age==20)> 我今年20岁 </#if>
- list 指令:迭代List集合
item_index:当前变量的索引值 item_has_next:是否存在下一个对象 break:跳出迭代 <#list 1..9 as i> ${i} </#list> <#list hobbyArr as hobby> 下标:${hobby_index} 值:${hobby}<br/> <#if !hobby_has_next> 已经是最后一个 <#break> </#if> </#list> 长度:${hobbyArr?size} <#--迭代Map集合--> <#assign keys = people?keys> <#--map的key集合--> <#list keys as key> ${key} = ${h[key]} </#list>
- switch 指令
<#assign age=10> <#switch age> <#case 0>0<#break> <#case 10>10<#break> <#case 20>20<#break> <#default>30 </#switch>
- include 指令:用于导入文件,它可以在模版中插入其他的静态文件,或者是freemarker模版
<#--parse=true 是否作为ftl语法解析,默认是true--> <#include "inc.ftl" encoding="UTF-8" parse=true>
- import 指令:导入文件,然后就可以在当前文件里使用被导入文件里的宏组件,类似于java里的import
<#--访问时使用 inc.--> <#import "inc.ftl" as inc> ${inc.name}
- noparse 指令:指定FreeMarker不处理该指定里包含的内容
使用
- 定义一个配置对象 参数是 Freemarker的版本
- Configuration conf=new Configuration(Configuration.VERSION_2_3_28);
- 设定模板路径
- conf.setDirectoryForTemplateLoading(new File(“url”));
- 获取ftl模板对象
- Template temp = conf.getTemplate(“模板名.ftl”);
- 为模板添加数据部分
- Map<String,Object> root=new HashMap<String, Object>();
- root.put(“数据参数名”, “value”);
- 设定生成文件路径
- FileWriter out=new FileWriter(“地址”);
- 生成目标文件
- temp.process(root, out);
- 关闭资源
- out.flush();
- out.close();
springmvc整合
<!-- 配置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">
<!-- 视图解析器在/tpl/路径下扫描视图文件 -->
<property name="templateLoaderPath" value="/tpl/" />
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape" />
</map>
</property>
<property name="freemarkerSettings">
<props>
<!-- 模板编码格式 -->
<prop key="default_encoding">UTF-8</prop>
<!-- 本地化设置 -->
<prop key="locale">UTF-8</prop>
<!-- url转义编码 -->
<prop key="url_escaping_charset">UTF-8</prop>
</props>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />
<!-- 配置freeMarker视图解析器 -->
<bean id="freemakerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<!-- 扫描路径內所有以ftl結尾的文件 -->
<property name="viewNames">
<array>
<value>*.ftl</value>
</array>
</property>
<!-- 配置逻辑视图自动添加的后缀名 -->
<property name="suffix" value=".ftl"/>
<property name="contentType" value="text/html; charset=UTF-8" />
<property name="exposeRequestAttributes" value="true" />
<!-- 是否在model自动把session中的attribute导入进去; -->
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="requestContextAttribute" value="request" />
<!-- 给视图解析器配置优先級,你可以给之前jsp视图解析器的值配为2 -->
<property name="order" value="1" />
</bean>
内建函数
- 通过?调用内置函数传参数
// string表示转换为string类型函数 参数是日期格式化参数
${参数?string("yyyy-MM-dd HH:mm:ss")}
Thymeleaf
概述
- Thymeleaf 是一种模板语言,包括数据(Data)、模板(Template)、模板引擎(Template Engine)和结果文档(Result Documents),可以完全替代 JSP
- 是SpringBoot推荐的模板引擎,语法更加接近HTML即使用html的标签来完成逻辑和数据的传入进行渲染
- 与其它模板引擎相比, Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用
- 支持SpEL,SpEL是可以用于Spring中的一种EL表达式
- 特点
- Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示
- Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言
- Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能
使用
- 1.导入thymeleaf-2.1.4.RELEASE.jar
// maven依赖
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>2.1.4</version>
</dependency>
- 2.HTML增加头文件
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
- 3.用th标签动态替换掉静态数据
<!-- 将后台传来的message显示,静态文件则显示thymeleaf -->
<td th:text="${message}">thymeleaf</td>
整合spring
- 导入thymeleaf-spring4-2.1.4.RELEASE.jar
// maven依赖
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
<version>2.1.4</version>
</dependency>
- SpringMVC配置文件
<context:component-scan base-package="com.test.thymeleaf.controller" />
<mvc:annotation-driven />
<!--springMVC+thymeleaf的跳转页面配置-->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
用法
标签属性(存在优先级)
- 片段包含
- th:fragment //定义待引用的模块
<div th:fragment="footer">
- th:insert //引用其他模块,保留自己的主标签,保留th:fragment的主标签
<div th:insert="test :: footer"></div>
- th:replace //引用其他模块,保留自己的主标签,不保留th:fragment的主标签
<div th:include="test::footer">test</div>
- th:replace //引用其他模块,不保留自己的主标签,保留th:fragment的主标签,Thymeleaf 3.0不再推荐使用
<div th:replace="test::footer">test</div>
- 遍历
- th:each //用于遍历集合中的对象,相当于jstl中的<c:forEach>标签
<tr th:each="user,userStat:${messages.list}"> <td th:text="${user.name}"></td> <td th:text="userStat.index"></td> </tr> // user是临时变量,userStat称为状态变量 // 状态变量属性有: index:当前迭代对象的迭代索引,从0开始,这是索引属性; count:当前迭代对象的迭代索引,从1开始,这个是统计属性; size:迭代变量元素的总量,这是被迭代对象的大小属性; current:当前迭代变量; even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算); first:布尔值,当前循环是否是第一个; last:布尔值,当前循环是否是最后一个;
- 条件判断
- th:if //用于判断条件,还可以多条件 and,or(二元操作符),!,not非(一元操作符)
<span th:if="${product.price lt 100}" class="offer">Special offer!</span> // 不能用"<”,">"等符号,要用"lt"等替代
- th:unless //用于判断条件,与th:if作用相反
- th:switch th:case //用于多个同等级相同目的判断,多选一时使用
<div th:switch="${user.name}"> // 若${user.name}中的值为maliming则显示,否则不显示 <p th:case="maliming">first</p> <p th:case="${otherUser.name}">second</p> </div>
- 声明变量
- th:object //用于表单数据对象绑定,后台controller中参数保持一致,和选择(星号)表达式
<form th:object="${user}"> <input th:value="*{name}"/> //*号代替了${user} </form>
- th:with
- 修改任意属性
- th:attr //用于设置任意属性
<input th:attr="value=${user.name}"/> 设置单个属性 <input th:attr="value=${user.username},name=username,style='background-size:cover;'"/> 设置多个属性之间用逗号隔开
- 修改指定属性默认值即替换原生属性的值 //th:任意html属性
- th:value //用于属性赋值
<option th:value="${user.name}"></option>
- th:src //用于外部资源的引入,例如图片,js文件
<img th:src="@{../images/myself.jpg}"/>或<script th:src="@{../static/login.js}"> </script>
- th:href //用于定义超链接,相当于<a>标签的href属性
<a th:href="@{/user/selectUser?(currentPage=1,reTypeid=${reTypeid},inquiry=${inquiry})}"></a>
- th:selected //用于选择框设置选中值。通常和th:each一起使用
<select οnchange="getChilds(this.value)" id="catId"> <option th:each="c:${categoryList}" th:selected="${goods.catId eq c.id}" th:value="${c.id}" th:text="${c.name}" value="1">蔬菜</option> </select>
- th:action //用于定义后台控制器的路径,表单的提交地址,相当于标签的action属性
<form th:action="@{user/login}" method="post"></form>
- 修改标签体内容
- th:text //用于文本的显示,并且可以进行简单的计算,会转义文本中的特殊字符,使效果不显示
- th:utext //用于文本的显示,常用于富文本编辑器编辑后的内容显示到前台页面上
- 移除片段
- th:remove //用于删除。可用表达式传参
- all:删除所在标签和内容及其所属的所有子标签。
- body:删除所在标签的内容及其所属的所有子标签。
- tag:删除所在标签,不删除任何所属的子标签。
- all-but-first:删除除第一个子标签外的其他子标签。
- none:不起作用,什么也不做
<tbody th:remove="all-but-first"> //用count进行统计,有顺序的显示 <tr th:each="product:${productList}"> <td th:text="${productStat.count}">1</td> <td th:text="${product.description}">Red Chair</td> </tr> <tr> <td>1</td> <td>White table</td> <tr> </tbody>
- th:remove //用于删除。可用表达式传参
- 其他
- th:block //只允许模板开发人员指定他们想要的属性的属性容器,唯一的一个Thymeleaf块级元素,Thymeleaf模板引擎在处理 th:block 的时候会删掉它本身,标签本身不显示,而保留其内容
<table> <th:block th:each="user : ${users}"> <tr> <td th:text="${user.login}">...</td> <td th:text="${user.name}">...</td> </tr> <tr> <td colspan="2" th:text="${user.address}">...</td> </tr> </th:block> </table>
- th:inline
- Thymeleaf模板中的三个模板被认为是文本:TEXT,JAVASCRIPT和CSS,标记模板模式:HTML和XML
- 区别:在文本模板中,没有标签,以属性的形式插⼊逻辑,因此我们必须依赖其他机制。最基本的机制是内联, 内联语法是以文本模板模式输出表达式结果的最简单方法
- 内联文本:
<p th:inline="text">Hello, [[#{test}]]</p>
- 内联JavaScript:
<script th:inline="javascript">var username = [[${session.user.name}]];</script>
- 内联CSS
<style th:inline="css"> .[[${classname}]] { text-align: [[${align}]]; } </style> //输出为 <style th:inline="css"> .main\ elems { text-align: center; } </style>
表达式
- 变量表达式:${…}
// 引用user对象的name属性值,未获取则为tom
<input type="text" value="tom" th:value="${user.name}" />
// 字符串拼接
<div th:text="${'$'+product.price}">888</div>
- 选择表达式:*{…}
// 一般跟在th:object后,直接取object中的属性
<div th:object="${session.user}">
<p>user: <span th:text="*{firstName}">tom</span></p>
</div>
// 等同于
<div>
<p>user: <span th:text="${session.user.firstName}">tom</span></p>
</div>
- 文字国际化表达式:#{}
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
调用国际化的welcome语句,国际化资源文件如下
resource_en_US.properties:home.welcome=Welcome to here!
resource_zh_CN.properties:home.welcome=欢迎您的到来!
- 链接网址表达式:@ {}
<img src="当前路径" th:src="@{${后台传来路径}}" />
- 片段表达式:〜{}
// 导入模块片段,常与th:insert或th:replace搭配进行片段插入
<div th:insert="~{commons :: main}">...</div>
// 可在任何地方使用,就像任何其他变量一样
<div th:with="frag=~{footer :: #main/text()}">
<p th:insert="${frag}">
</div>
表达式内置对象
- #ctx:上下文对象
- #locale:上下文区域设置
- #vars:上下文变量
- #request :(仅在Web Contexts中)HttpServletRequest对象
- #session :(仅在Web上下文中)HttpSession对象
- #servletContext :(仅在Web上下文中)ServletContext对象
- #response:(仅在Web上下文中)HttpServletResponse对象
- #execInfo:有关正在处理的模板的信息
- #messages:用于在变量表达式中获取外部化消息的方法,与使用
- #uris:转义URL / URI部分的方法
- #conversions:执行配置的转换服务(如果有的话)的方法
- #dates:java.util.Date对象的方法:格式化,组件提取等
- #calendars:类似于#dates,但对于java.util.Calendar对象
- #numbers:用于格式化数字对象的方法
- #strings:String对象的⽅法:contains,startsWith,prepending /appending等
- #objects:一般对象的方法,参照java.lang.Object
- #bools:判断布尔类型工具
- #arrays:数组操作的工具
- #lists:列表操作的工具,参照java.util.List
- #sets:Set操作工具,参照java.util.Set
- #maps:Map操作工具,参照java.util.Map
- #aggregates:操作数组或集合的工具
- #ids:处理可能重复的id属性的方法(例如,作为迭代的结果)