springboot集成freemarker,生成静态化页面

1.简介

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,它没有被绑定到 Servlet或HTML或任意Web相关的东西上。它也可以用于非Web应用环境中
freemarker并不关心数据的来源,只是根据模板的内容,将数据模型在模板中显示并输出文件(通常为html,也可以生成其它格式的文本文件)。
springBoot虽然支持JSP,但是官方不建议使用,所以要学习下freemarker。
image.png
🤔总的来说,模板和数据模型是FreeMarker来生成输出(比如第一个展示的HTML)所必须的:
模板 + 数据模型 = 输出
中文手册:http://freemarker.foofun.cn/toc.html

2.springboot集成freemarker

2.1.创建springboot web项目,并引入freemarker的依赖

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

2.2.编写配置文件
还有很多其他的配置选项,但是一般不需要配置太多,配置个后缀名就够了,需要其他的再添

server:
  port: 8080
spring:
  freemarker:
    #开启 freemarker 功能,默认为true
    enabled: true
    #页面模板后缀名
    suffix: .ftl
    #页面模板位置(默认为 classpath:/templates/)
    template-loader-path: classpath:/templates/
    #..................

2.3.在resources创建包templates,此目录为freemarker的默认模板存放目录。
image.png
2.4.编写模板,文件后缀名为 .ftl
模板(FTL编程)是由如下部分混合而成的:

  • 文本:文本会照着原样来输出。
  • 插值:这部分的输出会被计算的值来替换。插值由 ${ and } 所分隔。
  • FTL 标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示, 而且不会打印在输出内容中。
  • 注释:注释和HTML的注释也很相似,但它们是由<#-- 和 --> 来分隔的。注释会被FreeMarker直接忽略, 更不会在输出内容中显示。

支持el表达式,区分大小写
image.png
5.controller层
return的结果要和模板名相同

@Controller
public class FMController {

    @RequestMapping("/hello")
    public String helloPage(Model model){
        model.addAttribute("name", "lvhan");
        return "hello";
    }
}

启动后:
image.png
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️

3.freemarker数据类型

  • 布尔型: 等价于 Java 的 boolean 类型,不同的是不能直接输出,可转换为字符串输出
  • 日期型: 等价于java 的 Date 类型,不同的是不能直接输出,需要转换成字符串再输出
  • 数值型:等价于java 中的 int,float,double 等数值类型,可以转换为: 数值型(默认)、货币型、百分比型的形式
  • 字符型: 等价于java 中的字符串,有很多内置函数
  • sequence (序列)类型: 等价于java 中的数组,List,Set 等集合类型
  • hash 类型: 等价于java 中的 Map 类型

3.1.布尔型

在controller中准备数据

model.addAttribute("flag",true);

写入模板

<#--布尔类型不能直接展示,要转换为字符串-->
<h1>布尔类型的展示:</h1>
<#--方式一:?c-->
${flag?c} <br>
<#--方式二:?then("true时对应的文本","false时对应的文本")-->
${flag?then("yes","no")} <br>

image.png

布尔类型不能直接展示,要转换为字符串

3.2.日期型

在controller中准备数据

model.addAttribute("date",new Date());

写入模板

<#--日期类型不能直接展示,要转换为字符串或者日期型-->
<h1>日期类型的展示:</h1>
<#--年月日?date-->
${date?date} <br>
<#--时分秒?time-->
${date?time} <br>
<#--年月日时分秒?datetime-->
${date?datetime} <br>
<#--指定格式,y: m: d: h: m: s:秒-->
${date?string("yyyy年mm月dd日 hh时mm分ss秒")} <br>

image.png

日期类型不能直接展示,要转换为字符串或者日期型

可以指定日期的显示格式

3.3.日期型

在controller中准备数据

model.addAttribute("age",19);
model.addAttribute("salary",18000);
model.addAttribute("avg",0.467);

写入模板

