认识模板引擎-Thymeleaf

什么是模板引擎 ?

【作用】模板引擎就是为了使用户界面与业务数据(内容)分离而产生的,它可以分离 Servlet Java 代码和 Html 网页代码(这是相对于 Servlet 直接返回动态页面来说,模板引擎的优点)

原理 / 流程

在这里插入图片描述

Thymeleaf 使用流程

Thymeleaf 是 Java 中的模板引擎,当前最流行的一种

1. 通过 maven 引入依赖

maven 中央仓库 搜索 Thymeleaf

在这里插入图片描述

选择一个合适的版本,如:3.0.12

<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf -->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>

引入依赖后,一定记得要刷新 Maven 面板
注意: web项目需要打包为 war格式 —— < packaging>war< /packaging>

2. 创建 Html 模板文件

创建 hello.html,放到 webapp / WEB-INF / templates 目录中

<h3 th:text="${message}"></h3>

举例:

<body>
    <h3>网页模板技术学习</h3>
    <p th:text="${message}"></p>
</body>

会发现,有飘红:

在这里插入图片描述
th:text 是 Thymeleaf 的语法,浏览器不能直接识别 th:text 属性

3. 编写 Servlet 代码

  1. 创建一个模板引擎 和 一个网页模板解析器
  2. 设置渲染时编码
  3. 设置网页模板文件,路径的前缀和后缀
  4. 将模板解析器绑定到模板引擎中
  5. 创建一个web上下文(环境的语义,里面是map结构,存放键值对数据)
  6. 设置键值对的数据
  7. 返回渲染后的网页字符串到响应正文
@WebServlet("/hello")
public class helloServlet extends HttpServlet {
    
    
    // 一般是浏览器地址栏输入 url 来访问网页,都是get方法
    // 模板引擎都是返回 html,所以重写 doGet
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setContentType("text/html;charset=utf-8");
        // 使用 thymeleaf 模板技术
        // 创建一个模板引擎
        TemplateEngine engine = new TemplateEngine();

        // 创建一个网页模板的解析器: getServletContext() 是 HttpServlet中的方法,返回 Servlet 上下文对象
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());

        // 设置渲染时的编码
        resolver.setCharacterEncoding("utf-8");

        // 设置网页模板文件,路径的前缀和后缀
        resolver.setPrefix("/WEB-INF/templates/"); // 前缀
        resolver.setSuffix(".html");  // 后缀

        // 将模板解析器绑定到模板引擎中
        engine.setTemplateResolver(resolver);

        // 创建一个web上下文(环境的语义,里边有一个map结构,可以存放键值对的数据)
        WebContext webContext = new WebContext(req,resp,getServletContext());
        // 设置了一个键值对数据,可以理解为: 为网页模板定义了一个变量,变量名为 message,值为 "hello模板引擎"
        // queryString 传入msg=xxx
        webContext.setVariable("message",req.getParameter("msg"));

        // 模板引擎渲染网页模板: 第一个参数为模板名称,第二个参数为 web上下文(里边保存了数据)
        // 会根据模板解析器设置的前缀+模板名称+后缀. 为模板路径,查找到模板,再组织模板内容+数据
        // 返回值就是渲染后的网页字符串
        String html = engine.process("hello",webContext);
        resp.getWriter().write(html);
    }
}

启动服务,刷新页面:

在这里插入图片描述

每次请求都创建一个模板引擎 和 一个网页模板解析器,效率是比较低的,也没有必要,我们可以重写一个 init 方法,因为 init 只执行一次,而 doGet 方法每次请求都会执行,可以将创建模板引擎 和 创建网页模板解析器的代码放到 init 方法里

@Override
public void init() throws ServletException {
    
    
    // 创建一个模板引擎
    TemplateEngine engine = new TemplateEngine();

    // 创建一个网页模板的解析器: getServletContext() 是 HttpServlet中的方法,返回 Servlet 上下文对象
    ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
    // 设置渲染时的编码
    resolver.setCharacterEncoding("utf-8");

    // 设置网页模板文件,路径的前缀和后缀
    resolver.setPrefix("/WEB-INF/templates/"); // 前缀
    resolver.setSuffix(".html");  // 后缀

    // 将模板解析器绑定到模板引擎中
    engine.setTemplateResolver(resolver);

}

但是此时,会发现代码会有飘红:

在这里插入图片描述
把 TemplateEngine engine = new TemplateEngine(); 放到 init() 方法外即

重新启动,刷新页面:
(效率得到了提高)

在这里插入图片描述

Thymeleaf 常用模板语法

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

${变量名},来引用 Java 代码中,设置的键值对数据 ( ${键}就是值 )

