Freemarker基本语法与案例讲解

🎉🎉欢迎来到我的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的特点

  1. 简单易用:Freemarker使用简洁的语法和标签,使模板设计和使用变得简单易懂。它支持常见的逻辑判断、循环和变量赋值等操作,使得模板编写更加灵活和可读性更强。

  2. 独立性:Freemarker是一个独立的模板引擎,不依赖于特定的Web框架或容器。这使得它在各种Java应用中都可以方便地使用,无论是基于Web的应用还是独立的命令行工具。

  3. 跨平台支持:由于Freemarker是基于Java开发的,所以它可以运行在几乎所有支持Java的平台上,包括Windows、Linux、Mac等。

  4. 强大的模板功能:Freemarker提供了丰富的模板功能,包括条件语句、循环语句、宏定义、函数调用等。这些功能可以帮助开发人员实现复杂的逻辑和数据处理,使得模板更加灵活和可扩展。

  5. 安全性:Freemarker具有良好的安全性,可以防止常见的模板注入攻击。它提供了严格的模板语法检查和输出过滤机制,可以有效地防止恶意用户篡改模板或注入恶意代码。

总的来说,Freemarker是一个功能强大、灵活易用、跨平台的Java模板引擎,广泛应用于各种Java应用开发中。它可以帮助开发人员将动态数据与静态模板进行分离,提高代码的可维护性和可重用性。

1.3.Freemarker对比JSP

当涉及到Freemarker和JSP的详细比较时,我们可以从以下几个方面进行更深入的讨论:

  1. 语法和标记:

    • JSP使用类似于HTML的标记语言,在其中插入Java代码需要使用特殊的标签,如<% %>。这使得JSP对于前端开发人员来说更容易理解和维护。
    • Freemarker则采用自己的表达式语法,使用${}或#{}来引用变量或执行函数。这种语法更加简洁,对于Java开发人员更友好。
  2. 数据源引用

    • JSP中,可以通过JavaBean、EL表达式或JSTL标签库等方式来引用外部数据源。这样可以直接在JSP页面中操作和展示数据。
    • Freemarker则需要将数据源封装成一个数据模型对象,并将模型对象传递给模板。这种方式更为灵活,可以将数据源与视图分离,提高代码的可维护性和可重用性。
  3. 性能:

    • JSP需要在第一次请求时编译成Java Servlet才能运行,这会导致一定的延迟。但一旦编译完成,后续的请求会比较快速。
    • Freemarker是基于纯Java代码实现的,不需要编译过程,因此在整体性能上可能更快,尤其是在大量页面渲染的情况下。
  4. 可读性和可维护性:

    • 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_exprunsafe_expr! or (unsafe_expr)!default_expr(unsafe_expr)!

这个操作符允许你为可能不存在的变量指定一个默认值。

${message!"default Value."}
<#assign message="Zking">
${message!"default Value."}

输出结果如下:

default Value.
Zking

如果默认值被省略了,那么结果将会是空串,空序列或空哈希表。(这是 FreeMarker 允许多类型值的体现)请注意,如果想让默认值为 0false,则不能省略它。

(${message!})
<#assign message = "Zking">
(${message!})

  • 不存在值检测操作符

使用形式: unsafe_expr??(unsafe_expr)??

这个操作符告诉我们一个值是否存在。基于这种情况, 结果是 truefalse

<#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

你可以使用 ifelseifelse 指令来条件判断是否越过模板的一个部分。 *condition* 必须计算成布尔值, 否则错误将会中止模板处理。elseifelse 必须出现在 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:/";}

效果演示

 请添加图片描述

到这里我的分享就结束了,欢迎到评论区探讨交流!!

💖如果觉得有用的话还请点个赞吧 💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/228789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python接口自动化测试-unittest-批量用例管理

我们日常项目中的接口测试案例肯定不止一个&#xff0c;当案例越来越多时我们如何管理这些批量案例&#xff1f;如何保证案例不重复&#xff1f;如果案例非常多&#xff08;成百上千&#xff0c;甚至更多&#xff09;时如何保证案例执行的效率&#xff1f;如何做&#xff08;批…

利用n_gram进行情感分析

一、思路 二、关键步骤实现 1、利用tf-idf进行特征提取 详见利用tf-idf对特征进行提取-CSDN博客 2、利用svm进行模型训练 详见​​​​​​​​​​​​​​利用svm进行情感分析-CSDN博客

搞懂这6 个持续集成工具,领先80%测试人!

开发人员喜欢把写的代码当成自己的孩子&#xff0c;他们会被当成艺术品一样呵护。作为家长&#xff0c;总是会认为自己的孩子是最好的&#xff0c;也会尽全力给自己的孩子最好的&#xff0c;就算有时候会超出自己的能力范围。 最终&#xff0c;孩子会走出去&#xff0c;和其他…

HarmonyOS云开发基础认证考试满分答案(100分)【全网最全-不断更新】【鸿蒙专栏-29】

系列文章&#xff1a; HarmonyOS应用开发者基础认证满分答案&#xff08;100分&#xff09; HarmonyOS应用开发者基础认证【闯关习题 满分答案】 HarmonyOS应用开发者高级认证满分答案&#xff08;100分&#xff09; HarmonyOS云开发基础认证满分答案&#xff08;100分&#xf…

