上篇博客中,我们了解了服务器渲染,并用Thymeleaf模板引擎写了一个简单的猜数字小游戏。
下面我们简单了解一下Thymeleaf的语法。
Thymeleaf常见命令
命令 |
功能 |
th:text |
在标签体中展示表达式求值结果的文本内容 |
th:[HTML标签属性] |
设置任意的 HTML 标签属性的值 |
th:if |
当表达式的结果为真时则显示内容,否则不显示 |
th:each |
循环访问元素 |
Thymeleaf语法有很多,我们这里先简单介绍这四个。th:text和th:if在猜数字小游戏案例已经使用过,这里不再介绍。
th:[属性]
1 2 3 4
| <body> <a th:href="${url1}">胖虎同学</a> <a th:href="${url2}">胖虎同学1</a> </body>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @WebServlet("/thymeleafUrl.html") public class ThymeleafUrlServlet extends HttpServlet { public TemplateEngine engine = new TemplateEngine(); public void init(){ ServletContext context = getServletContext(); ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context); resolver.setCharacterEncoding("utf-8"); resolver.setPrefix("/WEB-INF/templates/"); resolver.setSuffix(".html"); engine.setTemplateResolver(resolver); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = getServletContext(); resp.setContentType("text/html;charset=utf-8"); WebContext webContext = new WebContext(req,resp,context); webContext.setVariable("url1","https://youngsay.cn"); webContext.setVariable("url2","http://blog.youngsay.cn"); engine.process("thymeleafUrl",webContext,resp.getWriter()); } }
|
th:each
列举游戏战绩:昵称、击杀、死亡、得分
1 2 3 4 5 6 7 8 9 10
| <body> <ul> <li th:each="person : ${persons}"> <span th:text="${person.name}"></span> <span th:text="${person.kill}"></span> <span th:text="${person.dead}"></span> <span th:text="${person.score}"></span> </li> </ul> </body>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| class Person { public String name; public int kill; public int dead; public int score;
public Person(String name, int kill, int dead, int score) { this.name = name; this.kill = kill; this.dead = dead; this.score = score; }
public String getName() { return name; }
public int getKill() { return kill; }
public int getDead() { return dead; }
public int getScore() { return score; } }
@WebServlet("/thymeleafEach") public class ThymeleafEach extends HttpServlet { public TemplateEngine engine = new TemplateEngine(); public void init() { ServletContext context = getServletContext(); ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context); resolver.setPrefix("/WEB-INF/templates/"); resolver.setSuffix(".html"); resolver.setCharacterEncoding("utf-8"); engine.setTemplateResolver(resolver); System.out.println("初始化成功"); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { List<Person> persons = new ArrayList<Person>(); persons.add(new Person("損友比过狗友i",12,2,80)); persons.add(new Person("马棚管理员",21,8,130)); persons.add(new Person("吃枣药丸",16,5,110)); ServletContext context = getServletContext(); WebContext webContext = new WebContext(req,resp,context); webContext.setVariable("persons",persons);
resp.setContentType("text/html;charset=utf-8"); engine.process("thymeleafEach",webContext, resp.getWriter()); } }
|
ServletContext
观察上篇博客猜数字游戏代码和上面的两段代码,我们发现,每个Servlet都创建了一个TemplateEngine对象并进行初始化,其实这完全没必要,一个webapp中,只创建一个TemplateEngine对象即可。
这就需要用到ServletContext,它是Servlet程序全局存储信息的空间,每个webapp中只有一个ServlectContext,多个Servlet之间共享一个ServlectContext。通过 HttpServlet.getServletContext() 方法获取到当前webapp 的ServletContext对象。
下面是ServletContext常见方法:
方法 |
描述 |
void setAttribute(String name, Object obj) |
设置属性(键值对) |
Object getAttribute(String name) |
根据属性名获取属性值, 如果 name 不存在, 返 回 null |
void removeAttribute(String name) |
删除对应的属性 |
我们用代码来证明多个一个webapp中多个Servlet类共用一个ServletContext。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @WebServlet("/writer") public class WriterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String message = req.getParameter("message"); ServletContext context = getServletContext(); context.setAttribute("message",message); resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write("设置成功"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| @WebServlet("/reader") public class ReaderServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = getServletContext(); String message = (String) context.getAttribute("message"); resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write(message); } }
|
监听器
要想做到一个webapp中只创建一个TemplateEngine对象,除了认识ServletContext,还需要了解监听器。
使用监听器监听ServletContext的创建,创建好后在ServletContext完成初始化操作,后续的 Servlet 直接从 ServletContext 中获取到engine实例即可,不必每创建一个Servlet都初始化一次。
首先创建一个监听器类Mylistener,实现ServletContextListener接口,重写contextInitialized方法。在contextInitialized方法内完成初始化等一系列操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @WebListener public class MyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); TemplateEngine engine = new TemplateEngine(); ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context); resolver.setPrefix("/WEB-INF/templates/"); resolver.setSuffix(".html"); resolver.setCharacterEncoding("utf-8"); engine.setTemplateResolver(resolver); context.setAttribute("engine",engine); } }
|
有了MyListener类,之前代码中engine对象的创建和init方法内的初始化操作都可以删掉了。