在这里插入图片描述

注意: 网站的绝对路径还是要加 http:// ,需要写全
举例:

webContext.setVariable("a1","http://www.baidu.com");

理解只创建一个引擎实例

整个web应用,只需要初始化一次(代码中的对象engine,resolver,只需要创建一次)
(原因:对象及属性不会改变),在文章前面部分,也提出了改进方法,放在 Servlet 的 init() 方法里

但仍然还存在问题: 每个 Servlet 都需要在 init 方法中创建,一个 webapp 中,还是有很多个engine,resolver对象
每个需要渲染页面的 Servlet 类都需要创建一个 TemplateEngine 实例并初始化,其实是完全没有必要的!

一个完整的项目中,只需要创建一个 TemplateEngine,并且只初始化一次即可
为了改进上边出现的问题,需要使用 Servlet 中的 ①ServletContext②"监听器"

ServletContext

ServletContext是一个 Servlet 程序中全局的储存信息的空间,服务器开始就存在,服务器关闭才销毁

如下图关系:
在这里插入图片描述

  • Tomcat 在启动时,它会为每个 webapp 都创建一个对应的 ServletContext.
  • 一个 Web应用中的所有 Servlet 共享同一个 ServletContext 对象
  • 可以通过 HttpServlet.getServletContext() 或者 HttpServletRequest.getServletContext() 获取到当前 webapp 的 ServletContext 对象

理解 Context: 上下文 / 环境;常用于设置一些数据到上下文环境中;上下文环境中的对象就可以互相引用对方的数据 (很多地方都有 Context 这样的概念,它是一个语义的概念)

即:
多个 Servlet 之间,无法直接传递数据,但可以通过共享的一个上下文环境,来设置 / 使用一些数据 (数据传递)
ServletContext 类似于 Map 结构,存放多组键值对数据

ServletContext 对象的重要方法

方法 描述
void setAttribute(String name, Objectobj) 设置属性(键值对)
Object getAttribute(String name) 根据属性名获取属性值,如果 name 不存在,返回 null
void removeAttribute(String name) 删除对应的属性

可以看到 ServletContext 和 HttpSession 类很类似,也是在内部组织了若干个键值对结构,相当于一个哈希表;此时同一个 webapp 的多个 Servlet 之间就可以通过 ServletContext 来共享数据

代码示例:多个 Servlet 共享数据

1) 创建 ContextWriteServlet 类

@WebServlet("/write")
public class ContextWriteServlet extends HttpServlet {
    
    

    // write?data=xxx
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String data = req.getParameter("data");
        // 把数据写入 Servlet 共享的上下文环境
        ServletContext sc = getServletContext();
        sc.setAttribute("d",data);

        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("写入Context成功!");
    }
}

2) 创建 ContextReadServlet 类

@WebServlet("/read")
public class ContextReadServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 把数据写入 Servlet 共享的上下文环境
        ServletContext sc = getServletContext();
        Object data = sc.getAttribute("d");

        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("读取Context:" + data);
    }
}

启动服务,打开页面:

在这里插入图片描述

在这里插入图片描述

如果我们不访问 /write,直接访问 /read,那么此时得到的 data 是 null:

在这里插入图片描述

监听器 Listener

监听器,属于一种设计模式

比如: 前边学些的,在 html / js 中,为一个 DOM 元素,绑定一个事件 (事件注册),不需要手动调用该事件的函数,而是在事件发生时,由浏览器来调用事件绑定的函数
这个"事件",其实就是监听器的设计模式
若我们自己设计,可能是:事件发生,执行一段代码 (耦合性太强);而上边例子是事件发生需要执行的代码,和事件发生,两个解耦

在 Servlet 运行过程中,会有一些特殊的 “时机”,可以供我们来执行一些我们自定义的逻辑
监听器就是让程序猿可以在这些 特殊时机 “插入代码”

监听器优点小结:

  • 将事件发生和事件发生后需要执行的代码进行解耦合
  • 事先注册一个函数或方法到监听器,在某个事件发生后,自动执行

代码示例:监听 ServletContext 的创建

步骤:

  • 首先创建一个类
  • 添加@WebListener 注解修饰,否则 Tomcat 不能识别
  • 实现 ServletContextListener 接口,并实现两个方法 contextInitialized 和 contextDestroyed
@WebListener
public class MyListener implements ServletContextListener {
    
    
@WebListener
public class MyListener implements ServletContextListener {
    
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
    
    
        // 这个会在 context 被创建的时候调用.
        // 创建的时机在所有 Servlet 实例化之前.
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    
    
        // 这个会在 context 被销毁的时候调用
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_47988201/article/details/123379401