目录
3.2 编写模板文件(将需要动态替换的数据用占位符号进行占位)
一、页面的渲染方式
1.1 页面分类
一个不变的页面,称为静态页面。
一个随着用户输入的不同,产生不同结果的页面,称为动态页面。
2.2 如何生成一个动态页面
2.2.1 服务器渲染
特点:①服务器返回一个完整的html页面。②html页面上的一些动态的数据,往往是通过模板引擎的方式进行动态替换的。
模板引擎:就是一个HTML,在这个HTML中将一些动态变化的数据挖空,用特殊符号占个位置,后面通过这些代码把空给补上。模板引擎就是在填空。
优点:前后端交互的次数比较少。(一次HTTP请求、响应,就能拿到一个完整的页面),比较高效。
缺点:前端代码和后端代码不能充分解耦合。前端开发人员和后端开发,很难进行一个明确的分工,同时也不能各自独立进行测试。
2.2.2 客户端渲染(前后端分离)
特点:①客户端通过ajax的方式和服务器进行交互。②服务器返回的不是完整的html,通常只是纯粹的数据.这些数据常见的是以json的方式来组织的
优点:能够让前后端进行充分的解耦.前端开发人员和后端开发人员各自开发,相互之间不干扰,并且也能各自分别进行测试。(后端的测试::Postman。前端的测试:使用mock server)
缺点: 前后端交互的次数比较多(页面中可能需要通过多组ajax来获取到完整的数据,效率比较低)
二、猜数字实例(没有模板引擎)
2.1 前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<form action="guess" method="post">
<input type="text" name="inputNum">
<input type="submit" value="提交">
</form>
</div>
<div>
结果:
</div>
</body>
</html>
2.2 后端代码
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;
@WebServlet("/guess")
public class GuessNumServlet extends HttpServlet {
Random random = new Random();
int num = random.nextInt(100)+1;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int guessNum = Integer.parseInt(req.getParameter("inputNum"));
String result = null;
if(num > guessNum){
result = "猜小了";
}else if(num < guessNum){
result = "猜大了";
}else {
result = "猜对了";
}
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
" <title>Document</title>\n" +
"</head>\n" +
"<body>\n" +
" <div>\n" +
" <form action=\"guess\" method=\"post\">\n" +
" <input type=\"text\" name=\"inputNum\">\n" +
" <input type=\"submit\" value=\"提交\">\n" +
" </form>\n" +
" </div>\n" +
" <div>\n" +
" 结果:\n" + result +
" </div>\n" +
"</body>\n" +
"</html>");
}
}
如果不采用模板引擎,在Java代码中通过拼装字符串的方式返回HTML,不仅将业务逻辑的代码和用户界面的代码混在一起,非常不友好。同时也非常容易出错。
三、猜数字实例(使用模板引擎)
Java的模板引擎很多,Thymeleaf是Spring官方推荐的模板引擎,因此,本文使用的是ThymeLeaf。
3.1 引入依赖(3.0.12)
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
3.2 编写模板文件(将需要动态替换的数据用占位符号进行占位)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<form action="guess" method="post">
<input type="text" name="inputNum">
<input type="submit" value="提交">
</form>
</div>
<div>
结果:
<span th:text="${result}"></span>
</div>
</body>
</html>
实际上,Thymeleaf相当于对HTML的语法进行了扩充。正常的HTML是没有th:text这个属性的,是Thymeleaf扩充的。一旦Thymeleaf看到这个符号,就会知道这是一个需要被替换的部分。${result}相当于在模板引擎中定义的变量,可以在Java代码中对这个变量进行赋值。
3.3 将模板放在特殊的目录下
WEB-INF ——》template——》.html模板文件
3.4 编写Servlet代码
3.4.1 Thymeleaf的初始化
[1]. 创建一个模板引擎对象engine
[2]. 因为Servlet被加载的时候,会调用init方法,将Thymeleaf的初始化放在这里很适合。
1) 重写init()方法
2) 创建一个ServletContextTemplateResolver对象resolver,从磁盘上加载模板引擎文件
3) 把engine和resolver关联起来
// 1.创建一个模板引擎对象
private TemplateEngine engine = new TemplateEngine();
// 2.因为servlet被加载的时候,会调用init方法,所以Thymeleaf的初始化就很适合放在这里
@Override
public void init() throws ServletException {
// 2.1 创建一个ServletContextTemplateResolver对象,功能就是从磁盘上加载模板引擎文件
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
//2.2 对resolver对象设置一些属性 加载 /WEB-INF/template/ 目录中, 以 .html 结尾的文件, 作为模板引擎
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("utf-8");
// 2.4 把resolver和engine关联起来
engine.setTemplateResolver(resolver);
}
3.4.2 进行模板渲染
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 通过模板引擎加载html文件
WebContext webContext = new WebContext(req,resp,getServletContext());
// 针对猜数字的初始页面,不需要替换内容,直接往下写
engine.process("guessNum",webContext, resp.getWriter());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
int guessNum = Integer.parseInt(req.getParameter("inputNum"));
String result = "";
if (num < guessNum) {
result = "猜高了";
} else if (num > guessNum) {
result = "猜低了";
} else {
result = "猜对了";
}
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("result",result);
engine.process("guessNum",webContext, resp.getWriter());
}
3.5 总结
TemplateEngine:表示一个模板引擎对象,功能是进行页面渲染。核心方法是process。
ServletContextTemplateEngine:解析器对象,用来加载模板文件,指定模板的位置。
WebContext:就是一个键值对结构,功能是把html中的占位符和具体的Java变量关联起来。
ServletContext:上下文对象,每个webapp都有一个上下文对象,p有多个servlet,这多个servlet之间可以共享ServletContext对象。可以基于这个ServletContext对象在多个Servlet之间传递数据。
四、表白墙实例(使用模板引擎)
4.1 创建maven工程项目文件
4.2 引入依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
4.3 新建文件夹
其中,MessageWall.html就是模板文件。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
4.4 配置tomcat和验证
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello");
}
}
在浏览器窗口输入:http://127.0.0.1:8080/MessageWallTemplate/hello可以显示出hello就证明没问题。
4.5 写代码
4.5.1 操作数据库
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBUTil {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/messagewall?characterEncoding=utf8&useSSL=false";
private static final String username = "root";
private static final String password = "1111";
private static DataSource dataSource = new MysqlDataSource();
static {
((MysqlDataSource)dataSource).setURL(URL);
((MysqlDataSource)dataSource).setUser(username);
((MysqlDataSource)dataSource).setPassword(password);
}
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
4.5.2 前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表白墙</title>
</head>
<body>
<style>
/* 清空浏览器默认样式 */
* {
margin: none;
padding: none;
box-sizing: border-box;
}
.container {
width: 300px;
/* 水平居中 */
margin: 0 auto;
}
h3 {
text-align: center;
padding: 10px 0;
}
p {
text-align: center;
font-size: 15px;
color: rgb(196, 180, 159);
}
.row {
display: flex;
width: 100%;
font-size: 18px;
justify-content: center;
align-items: center;
height: 40px;
}
.edit {
margin: 2px 0;
height: 38px;
width: 200px;
}
span {
width: calc(100% - 200px);
}
.submit {
width: 300px;
height: 35px;
background-color: pink;
color: azure;
font-size: 20px;
border-radius: 3px;
border: 0;
}
.submit:active {
background-color: green;
}
</style>
<!-- 给外层加个容器,通过这个容器实现对齐的效果 -->
<div class="container">
<h3>表白墙</h3>
<p>输入后点击提交,会将信息显示在表格中</p>
<form action="message" method="post">
<div class="row">
<span>谁:</span>
<input type="text" class="edit" id="name1" name="from">
</div>
<div class="row">
<span>对谁:</span>
<input type="text" class="edit" id="name2" name="to">
</div>
<div class="row">
<span>说什么:</span>
<input type="text" class="edit" id="message" name="message">
</div>
<div class="row">
<input type="submit" value="提交" class="submit">
</div>
</form>
<!-- 接下来的div就通过循环的方式,来获取到内容 -->
<div class="row" th:each="message:${messages}">
<span th:text="${message.from}"></span>
对
<span th:text="${message.to}"></span>
说:
<span th:text="${message.message}"></span>
</div>
</div>
</body>
</html>
4.5.3 后端代码
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/message")
public class MessageWallTemplate extends HttpServlet {
// 1.创建一个模板引擎对象
private TemplateEngine engine = new TemplateEngine();
// 2.因为servlet被加载的时候,会调用init方法,所以Thymeleaf的初始化就很适合放在这里
@Override
public void init() throws ServletException {
// 2.1 创建一个ServletContextTemplateResolver对象,功能就是从磁盘上加载模板引擎文件
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
//2.2 对resolver对象设置一些属性 加载 /WEB-INF/template/ 目录中, 以 .html 结尾的文件, 作为模板引擎
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("utf-8");
// 2.4 把resolver和engine关联起来
engine.setTemplateResolver(resolver);
}
private static List<Message> messages = new ArrayList<>();
// 返回所有的留言
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 从数据库中读出所有数据
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
DBUTil dbuTil = new DBUTil();
try {
connection = dbuTil.getConnection();
String sql = "select * from message";
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while (resultSet.next()){
Message message = new Message();
message.from = resultSet.getString("from");
message.to = resultSet.getString("to");
message.message = resultSet.getString("message");
messages.add(message);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
dbuTil.close(connection,statement,resultSet);
}
// 渲染模板
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("messages",messages);
engine.process("MessageWall",webContext, resp.getWriter());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 请求的body中可能包含中文,设置一下编码格式
// 从请求中拿到数据
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
Message message = new Message();
message.from = req.getParameter("from");
message.to = req.getParameter("to");
message.message = req.getParameter("message");
// 写到数据库中
Connection connection = null;
PreparedStatement statement = null;
DBUTil dbuTil = new DBUTil();
try {
connection = dbuTil.getConnection();
String sql = "insert into message values(?,?,?)";
statement = connection.prepareStatement(sql);
statement.setString(1,message.from);
statement.setString(2,message.to);
statement.setString(3,message.message);
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
dbuTil.close(connection,statement,null);
}
messages.add(message);
// 渲染模板
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("messages",messages);
engine.process("MessageWall",webContext, resp.getWriter());
}
}
class Message{
public String from;
public String to;
public String message;
}
总结
setp1:写好前端模板
step2:初始化thymeleaf模板
创建WEB-INF—》template—》的目录结果,将前端模板拷入该目录下。
复制初始化代码
step3:渲染模板