一、使用idea新建web工程
1、引入freemarker依赖:
2、pom.xml文件为:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cobra.freemarker</groupId>
<artifactId>freemarkerdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>freemarkerdemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、整个工程目录结构:
二、后端coding:
1、定义domain,User.java:
package com.cobra.freemarker.domain;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/23 22:34
*/
public class User {
private Integer userId;
private String username;
private String address;
private String email;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", username='" + username + '\'' +
", address='" + address + '\'' +
", email='" + email + '\'' +
'}';
}
}
2、service层
定义接口UserService和方法:
package com.cobra.freemarker.service;
import com.cobra.freemarker.domain.User;
import java.util.Collection;
/**
* @Author: Baron
* @Description: 用户服务接口
* @Date: Created in 2019/3/23 23:26
*/
public interface UserService {
/**
* 根据userId查找User
* @param userId
* @return
*/
User findById(Integer userId);
/**
* 添加新用户
* @param user
*/
void add(User user);
/**
* 查询所有用户
* @return
*/
Collection<User> findAllUsers();
}
实现接口方法,使用ConcurrentHashMap存储用户信息,AtomicInteger生成用户id:
package com.cobra.freemarker.service.impl;
import com.cobra.freemarker.service.UserService;
import com.cobra.freemarker.domain.User;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author: Baron
* @Description: 用户服务实现
* @Date: Created in 2019/3/23 23:42
*/
@Service
public class UserServiceImpl implements UserService {
private ConcurrentMap<Integer,User> userMap = new ConcurrentHashMap<>();
private final static AtomicInteger idGenerator = new AtomicInteger();
/**
* 根据userId查找User
*
* @param userId
* @return
*/
@Override
public User findById(Integer userId) {
return userMap.get(userId);
}
/**
* 添加新用户
*
* @param user
*/
@Override
public void add(User user) {
user.setUserId(idGenerator.incrementAndGet());
userMap.put(user.getUserId(), user);
}
/**
* 查询所有用户
*
* @return
*/
@Override
public Collection<User> findAllUsers() {
return userMap.values();
}
}
3、controller层:
package com.cobra.freemarker.controller;
import com.cobra.freemarker.service.StaticService;
import com.cobra.freemarker.service.UserService;
import com.cobra.freemarker.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.Collection;
import java.util.Map;
/**
* @Author: Baron
* @Description: user的列表、添加、查看
* @Date: Created in 2019/3/23 22:25
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 获取所有用户
* @param modelAndView
* @param map
* @return
*/
@GetMapping("/list")
public ModelAndView index(ModelAndView modelAndView, Map<String, Object> map) {
Collection<User> users = userService.findAllUsers();
map.put("users",users);
return new ModelAndView("list",map);
}
/**
* 根据id获取单个用户详情
* @param userId
* @param map
* @return
*/
@GetMapping("/{userId}")
public ModelAndView detail(@PathVariable("userId")Integer userId, Map<String, Object> map) {
User user = userService.findById(userId);
map.put("user", user);
return new ModelAndView("detail",map);
}
/**
* 返回添加用户页
* @return
*/
@GetMapping("/add")
public ModelAndView add() {
return new ModelAndView("add");
}
/**
* 添加用户操作
* @param user
* @return
*/
@PostMapping("/save")
public ModelAndView save(User user) {
userService.add(user);
return new ModelAndView("success");
}
}
三、前端视图模板的定义:
在resources下templates中定义模板,新建html文件,然后将文件名改为ftl(业务逻辑可以提前看第四部分测试):
1、用户list.ftl列表页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>列表页</title>
</head>
<style>
td{text-align: center; height: 30px;}
.code{width:40px }
.username{width: 80px}
.address{width: 150px}
.link{width: 100px}
</style>
<body>
<h3>欢迎来到!</h3>
<a href="/user/add">添加新用户</a>
<br>
<br>
<table>
<thead>
<tr>
<td class="code">编号</td>
<td class="username">姓名</td>
<td class="address">地址</td>
<td class="link">详情</td>
</tr>
</thead>
<tbody>
<#list users as user>
<tr>
<td class="code">${user.userId}</td>
<td class="username">${user.username}</td>
<td class="address">${user.address}</td>
<td class="link"><a href="/user/${user.userId}" target="_blank">查看详情</a></td>
</tr>
</#list>
</tbody>
</table>
</body>
</html>
2、用户add.ftl添加页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新建用户</title>
</head>
<body>
<h3>新建用户</h3>
<form action="/user/save" method="post">
<label>姓名:</label><input type="text" name="username" /><br><br>
<label>地址:</label><input type="text" name="address" /><br><br>
<label>邮箱:</label><input type="text" name="email" /><br><br>
<input type="submit" value="提交" />
</form>
</body>
</html>
3、用户success.ftl添加成功页,添加用户成功后返回列表页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加成功</title>
</head>
<body>
<h4>添加成功!</h4><a href="http://localhost:8080/user/list" class="alert-link">三秒后自动跳转!</a>
</body>
<script>
setTimeout('location.href="http://localhost:8080/user/list"',3000)
</script>
</html>
4、单个用户detail.ftl详情页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户详情</title>
<style>
td{height: 30px;}
.left{width: 50px;}
.right{width: 150px;}
</style>
</head>
<body>
<h3>用户详情</h3>
<table>
<tr><td class="left">编号:</td><td class="right">${user.userId}</td>
<tr><td>姓名:</td><td>${user.username}</td>
<tr><td>地址:</td><td>${user.address}</td>
<tr><td>邮编:</td><td>${user.email}</td>
</table>
</body>
</html>
四、测试freemarker的模板引擎功能:
1、启动工程,访问http://localhost:8080/user/list:
2、点击添加用户,并填写信息:
3、提交,显示添加成功:
4、返回列表:
5、点击查看详情:
五、页面静态化实现模板转化为html页面,可以让前端直接浏览html页面,减少对数据库的请求:
1、定义静态化服务接口StaticService 及将list.ftl生成index.html的方法:
package com.cobra.freemarker.service;
/**
* @Author: Baron
* @Description: 生成静态页面service
* @Date: Created in 2019/3/24 2:04
*/
public interface StaticService {
/**
* 生成首页静态页面
*/
void createIndexHtml();
}
2、实现类:
package com.cobra.freemarker.service.impl;
import com.cobra.freemarker.service.StaticService;
import com.cobra.freemarker.service.UserService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/24 2:07
*/
@Service
public class StaticServiceImpl implements StaticService {
@Autowired
private UserService userService;
@Autowired
private Configuration configuration;
/**
* 生成首页静态页面
*/
@Override
public void createIndexHtml() {
try {
/**获取输出目标文件输出流------开始*/
String filepath = this.getClass().getResource("/").toURI().getPath()+"static/";
File folder = new File(filepath);
//如果文件夹不存在
if (!folder.exists()) {
folder.mkdir();
}
String indexFileName = "index.html";
File indexHtml = new File(folder, indexFileName);
//如果html文件不存在
if (!indexHtml.exists()) {
indexHtml.createNewFile();
}
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexHtml),"UTF-8"));
/**获取输出目标文件输出流------结束*/
//获取数据
Map<String, Object> map = new HashMap<>();
map.put("users", userService.findAllUsers());
//获取模板
Template template = configuration.getTemplate("list.ftl");
//把数据和输出文件信息交给模板得到静态html文件
template.process(map,out);
out.flush();
out.close();}
catch (URISyntaxException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
3、在UserController中,添加用户时,调用静态方法,实现每次添加用户,都会生成最新的静态页面,如果有修改、删除操作,也要调用静态化方法:
package com.cobra.freemarker.controller;
import com.cobra.freemarker.service.StaticService;
import com.cobra.freemarker.service.UserService;
import com.cobra.freemarker.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.Collection;
import java.util.Map;
/**
* @Author: Baron
* @Description: user的列表、添加、查看
* @Date: Created in 2019/3/23 22:25
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private StaticService staticService;
/**
* 获取所有用户
* @param modelAndView
* @param map
* @return
*/
@GetMapping("/list")
public ModelAndView index(ModelAndView modelAndView, Map<String, Object> map) {
Collection<User> users = userService.findAllUsers();
map.put("users",users);
return new ModelAndView("list",map);
}
/**
* 根据id获取单个用户详情
* @param userId
* @param map
* @return
*/
@GetMapping("/{userId}")
public ModelAndView detail(@PathVariable("userId")Integer userId, Map<String, Object> map) {
User user = userService.findById(userId);
map.put("user", user);
return new ModelAndView("detail",map);
}
/**
* 返回添加用户页
* @return
*/
@GetMapping("/add")
public ModelAndView add() {
return new ModelAndView("add");
}
/**
* 添加用户操作
* @param user
* @return
*/
@PostMapping("/save")
public ModelAndView save(User user) {
userService.add(user);
staticService.createIndexHtml();
return new ModelAndView("success");
}
}
4、测试:
添加一个用户之后,在static下会生成一个index.html页面:
直接访问生成的html页面:http://localhost:8080/index.html: