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'。这两种形式是等同的。 如果文本自身包含用于字符引用的引号 ( "')或反斜杠时, 应该在它们的前面再加一个反斜杠;这就是转义。 转义允许直接在文本中输入任何字符, 也包括换行。

java 复制代码
${"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 值。

java 复制代码
<#-- 如果值不存在,直接输出会报错 -->
<#--${str}-->
<#-- 使用!,当值不存在时,默认显示空字符串 -->
${str!}<br>
<#-- 使用!"xx",当值不存在时,默认显示指定字符串 -->
${str!"这是一个默认值"}<br>
<#-- 使用??,判断字符串是否为空;返回布尔类型。如果想要输出,需要将布尔类型转换成字符串 -->
${(str??)?string}<br>

2.1.2.数值

输入不带引号的数字就可以直接指定一个数字, 必须使用点作为小数的分隔符而不能是其他的分组分隔符。

java 复制代码
${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中布尔类型不能直接输出;如果输出要先转成字符串

java 复制代码
${flag?c}<br>
${flag?string}<br>
${flag?string("yes","no")}<br>

2.1.4.日期

日期变量可以存储和日期/时间相关的数据。

在freemarker中日期类型不能直接输出;如果输出要先转成日期型或字符串

日期格式输出:

输出方式 说明
?date 年月日
?time 时分秒
?datetime 年月日时分秒
?string("自定义格式") 指定格式
java 复制代码
<#-- 输出日期格式 -->
${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)!

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

java 复制代码
${message!"default Value."}
<#assign message="Zking">
${message!"default Value."}

输出结果如下:

java 复制代码
default Value.
Zking

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

java 复制代码
(${message!})
<#assign message = "Zking">
(${message!})
  • 不存在值检测操作符

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

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

java 复制代码
<#if name??>
  存在
<#else>
  不存在
</#if>
  • exists用在逻辑判断

exists用作逻辑判断,返回的是true或者false。

java 复制代码
<#if name?exists>
    ${name}
</#if>
  • if_exists用来打印东西

if_exists用于输出的时候,如果存在则输出,不存在就输出空字符串。

java 复制代码
${name?if_exists}

2.2.2.assign

使用该指令你可以创建一个新的变量, 或者替换一个已经存在的变量。语法格式如下:

java 复制代码
<#assign name1=value1 name2=value2 ... nameN=valueN>
或
<#assign name>
  capture this
</#assign>

案例演示:

java 复制代码
<#-- 创建一个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 是可选的。

java 复制代码
<#if condition>
  ...
<#elseif condition2>
  ...
<#elseif condition3>
  ...
...
<#else>
  ...
</#if>

2.2.4.list

list 指令执行在 list 开始标签和 list 结束标签 ( list 中间的部分) 之间的代码, 对于在序列(或集合)中每个值指定为它的第一个参数。 对于每次迭代,循环变量将会存储当前项的值。

循环变量仅仅存在于 list 标签体内。 而且从循环中调用的宏/函数不会看到它(就像它只是局部变量一样)。

java 复制代码
<#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: 循环变量的名称 (不是表达式)

java 复制代码
<#list arrs as item>
    ${item}
<#else>
    集合是空的
</#list>

2.2.5.include

可以使用它在你的模板中插入另外一个 FreeMarker 模板文件 (由 path 参数指定)

java 复制代码
<#list arrs as item>
    ${item}
<#else>
    集合是空的
</#list>

这里:

  • path: 要包含文件的路径;

  • options: 一个或多个这样的选项: encoding=encoding, parse=parse

    • encoding: 算作是字符串的表达式

    • parse: 算作是布尔值的表达式(为了向下兼容,也接受一部分字符串值)

    • ignore_missing: 算作是布尔值的表达式

java 复制代码
<h1>Hello Freemarker</h1>
<#include "/common/head.ftl">

三、Freemarker综合案例

3.1.SpringBoot集成Freemarker

配置pom.xml,引入依赖

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

application.yml或application.properties文件,添加以下配置

XML 复制代码
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

XML 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
欢迎来到FreeMarker所编写的页面!!
</body>
</html>

我们再写一个controller类进行访问

java 复制代码
@Controller
public class HomeController {
    @RequestMapping("/")
    public String index(){
        return "index";
        //这里的return的字符串和页面名称对应
    }

}

访问成功!!

3.2.查询(Select)

为了让我们的页面更加美观加入bootstrap框架

创建一个公共页面用于引用资源

java 复制代码
<#--运行路径-->
<#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代码

java 复制代码
<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代码

java 复制代码
@RestController
@RequestMapping("/book")
public class TBookController {
    @Autowired
    private TBookService tbookservice;

    @RequestMapping("/list")
    public Object list(PageBean pageBean) {
        PageHelper.startPage(pageBean.getPage(),pageBean.getRows());
        return tbookservice.selectBook(pageBean);

    }
}

效果演示

3.3.新增(Add)

这里写一个共用页面,用于新增和修改

java 复制代码
<!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代码

java 复制代码
  /*根据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代码如下

java 复制代码
   /*修改书籍*/
    @RequestMapping("/edit")
    public String edit(TBook book){
        tbookservice.updateByPrimaryKey(book);
        /*重定向到查询的方法*/
        return "redirect:/";
    }

效果演示

3.5.删除(Delete)

删除就是个a标签跳转

java 复制代码
 <a href="${ctx}/delete?id=${b.id}">删除</a>

controller代码

java 复制代码
   /*删除书籍*/
    @RequestMapping("/delete")
    public String delete(TBook book){
        Long id=Long.parseLong(book.getId()+"");
        tbookservice.deleteByPrimaryKey(id);
        /*重定向到查询的方法*/
        return "redirect:/";
    }

效果演示

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

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

相关推荐
白总Server1 小时前
API架构解说
java·网络·jvm·物联网·安全·web安全·架构
rosener2 小时前
pom中无法下载下来的类外部引用只给一个jar的时候
java·jar
黄名富2 小时前
SQL 语句优化及编程方法
java·数据库·mysql
水w2 小时前
VuePress v2 快速搭建属于自己的个人博客网站
开发语言·前端·vue·vuepress
follycat3 小时前
ISCTF2024
java·网络·数据库·学习·网络安全·python3.11
不爱说话郭德纲3 小时前
理解 Object.create 并正确使用 Object.create
前端·javascript·vue.js·es6·html5
baozhengw3 小时前
IntelliJ+SpringBoot项目实战(七)--在SpringBoot中整合Redis
java·spring boot·redis
羊小猪~~3 小时前
前端入门一之ES6--递归、浅拷贝与深拷贝、正则表达式、es6、解构赋值、箭头函数、剩余参数、String、Set
开发语言·前端·javascript·css·正则表达式·html·es6
花弄影15214 小时前
vue之axios根据某个接口创建实例,并设置headers和超时时间,捕捉异常
前端·javascript·vue.js
服务端相声演员4 小时前
IOException: Broken pipe与IOException: 远程主机强迫关闭了一个现有的连接
java·服务器·网络