spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成

文章目录

  • 概述
  • 引入相关依赖
  • 第一个实例程序
  • 代码中使用freemarker
  • 通用freemarker工具类
  • freemarker语法demo

概述

FreeMarker是一款用java语言编写的模版引擎,它虽然不是web应用框架,但它很合适作为web应用框架的一个组件。

特点:

  1. 轻量级模版引擎,不需要Servlet环境就可以很轻松的嵌入到应用程序中
  2. 能生成各种文本,如html,xml,java,等
  3. 入门简单,它是用java编写的,很多语法和java相似

工作原理:
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第1张图片

引入相关依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>


    <dependency>
        <groupId>org.webjarsgroupId>
        <artifactId>bootstrapartifactId>
        <version>3.3.5version>
    dependency>
    <dependency>
        <groupId>org.webjarsgroupId>
        <artifactId>jqueryartifactId>
        <version>3.1.1version>
    dependency>
    
        
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-freemarkerartifactId>
    dependency>

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>${lombok.version}version>
        <scope>providedscope>
    dependency>

    <dependency>
        <groupId>org.testnggroupId>
        <artifactId>testngartifactId>
        <version>${testng.version}version>
        <scope>testscope>
    dependency>
dependencies>

配置文件:

server:
  port: 8095
spring:
  freemarker:
    template-loader-path: ["classpath:/templates/"] # 设置ftl文件路径
    cache: false  # 设置页面缓存
    charset: UTF-8 # 设置页面编码格式
    check-template-location: true
    content-type: text/html # 设置文档类型
    expose-request-attributes: false
    expose-session-attributes: false
    request-context-attribute: request #可以让Freemarker获取项目根路经
    suffix: .ftl # 设置模板后缀名

  # 设置静态文件路径,js,css等
  mvc:
    static-path-pattern: /static/**

第一个实例程序

编写index.ftl文件:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
this is index page
body>
html>

编写welcome.ftl文件:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    Hello ${name} from resource freemark!
body>
html>

编写controller

//Tips: 由于要返回模板页面文件,所以我们只能使用@Controller 而不可以使用@RestController
//@RestController
@Controller
@Slf4j
public class StuController {

    @RequestMapping(value = "/")
    public String index() {
        return "index";
    }

    @RequestMapping(value = "/welcome")
    public String hello1(Model m){
        m.addAttribute("name", "spring-boot11");
        return "welcome";
    }

    @RequestMapping("hello")
    public ModelAndView hello(ModelAndView m){
        m.addObject("name", "spring-boot");
        m.setViewName("welcome");
        return m;
    }
}

启动服务,测试:
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第2张图片
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第3张图片
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第4张图片
接下来先写一个复杂一点的

@RequestMapping("sysUser")
public String user(Model m){
    List<SysUser> list = new ArrayList<>();
    SysUser u1 = new SysUser(0001, "hello1", "11111111111111111");
    SysUser u2 = new SysUser(0002, "hello2", "22222222222222222");
    SysUser u3 = new SysUser(0003, "hello3", "33333333333333333");
    list.add(u1);
    list.add(u2);
    list.add(u3);
    m.addAttribute("userList", list);
    m.addAttribute("sysUser", "SysUser");
    return "sysUser/users";
}

src\main\resources\templates\sysuser目录下编写users.ftl:


<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <meta content="text/html;charset=utf-8">meta>
        <title>Hello World!title>
        <#--<script src="https://code.jquery.com/jquery-3.3.1.min.js">script>-->
        <script src="webjars/jquery/3.1.1/jquery.min.js">script>
        <script src="webjars/bootstrap/3.3.5/js/bootstrap.min.js">script>
        <link rel="stylesheet" href="webjars/bootstrap/3.3.5/css/bootstrap.min.css" />
    head>
<body>
<div class="container">
        <table class="table">
            <caption>${sysUser}caption>
            <thead>
                <tr>
                    <th>First Nameth>
                    <th>Last Nameth>
                    <th>User Nameth>
                tr>
            thead>
            <tbody>
                <tr>
                    <td>aehyoktd>
                    <td>leotd>
                    <td>@aehyoktd>
                tr>
                <tr>
                    <td>lynntd>
                    <td>thltd>
                    <td>@lynntd>
                tr>
                <#list userList as user>
                <tr>
                    <td>${user.id}td>
                    <td>${user.name}td>
                    <td>${user.phone}td>
                tr>
                   #list>

            tbody>
        table>
    div>
body>
html>

启动服务,访问:
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第5张图片
至此,项目目录结构如下:
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第6张图片

代码中使用freemarker

上面都是讲的返回页面使用freemarker,有时候可能会需要在代码中使用到freemarker进行模板的运算。接下来写个demo。
编写一个测试类

package com.example.service;

import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class FreemarkerDemo {

    private static final String TEMPLATE_PATH = "springboot-freemarker/src/main/java/com/example/service";
    private static final String CLASS_PATH = "springboot-freemarker/src/main/java/com/example/service";

    public static void main(String[] args) {
        // step1 创建freeMarker配置实例
        Configuration configuration = new Configuration();
        Writer out = null;
        try {
            // step2 获取模版路径
            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
            // step3 创建数据模型
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("classPath", "com.example.service");
            dataMap.put("className", "AutoCodeDemo");
            dataMap.put("helloWorld", "通过简单的 <代码自动生产程序> 演示 FreeMarker的HelloWorld!");
            // step4 加载模版文件
            Template template = configuration.getTemplate("hello.ftl");
            // step5 生成数据
            File docFile = new File(CLASS_PATH + "\\" + "AutoCodeDemo.java");
            if (!docFile.exists()) {
                docFile.createNewFile();
            }
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
            // step6 输出文件
            template.process(dataMap, out);
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^AutoCodeDemo.java 文件创建成功 !");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != out) {
                    out.flush();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}

编写hello.ftl

package ${classPath};

public class ${className} {

    public static void main(String[] args) {
        System.out.println("${helloWorld}");
    }
}

执行FreemarkerDemo的main方法,会在com.example.service包下生成一个新的类:AutoCodeDemo.java

通用freemarker工具类

上面的方式可以在代码中使用了,但是不够友好,侵入性大。下面使用通用的工具类来实现相关功能:
编写一个freemarker的service作为工具类:

package com.example.service;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class FreemarkerService {
    private Logger logger = LoggerFactory.getLogger(FreemarkerService.class);
    private Map<String, Template> templateMap = new ConcurrentHashMap<>();
    private freemarker.template.Configuration cfg;

    @PostConstruct
    public void init() throws IOException {
        cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_0);
        cfg.setDirectoryForTemplateLoading(new File(FreemarkerService.class.getResource("/templates/ftls").getPath()));//这里加载模板文件存放的路径
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateUpdateDelayMilliseconds(0);//设置在检查是否存在比缓存模板更新版本的模板“文件”之前必须经过的时间(以毫秒为单位)。 默认为5000毫秒。
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
    }

    public String process(String tempName, Map conditions) {
        try {
            if (!templateMap.containsKey(tempName)) {
                templateMap.put(tempName, cfg.getTemplate(tempName));
            }

            StringWriter out = new StringWriter();
            templateMap.get(tempName).process(conditions, out);
            String rs = out.getBuffer().toString();
            out.close();
            return rs;
        } catch (TemplateException | IOException e) {
            logger.error("生成文本失败:", e);
        }
        return null;
    }

    public String process(String tempName, String key, Object value) {
        Map conditions = new HashMap();
        conditions.put(key, value);
        return process(tempName, conditions);
    }

    public void clearAll() {
        templateMap.clear();
    }

}

然后ftl模板文件不放在src/main/java目录下,而是放到src/main/resources目录下。在src\main\resources\templates\ftls目录下新建test1.ftl:

Hello ${name} from resource freemark! age=${age}

在controller中添加测试方法:

@Autowired
private FreemarkerService freemarkerService;

@RequestMapping("test1")
@ResponseBody
public String test1(){
    HashMap<Object, Object> map = new HashMap<>();
    map.put("name","张三");
    map.put("age",20);
    String s = freemarkerService.process("test1.ftl", map);
    log.info(s);
    return s;
}

启动服务,访问:
在这里插入图片描述
至此,完整的目录结构:
spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成_第7张图片

freemarker语法demo

下面会介绍freemarker的一些语法以及使用demo。读者可以根据输出理解freemarker的语法。
在controller中添加一个测试的入口

@RequestMapping("test2")
@ResponseBody
public String test2() {
    Map<String, Object> map = new HashMap<>();
    map.put("name", "FreeMarker是一款用java语言编写的模版引擎");
    map.put("dateTime", new Date());

    List<SysUser> users = new ArrayList<>();
    users.add(new SysUser(1, "liubenlong007", "111"));
    users.add(new SysUser(2, "欢迎", "13333333333"));
    users.add(new SysUser(3, "You!", null));
    map.put("users", users);
    String s = freemarkerService.process("test2.ftl", map);
    log.info(s);
    return s;
}

test2.ftl:

字符串输出:
${"Hello ${name} !"} / ${"Hello " + name + " !"}
<#assign cname=r"特殊字符完成输出(http:\www.baidu.com)">
${cname}

字符串截取 :
通过下标直接获取下标对应的字母: ${name[2]}
起点下标..结尾下标截取字符串:${name[0..5]}

算数运算:
<#-- 支持"+"、"-"、"*"、"/"、"%"运算符 -->
<#assign number1 = 10>
<#assign number2 = 5>
"+" : ${number1 + number2}
"-" : ${number1 - number2}
"*" : ${number1 * number2}
"/" : ${number1 / number2}
"%" : ${number1 % number2}

比较运算符:
<#if number1 + number2 gte 12 || number1 - number2 lt 6>
"*" : ${number1 * number2}
<#else>
"/" : ${number1 / number2}


内建函数:
<#assign data = "abcd1234">
第一个字母大写:${data?cap_first}
所有字母小写:${data?lower_case}
所有字母大写:${data?upper_case}
<#assign floatData = 12.34>
数值取整数:${floatData?int}
获取集合的长度:${users?size}
时间格式化:${dateTime?string("yyyy-MM-dd")}

<#--
!:指定缺失变量的默认值 [下面user.phone指定了默认值]
??:判断某个变量是否存在,返回boolean值
-->
空判断和对象集合:
<#if users??>
    <#list users as user >
        ${user.id} - ${user.name} - ${user.phone!"--"}
    
<#else>
    ${user!"变量为空则给一个默认值"}


Map集合:
<#assign mapData={"name":"程序员", "salary":15000}>
直接通过Key获取 Value值:${mapData["name"]}
通过Key遍历Map:
<#list mapData?keys as key>
Key: ${key} - Value: ${mapData[key]}

通过Value遍历Map:
<#list mapData?values as value>
Value: ${value}


List集合:
<#assign listData=["ITDragon", "blog", "is", "cool"]>
<#list listData as value>${value} 

include指令:
引入其他文件:<#include "test3.ftl" />
${otherName}<#--引入的内容是可以直接使用的-->
<@addMethod a=1 b=2 />

macro宏指令:
<#macro mo>
定义无参数的宏macro--${name}

使用宏macro: <@mo />
<#macro moArgs a b c>
定义带参数的宏macro-- ${a+b+c}

使用带参数的宏macro: <@moArgs a=1 b=2 c=3 />

命名空间:
<#import "test3.ftl" as otherFtl>
${otherFtl.otherName}
<@otherFtl.addMethod a=10 b=20 />
<#assign otherName="修改otherFreeMarker.ftl中的otherName变量值"/><#--这样不行,需要指定命名空间-->
${otherFtl.otherName}
<#assign otherName="修改otherFreeMarker.ftl中的otherName变量值" in otherFtl />
${otherFtl.otherName}

test3.ftl:

其他FreeMarker文件
<#macro addMethod a b >
result : ${a + b}

<#assign otherName="另外一个FreeMarker的变量">

启动项目,执行方法输出如下:

字符串输出:
Hello FreeMarker是一款用java语言编写的模版引擎 ! / Hello FreeMarker是一款用java语言编写的模版引擎 !
特殊字符完成输出(http:\www.baidu.com)

字符串截取 :
通过下标直接获取下标对应的字母: e
起点下标..结尾下标截取字符串:FreeMa

算数运算:
"+" : 15
"-" : 5
"*" : 50
"/" : 2
"%" : 0

比较运算符:
"*" : 50

内建函数:
第一个字母大写:Abcd1234
所有字母小写:abcd1234
所有字母大写:ABCD1234
数值取整数:12
获取集合的长度:3
时间格式化:2019-03-19

空判断和对象集合:
        1 - liubenlong007 - 111
        2 - 欢迎 - 13333333333
        3 - You! - --

Map集合:
直接通过Key获取 Value值:程序员
通过Key遍历Map:
Key: name - Value: 程序员
Key: salary - Value: 15,000
通过Value遍历Map:
Value: 程序员
Value: 15,000

List集合:
ITDragon blog is cool 

include指令:
引入其他文件:其他FreeMarker文件

另外一个FreeMarker的变量
result : 3

macro宏指令:
使用宏macro: 定义无参数的宏macro--FreeMarker是一款用java语言编写的模版引擎

使用带参数的宏macro: 定义带参数的宏macro-- 6


命名空间:
另外一个FreeMarker的变量
result : 30
另外一个FreeMarker的变量
修改otherFreeMarker.ftl中的otherName变量值

更多详细的语法请参考:

  • FreeMarker 2.3.23 中文官方参考手册
  • FreeMarker 2.3.28 官方文档

你可能感兴趣的:(springboot)