如何在Spring Boot中使用Freemarker

背景

最近项目中需要用到文书生成,通过参数生成HTML标签,以供前端展示。最后使用Freemarker的FTL文件来实现。本文正好梳理下Freemarker常见的使用方式、标签,方便大家了解。

引入与配置

首先引入依赖包。

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

因为Freemarker每次都会输出完整的文件内容,可以通过配置日志输出级别限制,防止日志文件过大。

# 日志配置
logging:
  level:
    freemarker.template.utility: ERROR

创建工具类

@Slf4j
public class FtlUtil {

    public static String generateHtml(Map<String, Object> dataModel, String templatePath) {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
        cfg.setClassForTemplateLoading(FtlUtil.class, "/templates");
        try {
            Template template = cfg.getTemplate(templatePath, "UTF-8"); // 模板文件的路径,例如 "test/thisTest.ftl"
            StringWriter stringWriter = new StringWriter();
            template.process(dataModel, stringWriter);
            return stringWriter.toString();
        } catch (IOException | TemplateException e) {
            log.error("[FTL处理] 生成HTML失败!", e);
            return null;
        }
    }
}

创建FTL文件

根据路径,FTL文件创建在/src/main/resources/templates目录下,可以创建子目录。

使用方法

package com.melon.module.land.one.util;

import com.melon.basic.common.entity.admin.UserEntity;
import com.melon.basic.common.exception.MelonException;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class FtlUtil {
    public static void main(String[] args) {
        Map<String, Object> dataModel = new HashedMap<>();
        // 基本使用 ${baseUse}
        // 空值不报错 ${baseUse!}
        dataModel.put("baseUse", "基础使用示例");

        // 对象使用 ${objUse.userName}
        // 空值不报错 ${objUse.userName!}
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername("MyUserName");
        dataModel.put("objUse", userEntity);

        // 判断使用 <#if ifUse?has_content>${ifUse}<#else>没有内容</#if>
        dataModel.put("ifUse", "maybeNull");

        // 列表使用 <#list listUse as one>#{one.userName}</#list>
        // 空值不报错 <#list listUse as one>#{one.userName!}</#list>
        UserEntity u1 = new UserEntity();
        userEntity.setUsername("MyUserName-1");
        UserEntity u2 = new UserEntity();
        userEntity.setUsername("MyUserName-2");
        List<UserEntity> userList = new ArrayList<>();
        userList.add(u1);
        userList.add(u2);
        dataModel.put("listUse", userList);

        // 静态方法使用 ${ftlUtil.test(1, baseUse)},需要有FtlUtil.test(Integer, String)方法
        dataModel.put("ftlUtil", new FtlUtil());
        String generatedHtml = generateHtml(dataModel, "test/thisTest.ftl");
        System.out.println(generatedHtml); // 打印生成的HTML
    }
}

总结

Freemarker官方网站:
https://freemarker.apache.org/index.html

整体使用还算简单,最麻烦的是方法调用,还有空值处理,判断逻辑之类的,稍后不慎程序就会报错,十分麻烦。该技术方案是否适用具体可根据实际应用场景选择。

消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息