文章目录
- 1. 动态页面的渲染方式
-
- 1.1 服务器渲染
- 1.2 客户端渲染
- 1.3 服务端渲染示例
-
- 示例1: 通过字符串拼接出HTML
- 示例2: 服务器版 猜数字游戏
- 2. 模板引擎
-
- 2.1 什么是模板引擎
- 2.2 Thymeleaf 的使用
-
- ① 引入依赖
- ② 创建一个 HTML 的模板文件
- ③ 编写 Servlet 代码
- ④ 运行 并查看运行结果
- 总结:
- 2.3 猜数字游戏 (模板引擎)
-
- 1) 创建HTML模板文件
- 2) 编写 Servlet 代码
- 3) 运行结果
- 2.4 Thymeleaf 模板语法
-
- a) 设置标签文本
- b) 设置标签的属性
- c) 条件判断
- d) 循环
- 3. ServletContext
-
- 3.1 什么是 ServletContext
- 3.2 ServletContext 对象的重要方法
- 3.3 代码示例: 演示多个 Servlet 共享数据
- 4. 监听器
-
- 4.1 什么是监听器( Listener )
- 4.2 ServletContextListener 接口
- 4.3 代码示例: 监听 ServletContext 的创建
- 5. 只创建一个引擎实例
-
- 5.1 使用监听器来初始化模板引擎
- 5.2 测试代码
1. 动态页面的渲染方式 1.1 服务器渲染 数据和页面结合的工作, 通过服务器完成.
相当于 客户端 发送 HTTP 请求,带上参数. 服务端根据请求取计算响应,然后拼装成完整的 HTML 返回 HTTP 响应给客户端.
文章图片
1.2 客户端渲染 服务器把数据返回给浏览器, 由浏览器把数据和页面结合起来.
浏览器和服务器之间的数据往往交互通过 ajax 进行, 数据的格式往往使用 JSON
文章图片
1.3 服务端渲染示例 示例1: 通过字符串拼接出HTML
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("/html")
public class htmlServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
StringBuilder html = new StringBuilder();
html.append("");
html.append("html页面 - 锐客网 ");
html.append("你好
");
html.append("");
resp.getWriter().write(html.toString());
}
}
运行截图:
文章图片
可以看出,这种比较简单的,还可以使用拼接的方式来实现.如果复杂了就很麻烦.
示例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 GuessServlet extends HttpServlet {
// 这里的 ToGuess 表示要猜的数字
private int ToGuess = 0;
// 这里的 count 表示本次猜了的次数
private int count = 0;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
Random random = new Random();
ToGuess = random.nextInt(100)+1;
count = 0;
StringBuilder html = new StringBuilder();
html.append("");
resp.getWriter().write(html.toString());
}@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
String str = req.getParameter("num");
int num = Integer.parseInt(str);
String res = "";
count++;
if(num > ToGuess){
res = "猜大了";
}else if (num < ToGuess){
res = "猜小了";
}else {
res = "猜对了";
}
StringBuilder html = new StringBuilder();
html.append("");
html.append(""+res+"");
html.append("当前猜了: "+count+"次");
resp.getWriter().write(html.toString());
}
}
运行截图:
文章图片
文章图片
在相当于复杂的情况下,再去用拼接就很麻烦.
2. 模板引擎 2.1 什么是模板引擎 模板引擎 就是为了解决 HTML 代码 和 Java 代码混杂在一起的问题.
可以把HTML 提取出来,放到单独的文件夹中,称为 模板.
对于页面中动态的部分,这些部分就可以使用 模板 中的 占位符 占位.当动态的部分计算好了之后,就可以把 该部分的占位符替换成 计算好的内容.然后组装成 HTML 返回给 浏览器.
这里我使用的模板引擎 是
Thymeleaf
2.2 Thymeleaf 的使用 ① 引入依赖
文章图片
文章图片
org.thymeleaf
thymeleaf
3.0.12.RELEASE
② 创建一个 HTML 的模板文件
创建一个目录,在
webapp/WEB-INF/template
,在里面新建一个 hello.html
文章图片
Document - 锐客网
③ 编写 Servlet 代码
首先在渲染之前,要进行初始化.
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;
@WebServlet("/hello")
public class HelloThymeleafServlet extends HttpServlet {
// 负责渲染工作
private TemplateEngine engine = new TemplateEngine();
/**
* 在执行模板渲染之前,需要先进行初始化
* @throws ServletException
*/
@Override
public void init() throws ServletException {
// 创建一个 模板解析器 对象
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(this.getServletContext());
// 让 模板解析器 加载 模板文件
// 这里的文件前缀 表示 模板文件所在的目录
// 这里的文件后缀 表示 模板文件的类型
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
// 把 解析器 设置到 engine 对象中
engine.setTemplateResolver(resolver);
}@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
String message = req.getParameter("message");
//把当前从请求中读取出来的 message 的值和 模板 中的 ${message} 关联起来
WebContext context = new WebContext(req,resp,getServletContext());
context.setVariable("message",message);
// 进行渲染
engine.process("hello",context, resp.getWriter());
}
}
④ 运行 并查看运行结果
此时 页面的内容就和message的取值有关
文章图片
文章图片
总结:
2.3 猜数字游戏 (模板引擎) 1) 创建HTML模板文件
- 在
Servlet
的init
方法中对TemplateEngine
进行初始化工作.resovler
的setPrefix
和setSuffix
指定了从哪个目录下筛选哪些文件engine.process
方法的第一个参数指定了要加载哪个模板文件WebContext
中指定了模板变量名和变量值的对应关系(类似于一个哈希表结构).setVariable
中的第一个参数, 要和模板文件中写的${message}
匹配.engine.process
方法会把刚才的WebContext
里的值替换到模板中, 并把最终结果写入到 resp对象里.- HTML文件 要写在 目录
webapp/WEB-INF/template
下
文章图片
文章图片
Document - 锐客网
2) 编写 Servlet 代码
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.util.Random;
@WebServlet("/guessNum")
public class GuessNumServlet extends HttpServlet {
private int ToGuess=0;
private int count=0;
private TemplateEngine engine = new TemplateEngine();
@Override
public void init() throws ServletException {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(this.getServletContext());
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("utf-8");
engine.setTemplateResolver(resolver);
}@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
Random random = new Random();
ToGuess = random.nextInt(100)+1;
count = 0;
WebContext context = new WebContext(req,resp,getServletContext());
context.setVariable("newGame",false);
engine.process("guess",context, resp.getWriter());
}@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
String str = req.getParameter("num");
int num = Integer.parseInt(str);
String res = "";
count++;
if(num > ToGuess){
res = "猜大了";
}else if (num < ToGuess){
res = "猜小了";
}else {
res = "猜对了";
}WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("newGame",true);
webContext.setVariable("result",res);
webContext.setVariable("count",count);
engine.process("guess",webContext,resp.getWriter());
}
}
3) 运行结果
文章图片
文章图片
相比于前一个服务器版,代码简化了不少.
2.4 Thymeleaf 模板语法
命令 | 功能 |
---|---|
th:text | 在标签体中展示表达式求值结果的文本内容 |
th:[HTML标签属性] | 设置任意的 HTML 标签属性的值 |
th:if | 当表达式的结果为真时则显示内容,否则不显示 |
th:each | 循环访问元素 |
这四种是常见的.a) 设置标签文本
th:text
的功能就是能设置标签的文本内容.前面的 使用示例已经演示过了
b) 设置标签的属性
可以用在 href,src,class,style…
示例:
前端重点代码
百度
搜狗
后端重点代码
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("url1","https://www.baidu.com");
webContext.setVariable("url2","http://www.sogou.com");
engine.process("Web",webContext,resp.getWriter());
}
运行截图
文章图片
文章图片
文章图片
c) 条件判断
th:if
在猜数字的演示代码中也用到过了d) 循环
th:each
的功能是可以循环的构造出多个元素语法格式为:
th:each="自定义的元素变量名称 : ${集合变量名称}
示例:
前端重点代码
-
th:text="${person.name}">
th:text="${person.phone}">
后端重点代码
resp.setContentType("text/html;
charset=utf-8");
List list = new ArrayList<>();
list.add(new Person("张三","110"));
list.add(new Person("李四","120"));
list.add(new Person("王五","119"));
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("persons",list);
engine.process("Each",webContext, resp.getWriter());
运行截图:
文章图片
3. ServletContext 3.1 什么是 ServletContext ServletContext是一个 Servlet 程序中全局的储存信息的空间, 服务器开始就存在, 服务器关闭才销毁.
Tomcat 在启动时,它会为每个Web app都创建一个对应的 ServletContext.
一个WEB应用中的所有 Servlet 共享同一个 ServletContext 对象.可以通过
HttpServlet.getServletContext()
或者HttpServletRequest.getServletContext()
获取到当前 webapp 的 ServletContext 对象相当于 Tomcat 路径下的 webapps 目录.
文章图片
相当于在一个启动一个Tomcat的时候,会有很多webapp,每个webapp都会创建一个ServletContext和多个Servlet程序.一个webapp中所有的Servlet 共用这一个ServletContext
3.2 ServletContext 对象的重要方法
方法 | 描述 |
---|---|
void setAttribute(String name, Object obj) | 设置属性(键值对) |
Object getAttribute(String name) | 根据属性名获取属性值, 如果 name 不存在, 返回 null |
void removeAttribute(String name) | 删除对应的属性 |
import javax.servlet.ServletContext;
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("/writer")
public class writerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
String message = req.getParameter("message");
ServletContext servletContext = req.getServletContext();
servletContext.setAttribute("message",message);
resp.getWriter().write("设置成功!");
}
}
Servlet2: 读取刚刚写入的message
import javax.servlet.ServletContext;
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("/reader")
public class readerServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
ServletContext servletContext = req.getServletContext();
String message = (String) servletContext.getAttribute("message");
resp.getWriter().write("message: " + message);
}
}
观察运行结果
当 writer 设置message之后 reader 也能获取到 message的内容
文章图片
文章图片
当message没有设置的时候,reader获取到的就是null
文章图片
4. 监听器 4.1 什么是监听器( Listener ) 在 Servlet 运行过程中, 会有一些特殊的 “时机”, 可以供我们来执行一些我们自定义的逻辑.监听器就是让程序猿可以在这些 特殊时机 “插入代码”.
Servlet 中的监听器种类有很多.目前我们只关心 监听 ServletContext 的创建.
4.2 ServletContextListener 接口 要使用接口
ServletContextListener
实现这个接口要重写
contextInitialized
方法 和 contextDestroyed
方法在 ServletContext 初始化完毕之后,会执行
contextInitialized
方法.在 ServletContext 销毁之前,会执行
contextDestroyed
方法为了让 Tomcat 识别这个监听器,还需要加上注解
@WebListener
4.3 代码示例: 监听 ServletContext 的创建
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
//加上注解才能让Tomcat识别
@WebListener
public class myListener implements ServletContextListener {
// ServletContext初始化之后,会执行这个方法
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("ServletContext 初始化完毕");
ServletContext context = servletContextEvent.getServletContext();
context.setAttribute("message","初始化message");
}// ServletContext销毁之前 会执行这个方法
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
// 此处不关心这个方法
}
}
运行结果演示
由于之前reader在writer没写入数据的时候是 null,此时给message初始化,再没有运行writer的时候,reader也能读到message
文章图片
文章图片
5. 只创建一个引擎实例 通过之前的代码可以看出.每次在实现一个示例的时候,都要通过重写
init()
方法来初始化 Thymeleaf
,这样每次创建就很麻烦.此时就可以通过 监听器的方法,把
TemplateEngine
初始化好,放到ServletContext
对象里.后面的Servlet程序就不需要再初始化了.直接取出engine对象就可以了.5.1 使用监听器来初始化模板引擎
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class ThymeleafConfig implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("初始化完毕!");
ServletContext context = servletContextEvent.getServletContext();
// 初始化
TemplateEngine engine = new TemplateEngine();
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context);
resolver.setPrefix("/WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("utf-8");
engine.setTemplateResolver(resolver);
// 把 engine 放到了 ServletContext 中 后面的Servlet程序就可以使用
context.setAttribute("engine",engine);
}@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {}
}
5.2 测试代码 修改一下之前的代码,
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import javax.servlet.ServletContext;
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("/forTest")
public class ForTestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;
charset=utf-8");
String message = req.getParameter("message");
WebContext webContext = new WebContext(req,resp,getServletContext());
webContext.setVariable("message",message);
ServletContext context = getServletContext();
TemplateEngine engine = (TemplateEngine) context.getAttribute("engine");
engine.process("hello",webContext, resp.getWriter());
}
}
【Java|JavaWeb --- 模板引擎】运行结果
使用这样的初始化
文章图片
推荐阅读
- css|.113轮播图练习
- java相关|一次线上http连接被拒绝问题的排查
- Java|基于Netty实现RPC框架
- java|网络编程懒人入门(一)(快速理解网络通信协议(上篇))
- java|IP协议报字段
- java|编程必备基础 计算机组成原理+操作系统+计算机网络
- javascript|lightningJS之动画
- 数据结构|线性表练习之Example040-删除单链表中数据域绝对值相等节点,仅保留第一次出现的节点而删除其余绝对值相等的节点
- 数据结构|线性表练习之Example018-删除单链表中所有值为 x 的节点