Bootstrap

javaweb基础:模板thymeleaf入门

其官网:https://www.thymeleaf.org/

看一下官网的解释:

Thymeleaf是⾯向Web和独⽴环境的现代服务器端Java模板引擎,能够处理HTML,XML,JavaScript,CSS甚⾄纯⽂本。
Thymeleaf旨在提供⼀个优雅的、⾼度可维护的创建模板的⽅式。 为了实现这⼀⽬标,Thymeleaf建⽴在⾃然模板的概念上,将其逻辑注⼊到模板⽂件中,不会影响模板设计原型。 这改善了设计的沟通,弥合了设计和开发团队之间的差距。
Thymeleaf从设计之初就遵循Web标准——特别是HTML5标准 ,如果需要,Thymeleaf允许您创建完全符合HTML5验证标准的模板。

看说明,可以得出好像说了什么,又好像什么都没有说。因为我也不知道说什么,不过 SpringBoot推荐的模板引擎就是Thymeleaf

不过现在不结合SpringBoot使用这个模板。直接同前面所学的servlet进行整合来使用,这样虽然麻烦点,但是至少学习这个模板,不会对其它的基础有要求。

搭建环境

依赖搭建

这个可以下载jar包,或者使用maven进行依赖环境配置:

搞这个需要的两个jar 包,既然是javaweb项目,所以必然有servlet这个jar包,还有一个thymeleaf的jar包:

servlet-api-***.jar
thymeleaf*.*.**.RELEASE    

其中* 是数字表示的是版本号,所以不再多说什么。

如果使用maven配置:

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

然后在IDE中创建一个Javaweb项目。

在这里插入图片描述

如果不知道如何在IDE中创建web项目:

  • 如果不会,想创建常用的web项目可以看另一篇文章:传送阵
  • 如果不会,想创建maven的web项目可以看另一篇文章:传送阵

配置解析器

既然启动Thymeleaf模板,那就是有要解析这个模板的类,看一下官网解释:

在这里插入图片描述

除了解释器,还有对 模版引擎的配置,这些就看了,一般会通过配置一个父类的servlet对加载的thymeleaf模板页面进行处理。然后自己的逻辑的servlet继承这个父类即可。

所以创建一个父类的servlet:

package com.xzd.servlet;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

同事还需与在web.xml中配置一些参数来满足:

  // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

具体配置如下:

    <!-- 在servletContext中配置上下文参数 -->
    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>

简单例子演示

先看一下整体结构

在这里插入图片描述

首先创建逻辑servlet类,其基础父类的servlet

//通过注释而配置servlet的 url 这样可以更加直观看web.xml中为thymeleaf做了什么
@WebServlet("/testservelt")
public class testservlet  extends  ViewBaseServlet{

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         HttpSession httpSession= req.getSession();
        List list=new ArrayList();
        list.add("战神");
        list.add("艾尔登法环");
        list.add("卧龙苍天陨落");
        list.add("霍格沃茨:遗产");
        httpSession.setAttribute("list",list);

//        //此处的视图名称是 index
//        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
//        //逻辑视图名称 :   testservlet  为了一致所以 html和servlet名字一样,当然也可以不一样
//        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
//        //所以真实的视图名称是:      /WEB-INF/html/       testservlet       .html
        super.processTemplate("testservlet",req,resp);

    }
}

看一下web.xml中的配置

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <!-- 在servletContext中配置上下文参数 -->
    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/WEB-INF/html/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>

</web-app>

然后写一个页面,不要关心thymeleaf的语法问题,主要是为了演示:

<!DOCTYPE html>
<!--在页面上外部导入thymeleaf-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        table {
            border-collapse: collapse;
        }

        table, td, th {
            border: 1px solid black;
        }

        #gameid {
            margin: 12px auto;
            collapse: 1px;
        }

        td {
            text-align: center;
            width: 160px;
        }
    </style>
</head>
<body>
<table id="gameid">
    <tr>
        <th class="w20">游戏名</th>
        <th>操作</th>
    </tr>
    <tr th:if="${#lists.isEmpty(session.list)}">
        <td colspan="4">对不起,库存为空!</td>
    </tr>
    <tr th:unless="${#lists.isEmpty(session.list)}" th:each="gamename : ${session.list}">

        <td><a th:text="${gamename}" href="#">默认没有如果不是通过服务器启动,就显示这个文本</a></td>

        <td><a th:text="购买" href="#">默认没有如果不是通过服务器启动,就显示这个文本</a></td>
    </tr>
