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 响应给客户端.
JavaWeb --- 模板引擎_第1张图片

1.2 客户端渲染

服务器把数据返回给浏览器, 由浏览器把数据和页面结合起来.
浏览器和服务器之间的数据往往交互通过 ajax 进行, 数据的格式往往使用 JSON
JavaWeb --- 模板引擎_第2张图片

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

运行截图:
JavaWeb --- 模板引擎_第3张图片
可以看出,这种比较简单的,还可以使用拼接的方式来实现.如果复杂了就很麻烦.

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

运行截图:
JavaWeb --- 模板引擎_第4张图片
JavaWeb --- 模板引擎_第5张图片
在相当于复杂的情况下,再去用拼接就很麻烦.

2. 模板引擎

2.1 什么是模板引擎

模板引擎 就是为了解决 HTML 代码 和 Java 代码混杂在一起的问题.
可以把HTML 提取出来,放到单独的文件夹中,称为 模板.

对于页面中动态的部分,这些部分就可以使用 模板 中的 占位符 占位.当动态的部分计算好了之后,就可以把 该部分的占位符替换成 计算好的内容.然后组装成 HTML 返回给 浏览器.

这里我使用的模板引擎 是 Thymeleaf

2.2 Thymeleaf 的使用

① 引入依赖

JavaWeb --- 模板引擎_第6张图片
JavaWeb --- 模板引擎_第7张图片


<dependency>
    <groupId>org.thymeleafgroupId>
    <artifactId>thymeleafartifactId>
    <version>3.0.12.RELEASEversion>
dependency>

② 创建一个 HTML 的模板文件

创建一个目录,在webapp/WEB-INF/template,在里面新建一个 hello.html
JavaWeb --- 模板引擎_第8张图片

doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>
<body>
    <h1 th:text="${message}">h1>
body>
html>

③ 编写 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的取值有关
JavaWeb --- 模板引擎_第9张图片
JavaWeb --- 模板引擎_第10张图片

总结:

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

2.3 猜数字游戏 (模板引擎)

1) 创建HTML模板文件

JavaWeb --- 模板引擎_第12张图片

doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>
<body>
    <form action="guessNum" method="POST">
        <input type="text" name="num">
        <input type="submit" value="提交">
    form>
    <div th:if="${newGame}">
        <div th:text="${result}">div>
        <div th:text="${count}">div>
    div>
body>
html>

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) 运行结果

JavaWeb --- 模板引擎_第13张图片
JavaWeb --- 模板引擎_第14张图片
相比于前一个服务器版,代码简化了不少.

2.4 Thymeleaf 模板语法

命令 功能
th:text 在标签体中展示表达式求值结果的文本内容
th:[HTML标签属性] 设置任意的 HTML 标签属性的值
th:if 当表达式的结果为真时则显示内容,否则不显示
th:each 循环访问元素

这四种是常见的.

a) 设置标签文本

th:text 的功能就是能设置标签的文本内容.
前面的 使用示例已经演示过了

b) 设置标签的属性

可以用在 href,src,class,style…
示例:
前端重点代码

    <a th:href="${url1}">百度a>
    <a th:href="${url2}">搜狗a>

后端重点代码

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

运行截图
JavaWeb --- 模板引擎_第15张图片
JavaWeb --- 模板引擎_第16张图片
JavaWeb --- 模板引擎_第17张图片

c) 条件判断

th:if在猜数字的演示代码中也用到过了

d) 循环

th:each 的功能是可以循环的构造出多个元素
语法格式为:

th:each="自定义的元素变量名称 : ${集合变量名称}

示例:
前端重点代码

 <ul>
        <li th:each="person : ${persons}">
            <span th:text="${person.name}">span>
            <span th:text="${person.phone}">span>
        li>
    ul>

后端重点代码

        resp.setContentType("text/html;charset=utf-8");
        List<Person> 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());

运行截图:
JavaWeb --- 模板引擎_第18张图片

3. ServletContext

3.1 什么是 ServletContext

ServletContext是一个 Servlet 程序中全局的储存信息的空间, 服务器开始就存在, 服务器关闭才销毁.
Tomcat 在启动时,它会为每个Web app都创建一个对应的 ServletContext.
一个WEB应用中的所有 Servlet 共享同一个 ServletContext 对象.可以通过HttpServlet.getServletContext()或者HttpServletRequest.getServletContext()获取到当前 webapp 的 ServletContext 对象

相当于 Tomcat 路径下的 webapps 目录.
JavaWeb --- 模板引擎_第19张图片

相当于在一个启动一个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的内容
JavaWeb --- 模板引擎_第20张图片
JavaWeb --- 模板引擎_第21张图片
当message没有设置的时候,reader获取到的就是null
JavaWeb --- 模板引擎_第22张图片

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
JavaWeb --- 模板引擎_第23张图片
JavaWeb --- 模板引擎_第24张图片

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

运行结果
使用这样的初始化
JavaWeb --- 模板引擎_第25张图片

你可能感兴趣的:(Java,Web,java,javascript,json)