C++设计模式-Builder 构建器

通过“对象创建” 模式绕开new&#xff0c;来避免对象创建&#xff08;new&#xff09;过程中所导致的紧耦合&#xff08;依赖具体类&#xff09;&#xff0c;从而支持对象创建的稳定。它是接口抽象之后的第一步工作。 一、动机 在软件系统中&#xff0c;有时候面临着“一个复…

Spark基础入门

spark基础入门 环境搭建 localstandlonespark ha spark code spark corespark sqlspark streaming 环境搭建 准备工作 创建安装目录 mkdir /opt/soft cd /opt/soft下载scala wget https://downloads.lightbend.com/scala/2.13.12/scala-2.13.12.tgz -P /opt/soft解压scala…

单元测试计划、用例、报告、评审编制模板

单元测试支撑文档编制模板&#xff0c;具体文档如下&#xff1a; 1. 单元测试计划 2. 单元测试用例 3. 单元测试报告 4. 编码及测试评审报告 软件项目相关资料全套获取&#xff1a;软件项目开发全套文档下载-CSDN博客 1、单元测试计划 2、单元测试用例 3、单元测试报告 4、编码…

FastSAM 分割一切 速度可以比 SAM 快 50 倍

一、FastSAM 在自然语言处理领域有 ChatGPT 通用大语言模型系列&#xff0c;但是在图像领域好像一直没有通用领域模型&#xff0c;但MetaAI 提出能够 分割一切 的视觉基础大模型 SAM 可以做到很好的分割效果&#xff0c;并且不限于场景、不限于目标&#xff0c;为探索视觉大模…

四. 基于环视Camera的BEV感知算法-BEVDet

目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第四章——基于环视Cam…

Java系列-HashMap构造方法

1.无参 只初始化了loadFactor public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {final float loadFactor;public HashMap() {this.loadFactor DEFAULT_LOAD_FACTOR; // all other fields defaulted} }2…

Android动画

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、动画实现3.1 帧动画资源文件中实现…

【MySQL】触发器trigger / 事件

文章目录 1. 触发器 trigger1.1 触发器命名1.2 new和old关键字1.3 案例&#xff1a;insert 触发器1.4 练习&#xff1a;delete 触发器1.5 查看触发器 show triggers1.6 使用触发器记录对表的操作 2 事件2.1 打开 / 关闭事件调度器2.2 创建事件 create event2.3 查看&#xff0c…

软件设计师——数据结构(二)

&#x1f4d1;前言 本文主要是【数据结构】——软件设计师——数据结构的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304…

5个免费、跨平台的SQLite数据库可视化工具

前言 SQLite是一个轻量级的嵌入式关系型数据库&#xff0c;目前最新的版本是 SQLite3。今天推荐5个实用的SQLite数据库可视化工具(GUI)&#xff0c;帮助大家更好的管理SQLite数据库。 什么是SQLite&#xff1f; SQLite是一个轻量级的嵌入式关系型数据库&#xff0c;它以一个…

dp中最短编辑距离的笔记(分析dp)

dp分析往往就是看最后一步的变化。 分析&#xff1a; 设a串长度为i&#xff0c;b串长度为j。题目要求为通过三种操作将a字符串转化为b字符串的最少次数。 删除操作&#xff1a; 把a[i]删除后a[1~i]和b[1~j]匹配&#xff0c;所以可以得到f[i - 1][j] 1&#xff0c;在此之前要先…

连锁管理系统是什么?有哪些功能?

连锁管理系统帮助门店实现POS收银管理、门店管理、采购订货管理、线上商城搭建、供应链管理一体化管理系统&#xff0c;快速提高门店管理效率&#xff0c;无论你的门店有多少&#xff0c;连锁总部都能通过系统随时洞察监管门店的所有运营数据。 连锁管理系统由&#xff1a;1个…

Eslint 要被 Oxlint替换了吗

什么是 Oxlint 由于最近的rust在前端领域的崛起,基于rust的前端生态链遭到rust底层重构,最近又爆出OxLint,是一款基于Rust的linter工具。Oxlint在国外前端圈引起热烈讨论,很多大佬给出了高度评价。 事实上,Oxlint 是 Oxc 项目旗下的一款产品,专为 JavaScript 和 TypeSc…

Java解决不同路径问题

Java解决不同路径问题 01 题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少…

linux修改mysql默认端口(很明智的选择因为后面会遇到各种问题)

1. 登录到mysql查看当前的端口号&#xff1a; show global variables like ‘port’; 2.编辑/etc/my.conf 文件添加port3506 这样的样式 保存退出&#xff1b; 内容: mysqld] port3506 datadir/var/lib/mysql socket/var/lib/mysql/mysql.sock usermysql # Disabling sy…

【CMU 15-445】Lecture 10: Sorting Aggregations Algorithms 学习笔记

Sorting & Aggregations Algorithms SortingTop-N Heap SortExternal Merge Sort2-WAY External Merge SortK-WAY External Merge SortDouble Buffering Optimization AggregationsSortingHashing 本节课主要介绍的是数据库系统中的排序算法以及聚合算法 Sorting 排序算法…