</table>
</body>
</html>

为了方便,在index.jsp中写一个转发:

<html>
<body>
<h2>Hello World!</h2>
<%--转发到自己配置的url上--%>
<jsp:forward page="/testservelt"></jsp:forward>
</body>
</html>

然后访问:http://localhost:8080/thymeleaf_web/

然后看一下结果:

在这里插入图片描述

只要有例子了,后面就直接聊语法了,因为按照上面配置环境肯定没问题。

常用语法

Thymeleaf 模板引擎支持多种表达式:

  • 变量表达式:${…}
  • 选择变量表达式:*{…}
  • 链接表达式:@{…}
  • 国际化表达式:#{…}
  • 片段引用表达式:~{…}

表达式语法

th:text

th:text 是用来修改标签文本值,比如:

<p th:text="th表达式text的值">P标签体原始值</p>

其实例子中也可以看出其在演示时候输出的是th:text的值。不过需要注意其使用不同,显示的值也是不同的。

  • 不经过服务器解析,直接用浏览器打开HTML文件,看到的是标签中间文本。
  • 经过服务器解析,Thymeleaf引擎根据th:text属性指定的文本会替换标签中间的文本。
th:value

修改value属性值,比如:

<input type="text" th:value="1111111" value="2222222">

也是如果是服务器启动页面显示是1111111,如果是普通浏览器打开那就是2222222。

链接表达式 @{ }

意思是解析URL地址,还是演示:

<p th:text="@{/aaa/bbb/ccc}"></p>

但是IDE会提示报错,不过不会影响运行结果;

在这里插入图片描述

看一下结果就明白了:

在这里插入图片描述

会自动在前面添加项目名字,因为我创建的项目名字就是thymeleaf_web。

这个语法的好处是:实际开发过程中,项目在不同环境部署时,Web应用的名字有可能发生变化。所以上下文路径不能写死。而通过@{}动态获取上下文路径后,不会出错误。

操作域数据

对于web项目中的域不了解的话可以看一下,前面的文章:传送阵

直接演示常用的请求域,会话域,以及应用域。

首先咋servelt中创建数据

  @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("request_data", "request_data");
        HttpSession httpsession= req.getSession();
        httpsession.setAttribute("session_data","session_data");
        ServletContext servletContext=getServletContext();
        servletContext.setAttribute("application_data","application");
        super.processTemplate("testservlet",req,resp);

    }
}

然后再页面如此操作:

<p th:text="${request_data}"> </p>
<p th:text="${session.session_data}"> </p>
<p th:text="${application.application_data}"> </p>

可以看出后台传递的数据,再thymeleaf中呈现文本显示的适合其值格式如下:

th:text="${}" 
获取请求参数 param

得到url中的参数,这个还是来一个例子:

http://localhost:8080/thymeleaf_web/?username=张三&favourite=篮球&favourite=rap

然后看例子:

<p th:text="${param.username}"> </p>
<p th:text="${param.favourite}"> </p>
<p th:text="${param.favourite[0]}"> </p>
<p th:text="${param.favourite[1]}"> </p>

看结果就明白了。

在这里插入图片描述

内置对象

jsp中有内置对象,对于thymeleaf 也不例外,这个直接列举了。

Thymeleaf 中常用的内置基本对象如下:

  • #ctx :上下文对象;
  • #vars :上下文变量;
  • #locale:上下文的语言环境;
  • #request:HttpServletRequest 对象(仅在 Web 应用中可用);
  • #response:HttpServletResponse 对象(仅在 Web 应用中可用);
  • #session:HttpSession 对象(仅在 Web 应用中可用);
  • #servletContext:ServletContext 对象(仅在 Web 应用中可用)。

来一个例子:

<p th:text="${#request.getContextPath()}"></p>
<p th:text="${#request.getAttribute('请求域中数据值')}"></p>

除了能使用内置的基本对象外,变量表达式还可以使用一些内置的工具对象。

  • strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等;
  • numbers:数字工具对象,常用的方法有:formatDecimal 等;
  • bools:布尔工具对象,常用的方法有:isTrue 和 isFalse 等;
  • arrays:数组工具对象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等;
  • lists/sets:List/Set 集合工具对象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等;
  • maps:Map 集合工具对象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等;
  • dates:日期工具对象,常用的方法有:format、year、month、hour 和 createNow 等。

