spring boot 2.1学习笔记【二十】SpringBoot 2 freemarker bootstrap 集成
概述
FreeMarker是一款用java语言编写的模版引擎,它虽然不是web应用框架,但它很合适作为web应用框架的一个组件。
特点:
- 轻量级模版引擎,不需要Servlet环境就可以很轻松的嵌入到应用程序中
- 能生成各种文本,如html,xml,java,等
- 入门简单,它是用java编写的,很多语法和java相似
工作原理:
引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--bootstrap相关-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.5</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.1.1</version>
</dependency>
<!--freemarker-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</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文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
this is index page
</body>
</html>
编写welcome.ftl文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</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;
}
}
启动服务,测试:
接下来先写一个复杂一点的
@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:
<!DOCTYPE html>
<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 Name</th>
<th>Last Name</th>
<th>User Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>aehyok</td>
<td>leo</td>
<td>@aehyok</td>
</tr>
<tr>
<td>lynn</td>
<td>thl</td>
<td>@lynn</td>
</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>
启动服务,访问:
至此,项目目录结构如下:
代码中使用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;
}
启动服务,访问:
至此,完整的目录结构: