Java|JavaWeb --- 模板引擎


文章目录

  • 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 响应给客户端.
Java|JavaWeb --- 模板引擎
文章图片

1.2 客户端渲染 服务器把数据返回给浏览器, 由浏览器把数据和页面结合起来.
浏览器和服务器之间的数据往往交互通过 ajax 进行, 数据的格式往往使用 JSON
Java|JavaWeb --- 模板引擎
文章图片

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()); } }

运行截图:
Java|JavaWeb --- 模板引擎
文章图片

可以看出,这种比较简单的,还可以使用拼接的方式来实现.如果复杂了就很麻烦.
示例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("
"); html.append(""); html.append(""); 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(""); html.append(""); html.append("
"); html.append(""+res+""); html.append("当前猜了: "+count+"次"); resp.getWriter().write(html.toString()); } }

运行截图:
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

在相当于复杂的情况下,再去用拼接就很麻烦.
2. 模板引擎 2.1 什么是模板引擎 模板引擎 就是为了解决 HTML 代码 和 Java 代码混杂在一起的问题.
可以把HTML 提取出来,放到单独的文件夹中,称为 模板.
对于页面中动态的部分,这些部分就可以使用 模板 中的 占位符 占位.当动态的部分计算好了之后,就可以把 该部分的占位符替换成 计算好的内容.然后组装成 HTML 返回给 浏览器.
这里我使用的模板引擎 是 Thymeleaf
2.2 Thymeleaf 的使用 ① 引入依赖
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

org.thymeleaf thymeleaf 3.0.12.RELEASE

② 创建一个 HTML 的模板文件
创建一个目录,在webapp/WEB-INF/template,在里面新建一个 hello.html
Java|JavaWeb --- 模板引擎
文章图片

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的取值有关
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

总结:
  1. Servlet init 方法中对 TemplateEngine 进行初始化工作.
  2. resovlersetPrefixsetSuffix 指定了从哪个目录下筛选哪些文件
  3. engine.process 方法的第一个参数指定了要加载哪个模板文件
  4. WebContext 中指定了模板变量名和变量值的对应关系(类似于一个哈希表结构). setVariable 中的第一个参数, 要和模板文件中写的 ${message} 匹配.
  5. engine.process 方法会把刚才的 WebContext 里的值替换到模板中, 并把最终结果写入到 resp对象里.
  6. HTML文件 要写在 目录webapp/WEB-INF/template
    Java|JavaWeb --- 模板引擎
    文章图片
2.3 猜数字游戏 (模板引擎) 1) 创建HTML模板文件
Java|JavaWeb --- 模板引擎
文章图片

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) 运行结果
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

相比于前一个服务器版,代码简化了不少.
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()); }

运行截图
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

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());

运行截图:
Java|JavaWeb --- 模板引擎
文章图片

3. ServletContext 3.1 什么是 ServletContext ServletContext是一个 Servlet 程序中全局的储存信息的空间, 服务器开始就存在, 服务器关闭才销毁.
Tomcat 在启动时,它会为每个Web app都创建一个对应的 ServletContext.
一个WEB应用中的所有 Servlet 共享同一个 ServletContext 对象.可以通过HttpServlet.getServletContext()或者HttpServletRequest.getServletContext()获取到当前 webapp 的 ServletContext 对象
相当于 Tomcat 路径下的 webapps 目录.
Java|JavaWeb --- 模板引擎
文章图片

相当于在一个启动一个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) 删除对应的属性
3.3 代码示例: 演示多个 Servlet 共享数据 Servlet1: 写入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("/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的内容
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

当message没有设置的时候,reader获取到的就是null
Java|JavaWeb --- 模板引擎
文章图片

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
Java|JavaWeb --- 模板引擎
文章图片

Java|JavaWeb --- 模板引擎
文章图片

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 --- 模板引擎】运行结果
使用这样的初始化
Java|JavaWeb --- 模板引擎
文章图片

    推荐阅读