来一个例子:

<p th:text="${#dates.createNow()}"></p>

在这里插入图片描述

公共页面抽取

抽取公共页面 th:fragment

使用th:fragment来给这个片段命名:

先创建一个test.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div th:fragment="fragment_name" id="fragment_id">
  <span>抽取的啊公共页面片段</span>
</div>
</body>
</html>

具体路径是:

引用公共页面

在 Thymeleaf 中,我们可以使用以下 3 个属性,将公共页面片段引入到当前页面中。

  • th:insert:将代码块片段整个插入到使用了 th:insert 属性的 HTML 标签中;
  • th:replace:将代码块片段整个替换使用了 th:replace 属性的 HTML 标签中;
  • th:include:将代码块片段包含的内容插入到使用了 th:include 属性的 HTML 标签中。

使用上 3 个属性引入页面片段,都可以通过以下 2 种方式实现。

  • ~{templatename::selector}:模板名::选择器
  • ~{templatename::fragmentname}:模板名::片段名
通常情况下,~{} 可以省略,其行内写法为 [[~{...}]] 或 [(~{...})],其中 [[~{...}]] 会转义特殊字符,[(~{...})] 则不会转义特殊字符。

现在演示一下:

<p> 这个是调用的页面啊</p>
<!--th:insert 片段名引入-->
<div th:insert="/utils/test::fragment_name"></div>
<!--th:insert id 选择器引入-->
<div th:insert="/utils/test::#fragment_id"></div>

在这里插入图片描述

补充 :直接执行表达式

这个需要借助一下serlvet才行,所在servert中配置:

 @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setAttribute("htmllabel", "<span>测试</span>");
 
        super.processTemplate("testservlet",req,resp);

    }
}

然后再html中如此写:

<p>有转义效果:[[${htmllabel}]]</p>
<p>无转义效果:[(${htmllabel})]</p>

先看结果:

在这里插入图片描述

可以看出如果传递的数据带有html标签要求可以在页面。

[[${ 内容  }]]: 显示完整的数据,哪怕是标签也会当作文本显示

[(${ 内容   })]  会让传递数据中的html标签其效果

分支与迭代

既然是模板,那肯定也会又逻辑判断以及迭代的语句,所以下面简单的聊一下。

分支
if和unless

让标记了th:if、th:unless的标签根据条件决定是否显示。

  • th:if: 满足条件执行
  • th:unless: 不满足条件执行

其实这个两个例子前面例子演示了,还是直接黏贴过来:

   <tr th:if="${#lists.isEmpty(session.list)}">
        <td colspan="4">对不起,库存为空!</td>
    </tr>
    <tr th:unless="${#lists.isEmpty(session.list)}" th:each="gamename : ${session.list}">

简单理解可以将th:if和th:unless 理解为 java中的 if ------if not-----

其中的th: if还可以搭配not关键字使用,比如上面th:unless可以如下写:

 <tr th:unless="${#lists.isEmpty(session.list)}"></tr>
     替代为:
<tr th:if="${not #lists.isEmpty(session.list)}">></tr>
switch

有if的必然有这个关键字。

th:switch 与 Java 的 switch case语句类似通常与 th:case 配合使用,根据不同的条件展示不同的内容

还是直接演示:

<div th:switch="${session.game.id}">
    <p th:case=" 1">艾尔登法环</p>
    <p th:case=" 2">战神</p>
</div>
迭代

th:each 遍历,支持 Iterable、Map、数组等。

这个其实在演示的例子中用了:

    <tr th:unless="${#lists.isEmpty(session.list)}" th:each="gamename : ${session.list}">

        <td><a th:text="${gamename}" href="#">默认没有如果不是通过服务器启动,就显示这个文本</a></td>

        <td><a th:text="购买" href="#">默认没有如果不是通过服务器启动,就显示这个文本</a></td>

当然thymeleaf的语法还有很多,现在不过多阐述了,可以具体使用的时候可以聊,同时还有一点那就是如何整合springmpv,springboot等,这些再用的时候演示如何配置,这里就不再多说了。

;