使用模板技术
- 自己动手的缺点(Object - > HTML格式):
- 代码繁琐
- 数据和逻辑耦合了
数据: html结构 逻辑:循环、字符串处理等 (1)容易出错 (2)一旦需要修改,很麻烦 - 模板引擎就是为了解决上面遇到的, HTML 和 Java 混在一起的问题. 我们可以把 HTML 的内容提取出来, 放到单独的文件中,称为 模板.
举例: js 中的模板字符串`hello ${user.username},Bye!’ => String String.format(“hello %s,Byte”, user.username) => String - web中要使用模板技术的时候,大多不是前后端分离的,而是后端直接产生html内容!
- 模板文件只是 web应用生成资源的一个中间事务,不是真正的web资源
Web应用上的模板技术
JSP、Thymeleaf(SpringBoot建议使用Thymeleaf 作为默认模板)、FreeMarker …
- 添加依赖
- 在普通类中使用
(1)模板引擎(TemplateEngin) (2)模板解析器(TemplateResolver) (3)供模板渲染(render)的数据/上下文(Context) (4)模板文件=>路径的形式体现=>真实需要的其实是模板文件里的内容 (5)模板处理之后的结果字符串 编译出的类的根路径
资源根路径下的所有文件,编译时 会被复制到类的根路径下
public static void main(String[] args) throws UnsupportedEncodingException {
TemplateEngine engine=new TemplateEngine();
ClassLoaderTemplateResolver resolver=new ClassLoaderTemplateResolver();
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("utf-8");
resolver.setCacheable(false);
resolver.setPrefix("templates/");
resolver.setSuffix(".html");
engine.setTemplateResolver(resolver);
User user=new User();
user.uid=1998;
user.username="张三";
user.password="123456";
List<Integer> list= Arrays.asList(1,2,3,4,5);
Context context=new Context();
context.setVariable("data",user);
context.setVariable("someString","你好世界");
context.setVariable("number",list);
String result = engine.process("demo", context);
ClassLoader cl = ThymeleafDemo.class.getClassLoader();
URL resource = cl.getResource("templates/demo.html");
System.out.println(URLDecoder.decode(resource.toString(), "UTF-8"));
System.out.println(result);
}
<!doctype html>
<html lang="zh-hans" xmlns:th="http://www.thymeleleaf.org">
<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>模板技术演示</title>
</head>
<body>
<h1 th:text="${data.username}">随便写什么</h1>
<h2 th:text="${data.uid}">会被真实的uid替换</h2>
<h2 th:text="${data.password}"></h2>
</body>
</html>
结果: thymeleaf 中的模板语言简介
背景知识xmlns:th= “http://www.thymeleaf.org”,是XML标准指定命名空间(namespace ns)
th:xxxx xxxx标签是输入th 命名空间下的(xmlns:th不写,只是有警告提示,不影响使用)
thymeleaf提供的所有模板语言功能都是以th:开头的标签
- th:text=“表达式语言” : ${data.uid} => user对象中的uid 属性 或者 user对象的getUid()方法
< h1>(替换掉这里的内容)< /h1> th:text ="“你好!’+ ${data.username}” - th:href = ""https://www.baidu.com/q?wd=’+ ${data.username}"替换标签中href属性
(除了几个特殊的标签,其他的都是替换标签中默认的属性)
<a href="https://www.qq.com" th:href="'https://www.baidu.com/q?wd='+ ${data.username} ">访问百度</a>
<img src="/img/demo.jpg" th:src="'https://some.img.com/img?id=' + ${data.uid}">
- th:text = "每个元素的名称 : ${列表}"
<ol>
<li th:each="s : ${number}">
<p th:text="${s}"></p>
</li>
</ol>
- th : if = " " :满足条件时
th : unless = " " :不满足条件时
<p th:if="${someString}">有someString</p>
<p th:unless="${someString}">没有someString</p>
- 其他的基本视为直接替换标签的属性,类似 th:href、th:src、th:class、th:id
在web应用中把模板用起来
- 有个专门的解析器对象(ServletContextResolver)
- 有个专门的Context对象(WebContext)
@WebServlet("/template-demo")
public class TemplateDemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
TemplateEngine engine=new TemplateEngine();
ServletContext servletContext = req.getServletContext();
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContext);
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("utf-8");
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setCacheable(false);
engine.setTemplateResolver(resolver);
WebContext webContext=new WebContext(req,resp,servletContext);
List<String> courseList=getCoursrList();
webContext.setVariable("courseList",courseList);
String responseBody=engine.process("course-list",webContext);
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
resp.getWriter().println(responseBody);
}
private List<String> getCoursrList() {
return Arrays.asList("JavaSE","JavaDS","JavaDB","JavaWeb","JavaTest","JavaEE");
}
}
<!doctype html>
<html lang="zh-hans" xmlns:th="http://www.thymeleaf.org">
<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>课程列表</title>
</head>
<body>
<h1>计算机专业的课程列表</h1>
<ol>
<li th:each="course : ${courseList}" th:text="${course}"></li>
</ol>
</body>
</html>
注意:
- Resolver对象和Context对象使用正确
- 模板文件放对位置
- 模板文件不是 web 资源(不能访问)
各个对象的生命周期:(最有效率的)
监听器
- 在 Servlet 运行过程中, 会有一些特殊的 “时机”, 可以供我们来执行一些我们自定义的逻辑. 监听器就是让程序猿可以在这些特殊时机 “插入代码”.
- 监听器(listen) 模式 <-> 事件驱动的Java版本
场景:注册用户 注册用户 -> 发送新用户奖励 -> 根据用户的不同地域生成不同的标签 -> 给用户发送成功通知… 监听上述操作 —监听器(listener)
如何编写代码在合适的时机,进行模板对象和解析对象的构建
-
希望在ServletContext刚被初始化好的时机下,执行我们的模板初始化工作 由于ServletContext只会被初始化一次,所以,我们的模板初始化工作也只有一次 举例: 在店铺刚开张的时候,执行模板初识化工作 由于店铺只会开张一次,所以模板只会初始化一次 以后每次卖商品时,直接使用开店时,初始化好的模板对象就可以了 -
Servlet标准提供方法,可以在ServletContext初始好后执行我们的代码 1. 添加@WebListener,代表我们写的类是一个监听器类 2. 实现ServletContextListener接口,我们关心的ServletContext初始化和销毁的事件 3. 重写contextlnitialized方法,在ServletContext初始化好后执行一些代码
引擎对象怎么传递过来? 看到ServletContext是不是同一个对象,把引擎对象放到ServletContext对象中来传递
@WebListener
public class ThymeleafConfig implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
TemplateEngine engine=new TemplateEngine();
ServletContext servletContext = sce.getServletContext();
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContext);
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("utf-8");
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setCacheable(false);
engine.setTemplateResolver(resolver);
servletContext.setAttribute("engine",engine);
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
@WebServlet("/template")
public class TemplateServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = req.getServletContext();
WebContext webContext=new WebContext(req,resp,servletContext);
List<String> courseList=getCoursrList();
webContext.setVariable("courseList",courseList);
TemplateEngine engine=(TemplateEngine)servletContext.getAttribute("engine");
String responseBody=engine.process("course-list",webContext);
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
resp.getWriter().println(responseBody);
}
private List<String> getCoursrList() {
return Arrays.asList("JavaSE","JavaDS","JavaDB","JavaWeb","JavaTest","JavaEE");
}
}
|