三个案例带你入门Thymeleaf。模板引擎,终于不用在后端拼接前端代码了。

本文介绍了如何使用Thymeleaf模板引擎在Servlet项目中实现前后端分离,避免在后端拼接HTML代码。通过创建TemplateEngine,设置ServletContextTemplateResolver和WebContext,结合th:text、th:if和th:each等模板语法,实现了动态渲染页面和数据绑定。Thymeleaf提高了代码可读性和降低了出错率,示例包括动态渲染参数、猜数字游戏和渲染列表数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板引擎,终于不用在后端拼接前端代码了

如果想要在Servlet项目中直接返回html页面,最原始的方式就是返回字符串,然后设置响应报头Content-Type: text/html让浏览器进行html渲染。但是在后端通过字符串的方式写前端代码效率不仅低,而且容易出错。因此就需要使用模板引擎。

模板引擎的作用就是在前端代码中添加一些占位符,然后让后端的模板引擎去填写这些占位符。这样就可以不同在后端手动拼接前端代码的字符串了。

这里模板解析器使用的是Thymeleaf,因为这个是Spring中推荐使用的。可以在maven仓库中找到。

常用的Thymeleaf模板语法

  • th:text:在标签中展示该表达式中的结果
  • th:[HTML 属性]:设置标签的属性
  • th:if:当表达式结果为true,则显示内容。否则不显示内容。(注意:是显示/不显示,不是渲染/不渲染。渲染/不渲染是对于dom节点来说的,而显示/不显示只是节点中内容是否显示,而节点还是会生成的)
  • th:each:循环渲染元素

Thymeleaf中的模板语法有很多,这里只罗列几个最常见的,其他的语法可以现用现查。

案例:使用th:text模板语法将url中的参数动态渲染到界面中

  • Servlet代码
@WebServlet("/helloThymeleaf")  
public class HelloThymeleafServlet extends HttpServlet {  
    // 1.创建模板引擎,用于渲染网页  
    private TemplateEngine engine = new TemplateEngine();  
      
    @Override  
    public void init() throws ServletException {  
        // 2.创建模板解析器,用于找到模板文件  
        // 每一个webapp中都会创建一个ServerContext对象,多个Servlet共享一个Context对象  
        // 通过Context对象创建一个webapp中唯一的一个模板解析器,模板解析器就是用来找到模板文件的  
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(this.getServletContext());  
        // 通过设定模板文件的前缀和后缀,判定模板是哪些文件  
        resolver.setPrefix("/WEB-INF/template/");  
        resolver.setSuffix(".html");  
        resolver.setCharacterEncoding("utf-8");  
          
        // 3.将模板引擎和模板解析器关联在一起,即模板引擎需要渲染出模板  
        engine.setTemplateResolver(resolver);  
    }  
  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 获得url中的参数  
        String message = req.getParameter("message");  
        // 4.使用webContext将模板中的参数进行替换,其实就相当于是一个哈希表  
        WebContext webContext = new WebContext(req, resp, this.getServletContext());  
        webContext.setVariable("message", message);  
  
        // 5.模板引擎渲染模板  
         engine.process("hello", webContext, resp.getWriter());  
        // 上面这句话也可以拆开来写  
        // String html = engine.process("hello", webContext);  
        // resp.getWriter().write(html);    }  
}
  • 前端代码
<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <meta http-equiv="X-UA-Compatible" content="IE=edge">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>Thymeleaf</title>  
</head>  
<body>  
	<!-- 通过模板引擎进行传递参数message,然后动态渲染 -->
    <h3 th:text="${message}"></h3>  
</body>  
</html>

注意:模板文件一定要放在webapp下的WEB-INF文件夹下的template(自己创建)文件夹下。
![[Pasted image 20220822224216.png]]

总结模板引擎套路

  1. 创建TemplateEngine模板引擎,之后使用该对象的process()渲染模板
  2. 创建ServletContextTemplateResolver模板解析器,用于找到模板文件文职,并加载模板文件,
  3. 创建WebContext对象,存储前端变量和Java变量之间的映射关系,之后可以配合模板解析器动态渲染模板。

此外,需要注意模板文件的目录位置模板文件中Thymeleaf的写法。如果目录位置或者模板语法出错,服务器会就返回500错误。

使用th:if,th:text模板语法完成一个Web版的猜数字界面

  • Servlet代码
@WebServlet("/guessNum")  
public class GuessNumServlet extends HttpServlet {  
    private int guessNum = 0; // 随机数字  
    private int count = 0; // 累计猜数字次数  
    // 创建模板引擎  
    private TemplateEngine engine = new TemplateEngine();  
  