<h1>数值类型的展示:</h1>
<#--数值类型可以直接输出-->
${age}${salary}${avg}  <br>
<#--转字符串  ?c普通字符串-->
${age?c}  <br>
<#--货币型字符串  ?string.currency-->
${salary?string.currency}  <br>
<#--百分比型字符串  ?string.percent 会自动四舍五入-->
${avg?string.percent}  <br>
<#--保留浮点数指定小数位-->
${avg?string["0.#"]}  <br>

image.png

数值类型可以直接输出,也可以转为货币型和百分比型,还能规定保留几位小数

3.4.字符串型

在controller中准备数据

model.addAttribute("str01","Hello2025");
model.addAttribute("str02","hi2025");

写入模板

<h1>字符串类型的展示:</h1>
<#--字符串类型可以直接输出-->
${str01}----${str02} <br>
<#--截取字符串 (左闭右开)?substring(start,end)-->
${str01?substring(1,4)} <br>
<#--首字母小写输出 ?uncap_first-->
${str01?uncap_first} <br>
<#--首字母大写输出 ?cap_first-->
${str02?cap_first} <br>
<#--字母转小写输出 ?lower_case-->
${str01?lower_case} <br>
<#--字母转大写输出 ?upper_case-->
${str02?upper_case} <br>
<#--获取字符串长度-->
${str02?length} <br>
<#--是否以指定字符开头,返回布尔类型,需要转字符串-->
${str01?starts_with("H")?string} <br>
<#--是否以指定字符结尾,返回布尔类型,需要转字符串-->
${str01?ends_with("25")?string} <br>
<#--获取指定字符的索引-->
${str02?index_of("i")} <br>
<#--去除字符串前后空格-->
${str02?trim} <br>
<#--替换指定字符串-->
${str02?replace("hi","cum")} <br>

字符串型可以直接输出,有很多方法

image.png

字符串空值情况处理:
在controller中准备数据,其中a值为null,b为空字符串

model.addAttribute("a",null);
model.addAttribute("b","");

写入模板

<h2>字符串空值情况处理</h2>
<#--如果字符串为null会报错,变量不存在也会报错,为空可以-->
${b} <br>
<#--!:指定缺失变量的默认值-->
${a!"yes"} <br>
<#--??:判断变量是否存在,返回布尔值,需要转为字符串-->
${b???string}

如果字符串为null会报错,变量不存在也会报错,为空可以

!:指定缺失变量的默认值

??:判断变量是否存在,返回布尔值,需要转为字符串

3.5.序列类型

在controller中准备数据

String[] strArr=new String[]{"小男娘1","小男娘2","小男娘3"};
model.addAttribute("strArr",strArr);

User[] userArr=new User[]{new User(18,"小男娘1"),new User(21,"小男娘2"),new User(19,"小男娘3")};
model.addAttribute("userArr",userArr);

写入模板

public class User {
    private int age;
    private String name;

