FreeMarker
http://freemarker.foofun.cn/
1.主要内容
2.FreeMarker概述
2.1FreeMarker概念
2.2FreeMarker特性
2.2.1.通用目标
2.2.2.强大的模板语言
2.2.3.通用的数据模型
2.2.4.为Web准备
2.2.5.智能的国际化和本地化
2.2.6.强大的XML处理能力
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WI5uFmS3-1651031146669)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220129100819859.png)]
2.3FreeMarker环境搭建
2.3.1.新建环境项目
pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>ferrmarker</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>ferrmarker Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- freemarker的坐标依赖 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
<!-- servlet-api的坐标依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies>
<build>
<finalName>ferrmarker</finalName>
<!--
插件地址:
Tomcat
http://tomcat.apache.org/maven-plugin-2.2/
Jetty
https://www.eclipse.org/jetty/documentation/current/jetty-mavenplugin.
html
-->
<plugins>
<!-- 配置jetty插件 -->
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.1.v20140609</version>
</plugin>
</plugins>
</build>
</project>
web.xml文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<!-- FreeMarker的servlet配置-->
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<init-param>
<!-- 模板路径-->
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
</init-param>
<init-param>
<!-- 模板默认的编码:UTF-8 -->
<param-name>default_encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<!-- 处理所有以.ft结尾的文件;ftl是free marker默认的文件后缀-->
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
</web-app>
运行成功
跟着教程一步一步来就好了
https://www.bilibili.com/video/BV1jt4y1r7Lx?p=2
然后就是第一遍做没做出来,第二遍就好了呀
第一遍的问题
问题(1)
工作名和组名那里要改正
问题(2)
jetty:run -Djetty.port=9090
run后面是个空格然后才是-
3.FreeMarker的数据类型
3.1布尔类型
eg:FreeMarker.java文件
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author yanchaochao
* @date 2022/1/29 19:40
*/
@WebServlet("/f02")
public class FreeMarker02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置数据
/*布尔类型*/
req.setAttribute("flag",true);
req.getRequestDispatcher("template/f02.ftl").forward(req,resp);
}
f02.ftl文件
<h4>FreeMarker 数据类型</h4>
<#--
FreeMarker 数据类型
布尔书数据类型
不能在FreeMarker直接输出,如果要输出需要转换成字符串
方式一:?c
方式二:?string或?string(‘为true显示的内容’,为false时显示的内容)
-->
<h5>布尔类型</h5>
${flag?c}<br>
${flag?string}<br>
${flag?string('yes','no')}<br>
${flag?string('俺喜欢','她不中')}<br>
<#--
FreeMarker 数据类型
布尔书数据类型
不能在FreeMarker直接输出,如果要输出需要转换成字符串
方式一:?c
方式二:?string或?string(‘为true显示的内容’,为false时显示的内容)
-->
3.2.日期类型
<#--
FreeMarker 数据类型
日期类型
不能在FreeMarker日期类型中直接输出,如果要输出需要转换成日期型或字符串
1.年月日: ?date
2.时分秒: ?time
3.年月日时分秒: ?datetime
4.自定义格式: ?string(”自定义")
y年 M月 d日
H时 m分 s秒
-->
eg:FreeMarker.java文件
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
/**
* @author yanchaochao
* @date 2022/1/29 19:40
*/
@WebServlet("/f02")
public class FreeMarker02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置数据
/*日期类型*/
req.setAttribute("createDate",new Date());
//请求转发到指定的模板页面--------template/f02.ftl
req.getRequestDispatcher("template/f02.ftl").forward(req,resp);
}
}
f02.ftl文件
<h4>FreeMarker--数据类型</h4>
<h5>布尔类型</h5>
${flag?c}<br>
${flag?string}<br>
${flag?string('yes','no')}<br>
${flag?string('俺喜欢','她不中')}<br>
<#--、-->
<#---->
<#--
FreeMarker 数据类型
日期类型
不能在FreeMarker日期类型中直接输出,如果要输出需要转换成日期型或字符串
1.年月日: ?date
2.时分秒: ?time
3.年月日时分秒: ?datetime
4.自定义格式: ?string(”自定义")
y年 M月 d日
H时 m分 s秒
-->
<h5>日期类型</h5>
${createDate?date}<br>
${createDate?time}<br>
${createDate?datetime}<br>
${createDate?string("yyy/MM/dd HH:mm:ss")}<br>
<#--根据自己的需求格式输出结果-->
3.3.数值类型
eg:FreeMarker.java文件
/*数值类型*/
req.setAttribute("age",18);
req.setAttribute("num",10000);
req.setAttribute("avg",5.5467);
f02.ftl文件
<h5>数值类型</h5>
${age}<br>
${num}<br>
${avg}<br>
<#--将数值转化成字符串类型-->
${age?c}<br>
<#--将数值转化成货币类型-->
${num?string.currency}<br>
<#--将数值转化为百分比类型的字符串-->
${num?string.percent}<br>
<#--将浮点型的数值转化成指定小数输出-->
${avg?string["0.##"]}
3.4.字符串类型
eg:FreeMarker.java文件
/*字符串类型*/
req.setAttribute("msg","hello");
req.setAttribute("msg2","freemarker");
f02.ftl文件
<h5>字符串类型</h5>
${msg}
${msg2}
<#--1.截取字符串-->
${msg?substring(0,2)}<br>
<#--2.首字母小写-->
${msg?uncap_first}<br>
<#--3.首字母大写-->
${msg?cap_first}<br>
<#--4.字母转小写输出-->
${msg?lower_case}<br>
<#--5.字母转大写输出-->
${msg?upper_case}<br>
<#--6.获取字符串的长度-->
${msg?length}<br>
<#--7.是否以指定字符开头-->
${msg?starts_with("a")?string}<br>
<#--8.是否以指定字符结尾-->
${msg?ends_with("o")?string}<br>
<#--9.获取指定字符的索引-->
${msg?index_of("m")}<br>
<#--10.去除字符串前后的空格-->
${msg?trim}<br>
<#--11.替换字符串-->
${msg?replace("he","we")}<br>
<h5>字符串类型</h5>
${msg}
${msg2}
<#--1.截取字符串-->
${msg?substring(0,2)}<br>
<#--2.首字母小写-->
${msg?uncap_first}<br>
<#--3.首字母大写-->
${msg?cap_first}<br>
<#--4.字母转小写输出-->
${msg?lower_case}<br>
<#--5.字母转大写输出-->
${msg?upper_case}<br>
<#--6.获取字符串的长度-->
${msg?length}<br>
<#--7.是否以指定字符开头-->
${msg?starts_with("a")?string}<br>
<#--8.是否以指定字符结尾-->
${msg?ends_with("o")?string}<br>
<#--9.获取指定字符的索引-->
${msg?index_of("m")}<br>
<#--10.去除字符串前后的空格-->
${msg?trim}<br>
<#--11.替换字符串-->
${msg?replace("he","we")}<br>
字符串空值情况处理
3.5.sequence类型
1.数组
eg:FreeMarker.java文件
//数组
String[] stars = new String[]{"周杰伦","林俊杰","五月天","陈奕迅"};
req.setAttribute("stars",stars);
f02.ftl文件
<#--数组操作-->
<#list stars as stars>
${stars}<br>
</#list>
获取序列长度:${stars?size}<br>
获取第一个元素:${stars?first}<br>
获取最后一个元素:${stars?last}<br>
<hr>
2.list
eg:FreeMarker.java文件
//List操作
List<String> citys = Arrays.asList("北京","上海","杭州","深圳");
req.setAttribute("cityList",citys);
f02.ftl文件
<#--list操作-->
<#list cityList as city>
${city} -
</#list>
<hr>
<#--排序-->
<#--倒序输出-->
<#list cityList?reverse as city>
${city} -
</#list>
<hr>
<#--升序输出-->
<#list cityList?sort as city>
${city} -
</#list>
<hr>
<#--降序输出-->
<#list cityList?sort?reverse as city>
${city} -
</#list>
<hr>
<hr>
<#list userList as user>
编号:${user.userId}
姓名:${user.uname}
编号:${user.uage}
<br>
</#list>
<hr>
3.JavaBean的排序
eg:FreeMarker.java文件
//JavaBean集合
List<User> userList = new ArrayList<>();
userList.add(new User(1,"张三",22));
userList.add(new User(2,"李四",18));
userList.add(new User(3,"王五",20));
req.setAttribute("userList",userList);
User文件
package com.xxxx.servlet.entity;
/**
* @author yanchaochao
* @date 2022/1/30 1:43
*/
public class User {
private Integer userId;
private String uname;
private Integer uage;
public User() {
}
public User(Integer userId, String uname, Integer uage) {
this.userId = userId;
this.uname = uname;
this.uage = uage;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Integer getUage() {
return uage;
}
public void setUage(Integer uage) {
this.uage = uage;
}
}
f02.ftl文件
<#--JavaBean的排序-->
<#list userList?sort_by("uage") as user>
编号:${user.userId}
姓名:${user.uname}
编号:${user.uage}
<br>
</#list>
3.6hash类型
eg:FreeMarker.java文件
//Map操作
Map<String,String> cityMap = new HashMap<>();
cityMap.put("sh","上海");
cityMap.put("bj","北京");
cityMap.put("sz","深圳");
req.setAttribute("cityMap",cityMap);
f02.ftl文件
<#--Hash-->
<#list cityMap? keys as key>
${key} - ${cityMap[key]}
</#list>
<br>
<#list cityMap? values as value>
${value}
</#list>
<br>
4.FreeMarker常见指令
4.1.assign自定义变量指令
<#assign name1=value1 name2=value2 ... nameN=valueN>
或
<#assign same as above... in namespacehash>
或
<#assign name>
capture this
</#assign>
或
<#assign name in namespacehash>
capture this
</#assign>
4.2.if, else, elseif
eg:FreeMarker03.java文件
package com.xxxx.servlet;
/**
* @author yanchaochao
* @date 2022/1/30 2:35
*/
import com.xxxx.servlet.entity.User;
import javax.net.ssl.ManagerFactoryParameters;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@WebServlet("/f03")
public class FreeMarker03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求转发到指定的模板页面--------template/f03.ftl
req.getRequestDispatcher("template/f03.ftl").forward(req,resp);
}
}
f02.ftl文件
<#--if, else, elseif-->
<#assign score=60>
<#if score lt 60>
<h6>你个小渣渣</h6>
<#elseif score == 80>
<h6>分不在高,及格就行</h6>
<#elseif score gt 60 &&score lt 80 >
<h6>革命尚未成功,同志仍需努力</h6>
<#else >
<h6>哎呦不错哦!</h6>
</#if>
<#--判断数据是否存在-->
<#assign list="">
<#if list??>
数据存在
<#else >
数据不存在
</#if>
4.3.list指令
eg:FreeMarker03.java文件
package com.xxxx.servlet;
/**
* @author yanchaochao
* @date 2022/1/30 2:35
*/
import com.xxxx.servlet.entity.User;
import javax.net.ssl.ManagerFactoryParameters;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@WebServlet("/f03")
public class FreeMarker03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求转发到指定的模板页面--------template/f03.ftl
req.getRequestDispatcher("template/f03.ftl").forward(req,resp);
}
}
f02.ftl文件
<#--list指令-->
<hr>
<#assign users = ["张三","李四","王五"]>
<#list users as user>
${user} |
</#list>
<br>
<#--判断数据不为空,再执行遍历(如果序列不存在,直接遍历会报错)-->
<#if user2??>
<#list users2 as user>
${user}
</#list>
</#if>
<#assign users3=['a']>
<#list users3 as user>
${user}
<#else >
用户数据不存在!
</#list>
4.4.macro自定义指令
<#--macro自定义指令-->
<#macro address>
这个就是自定义的指令
</#macro>
<#--使用自定义指令-->
<@address></@address>
<@address></@address>
<@address></@address>
<hr>
<#--自定义有参数的指令-->
<#macro queryUserByName uname>
通过用户名查询用户对象-${uname}
</#macro>
<@queryUserByName uname="admin"></@queryUserByName>
<hr>
<#macro queryUserByName02 uname upwd phone>
通过用户名查询用户对象-${uname}-${upwd}-${phone}
</#macro>
<@queryUserByName02 uname="张三" upwd= "123456" phone="666"></@queryUserByName02>
<hr>
<hr>
<#--做一个九九乘法表-->
<#macro cfb>
<#list 1..9 as i>
<#list 1..i as j>
${j} * ${i} = ${j*i}
</#list>
<br>
</#list>
</#macro>
<@cfb></@cfb>
<#--升级九九乘法表-->
<#macro cfb02 num>
<#list 1..num as i>
<#list 1..i as j>
${j} * ${i} = ${j*i}
</#list>
<br>
</#list>
</#macro>
<@cfb02 num=5></@cfb02>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMLf9pry-1651031146676)(https://gitee.com/yan-chaochao/typora-library/raw/master/typora-library/image-20220427114342203.png)]
4.5.nested占位指令
<#--占位指令-->
<#macro test>
<#nested >
<br>
这是一段文本
<#nested >
</#macro>
<@test>xxxxxxxxxx</@test>
4.6.import导入指令
eg:FreeMarker04.java文件
package com.xxxx.servlet;
/**
* @author yanchaochao
* @date 2022/1/30 11:24
*/
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/f04")
public class FreeMarker04 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求转发到指定的模板页面--------template/f03.ftl
req.getRequestDispatcher("template/f04.ftl").forward(req,resp);
}
}
f04.ftl文件
<#--通过import指令引入命令空间-->
<#--引用f03文件中的-->
<#import "f03.ftl" as f3>
<@f3.cfb></@f3.cfb>
<hr>
<#--设置一个通用文件调用-->
<#import "commons.ftl" as cm>
<@cm.cfb02 num =5></@cm.cfb02>
commons.ftl文件
<#macro cfb02 num>
<#list 1..num as i>
<#list 1..i as j>
${j} * ${i} = ${j*i}
</#list>
<br>
</#list>
</#macro>
<@cfb02 num=5></@cfb02>
4.7.include包含指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-661DSqmn-1651031146677)(https://gitee.com/yan-chaochao/typora-library/raw/master/typora-library/image-20220427114420811.png)]
f04.ftl文件
<#--包含指令-->
<#--html文件-->
<#include "tset.html">
tset.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>包含</title>
</head>
<body>
Hello
</body>
</html>
5.FreeMarker页面静态化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3laUZsDo-1651031146677)(FreeMarker.assets/image-20220130114432562.png)]
5.1.定义模板
5.2加载模板
NewsServlet.java文件
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @author yanchaochao
* @date 2022/1/30 11:50
*/
@WebServlet("/news")
public class NewsServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//实例化模板对象
Configuration configuration = new Configuration();
//设置加载模板的上下文 以及模板的加载路径(模板的存放路径)
configuration.setServletContextForTemplateLoading(getServletContext(), "/template");
//设置模板的编码格式
configuration.setDefaultEncoding("UTF-8");
//加载模板文件 获取模板对象
Template template = configuration.getTemplate("news.ftl");
//设置数据模型
Map<String, Object> map = new HashMap<>();
map.put("title", "国务院联防联控机制:坚决防止春节返乡政策“一刀切”");
map.put("source", "光明网-《光明日报》");
map.put("pubTime", "2022-01-30 03:41");
map.put("content", "春节将至,一些群众返乡遇阻引发社会关注,国家卫健委新闻发言人米锋在1月29日国务院联防联控机制举行的发布会上表示,国务院联防联控机制综合组已进行核实,并及时反馈地方,要求立即整改,坚决防止返乡政策“简单化一刀切,让广大群众度过一个健康、欢乐、祥和的春节。");
//获取项目的根目录
String basePath = req.getServletContext().getRealPath("/");
//设置html的存放路径
File htmlFile = new File(basePath + "/html");
//判断文件(目录)是否存在
if (!htmlFile.exists()) {
//如果文件目录不存在,则新建文件目录
htmlFile.mkdir();
}
//得到生成的文件名(生成随机不重复的文件名)
String fileName = System.currentTimeMillis() + ".html";
//创建html文件
File file = new File(htmlFile, fileName);
//获取文件输出流
FileWriter writer = new FileWriter(file);
//生成html(将数据模型填充到模板中)
try {
template.process(map, writer);
} catch (TemplateException e) {
e.printStackTrace();
} finally {
//关闭资源
writer.flush();
writer.close();
}
}
}
new.ftl
<!DOCTYPE html>
<html>
<head>
<#--freemarker模板中设置编码格式,否则中文有可能乱码-->
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
</head>
<body>
<#--新闻标题-->
<h2 align="center">${title}</h2>
<#--新闻来源和发布时间-->
<p align="center">
新闻来源:${source}
发布时间:${pubTime}
</p>
<#--新闻内容-->
<p style="text-indent: 2em">
${content}
</p>
</body>
</html>
先运行
http://localhost:9090/news
然后会在webapp中生成1643517894900.html
再次访问
http://localhost:9090/html/1643517894900.html
6.FreeMarker运算符
6.1.算术运算符
6.2.逻辑运算符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r4oSQWsc-1651031146679)(FreeMarker.assets/image-20220130124022134.png)]
6.3.比较运算符
6.4.控制运算符