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 {
    @Autowired
    private 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:/";
    }

效果演示

 请添加图片描述

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

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

相关推荐

  1. GO语言基础案例讲解

    2023-12-17 08:44:01       35 阅读
  2. Freemarker

    2023-12-17 08:44:01       10 阅读
  3. springboot_3.2_freemark_基础环境配置

    2023-12-17 08:44:01       37 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-17 08:44:01       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-17 08:44:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-17 08:44:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-17 08:44:01       20 阅读

热门阅读

  1. 加州数据集介绍

    2023-12-17 08:44:01       37 阅读
  2. 安卓免Root做klipper上位机教程

    2023-12-17 08:44:01       58 阅读
  3. 如何进行软件测试和测试驱动开发(TDD)?

    2023-12-17 08:44:01       35 阅读
  4. CentOS新系统工具安装

    2023-12-17 08:44:01       51 阅读
  5. 如何下载 GitHub 私有仓库

    2023-12-17 08:44:01       34 阅读
  6. FlinkSQL的联结和函数

    2023-12-17 08:44:01       40 阅读
  7. 凑够五个字

    2023-12-17 08:44:01       44 阅读
  8. uniapp 消息队列 localstorage 消息队列用法

    2023-12-17 08:44:01       42 阅读
  9. Qt绘图控件的实现

    2023-12-17 08:44:01       40 阅读
  10. nlohmann-json使用

    2023-12-17 08:44:01       51 阅读