    public User() {
    }

    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
<h1>序列类型的展示:</h1>
<#list strArr as str>
    员工:${str} -- 索引: ${str?index} <br>
</#list>
--------<br>
获取序列的长度:${strArr?size}<br>
获取序列的第一个元素:${strArr?first}<br>
获取序列的最后一个元素:${strArr?last}<br>
--------<br>
倒序输出序列<br>
<#list strArr?reverse as str>
    员工:${str} -- 索引: ${str?index} <br>
</#list>
--------<br>
升序输出<br>
<#list strArr?sort as str>
    员工:${str} -- 索引: ${str?index} <br>
</#list>
--------<br>
降序输出<br>
<#list strArr?sort?reverse as str>
    员工:${str} -- 索引: ${str?index} <br>
</#list>
--------<br>
<br>
<#list userArr as user>
    员工:${user.name} --年龄:${user.age}-- 索引: ${user?index} <br>
</#list>
--------<br>
对user数组按照年龄进行排序<br>
<#list userArr?sort_by("age") as user>
    员工:${user.name} --年龄:${user.age}-- 索引: ${user?index} <br>
</#list>

image.png

<#list 数组名 as 变量名></#list>

list和set差不多类似的指令

3.6.hash类型

对应java里的map
在controller中准备数据

Map<String,String> citymap=new HashMap<>();
citymap.put("beijing","北京");
citymap.put("shanghai","上海");
citymap.put("shenzhen","深圳");
model.addAttribute("citymap",citymap);

写入模板

<h1>hash类型的展示:</h1>
<#--遍历key得到value-->
<#list citymap?keys as key>
    城市:${key} -- ${citymap[key]} <br>
</#list>
--------<br>
<#--直接遍历value-->
<#list citymap?values as value>
    城市:${value} <br>
</#list>

image.png

可以直接遍历key再得到value,也可以直接遍历value

4.freemarker常用指令

4.1.assign指令

有时候我们需要在页面中定义数据使用,那么就需要assign指令
使用**assign**指令可以创建一个新的变量,或者替换一个已经存在的变量
写入模板

<#--自定义变量-->
<#assign str="lvhan">
${str}<br>

<#--定义多个变量-->
<#assign num=1 names=["a","b","c","d","e","f"]>
${num}<br>
${names?join("~~~")}<br>

image.png
使用join函数把数组中的元素遍历出来,并用join函数中的符号把他们分隔开

4.2.逻辑判断指令

<#if>,<#elseif>,<#else>
写入模板

<h1>逻辑判断指令:</h1>
<#assign score=72>
<#if score lt 60>
    不及格!
    <#elseif score == 60>
    及格!
    <#elseif score gt 60 && score lt 80>
    良好!
    <#else>
    优秀!
</#if><br>

<#if b??>
    数据存在
    <#else>
    数据不存在
</#if>

image.png

4.3.list遍历指令

<h1>list遍历指令:</h1>
<#assign names=["a","b","c","d"]>
<#if names??>
    <#list names as name>
        ${name}
    </#list>
</#if> <br>

<#assign names2=[]>
<#list names2 as name>
    ${name}
    <#else>
    您需要遍历的数组中没有元素!
</#list>

image.png

当list中没有选项时,执行else指令

4.4.自定义指令 宏 macro

相当于java里的方法
<#macro 指令名></#macro>
调用:<@指令名></@指令名>

占位命令:<#nested>,相当于占位符,一般结合macro指令一起用
在调用时,标签内写占位的内容,<@指令名>占位的内容</@指令名>

<h1>自定义指令  宏:</h1>
<#--就像是java里的方法-->
<#macro a>
    <h3>The boy with the thorn in his side</h3>
</#macro>
<@a></@a>

<#macro b num1 num2>
    ${num1} ----- ${num2}
</#macro>
<@b num1=100 num2=200></@b><br>

<#macro c num>
    <#list 1..num as i>
        <#list 1..i as j>
            ${i} * ${j} = ${i * j} &nbsp;
        </#list>
        <br>
    </#list>
</#macro>
<@c 7></@c>

<#macro d>
    公司: <#nested >
</#macro>
<@d>美团</@d><br>
<@d>饿了吗</@d>

image.png

4.5.import导入指令

新建一个模板文件,里面写入macro指令
image.png
原来的模板文件:

<h1>import导入指令:</h1>
common里的宏指令:
<#import "common.ftl" as common>
<@common.c 9></@common.c>

image.png

相当于java中的包,导入别的包使用

4.6.include包含指令

作用:在模板中包含另一个模板(可以是html,ftl,txt等)
可以使用 include 指令在你的模板中插入另外一个 FreeMarker 模板文件。被包含模板的输出格式是在 include 标签出现的位置插入的。 被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。
image.png

<h1>include包含指令:</h1>
<#include "testInclude.ftl">
<#include "testInclude.html">
<#include "testInclude.txt">

image.png

5.运算符

5.1.算术运算符

‘+’,‘-’,‘*’,‘/’
加减乘除都跟其他的一样,但是要写在插值里才有用

5.2.逻辑运算符

‘&&’,‘||’,‘!’
跟java的一样,且 或 非

5.3.比较运算符

