模板引擎FreeMarker的介绍和使用

模板引擎

  • 模板引擎的目标是“数据+模板=结果”
  • 模板引擎将数据与展现有效的“解耦”
  • 前端只需要知道怎么编写前端,后端只需关注后端,用模板引擎把两者整合

在这里插入图片描述

主流的模板引擎

  • Java Server Page(jsp)

  • FreeMarker

  • Beetl(拥有前两者的优点,但是作为新的模板,还未普及,前面两个更常用)

FreeMarker和JSP
在这里插入图片描述

  • 只要不是开发淘宝、京东这样的大型软件,两者的执行效率相差不多

FreeMarker

  • FreeMarker是免费开源的模板引擎技术
  • 要下载jar
  • FreeMarker脚本为FreeMarker Template Language
  • FreeMarker 提供了大量内建函数来简化开发(这就是很多人放弃jsp用FreeMarker的原因)

在java类中创建数据

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;

public class FreeMarkerSample {

	public static void main(String[] args) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
		
		//1、加载模板
		//创建核心配置对象
		/*传入版本号,每个版本的FreeMarker语法和解析方式都略有不同*/
		Configuration config=new Configuration(Configuration.VERSION_2_3_28);
		//设置加载的目录
		/*第一个参数表示在这个类所在包中加载指定的ftl文件,第二个参数是空字符串,表示当前包 */
		config.setClassForTemplateLoading(FreeMarkerSample.class, "");
		//得到模板对象
		/*因为上面指定了只在特定的类所在的包中加载ftl文件,所以这里直接写文件名就行*/
		Template t=config.getTemplate("sample1.ftl");
		
		//2、创建数据
		/*FreeMarker中的数据就是一个Map对象5*/
		Map<String,Object> data=new HashMap<>();
		data.put("site", "百度");
		data.put("url","http://www.baidu.com");
		data.put("date",Calendar.getInstance().getTime());
		data.put("number",456654456.7889);
		
		Map<String,Object> info=new HashMap<>();
		info.put("cpu","i5");
		Computer computer=new Computer("123","张三",7896.5f,info);
		data.put("compu",computer);
        
		//3、产生输出(可以向控制台、网络中的流、文件中输出)
		/*第一个参数是数据,第二个参数是向哪里输出*/
		t.process(data,new OutputStreamWriter(System.out));//像控制台中输出
	}
}

语法(均在.ftl文件中进行演示)

  • FTL取值

    只有输出才要加${}

在这里插入图片描述

<#-- FreeMarker取值 -->
${site}-${url}

<#-- 默认值,如果取的值不存在则会输出后面的默认值 -->
${author!"不存在的属性"}

<#-- 日期格式化输出,如果不格式化会抛异常(日期不能转成字符串) -->
${date?string("yyyy年MM月dd日 HH:mm:ss")}

<#-- 数字格式化输出,如果不指定格式,默认按国际化货币格式输出(三位一逗号,保留三位小数),四舍五入 -->
${number?string("0,0000.00")}


<#-- ${属性名.对象中的属性名} -->
ID:${compu.id}
User:${compu.user}
Price:${compu.price?string("0.00")}
<#-- 对象中集合属性中值的获取 -->
<#-- 数据中(Map中)保存对象的输出方式跟EL表达式差不多 -->
<#-- ${属性名.对象中集合属性的属性名["集合中的key"]}通过key获取value -->
CPU:${compu.info["cpu"]}
Memory:${compu.info["memory"]!"memory not exist"}

关于多级访问的变量,比如 animals.python.price, 书写代码:animals.python.price!0 当且仅当 animals.python 永远存在, 而仅仅最后一个子变量 price 可能不存在时是正确的 (这种情况下我们假设价格是 0)。 如果 animalspython 不存在, 那么模板处理过程将会以"未定义的变量"错误而停止。为了防止这种情况的发生, 可以如下这样来编写代码 (animals.python.price)!0。 这种情况就是说 animalspython 不存在时, 表达式的结果是 0。对于 ?? 也是同样用来的处理这种逻辑的; 将 animals.python.price?? 对比(animals.python.price)??来看。

  • if 分支判断

在这里插入图片描述

<#-- if分支 -->
<#-- FreeMarker中字符串的判断直接用==  -->
<#if compu.id=="123">
这是重要设配
<#elseif compu.id=="456">
正常保护等级
<#else>
接近废弃的电脑
</#if>

<#-- ??用于判断该对象是否为空,不为空返回true,为空返回false -->
<#if compu.user??>
这台电脑有人使用
<#else>
这台电脑无人使用
</#if>
  • switch分支判断

在这里插入图片描述

<#--在FreeMarker中,空格也会输出,所以这里为了格式不留空格书写-->

<#-- switch分支 -->
<#switch compu.id>
<#case "123">
这台电脑很重要
<#break>
<#case "456">
正常保护等级
<#break>
<#default>
废弃电脑
</#switch>
  • list迭代列表

