深入解析Freemarker模板引擎及其在Spring Boot中的高级整合


在这里插入图片描述

引言

Freemarker作为一款强大的模板引擎,与Spring Boot的整合能够极大地提升Web应用的开发效率和灵活性。本篇博客将深入探讨Freemarker的原理和核心概念,并重点介绍在Spring Boot项目中如何配置和应用Freemarker模板引擎。通过全面讲解与丰富示例,旨在帮助读者充分理解并熟练运用这一强大的技术组合。

1. Freemarker

1.1.什么是Freemarker

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

在这里插入图片描述

这种方式通常被称为MVC (模型 视图 控制器) 模式,对于动态网页来说,是一种特别流行的模式。 它帮助从开发人员(Java 程序员)中分离出网页设计师(HTML设计师)。设计师无需面对模板中的复杂逻辑, 在没有程序员来修改或重新编译代码时,也可以修改页面的样式。

而FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,它没有被绑定到 Servlet或HTML或任意Web相关的东西上。它也可以用于非Web应用环境中。

1.2 Freemarker模板组成部分

FreeMarker模板文件主要由如下4个部分组成:

  • 文本:直接输出的部分
  • 注释:使用<#-- … -->格式做注释,里面内容不会输出
  • 插值:即${…}或#{…}格式的部分,类似于占位符,将使用数据模型中的部分替代输出
  • FTL指令:即FreeMarker指令,全称是:FreeMarker Template Language,和HTML标记类似,但名字前加#予以区分,不会输出

FreeMarker与Web容器无关

FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP,故此FreeMarker不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java等各种文本文件。

在Java Web领域,FreeMarker是应用广泛的模板引擎,主要用于MVC中的view层,生成html展示数据给客户端,可以完全替代JSP。

总之,FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写,模板中没有业务逻辑,外部Java程序通过数据库操作等生成数据传入模板(template)中,然后输出页面。它能够生成各种文本:HTML、XML、RTF、Java源代码等等,而且不需要Servlet环境,并且可以从任何源载入模板,如本地文件、数据库等等。

1.3.优点

FreeMarker的诞生是为了取代JSP。虽然JSP功能强大,可以写Java代码实现复杂的逻辑处理,但是页面会有大量业务逻辑,不利于维护和阅读,更不利于前后台分工,容易破坏MVC结构,所以舍弃JSP,选择使用FreeMarker是大势所趋。当前很多企业使用FreeMarker取代JSP,FreeMarker有众多的优点,如下所示:

  • 很好地分离表现层和业务逻辑

JSP功能很强大,它可以在前台编写业务逻辑代码,但这也带来了一个很大的弊端——页面内容杂乱,可读性差,这将会大大增加后期的维护难度。而FreeMarker职责明确,功能专注,仅仅负责页面的展示,从而去掉了繁琐的逻辑代码。FreeMarker的原理就是:模板+数据模型=输出,模板只负责数据在页面中的表现,不涉及任何的逻辑代码,而所有的逻辑都是由数据模型来处理的。用户最终看到的输出是模板和数据模型合并后创建的。

  • 提高开发效率

众所周知,JSP在第一次执行的时候需要转换成Servlet类,之后的每次修改都要编译和转换。这样就造成了每次修改都需要等待编译的时间,效率低下。而FreeMarker模板技术并不存在编译和转换的问题,所以就不会存在上述问题。相比而言,使用FreeMarker可以提高一定的开发效率。

  • 明确分工

JSP页面前后端的代码写到了一起,耦合度很高,前端开发需要熟悉后台环境,需要去调试,而后台开发人员需要去做不熟悉的前端界面设计。对两者而言,交替性的工作需要花费一定的学习成本,效率低下。而使用FreeMarker后,前后端完全分离,大家各干各的,互不影响。

  • 简单易用,功能强大

FreeMarker支持JSP标签,宏定义比JSP Tag方便,同时内置了大量常用功能,比如html过滤,日期金额格式化等等。FreeMarker代码十分简洁,上手快,使用非常方便。

2. Spring Boot整合Freemarker

首先先把springboot项目启动配置好

2.1 配置

配置pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

配置yml

      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/**

然后在resource创建templates包,在templates包里面创建index.flt

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
${
   name}
</body>
</html>

PageController

package com.yuan.springboot2.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author 叶秋
 * @site
 * @company 卓京公司
 * @create 2023-12-13 19:17
 */
@Controller
public class PageController {
   

    @RequestMapping("/")
    public String home(Model model){
   
        model.addAttribute("name","zs");
        return "index";
    }

    @RequestMapping("/{path}")
    public String to(@PathVariable("path") String path){
   
        return path;
    }

    @RequestMapping("/{dir}/{path}")
    public String to(@PathVariable("dir") String dir,@PathVariable("path") String path){
   
        return dir+"/"+path;
    }
}

在这里插入图片描述

2.2 数据类型

在文本中确定字符串值的方法是看双引号,比如: "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>

3. 案例

pageController