  • gt:大于
  • lt:小于
  • gte:大于等于
  • lte:小于等于
  • ==:等于
  • !=:不等于

5.4.空值运算符

看上边字符串的空值处理

6.freemarker静态化

用户访问动态页面时都需要通过ajax发送请求查询数据库获取动态数据进行展示,但是这页面的访问量如果比较大且数据库中的数据变化频率并不高,这就会对数据库造成了很大的访问压力。如何对数据库减压并提高系统运行性能呢?答案就是页面静态化。
页面静态化其实就是将原来的动态网页(例如通过ajax请求动态获取数据库中的数据并展示的网页)改为通过静态化技术生成的静态网页,这样用户在访问网页时,服务器直接给用户响应静态html页面,没有了动态查询数据库的过程。

生成工具类

@Component
public class GenUtil {

    /**
     * 根据模板,利用提供的数据,生成文件
     *
     * @param sourceFile 模板文件,带路径
     * @param data       数据
     * @param aimFile    最终生成的文件,若不带路径,则生成到当前项目的根目录中
     */
    public void gen(String sourceFile, String aimFile, Map<String, Object> data) {
        try {
            //创建Freemarker配置实例
            Configuration conf = new Configuration();
            //加载模板文件
            Template template = conf.getTemplate(sourceFile);
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aimFile), StandardCharsets.UTF_8));
            template.process(data, out);
            out.flush();
            out.close();
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
    }

}

生成模板

<html>
<head>
<title>${title}</title>
</head>
<body>

<h2>${msg}</h2>
</body>
</html>

测试类

@SpringBootTest
public class GenTemplateTest {
    @Resource
    private GenUtil genUtil;

    @Test
    public void testGen() {
        Map<String, Object> map = new HashMap<>();
        map.put("title", "Crawling King Snake -- The Doors");
        map.put("msg", "Get on out there on your hands and knees, baby");
        genUtil.gen("src\\main\\resources\\templates\\genTemplate.ftl", "src/main/resources/templates/testGen.html", map);
    }
}

结果
image.png
运行测试代码发现在当前项目的templates目录下生成了一个testGen.html的文件。

如果你遇到这样的问题
Java HotSpot™ 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
image.png
可以看我的另一篇博客https://blog.csdn.net/PiggyOne123/article/details/136357760?spm=1001.2014.3001.5501

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用 Spring Boot 中的 Freemarker 模板引擎来生成静态 HTML 页面,然后让前端通过 HTTP 请求访问这些页面。 下面是一个简单的示例: 1. 在 Spring Boot 项目中添加 Freemarker 依赖,比如: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> ``` 2. 在 application.properties 文件中配置 Freemarker 相关属性,比如: ``` # 模板文件所在目录 spring.freemarker.template-loader-path=classpath:/templates/ # 静态文件生成目录 spring.freemarker.static-file-location=file:/path/to/static/files/ ``` 3. 创建一个 Freemarker 模板文件,比如 `/templates/index.ftl`: ``` <!DOCTYPE html> <html> <head> <title>My Page</title> </head> <body> <h1>Hello, ${name}!</h1> </body> </html> ``` 4. 创建一个 Spring Controller 类,生成静态 HTML 页面: ``` @Controller public class MyController { @Autowired private Configuration freemarkerConfig; @GetMapping("/generate") public void generateHtml(@RequestParam("name") String name, HttpServletResponse response) throws Exception { Template template = freemarkerConfig.getTemplate("index.ftl"); Map<String, Object> model = new HashMap<>(); model.put("name", name); StringWriter stringWriter = new StringWriter(); template.process(model, stringWriter); String html = stringWriter.toString(); response.setContentType("text/html;charset=UTF-8"); response.getWriter().write(html); response.getWriter().flush(); response.getWriter().close(); } } ``` 5. 启动 Spring Boot 应用,访问 `http://localhost:8080/generate?name=World`,即可生成静态 HTML 页面,并在浏览器中显示。 注意:在实际生产环境中,你需要将生成静态 HTML 页面放到一个静态文件目录中(比如 `/path/to/static/files/`),然后让前端通过 HTTP 请求访问这些页面

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值