🎉🎉欢迎来到我的CSDN主页!🎉🎉
🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚
🌟推荐给大家我的专栏《SpringBoot》。🎯🎯
👉点击这里,就可以查看我的主页啦!👇👇
Java方文山的个人主页
🎁如果感觉还不错的话请给我点赞吧!🎁🎁
💖期待你的加入,一起学习,一起进步!💖💖
目录
一、Freemarker简介
1.1.什么是Freemarker
1.2.Freemarker的特点
1.3.Freemarker对比JSP
二、FreeMarker的使用
2.1.数据类型
2.1.1.字符串
2.1.2.数值
2.1.3.布尔值
2.1.4.日期
2.2.常见指令
2.2.1.处理不存在的值
2.2.2.assign
2.2.3.if/elseif/else
2.2.4.list
2.2.5.include
三、Freemarker综合案例
3.1.SpringBoot集成Freemarker
3.2.查询(Select)
3.3.新增(Add)
3.4.修改(Update)
3.5.删除(Delete)
一、Freemarker简介
1.1.什么是Freemarker
Freemarker是一个Java模板引擎,用于生成动态的网页、电子邮件、XML文档、JSON等内容。它基于模板和数据模型,将数据与模板进行结合,然后输出所需的结果。Freemarker支持强大的模板标签语言,包括条件语句、循环语句、变量赋值、宏定义等,使得模板设计更加灵活且易于维护。Freemarker也被广泛应用于Java Web框架中,如Spring MVC、Struts、Play等。
1.2.Freemarker的特点
-
简单易用:Freemarker使用简洁的语法和标签,使模板设计和使用变得简单易懂。它支持常见的逻辑判断、循环和变量赋值等操作,使得模板编写更加灵活和可读性更强。
-
独立性:Freemarker是一个独立的模板引擎,不依赖于特定的Web框架或容器。这使得它在各种Java应用中都可以方便地使用,无论是基于Web的应用还是独立的命令行工具。
-
跨平台支持:由于Freemarker是基于Java开发的,所以它可以运行在几乎所有支持Java的平台上,包括Windows、Linux、Mac等。
-
强大的模板功能:Freemarker提供了丰富的模板功能,包括条件语句、循环语句、宏定义、函数调用等。这些功能可以帮助开发人员实现复杂的逻辑和数据处理,使得模板更加灵活和可扩展。
-
安全性:Freemarker具有良好的安全性,可以防止常见的模板注入攻击。它提供了严格的模板语法检查和输出过滤机制,可以有效地防止恶意用户篡改模板或注入恶意代码。
总的来说,Freemarker是一个功能强大、灵活易用、跨平台的Java模板引擎,广泛应用于各种Java应用开发中。它可以帮助开发人员将动态数据与静态模板进行分离,提高代码的可维护性和可重用性。
1.3.Freemarker对比JSP
当涉及到Freemarker和JSP的详细比较时,我们可以从以下几个方面进行更深入的讨论:
-
语法和标记:
- JSP使用类似于HTML的标记语言,在其中插入Java代码需要使用特殊的标签,如<% %>。这使得JSP对于前端开发人员来说更容易理解和维护。
- Freemarker则采用自己的表达式语法,使用${}或#{}来引用变量或执行函数。这种语法更加简洁,对于Java开发人员更友好。
-
数据源引用:
- 在JSP中,可以通过JavaBean、EL表达式或JSTL标签库等方式来引用外部数据源。这样可以直接在JSP页面中操作和展示数据。
- Freemarker则需要将数据源封装成一个数据模型对象,并将模型对象传递给模板。这种方式更为灵活,可以将数据源与视图分离,提高代码的可维护性和可重用性。
-
性能:
- JSP需要在第一次请求时编译成Java Servlet才能运行,这会导致一定的延迟。但一旦编译完成,后续的请求会比较快速。
- Freemarker是基于纯Java代码实现的,不需要编译过程,因此在整体性能上可能更快,尤其是在大量页面渲染的情况下。
-
可读性和可维护性:
- JSP的语法类似于HTML,对于前端开发人员来说更易于理解和维护。但对于Java开发人员来说,JSP中的Java代码可能会比较繁琐。
- Freemarker采用了更简单直观的语法,易于阅读和维护。它提供了更丰富的模板功能,如条件语句、循环语句、宏定义等,使得模板更加灵活和可扩展。
二、FreeMarker的使用
2.1.数据类型
2.1.1.字符串
在文本中确定字符串值的方法是看双引号,比如: "some text"
,或单引号,比如: 'some text'
。这两种形式是等同的。 如果文本自身包含用于字符引用的引号 ( "
或 '
)或反斜杠时, 应该在它们的前面再加一个反斜杠;这就是转义。 转义允许直接在文本中输入任何字符, 也包括换行。
${"It's \"quoted\" and
this is a backslash: \\"}
字符串类型处理:
方法 | 含义 |
---|---|
?substring(start,end) | 截取字符串(左闭右开) |
?uncap_first | 首字母小写输出 |
?cap_first | 首字母大写输出 |
?lower_case | 字母转小写输出 |
?upper_case | 字母转大写输出 |
?length | 获取字符串长度 |
?starts_with("xx")?string | 是否以指定字符开头(boolean类型) |
?ends_with("xx")?string | 是否以指定字符结尾(boolean类型) |
?index_of("xx") | 获取指定字符的索引 |
?trim | 去除字符串前后空格 |
?replace("xx","xx") | 替换指定字符串 |
字符串空值情况处理:
FreeMarker 的变量必须赋值,否则就会抛出异常。而对于 FreeMarker 来说,null 值和不存在的变量是完全一样的,因为 FreeMarker 无法理解 null 值。
<#-- 如果值不存在,直接输出会报错 -->
<#--${str}-->
<#-- 使用!,当值不存在时,默认显示空字符串 -->
${str!}<br>
<#-- 使用!"xx",当值不存在时,默认显示指定字符串 -->
${str!"这是一个默认值"}<br>
<#-- 使用??,判断字符串是否为空;返回布尔类型。如果想要输出,需要将布尔类型转换成字符串 -->
${(str??)?string}<br>
2.1.2.数值
输入不带引号的数字就可以直接指定一个数字, 必须使用点作为小数的分隔符而不能是其他的分组分隔符。
${0.45}<br>
${18}<br>
<#-- 将数值转换成字符串输出 -->
${1000?c} <br>
<#-- 将数值转换成货币类型的字符串输出 -->
${1000?string.currency} <br>
<#-- 将数值转换成百分比类型的字符串输出 -->
${0.45?string.percent} <br>
<#-- 将浮点型数值保留指定小数位输出 (##表示保留两位小数) -->
${0.45723123?string["0.##"]} <br>
2.1.3.布尔值
直接写 true
或者 false
就表示一个布尔值了,不需使用引号。
在freemarker中布尔类型不能直接输出;如果输出要先转成字符串
${flag?c}<br>
${flag?string}<br>
${flag?string("yes","no")}<br>
2.1.4.日期
日期变量可以存储和日期/时间相关的数据。
在freemarker中日期类型不能直接输出;如果输出要先转成日期型或字符串
日期格式输出:
输出方式 | 说明 |
---|---|
?date | 年月日 |
?time | 时分秒 |
?datetime | 年月日时分秒 |
?string("自定义格式") | 指定格式 |
<#-- 输出日期格式 -->
${createDate?date} <br>
<#-- 输出时间格式 -->
${createDate?time} <br>
<#-- 输出日期时间格式 -->
${createDate?datetime} <br>
<#-- 输出格式化日期格式 -->
${createDate?string("yyyy年MM月dd日 HH时mm分ss秒")} <br>
2.2.常见指令
2.2.1.处理不存在的值
当试图访问一个不存在的变量时, FreeMarker 将会报错而导致模板执行中断。 通常我们可以使用两个特殊操作符来压制这个错误,控制这种错误情况。被控制的变量可以是顶层变量,哈希表或序列的子变量。 此外这些操作符还能处理方法调用的返回值不存在的情况。
-
默认值操作符
使用形式: unsafe_expr!default_expr
或 unsafe_expr!
or (unsafe_expr)!default_expr
或 (unsafe_expr)!
这个操作符允许你为可能不存在的变量指定一个默认值。
${message!"default Value."}
<#assign message="Zking">
${message!"default Value."}
输出结果如下:
default Value.
Zking
如果默认值被省略了,那么结果将会是空串,空序列或空哈希表。(这是 FreeMarker 允许多类型值的体现)请注意,如果想让默认值为 0
或 false
,则不能省略它。
(${message!})
<#assign message = "Zking">
(${message!})
-
不存在值检测操作符
使用形式: unsafe_expr??
或 (unsafe_expr)??
这个操作符告诉我们一个值是否存在。基于这种情况, 结果是
true
或false
。
<#if name??>存在
<#else>不存在
</#if>
-
exists用在逻辑判断
exists用作逻辑判断,返回的是true或者false。
<#if name?exists>${name}
</#if>
-
if_exists用来打印东西
if_exists用于输出的时候,如果存在则输出,不存在就输出空字符串。
${name?if_exists}
2.2.2.assign
使用该指令你可以创建一个新的变量, 或者替换一个已经存在的变量。语法格式如下:
<#assign name1=value1 name2=value2 ... nameN=valueN>
或
<#assign name>capture this
</#assign>
案例演示:
<#-- 创建一个str的变量 -->
<#assign str="hello">
<#-- 输出str -->
${str} <br>
<#-- 一次创建多个变量 -->
<#assign num=1 names=["zhangsan","lisi","wangwu"] >
${num} -- ${names?join(",")}
2.2.3.if/elseif/else
你可以使用 if
, elseif
和 else
指令来条件判断是否越过模板的一个部分。 *condition*
必须计算成布尔值, 否则错误将会中止模板处理。elseif
和 else
必须出现在 if
内部 (也就是,在 if
的开始标签和结束标签之间)。 if
中可以包含任意数量的 elseif
(包括0个) 而且结束时 else
是可选的。
<#if condition>...
<#elseif condition2>...
<#elseif condition3>...
...
<#else>...
</#if>
2.2.4.list
list
指令执行在 list
开始标签和 list
结束标签 ( list
中间的部分) 之间的代码, 对于在序列(或集合)中每个值指定为它的第一个参数。 对于每次迭代,循环变量将会存储当前项的值。
循环变量仅仅存在于 list
标签体内。 而且从循环中调用的宏/函数不会看到它(就像它只是局部变量一样)。
<#list sequence as item>Part repeated for each item
<#else>Part executed when there are 0 items
</#list>
在
list
中的else
仅从 FreeMarker 2.3.23 版本开始支持。
注意:
-
else
部分是可选的, 而且仅仅从 FreeMarker 2.3.23 版本开始支持。 -
sequence
: 将我们想要迭代的项,算作是序列或集合的表达式 -
item
: 循环变量的名称 (不是表达式)
<#list arrs as item>${item}
<#else>集合是空的
</#list>
2.2.5.include
可以使用它在你的模板中插入另外一个 FreeMarker 模板文件 (由 path
参数指定)
<#list arrs as item>${item}
<#else>集合是空的
</#list>
这里:
-
path
: 要包含文件的路径; -
options
: 一个或多个这样的选项:encoding=encoding
,parse=parse
-
encoding
: 算作是字符串的表达式 -
parse
: 算作是布尔值的表达式(为了向下兼容,也接受一部分字符串值) -
ignore_missing
: 算作是布尔值的表达式
-
<h1>Hello Freemarker</h1>
<#include "/common/head.ftl">
三、Freemarker综合案例
3.1.SpringBoot集成Freemarker
配置pom.xml,引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
application.yml或application.properties文件,添加以下配置
spring:freemarker:# 设置模板后缀名suffix: .ftl# 设置文档类型content-type: text/html# 设置页面编码格式charset: UTF-8# 设置页面缓存cache: false# 设置ftl文件路径template-loader-path: classpath:/templates# 设置静态文件路径,js,css等mvc:static-path-pattern: /static/**
刚刚开始我们右键创建类是没有Freemarker选项的,所以我们进行配置File>Settings>Editor>File and Code Templates
首先复制HTML模板
修改负责的HTML模板
在resources下创建一个名为templates的包随后创建一个FreeMarker文件
index.ftl
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title>
</head>
<body>
欢迎来到FreeMarker所编写的页面!!
</body>
</html>
我们再写一个controller类进行访问
@Controller
public class HomeController {@RequestMapping("/")public String index(){return "index";//这里的return的字符串和页面名称对应}}
访问成功!!
3.2.查询(Select)
为了让我们的页面更加美观加入bootstrap框架
创建一个公共页面用于引用资源
<#--运行路径-->
<#assign ctx>${springMacroRequestContext.contextPath}
</#assign><#--bootstrap的css-->
<link rel="stylesheet" href="${ctx}/bootstrap-3.4.1-dist/css/bootstrap.min.css">
<#--bootstrap的js-->
<script src="${ctx}/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
<#--jquery的js-->
<script src="${ctx}/jquery-3.6.1.js"></script>
index.ftl代码
<a href="${ctx}/booktoedit">新增书籍</a>
<#--表格内容-->
<#if books??><table class="table table-striped"><thead><tr><th scope="col">书籍ID</th><th scope="col">书籍名称</th><th scope="col">价格</th><th scope="col">书籍类型</th><th scope="col">操作</th></tr></thead><tbody><#list books as b><tr><th scope="row">${b.id}</th><td>${b.bookname}</td><td>${b.price}</td><td>${b.booktype}</td><td><a href="${ctx}/booktoedit?id=${b.id}">修改</a><a href="${ctx}/delete?id=${b.id}">删除</a></td></tr></#list></table></tbody>
</#if>
controller代码
@RestController
@RequestMapping("/book")
public class TBookController {@Autowiredprivate TBookService tbookservice;@RequestMapping("/list")public Object list(PageBean pageBean) {PageHelper.startPage(pageBean.getPage(),pageBean.getRows());return tbookservice.selectBook(pageBean);}
}
效果演示
3.3.新增(Add)
这里写一个共用页面,用于新增和修改
<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>书籍编辑页面</title>
</head>
<body>
<#include 'head.ftl' />
<#--如果有值就是修改否者就是新增-->
<#if b??>
<#-- 修改--><form action="${ctx }/edit">书籍ID: <input type="text" name="id" value="${b.id}" readonly>书籍名称:<input type="text" name="bookname" value="${b.bookname }">书籍价格:<input type="text" name="price" value="${b.price }">书籍类别:<input type="text" name="booktype" value="${b.booktype }"><input type="submit"></form>
<#else>
<#-- 新增 --><form action="${ctx }/add" method="post">书籍ID:<input type="text" name="id" value="">书籍名称:<input type="text" name="bookname" value="">书籍价格:<input type="text" name="price" value="">书籍类别:<input type="text" name="booktype" value=""><input type="submit"></form>
</#if></body>
</html>
controller代码
/*根据ID查询书籍*/@RequestMapping("/booktoedit")public String toedit(TBook book, HttpServletRequest request) {/*不为空说明是修改*/if (book.getId() != null) {Long id=Long.parseLong(book.getId()+"");TBook tBook = tbookservice.selectByPrimaryKey(id);System.out.println(tBook);request.setAttribute("b",tBook);}return "toedit";/*这里的return的字符串和页面名称对应*/}/*新增书籍*/@RequestMapping("/add")public String add(TBook book){int insert = tbookservice.insert(book);/*重定向到查询的方法*/return "redirect:/";}
效果演示
3.4.修改(Update)
页面就是刚刚上面的,共用一个ftl文件,至于controller代码如下
/*修改书籍*/@RequestMapping("/edit")public String edit(TBook book){tbookservice.updateByPrimaryKey(book);/*重定向到查询的方法*/return "redirect:/";}
效果演示
3.5.删除(Delete)
删除就是个a标签跳转
<a href="${ctx}/delete?id=${b.id}">删除</a>
controller代码
/*删除书籍*/@RequestMapping("/delete")public String delete(TBook book){Long id=Long.parseLong(book.getId()+"");tbookservice.deleteByPrimaryKey(id);/*重定向到查询的方法*/return "redirect:/";}
效果演示
到这里我的分享就结束了,欢迎到评论区探讨交流!!
💖如果觉得有用的话还请点个赞吧 💖