1. 模板引擎简介2. 模板引擎与 Thymeleaf 关系3. 模板引擎原理4. 使用流程
流程一:通过 maven 引入依赖流程二:创建 HTML 模板文件流程三:编写 servlet 代码流程四:部署程序 5. 理解只创建一个引擎实例?
(1) ServletContext代码示例:多个 servlet 共享数据(2) 监听器(3)修改 Thymeleaf 引擎初始化代码 6. Thymeleaf 模板语法
(1)常用命令及功能(2)设置标签文本(3)设置标签属性(4)条件判断(5)循环
1. 模板引擎简介模板引擎?你可能第一次听说模板引擎,估计你会禁不住想问:什么是模板引擎呢?
模板引擎(这里特指用于Web开发的模板引擎),是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的html文档;
从字面上理解:模板引擎最重要的就是 模板 二字,相当于做好一个模板后并套入对应位置的数据,最终以html的格式展示出来;将模板设计好之后直接填充数据即可,而不需要重新设计整个页面,这样就提高了页面以及代码的复用性; 2. 模板引擎与 Thymeleaf 关系
Java中模板引擎有许多,模板引擎作为动态网页发展进步的产物,在最初并且流传度最广的jsp就是一个模板引擎,但由于jsp的缺点比较多,所以很多人弃用jsp选用第三方的模板引擎,市面上开源的第三方的模板引擎也比较多,有Thymeleaf、FreeMaker、Velocity等模板引擎受众较广。
使用 Thymeleaf 优点:
动静分离:Thymeleaf 使用 html 通过一些特定标签语法代表其含义,而且并未破坏html结构,即使无网络、不通过后端渲染也能在浏览器成功打开,大大方便了界面的测试和修改;
3. 模板引擎原理关系:Thymeleaf 是模板引擎的其中一种产品!!!
首先:客户端浏览器发起HTTP请求到 servlet中;servlet 调用模板引擎组织 模板(静态不动的资源)+数据(动态的资源),将两者拼接为一个HTML字符串;将该HTML字符串返回给服务端; 4. 使用流程 流程一:通过 maven 引入依赖
在 maven 中央仓库搜索 Thymeleaf 并选择一个版本;
maven 中央仓库网址:https://mvnrepository.com/
进入之后,搜索 Thymeleaf:
选择 3.0.12版本;
拷贝依赖代码到 pox.xml 中并刷新;
同时需要使用servlet,因此也要引入servlet依赖包;
流程二:创建 HTML 模板文件javax.servlet javax.servlet-api 3.1.0 provided
创建 hello.html , 放到 webapp/WEB-INF/templates 目录中;
document
网页模板技术学习
流程三:编写 servlet 代码
操作步骤:
创建一个模板引擎;创建一个网页模板解析器;设置渲染时编码;设置网页模板文件路径的前缀与后缀;将模板解析器绑定到模板引擎中;创建一个web上下文(环境的语义,里面是map结构,存放键值对数据);设置键值对的数据;返回渲染后的网页字符串;
package org.example;
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 HelloServlet extends HttpServlet {
//模板引擎都是返回HTML,因此重写HTML
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置body格式与编码格式
resp.setContentType("text/html; charset = utf-8");
//1.创建一个模板引擎
TemplateEngine engine = new TemplateEngine();
//2.创建一个网页模板解析器
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
//3.设置渲染时编码
resolver.setCharacterEncoding("utf-8");
//4.设置网页模板文件路径的前缀与后缀
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
//5.将模板解析器绑定到模板引擎中
engine.setTemplateResolver(resolver);
//6.创建一个web上下文(环境的语义,里面是map结构,可以存放键值对数据)
WebContext webContext =new WebContext(req,resp,getServletContext());
//7.设置键值对的数据:可以理解为:为网页模板定义了一个变量(变量名为message,值为hello模板引擎)
webContext.setVariable("message","hello模板引擎");
//模板引擎渲染网页模板:第一个参数为模板名称,第二个参数为web上下文(里面保存了数据)
//会根据模板解析器设置的前缀+模板名称+后缀,为模板路径,查找到模板,再组织模板内容+数据
//8.返回值就是渲染后的网页字符串
String html =engine.process("hello",webContext);
resp.getWriter().write(html);
}
}
流程四:部署程序
通过 URL
http://127.0.0.1:8080/Thymeleaf-study/hello
访问服务器,可以看到网页显示:
此时,页面看起来仍是静态不变的,做如下更改:
//此处为固定页面显示
//webContext.setVariable("message","hello模板引擎");
//设置动态变化的 msg=xxx
webContext.setVariable("message", req.getParameter("msg"));
这样就可以通过浏览器地址栏URL输入内容的不同而产生不同的效果!
代码分析:
但以上 servlet 代码,执行效率并不高,且存在冗余!
原因:每次只要发送URL请求:就会创建一个模板引擎及解释器;
优化代码:
将创建的模板引擎与解释器放置在init()方法中,该方法只调用一次!
package org.example;
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 HelloServlet extends HttpServlet {
//1.创建一个模板引擎
TemplateEngine engine = new TemplateEngine();
@Override
public void init() throws ServletException {
//2.创建一个网页模板解析器
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
//3.设置渲染时编码
resolver.setCharacterEncoding("utf-8");
//4.设置网页模板文件路径的前缀与后缀
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
//5.将模板解析器绑定到模板引擎中
engine.setTemplateResolver(resolver);
}
//模板引擎都是返回HTML,因此重写HTML
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置body格式与编码格式
resp.setContentType("text/html; charset = utf-8");
//创建一个web上下文(环境的语义,里面是map结构,可以存放键值对数据)
WebContext webContext =new WebContext(req,resp,getServletContext());
//设置键值对的数据:可以理解为:为网页模板定义了一个变量(变量名为message,值为hello模板引擎)
//此处为固定页面显示
//webContext.setVariable("message","hello模板引擎");
//设置动态变化的 msg=xxx
webContext.setVariable("message", req.getParameter("msg"));
//模板引擎渲染网页模板:第一个参数为模板名称,第二个参数为web上下文(里面保存了数据)
//会根据模板解析器设置的前缀+模板名称+后缀,为模板路径,查找到模板,再组织模板内容+数据
//返回值就是渲染后的网页字符串
String html =engine.process("hello",webContext);
resp.getWriter().write(html);
}
}
5. 理解只创建一个引擎实例?
上面优化后,还存在另一个问题?
当创建另一个 Servlet 时,还是需要创建一个 TemplateEngine 实例并进行初始化,因此,还是存在多个模板引擎对象与解析器对象的,但其实是完全没有必要的!!!
一个完整的项目中, 只需要创建一个 TemplateEngine, 并且只初始化一次即可~
(1) ServletContext为了达到这样的目的, 就需要使用 Servlet 中的 ServletContext 和 “监听器”;
ServletContext 是一个 Servlet 程序中全局储存信息的空间, 服务器开始就存在, 服务器关闭才销毁;
Tomcat 在启动时,它会为每个Web app都创建一个对应的 ServletContext;一个Web应用中的所有 Servlet 共享同一个 ServletContext 对象;可以通过 HttpServlet.getServletContext() 或者HttpServletRequest.getServletContext() 获取到当前 webapp 的 ServletContext 对象;
如下所示关系:
ServletContext 对象的重要方法:
| 方法 | 功能 |
|---|---|
| void setAttribute(String name,Object obj) | 设置属性(键值对的形式) |
| Object getAttribute(String name) | 根据属性名获取属性值, 如果 name 不存在, 返回 null |
| void removeAttribute(String name) | 删除对应的属性 |
(1) 创建一个 writeServlet类;
package org.example;
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("/write")
public class writeServlet extends HttpServlet {
// write?data=xxx
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String data = req.getParameter("data");
//将数据写入servlet共享的上下文环境
//获取当前servletContext对象
ServletContext sc = getServletContext();
//设置属性
sc.setAttribute("d",data);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("写入context成功");
}
}
(2) 创建一个 readServlet 类;
package org.example;
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("/read")
public class readServlet extends HttpServlet {
// write?data=xxx
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取当前servletContext对象
ServletContext sc = getServletContext();
//根据属性名,获取属性值
Object data = sc.getAttribute("d");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("读取context:"+data);
}
}
(3)通过ServletContext进行数据共享;
通过地址栏访问URL:http://localhost:8080/Thymeleaf-study/write?data=shd,可以看到写入成功标志,在http://localhost:8080/Thymeleaf-study/read访问可以读取写入的数据;
如下所示:
监听器:属于一种设计模式;
使用监听器优点:
将事件发生和事件发生后需要执行的代码进行解耦合;事先注册一个函数或方法到监听器,在某个事件发生后,自动执行;
使用步骤:
创建一个类;添加@WebListener 注解,否则 Tomcat 不能识别;实现 ServletContextListener 接口, 并实现两个方法 contextInitialized 和 contextDestroyed;
代码如下:
package org.example;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
(3)修改 Thymeleaf 引擎初始化代码
package org.example;
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 MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//1. 先获取context对象
ServletContext context = sce.getServletContext();
//2. 创建Templateengine对象
TemplateEngine engine = new TemplateEngine();
//3.创建解析器对象
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context);
//4.设置resolver的一些属性
resolver.setCharacterEncoding("utf-8");
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
//5.绑定 resolver 和 engine
engine.setTemplateResolver(resolver);
//6.将 engine 放到 ServletContext中,供其他servlet使用
context.setAttribute("engine",engine);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
后续的 Servlet 直接从 ServletContext 中获取到 engine 对象即可;
6. Thymeleaf 模板语法 (1)常用命令及功能| 命令 | 功能 |
|---|---|
| th:text | 在标签体中展示表达式求值结果的文本内容 |
| th:[HTML标签属性] | 设置任意的 HTML 标签属性的值 |
| th:if | 当表达式的结果为真时则显示内容,否则不显示 |
| th:each | 循环访问元素 |
最后结果:将webContext 设置的键值对数据,键为message的值设置到标签内容中;
(3)设置标签属性常见的属性:
hrefsrcclassstyle…
如设置链接 a 标签的 href 属性:
前端代码:
百度 搜狗
servlet代码:
package org.example;
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 HelloServlet extends HttpServlet {
//1.创建一个模板引擎
TemplateEngine engine = new TemplateEngine();
@Override
public void init() throws ServletException {
//2.创建一个网页模板解析器
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
//3.设置渲染时编码
resolver.setCharacterEncoding("utf-8");
//4.设置网页模板文件路径的前缀与后缀
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
//5.将模板解析器绑定到模板引擎中
engine.setTemplateResolver(resolver);
}
//模板引擎都是返回HTML,因此重写HTML
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置body格式与编码格式
resp.setContentType("text/html; charset = utf-8");
//创建一个web上下文(环境的语义,里面是map结构,可以存放键值对数据)
WebContext webContext =new WebContext(req,resp,getServletContext());
//设置键值对的数据:
webContext.setVariable("a1","http://www.baidu.com");
webContext.setVariable("a2","http://www.sogou.com");
//模板引擎渲染网页模板:第一个参数为模板名称,第二个参数为web上下文(里面保存了数据)
//会根据模板解析器设置的前缀+模板名称+后缀,为模板路径,查找到模板,再组织模板内容+数据
//返回值就是渲染后的网页字符串
String html =engine.process("hello",webContext);
resp.getWriter().write(html);
}
}
(4)条件判断
条件判断 th:if :根据条件决定该标签是否显示;
已经登陆
当 webContext.setVariable("islogin",true);传入的值为true时,就显示为:已经登陆,否则不显示;
网页显示:
th:each 循环的构造出多个元素;
webContext.setVariable("names", Arrays.asList("张三","李四","王五"));
网页显示结果:



