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.hqwc.cn/news/282284.html

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

相关文章

Azure Machine Learning - 提示工程简介

OpenAI的GPT-3、GPT-3.5和GPT-4模型基于用户输入的文本提示工作。有效的提示构造是使用这些模型的关键技能&#xff0c;涉及到配置模型权重以执行特定任务。这不仅是技术操作&#xff0c;更像是一种艺术&#xff0c;需要经验和直觉。本文旨在介绍适用于所有GPT模型的提示概念和…

网络(十)ACL和NAT

前言 网络管理在生产环境和生活中&#xff0c;如何实现拒绝不希望的访问连接&#xff0c;同时又要允许正常的访问连接&#xff1f;当下公网地址消耗殆尽&#xff0c;且公网IP地址费用昂贵&#xff0c;企业访问Internet全部使用公网IP地址不够现实&#xff0c;如何让私网地址也…

前端面试(5)

1、移动端适配 1.1、设置meta缩放比例&#xff0c;将设备窗口调整为设计图大小。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,initial-sc…

基于ssm的简单学校课程管理系统的设计与实现(源码+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于ssm的简单学校课程管…

C++之程序生成

一、C的发展史 截止到2023年12月&#xff0c;C已经更新了很多版本&#xff0c;并在每个版本中修复了bug和添加了新的特性&#xff0c;ISO C委员会每三年会对C进行一次更新&#xff1a; C98&#xff1a;于1998年发布&#xff0c;是最早的国际标准化版本。它包含了面向对象编程…

可替代LM5145,5.5V-100V Vin同步降压控制器_SCT82A30

SCT82A30是一款100V电压模式控制同步降压控制器&#xff0c;具有线路前馈。40ns受控高压侧MOSFET的最小导通时间支持高转换比&#xff0c;实现从48V输入到低压轨的直接降压转换&#xff0c;降低了系统复杂性和解决方案成本。如果需要&#xff0c;在低至6V的输入电压下降期间&am…

GMP原理与调度

GMP是Go语言运行时(runtime)层面的实现,是go语言自己实现的一套调度系统,区别于操作系统调度OS线程 Golang"调度器"的由来 单进程时代不需要调度器 我们知道,一切的软件都是跑在操作系统上,真正用来干活(计算)的是CPU,早期的操作系统每个程序就是一个进程,直到一个…

Yapi详细安装过程(亲测可用)

1. 前置条件 1、Git 2、NodeJs&#xff08;7.6&#xff09; 3、Mongodb&#xff08;2.6&#xff09; 2. NodeJs的安装 1、获取资源 curl -sL https://rpm.nodesource.com/setup_8.x | bash - 2、安装NodeJS yum install -y nodejs 3、查看NodeJs和Npm node -v npm -v…

学习MS Dynamics AX 2012编程开发 2. X++语言

X是用于构建Dynamics AX功能的编程语言。X是一种与C类似的面向对象编程语言。 完成本章后&#xff0c;您将能够理解X语言&#xff1b;您将知道可用的数据类型是什么&#xff0c;如何创建各种循环&#xff0c;如何比较和操作变量&#xff0c;在哪里可以找到预定义的函数&#x…

LCR 181. 字符串中的单词反转

解题思路&#xff1a; class Solution {public String reverseMessage(String message) {message message.trim(); // 删除首尾空格int j message.length() - 1, i j;StringBuilder res new StringBuilder();while (i > 0) {while (i >…

PyQt6 QScrollBar滚动条控件

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计48条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

6.23删除二叉搜索树中的节点(LC450-M)

算法&#xff1a; 一共有五种可能的情况&#xff1a; 第一种情况&#xff1a;没找到删除的节点&#xff0c;遍历到空节点直接返回了找到删除的节点 第二种情况&#xff1a;左右孩子都为空&#xff08;叶子节点&#xff09;&#xff0c;直接删除节点&#xff0c; 返回NULL为根…