在这里插入图片描述

<#-- 迭代List,并把值赋给arr,其中arr_index代表迭代的索引,从0开始 -->
<#list arrayList as arr>
${arr_index+1}-${arr}
</#list>

  • list迭代Map

在这里插入图片描述

<#-- 把Map中的key取出来(linkedMap?keys)当作一个List,再迭代 -->
<#list linkedMap?keys as key>
${key}-${linkedMap[key]}
</#list>

FreeMarker内建函数

在这里插入图片描述

${words?replace("blood","*****")}将字符串words中的blood子字符串替换为*****输出

?string实现三目运算符的操作${(words?index_of("blood")!=-1)?String("包含敏感词汇",words)}

${name?cap_first}
${brand?upper_case}
${brand?length}
${words?replace("blood" , "*****")}
${words?index_of("blood")}
<#-- 利用?string实现三目运算符的操作 -->
${(words?index_of("blood") != -1)?string("包含敏感词汇","不包含敏感词汇")}

${n?round}
${n?floor}
${n?ceiling}

公司共有${computers?size}台电脑
第一台:${computers?first.model}
最后一台:${computers?last.model}

排序

<#-- 默认按照指定属性升序排列,可以调用reverse函数进行降序排列 -->
<#list computers?sort_by("price")?reverse as c>
	${c.sn}-${c.price}
</#list>

Freemarker与Servlet的整合

ftl文件怎么在web项目中被执行

  • Freemarker对整合servlet有良好的支持,在FreeMarker.jar包中存在支持Servlet的类

在这里插入图片描述

  • 需要使用这个Servlet类就必须在web.xml中注册
<!--注册FreemarkerServlet  -->
  <servlet>
  	<servlet-name>freemarker</servlet-name>
  	<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
  	<!--配置初始化参数,通知FreemarkerServlet在哪个目录下寻找.ftl文件(设置加载的目录)  -->
  	<init-param>
  		<param-name>TemplatePath</param-name>
  		<param-value>/WEB-INF/ftl</param-value>
  	</init-param>
  </servlet>
  
  <!--FreemarkerServlet映射地址,只要浏览器地址栏中的URL是以.ftl结尾,就会被FreemarkerServlet处理  -->
  <servlet-mapping>
  	<servlet-name>freemarker</servlet-name>
  	<url-pattern>*.ftl</url-pattern>
  </servlet-mapping>

在配置初始化参数的时候,我们指定了FreemarkerServlet在哪个目录下寻找.ftl脚本文件,所以我们的.ftl文件都要保存在这个文件中

在这里插入图片描述

通过在浏览器中输入http://localhost:8080/项目名/test.ftl就可以输出这个脚本文件中的内容(并不要把完整的路径输入到浏览器中)

在这里插入图片描述

**执行原理:**当浏览器地址栏中输入的URL以.ftl结尾,就会被FreemarkerServlet类处理,FreemarkerServlet类就会到web.xml配置文件指定的加载目录中(就是init-param中配置的templatePath参数值)寻找和URL中同名的.ftl脚本文件进行输出(上面是在/WEB-INF/ftl文件下寻找test.ftl文件进行输出)

Freemarker与servlet

ListServlet.java

@WebServlet("/list")
public class ListServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ListServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		List<Employee> employees=new ArrayList<>();
		employees.add(new Employee(7823l,"李四","技术部","java高级工程师",15000f));
		employees.add(new Employee(7824l,"张丹","市场部","客户经理",14500f));
		request.setAttribute("employees", employees);
        
        //FreemarkerServlet会检测到是以.ftl结尾的URL,进行处理(寻找对应的.ftl脚本文件进行输出)
		request.getRequestDispatcher("/employee.ftl").forward(request, response);
	}
}

employee.ftl

<table class="table table-bordered table-hover">
                <thead>
                <tr>
                    <th>序号</th>
                    <th>员工编号</th>
                    <th>姓名</th>
                    <th>部门</th>
                    <th>职务</th>
                    <th>工资</th>
                    <th>&nbsp;</th>
                </tr>
                </thead>
                <tbody>
                <#--按员工编号升序输出-->
                <#list employees?sort_by("empno") as emp>
                <tr>
                    <td>${emp_index+1}</td>
                    <#-- 整数输出 -->
                    <td>${emp.empno?string("0")}</td>
                    <td>${emp.name}</td>
                    <td>${emp.department}</td>
                    <td>${emp.job}</td>
                    <td style="color: red;font-weight: bold">¥${emp.salary?string("0,000.00")}</td>
                </tr>
               </#list>
                </tbody>
 </table>

.ftl脚本文件中的数据是从哪里获取的?

从当前页面的请求、会话、ServletContext中自动依次查找,如果都没查找到,又没有做其他处理,则会抛出异常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章