认识模板引擎-Thymeleaf
Posted 一朵花花
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了认识模板引擎-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 代码
- 创建一个模板引擎 和 一个网页模板解析器
- 设置渲染时编码
- 设置网页模板文件,路径的前缀和后缀
- 将模板解析器绑定到模板引擎中
- 创建一个web上下文(环境的语义,里面是map结构,存放键值对数据)
- 设置键值对的数据
- 返回渲染后的网页字符串到响应正文
@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 被销毁的时候调用
以上是关于认识模板引擎-Thymeleaf的主要内容,如果未能解决你的问题,请参考以下文章