package com.yuan.springboot2.Controller;

import com.yuan.springboot2.mapper.TBookMapper;
import com.yuan.springboot2.pojo.TBook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

/**
 * @author 叶秋
 * @site
 * @company 卓京公司
 * @create 2023-12-13 19:17
 */
@Controller
public class PageController {
   

    @Autowired
    private TBookMapper tBookMapper;
    @RequestMapping("/")
    public String home(Model model){
   
        List<TBook> tBooks = tBookMapper.selectAllbook();
        model.addAttribute("name","zs");
        model.addAttribute("tBooks",tBooks);
        return "index";
    }

    @RequestMapping("/{path}")
    public String to(@PathVariable("path") String path){
   
        return path;
    }

    @RequestMapping("/{dir}/{path}")
    public String to(@PathVariable("dir") String dir,@PathVariable("path") String path){
   
        return dir+"/"+path;
    }

    @RequestMapping("/del")
    public String del(TBook tBook){
   
        tBookMapper.deleteByPrimaryKey(Long.valueOf(tBook.getId()));
        return "redirect:/";
    }
    @RequestMapping("/add1")
    public String add1(TBook tBook){
   
        return "add1";
    }

    @RequestMapping("/edit")
    public String edit(TBook tBook){
   
        if(tBook.getId()==null){
   
            tBookMapper.insertSelective(tBook);
        }else{
   
            tBookMapper.updateByPrimaryKeySelective(tBook);
        }
        return "redirect:/";
    }

    @RequestMapping("/chaxun")
    public String chaxun(TBook tBook,Model model){
   
        if(tBook.getId()!=null){
   
            TBook tBook1 = tBookMapper.selectByPrimaryKey(Long.valueOf(tBook.getId()));
            model.addAttribute("tBook1",tBook1);
        }
        model.addAttribute("tBook1",tBook);
        return "add";
    }

}

add

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <#include "common.ftl">
</head>
<body>
    <form action="${ctx}/edit?id=${tBook1.id}" method="post">
        <div class="form-group" >
            <label for="itemName">书籍名称</label>
            <input type="text" class="form-control" name="bookname" id="bookname" value="${tBook1.bookname}" placeholder="">
        </div>
        <div class="form-group">
            <label for="itemName">书籍价格</label>
            <input type="text" class="form-control" name="price" id="price" value="${tBook1.price}" placeholder="">
        </div>
        <div class="form-group">
            <label for="itemName">书籍类型</label>
            <input type="text" class="form-control" name="booktype" id="booktype" value="${tBook1.booktype}" placeholder="">
        </div>
        <button type="submit" class="btn btn-primary">确定</button>
    </form>

<script>

</script>
</body>
</html>

index

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <#include "common.ftl">
</head>
<body>
${
   name}

<a href="${ctx}/a"></a>
<a href="${ctx}/add1">新增</a>
<#if tBooks??>
    <table class="table table-striped">
            <#list tBooks as b>
                <tr>
                <td>${
   b.id}</td>
                <td>${
   b.bookname} </td>
                <td>${
   b.price}</td>
                <td>${
   b.booktype}</td>
                <td><a href="${ctx}/del?id=${b.id}">删除</a></td>
                <td><a href="${ctx}/chaxun?id=${b.id}">修改</a></td>
                </tr>
            </#list>
    </table>

    <div class="container mt-5">


    </div>

</#if>
</body>
</html>

common

<#assign ctx="${springMacroRequestContext.contextPath}">
<link rel="stylesheet" href="${ctx}/bootstrap-3.4.1-dist/css/bootstrap.css">
<script src="${ctx}/jquery-3.6.1.js">
<script src="${ctx}/bootstrap-3.4.1-dist/js/bootstrap.js">



</script>

总结

总结部分将对本篇博客进行回顾,并强调Freemarker模板引擎在Spring Boot中的重要性和应用前景。通过深入的讲解和丰富的实例,本篇博客旨在帮助读者掌握Freemarker模板引擎的核心概念和应用技巧,并能够灵活应用于实际的Web开发项目中。

最近更新

  1. TCP协议是安全的吗?

    2023-12-14 09:26:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-14 09:26:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-14 09:26:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-14 09:26:02       20 阅读

热门阅读

  1. prim算法求最小生成树

    2023-12-14 09:26:02       33 阅读
  2. QEMU源码全解析 —— virtio(6)

    2023-12-14 09:26:02       47 阅读
  3. Android WebView 响应缓存 笔记

    2023-12-14 09:26:02       44 阅读
  4. 【工具】VUE 前端列表拖拽功能代码

    2023-12-14 09:26:02       44 阅读
  5. 部署Openstack HA

    2023-12-14 09:26:02       33 阅读
  6. 7、无消息丢失配置怎么实现?

    2023-12-14 09:26:02       27 阅读
  7. 文本生成图片 学习笔记

    2023-12-14 09:26:02       43 阅读
  8. Node.js模块化的基本概念和分类及使用方法

    2023-12-14 09:26:02       31 阅读