目录
1. 初识模板引擎
什么是模板引擎?
模板引擎就是为了解决HTML代码和Java代码混合在一起这个问题的,我们可以把HTML内容提取出来单独的放在一个文件中,称为模板,对于一些动态的内容,可以将这些内容在模板中使用占位符占位,当服务器把这些动态的内容计算好了之后,就可以把模板中占位符替换成动态计算的结果,然后把组装好的HTML格式的字符串在返回给浏览器
模板引擎的作用
- 通过组织网页模板和数据,就可以返回一个动态的网页
- 可以分离Servlet Java代码和HTML网页代码(模板引擎的最大优点)
模板引擎的使用原理
2. Thymleaf的使用流程
2.1 通过Maven引入依赖
在Maven中央仓库搜索Thymeleaf
选择一个合适的版本,这里选择的是3.0.12
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
2.2 创建HTML模板文件
我们创建一个hello.html放到webapp/WEB-INF/templates目录中
注意:web.xml和templates是同级目录,都在WEB-INF目录下,hello.html在templates目录下
<body>
<h3>模板技术学习</h3>
<p th:text="${message}"></p>
</body>
说明:th:text是Thymeleaf的语法,后边介绍更多的Thymeleaf语法
2.3 编写Servlet代码
创建HelloServlet类,注解为@WebServlet(“/hello”),继承HttpServlet,重写doGet方法,在该类中先创建模板引擎和模板解析器,再设置数据和模板名称,最后再将渲染的html设置到响应正文
创建模板引擎和模板解析器
//创建模板引擎,用于最终完成最终页面渲染工作
TemplateEngine engine = new TemplateEngine();
//创建渲染网页模板的解析器
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());
resolver.setCharacterEncoding("utf-8");//设置渲染时编码
resolver.setPrefix("/WEB-INF/templates/");//前缀
resolver.setSuffix(".html");//后缀
//将解析器绑定到模板引擎中
engine.setTemplateResolver(resolver);
设置数据和模板名称
//创建一个web上下文(里面有一个map结构,存放键值对)
WebContext wc = new WebContext(req,resp,getServletContext());
//设置一个键值对数据,键为message(模板中的变量),值为好好学习(要渲染的值),
wc.setVariable("message","好好学习");
//模板引擎渲染网页模板,第一个参数为模板名称,第二个参数为web上下文
//根据模板解析器设置的前缀+模板名称+后缀为模板路径,查找到模板,再组织模板内容+数据
//返回值就是渲染后的网页字符串
String html = engine.process("hello",wc);
将渲染的html设置到响应正文
resp.setContentType("text/html; charset=utf-8");//设置响应编码
resp.getWriter().write(html);
2.4 部署程序
1. 点击启动tomcat
2. 输入路径hello
3. 观察结果
2.5 小结
- resovler的setPefix和setSuffix方法指定了从那个目录下筛选哪些文件
- engine.process方法第一个参数指定了要加载哪个模板文件
- webContext中指定了模板变量名和变量值的对应关系(类似哈希表结构),setVariable中的第一个参数要和模板文件中写的 ${message} 匹配
- engine.process方法会把刚才的webContext里的值替换到模板中,并把最终结果写到resp对象中
在上述代码中,有这三个关键类:
- TemplateEngine,核心功能是通过process()方法完成渲染工作
- ServletContextTemplateResolver,核心功能是加载模板文件,为后边的渲染做准备
- webContext,核心功能是组织模板变量要替换为什么值
3. Thymeleaf的常用语法
命令 | 功能 |
---|---|
th:text | 设置标签文本 |
th:[HTML标签属性] | 设置标签属性 |
th:if | 当表达式的结果为真时则显示内容,否则不显示 |
th:each | 循环访问元素 |
Thymeleaf语法很多,此处只介绍最常用的几个
3.1 设置标签文本
th:text功能就是设置标签文本
<p th:text="${message}"></p>
3.2 设置标签属性
常需要设置的属性:href src class style…
示例:设置a标签的href属性
<a th:href="${url1}">百度</a>
<a th:href="${url2}">搜狗</a>
对应后端代码:
wc.setVariable("url1","http://www.baidu.com");
wc.setVariable("url2","http://www.sogou.com");
运行程序,访问页面,点击就会跳转到对应的页面
3.3 条件判断
th:if功能就是根据条件决定该标签是否显示
<P th:if="${isLogin}">已经登陆</P>
<p th:if="${noLogin}">没有登陆</p>
wc.setVariable("isLogin",true);
wc.setVariable("noLogin",false);
结果:只显示已经登陆
3.4 循环
th:each的功能是可以循环的构造出多个元素
语法格式:th:each=”自定义变量元素名称 : ${集合变量名称}”
<ul>
<Li th:each="u : ${users}">
姓名:<span th:text="${u.name}"></span>
年龄:<span th:text="${u.age}"></span>
</Li>
</ul>
wc.setVariable("users",Arrays.asList(
new User("张三",21),
new User("李四",23),
new User("王五",28)
));
private static class User{
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
注意:创建的User类需要提供getter方法
结果:
4. 如何创建一个引擎实例?
上述初始化引擎及解析器的代码,每个需要渲染页面的Servlet类都需要写一次,其实没有必要,一个完整的项目中,TemplateEngine和ServletContextTemplateResolver只需要创建一次并且初始化一次,为了完成这个目的,就需要使用Servlet中的ServletContext和ServletContextListener监听器
4.1 什么是ServletContext
ServletContext是一个Servlet程序中全局储存信息的空间,服务器启动就创建,服务器关闭就销毁
- Tomcat在启动时,它会为每个webapp都创建一个对应的ServletContext
- 一个Web应用的所有Servlet共享同一个ServletContext对象
- 可以通过HttpServlet.getServletContext()或HttpServletRequest.getServletContext()获取到当前webapp的ServletContext对象
理解Context:上下文/环境,常用于设置一些信息到上下文环境中,上下文环境中的对象就可以相互引用对方的数据
多个Servlet之间无法传递数据,但可以通过共享的上下文环境来设置或使用一些数据(数据传递)
ServletContext对象的重要方法
方法 | 说明 |
---|---|
void setAttribute(String name,Object obj) | 设置属性(键值对) |
Object getAttribute(String name) | 根据name获取对应的值,如果name为不存在,返回null |
void removeAttribute(String name) | 删除对应的属性 |
ServletContext类似Map结构,存放键值对数据
4.2 什么是监听器(Listener)
监听器属于一种设计模式,在Servlet运行过程中,会有一些特殊的“时机”供我们执行一些我们自己定义的逻辑,“监听器”就是可以让程序员在这些特殊的时机插入代码
此处学习的ServletContextListener,也是类似一种监听器的设计,在事件发生的时候不用我们自己写代码做事情,而是先注册一个方法到监听器,在某个事件发生后就会自动执行
此处我们需要使用监听器监听ServletContext的创建即可
4.3 修改Thymeleaf引擎初始化代码
结合ServletContext和Listener,我们就可以对之前的Thymeleaf引擎初始化代码做出调整
- 创建监听器,监听ServletContext的创建
- 当ServletContext创建完后,在contextInitialized方法中创建TemplateEngine实例和ServletContextTemplateResolver实例,并完成初始化
- 把创建出来的TemplateEngine实例放到ServletContext中
- 后续Servlet如果要使用TemplateEngine,那么直接从ServletContext获取之前创建好的实例
创建监听器
@WebListener
public class TemplateEngineListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
TemplateEngine engine = new TemplateEngine();
ServletContext sc = sce.getServletContext();
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(sc);
resolver.setCharacterEncoding("utf-8");
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
engine.setTemplateResolver(resolver);
sc.setAttribute("engine",engine);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
写前端test.html代码
<p th:text="${content}"></p>
写对应的后端代码
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext sc = req.getServletContext();
WebContext wc = new WebContext(req,resp,sc);
wc.setVariable("content","写一篇博客");
TemplateEngine engine = (TemplateEngine) sc.getAttribute("engine");
String html = engine.process("test",wc);
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write(html);
}
}
启动Tomcat,输入url,观察结果