    // 在init()中创建模板解析器  
    @Override  
    public void init() throws ServletException {  
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(this.getServletContext());  
        resolver.setPrefix("/WEB-INF/template/");  
        resolver.setSuffix(".html");  
        resolver.setCharacterEncoding("utf-8");  
        // 模板引擎和模板解析器关联  
        engine.setTemplateResolver(resolver);  
    }  
  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        resp.setContentType("text/html; charset=utf-8");  
        Random random = new Random();  
        guessNum = random.nextInt(100) + 1; // [1, 100]  
        // 建立映射关系  
        WebContext webContext = new WebContext(req, resp, this.getServletContext());  
        webContext.setVariable("guessNum", true);  
        // 渲染模板  
        engine.process("guessNum", webContext, resp.getWriter());  
    }  
  
    @Override  
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 比较数字大小  
        resp.setContentType("text/html; charset=utf-8");  
        String parameter = req.getParameter("num");  
        int num = Integer.parseInt(parameter);  
        String result = "";  
        if (num > guessNum) {  
            result = "猜大了";  
        } else if (num < guessNum) {  
            result = "猜小了";  
        } else {  
            result = "猜对了";  
        }  
        count ++;  
  
        // 建立映射关系  
        WebContext webContext = new WebContext(req, resp, this.getServletContext());  
        webContext.setVariable("newGame", false);  
        webContext.setVariable("result", result);  
        webContext.setVariable("count", count);  
        // 渲染模板  
        engine.process("guessNum", webContext, resp.getWriter());  
    }  
}
  • 前端代码
<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <meta http-equiv="X-UA-Compatible" content="IE=edge">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>猜数字</title>  
</head>  
<body>  
    <form action="guessNum" method="POST">  
        <input type="text" name="num">  
        <br>        <input type="submit" value="提交">  
    </form>  
    <div th:if="${!newGame}">  
        <div th:text="${result}"></div>  
        <div th:text="${count}"></div>  
    </div></body>  
</html>

模板引擎存在的最大意义就是让Java代码和前端代码分离开来了。这样使得代码的阅读星提高了,出错率降低了。

案例:使用th:each模板语法在前端渲染出多个人的姓名和手机号

  • Servlet代码
class Person {  
    public String name;  
    public String phone;  
  
    public Person(String name, String phone) {  
        this.name = name;  
        this.phone = phone;  
    }  
}  
  
@WebServlet("/each")  
public class EachServlet extends HttpServlet {  
    private TemplateEngine engine = new TemplateEngine();  
  
    @Override  
    public void init() throws ServletException {  
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(getServletContext());  
        resolver.setPrefix("/WEB-INF/template/");  
        resolver.setSuffix(".html");  
        resolver.setCharacterEncoding("utf-8");  
        engine.setTemplateResolver(resolver);  
    }  
  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        resp.setContentType("text/html; charset=utf-8");  
        List<Person> persons = new ArrayList<Person>();  
        persons.add(new Person("张三", "123"));  
        persons.add(new Person("李四", "456"));  
        persons.add(new Person("王五", "789"));  
  
        WebContext webContext = new WebContext(req, resp, getServletContext());  
        webContext.setVariable("persons", persons);  
        // 如果使用engine.process("thymeleafEach", webContext, resp.getWriter());的话,  
        // 异常会被“消化”,因此如果模板语法出错或者Servlet代码出错服务器是不会响应异常的  
        // engine.process("thymeleafEach", webContext, resp.getWriter());  
  
        // 如果先使用engine.process("thymeleafEach", webContext);然后通过resp.getWriter().write()渲染的话  
        // 那么如果代码出错,服务器就会显示异常。  
        // 因此推荐当服务器出错的话,使用这种写法比较好  
        String html = engine.process("thymeleafEach", webContext);  
        resp.getWriter().write(html);  
    }  
}
  • 前端代码
<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <meta http-equiv="X-UA-Compatible" content="IE=edge">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>Document</title>  
</head>  
<body>  
    <ul>        <li th:each="person: ${persons}">  
            <span th:text="${person.name}"></span>  
            :   
            <span th:text="${person.phone}"></span>  
        </li>    </ul></body>  
</html>
  • 实验结果
    ![[Pasted image 20220823083223.png]]

编写Thymeleaf如果出错,经常出现问题的地方

一般Thymeleaf出现问题,都是模板语法出现问题,或者是**前后端的变量没有关联(WebContext出现问题)**上。

如果使用engine.process("模板", wecContext, resp.getWriter()),这个方法会自动处理抛出来的异常,所以如果模板出现问题也不会抛出异常。

如果先通过engine.process("模板", webContext)html页面的字符串获得,然后使用resp.getWriter().write()方法的话,那么模板出现问题,服务器就会出现异常,并返回500页面,通过500页面中的错误提示,就可以很快定位到问题所在。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值