springboot thymeleaf【转】【补】

 

thymeleaf模板

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html

thymeleaf模板引擎入门==>https://www.cnblogs.com/ai-developers/p/7395588.html

1、引入thymeleaf依赖

<!-- 切换thymeleaf版本 -->
<properties>
        <thymeleaf-spring5.version>3.0.9.RELEASE</thymeleaf-spring5.version>
        <!-- 布局功能的支持程序  thymeleaf3适配layout2以上版本 , thymeleaf2 适配 layout1版本 -->
        <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>

<dependencies>
    <!--在thymeleaf中使用认证标签需要的额外依赖-->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>3.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
</dependencies>

解决spring5与thymeleaf版本冲突的问题==>https://blog.csdn.net/m0_67401660/article/details/123842540

解决spring-boot配置thymeleaf版本问题(亲测有效)==>https://blog.csdn.net/qq_41115379/article/details/112983998

 

2、Thymeleaf使用

配置属性类

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
​
    private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
​
    private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
​
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
​
    public static final String DEFAULT_SUFFIX = ".html";
    ...

 

 

后台controller

PersonController中的方法

    /**
     * http://localhost:8080/jpa/thymeleaf/test
     * @return
     */
    @RequestMapping("/thymeleaf/test")
    public String thymeleafTest(Model model) {
        Person person = new Person("bobo", "123456789", "bobo@qq.com");
        model.addAttribute("person", person);
        return "savePerson";   //页面地址
    }

 

 

使用thymeleaf

前端savePerson.html

 

1、把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染;

2、导入thymeleaf的名称空间  <html lang="en" xmlns:th="http://www.thymeleaf.org">

3、使用thymeleaf语法;

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>成功!</h1>
    <!--th:text 将div里面的文本内容设置为 -->
    <div th:text="${person.name}">姓名</div>
  <div> [[${person.name}]] </div>
</body>
</html>

 

 

 

 

 thymeleaf语法规则

 基本元素

 

Order优先级从高到低 Feature Attributes 中文说明
1 Fragment inclusion th:insert
th:replace
片段包含: jsp:include
2 Fragment iteration th:each 遍历: c:forEach
3 Conditional evaluation th:if
th:unless
th:switch
th:case
条件判断: c:if
4 Local variable definition th:object
th:with
声明变量: c:set
5 General attribute modification th:attr
th:attrprepend
th:attrappend

任意属性修改

支持prepend, append

6 Specific attribute modification th:value
th:href
th:src
...
修改指定属性默认值
7 Text (tag body modification) th:text
th:utext
修改标签体内容
8 Fragment specification th:fragment 声明片段
9 Fragment removal th:remove  

 表达式

Simple expressions:(表达式语法)
Variable Expressions: ${...}:

获取变量值;OGNL;

1)、获取对象的属性、调用方法
2)、使用内置的基本对象:

#ctx : the context object.
#vars: the context variables.
#locale : the context locale.
#request : (only in Web Contexts) the HttpServletRequest object.
#response : (only in Web Contexts) the HttpServletResponse object.
#session : (only in Web Contexts) the HttpSession object.
#servletContext : (only in Web Contexts) the ServletContext object.

${session.foo}

3)、内置的一些工具对象:


#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).

Selection Variable Expressions

*{...}:选择表达式:和${}在功能上是一样;
补充:配合 th:object="${session.user}:

<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>

 

Message Expressions: #{...}:获取国际化内容
Link URL Expressions: @{...}:定义URL;

@{/order/process(execId=${execId},execType='FAST')}

Fragment Expressions: ~{...}:片段引用表达式


<div th:insert="~{commons :: main}">...</div>

 

Literals(字面量)


Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…

 

Text operations:(文本操作)


String concatenation: +
Literal substitutions: |The name is ${name}|

Arithmetic operations:(数学运算)


Binary operators: + , - , * , / , %
Minus sign (unary operator): -

Boolean operations:(布尔运算)


Binary operators: and , or
Boolean negation (unary operator): ! , not

Comparisons and equality:(比较运算)


Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )

Conditional operators:条件运算(三元运算符)


If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)

Special tokens:


No-Operation: _

 

thymeleaf片断fragment

 

基本片断(被引用)

myfragment.html

具体位置: resources/templates/commons/myfragment.html   (不一定要位于commons,但一定要在templates下)

<body>
    <!-- 无参片断 -->
    <nav th:fragment="topBar">
        <p> fragment no arg </p>
    </nav>

    <!-- 有参片断 -->
    <nav th:fragment="sideBar(fragmentArg1,fragmentArg2)">
        <p> fragment has arg </p>
        <a href="#" th:class="${fragmentArg1 =='main'?'nav-link active':'nav-link'}">
            超链接
        </a>
    </nav>
</body>

 

 

无参引用方式

 引用片断方式 说明  无参样例 效果
th:insert 将公共片段整个插入到声明引入的元素中

 

 

<div th:insert="commons/myfragment :: topBar"></div>

 

 

 
<div>
    <nav th:fragment="topBar">
        <p> fragment no arg </p>
    </nav>
</div>

 

th:replace 将声明引入的元素替换为公共片段

 

<div th:replace="commons/myfragment :: topBar"></div>

 

 

 
    

<nav th:fragment="topBar"> <p> fragment no arg </p> </nav>

 

th:include 将被引入的片段的内容包含进这个标签中

 

<div th:include="commons/myfragment :: topBar"></div>

 

 

 
<div>
    
        <p> fragment no arg </p>
    
</div>

 

 

有参引用方式

仅以th:replace为例

 

 

 引用片断方式 说明  有参样例,见小括号中两个参数 效果
th:insert 将公共片段整个插入到声明引入的元素中

 

 

<nav th:replace="~{commons/myfragment :: sideBar(fragmentArg1='main',fragmentArg2='none')}"></nav>

 

 

 

 

<nav th:fragment="sideBar(fragmentArg1,fragmentArg2)">
    <p> fragment has arg </p>
    <a href="#" th:class="${fragmentArg1 =='main'?'nav-link active':'nav-link'}">
        超链接
    </a>
</nav>

 

 

 

 thymeleaf获取上下文路径

关键字: springboot获取上下文路径 ,  thymeleaf获取上下文路径

https时会遇到跨域问题

            <script type="text/javascript" th:inline="javascript">
                 basePath = [[${#httpServletRequest.getScheme() + '://' + #httpServletRequest.getServerName() + ':' + #request.getServerPort()  + #request.getContextPath()}]]
                console.log("basePath="+basePath);
            </script>

console 打印:   basePath=https://localhost:80/managerSys/

以上带https头之后 , 当有反向代理nginx时, 获取的端口可能会不匹配, 此时最好把 ':' + #request.getServerPort() 去掉

 

 

https正常

  <script type="text/javascript" th:inline="javascript">
    var basePath = [[${ '//' + #httpServletRequest.getServerName()   + #request.getContextPath()}]];
    // var basePath = window.location.origin+"/managerSys"
    console.log("basePath=" + basePath);
  </script>

console 打印:   basePath=//localhost/managerSys 

以上不带schema头的基本路径(即不带http , https)等,此时浏览器会自动判断schema头,并在请求时自动追加 , 但有个缺点是只能暴露80或443端口 ,不能用其它端口, 不然默认跳到80或443中去导致找不到请求.

 

https正常

  <script type="text/javascript" th:inline="javascript">
    var basePath = window.location.origin+"/managerSys"
    console.log("basePath=" + basePath);
  </script>

console 打印:   basePath=http://localhost/managerSys

 

 

所以终极方案为

终极方案1

<html>
<script type="text/javascript">
   let basePath= window.location.origin + "[[${#request.getContextPath()}]]";
   alert("basePath=" + basePath);
</script>
</html>

 

终极方案2

thymeleaf内联写法

<script type="text/javascript" th:inline="javascript">
   let basePath= window.location.origin + [[${#request.getContextPath()}]];
   alert("basePath=" + basePath);
</script>

th:inline="javascript"这是Thymeleaf中的内联写法,支持在javascript访问model中的数据,所以以后想写[[${xxx.xxx}]]这样写法的时候一定要记得在script中写上th:inline="javascript"这样才能骚起来……不然就需要就双引号括起来写成"[[${xxx.xxx}]]"

 

alert弹窗http://localhost/managerSys  , 于是彻底解决https , http , 80 , 443等问题

 

thymeleaf资源加载问题(从Controller跳转)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Login</title>
    <!-- 第一种方式:<base> 标签为页面上的所有链接规定默认地址或默认目标 -->
    <base th:href="@{/}">
    <!-- 上面定义了base路径标签,那么这里的css路径就可以直接写css路径,Springboot中,static文件夹默认就是静态资源文件夹,所以这里static/css/mycss.css可以不写static/了 -->
    <link href="css/mycss.css" rel="stylesheet">

    <!-- 如果不使用base,那么这种方式也是可以的,@{/你的文件路径},缺陷就是每次引用都必须带上th:src="@{/}"这个才能正确引用,具体用什么方式,看你们自己 -->
    <script th:src="@{/js/myjs.js}"></script>

</head>
<body onload="f()">
<!--<div style="text-align: center;margin:0 auto;width: 1000px; ">-->
<div class="mydiv">
    <h1>配置Thymeleaf模板</h1>
    <table width="100%" border="1" cellspacing="1" cellpadding="0">
        <tr>
            <td>姓名</td>
            <td>年龄</td>
            <td>地址</td>
        </tr>
        <tr th:each="Admin:${list}" >
            <td th:text="${Admin.id}"></td>
            <td th:text="${Admin.a_id}"></td>
            <td th:text="${Admin.a_pwd}"></td>
        </tr>
    </table>
    <h2>ddd</h2>
</div>
</body>
</html>

 

个人比较倾向于在头部添加<base th:href="@{/}">标签,这样就不用在每个需要引入的地方都使用Thymeleaf th:href="@{/路径}"语法.
 

thymeleaf模板重定向和转发

在controller中使用"redirect:/xxx" 或 "forward:/yyy"即可

return "redirect:/emps";//新增成功后,返回到列表页面

 

因为在ThymeleafViewResolver.java的createView(...)中, 针对redirect: 和 forward: 有做特殊处理

    @Override
    protected View createView(final String viewName, final Locale locale) throws Exception {
        // First possible call to check "viewNames": before processing redirects and forwards
        if (!this.alwaysProcessRedirectAndForward && !canHandle(viewName, locale)) {
            vrlogger.trace("[THYMELEAF] View \"{}\" cannot be handled by ThymeleafViewResolver. Passing on to the next resolver in the chain.", viewName);
            return null;
        }
        // Process redirects (HTTP redirects)
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
            vrlogger.trace("[THYMELEAF] View \"{}\" is a redirect, and will not be handled directly by ThymeleafViewResolver.", viewName);
            final String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length(), viewName.length());
            final RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
            return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
        }
        // Process forwards (to JSP resources)
        if (viewName.startsWith(FORWARD_URL_PREFIX)) {
            // The "forward:" prefix will actually create a Servlet/JSP view, and that's precisely its aim per the Spring
            // documentation. See http://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-redirecting-forward-prefix
            vrlogger.trace("[THYMELEAF] View \"{}\" is a forward, and will not be handled directly by ThymeleafViewResolver.", viewName);
            final String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length(), viewName.length());
            return new InternalResourceView(forwardUrl);
        }
        // Second possible call to check "viewNames": after processing redirects and forwards
        if (this.alwaysProcessRedirectAndForward && !canHandle(viewName, locale)) {
            vrlogger.trace("[THYMELEAF] View \"{}\" cannot be handled by ThymeleafViewResolver. Passing on to the next resolver in the chain.", viewName);
            return null;
        }
        vrlogger.trace("[THYMELEAF] View {} will be handled by ThymeleafViewResolver and a " +
                        "{} instance will be created for it", viewName, this.viewClass.getSimpleName());
        return loadView(viewName, locale);
    }

 

 

 

何为RESTFUL

URI: /资源名称/资源标识 HTTP请求方式区分对资源CRUD操作

  普通CRUD(uri来区分操作) RestfulCRUD
查询 getEmp emp---GET
添加 addEmp?name=bobo&age=28 emp---POST
修改 updateEmp?id=29&name=bobo emp/{id}---PUT
删除 deleteEmp?id=2 emp/{id}---DELETE

 

2)、实验的请求架构;

实验功能 RestfulCRUD 请求URI 请求方式  
查询所有员工 emps GET

 

    //用于列表界面
    @GetMapping(value = "/emps")
    public String queryAll(ModelMap model, HttpSession session) {

 

 

 

查询某个员工(详情查看页) emp/2 GET

 

 

 

 

来到添加页面 emp GET

 

    //用于新增前
    @GetMapping(value = "/emp")
    public String gotoAddPage( ModelMap model, HttpSession session) {

 

 

添加员工 emp POST

 

 

<form th:action="@{/emp}" method="post">
    <input type="hidden" name="_method" th:value="${emp} != null ? 'put':''"/>
    <input type="hidden" name="id" th:value="${emp} != null ? ${emp.id}:''"/>
    <button type="submit" class="btn btn-default btn-danger">删除</button>
</form>    

 

 

来到修改页面(查出员工进行信息回显) emp/2 GET

 

 

    //用于更新前
    @GetMapping(value = "/emp/{id}")
    public String gotoUpdatePage(@PathVariable("id") Integer id, ModelMap model, HttpSession session) {

 

 

修改员工 emp PUT

 

<form th:action="@{/emp}" method="post">
    <input type="hidden" name="_method" th:value="${emp} != null ? 'put':''"/>
    <input type="hidden" name="id" th:value="${emp} != null ? ${emp.id}:''"/>
    <button type="submit" class="btn btn-default btn-danger">删除</button>
</form>    

 

 

删除员工 emp/2 DELETE

 

 

<form th:action="@{/emp/}+${emp.id}" method="post">
      <input type="hidden" name="_method" value="delete"/>
      <button type="submit" class="btn btn-default btn-danger">删除</button>
</form>

 

 

判断是否存在 emp/2 HEAD

存在就返回200,不存在返回400 (ElasticSearch 就是这么做的)

 

 

thymeleaf之独立使用模板引擎*****

$$$$$hymeleaf模板引擎入门==>https://www.cnblogs.com/ai-developers/p/7395588.html

https://www.programcreek.com/java-api-examples/?class=org.thymeleaf.templateresolver.TemplateResolver&method=setPrefix

    public void exportExcel(HttpServletRequest request, HttpServletResponse response, @RequestBody(required = false) Map<String, Object> parameters,
                            @RequestParam(value = "from", required = false) Integer from,
                            @RequestParam(value = "limit", required = false) Integer limit,
                            @RequestParam(value = "sorting", required = false) String sorting) {
        TemplateEngine templateEngine;
        //ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(request.getServletContext());//zcpd;
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        try {

            templateEngine = new TemplateEngine();
            templateResolver = new ClassLoaderTemplateResolver();
            templateResolver.setPrefix("templates/"); //模板位置
            templateResolver.setSuffix(".html");   //模板扩展名
            templateResolver.setTemplateMode("TEXT");//'HTML', 'XML', 'TEXT', 'JAVASCRIPT', 'CSS', 'RAW'
            templateResolver.setCharacterEncoding("UTF-8");
            templateResolver.setOrder(1);
            templateResolver.setCacheable(false);
            templateEngine.setTemplateResolver(templateResolver);

            //Context context = new Context();
            WebContext context = new WebContext(request, response, request.getServletContext());
            context.setVariable("results", request);

            //添加变量message到context
            context.setVariable("message", "hello thymeleaf");

            StringWriter stringWriter = new StringWriter();
            //解析模板并显示到浏览器
            templateEngine.process("bobo", context, stringWriter);
            //logger.info("stringWriter  = " + stringWriter);
            response.getWriter().write(stringWriter.toString());

            Document document = DocumentHelper.parseText(stringWriter.toString());
            String xmlData = document.asXML();
            logger.info(xmlData);

        } catch (Exception e) {
            e.printStackTrace();
        }


    }

 

 

thymeleaf方言dialect

Thymeleaf本身提供了StandardDialect,以及结合了Spring之后提供的SpringStandardDialect。Thymeleaf默认的语法 th:if等,就是定义在了StandardDialect中,th为方言的前缀,if为方言的处理器名称。

Thymeleaf3自定义方言Dialect与处理器==>https://blog.csdn.net/edzhou00/article/details/83276672

 

th:block

<th:block></th:block>是Thymeleaf提供的唯一的一个Thymeleaf块级元素,其特殊性在于Thymeleaf模板引擎在处理<th:block>的时候会删掉它本身,标签本身不显示,而保留其内容,应用场景主要有如下两个:

1、同时控制相连两个标签是否显示
如下代码:

<div id="div1" th:if="...">
</div>
<div id="div2" th:if="...">
</div>

 

div1和div2中两个if条件一样时,可以改成如下写法:

<th:block th:if="...">
    <div id="div1">
    </div>
    <div id="div2">
    </div>
</th:block>

 

2、循环同级标签
比如在表格中需要使用th:each循环两个tr,在不知道th:block标签时,可能会用th:each配合th:if使用,但是使用th:block就简单了,如下:

<table>
    <th:block th:each="...">
        <tr>...</tr>
        <tr>...</tr>
    </th:block>
</table>

转自: thymeleaf块标签(空标签)th:block,标签本身不显示==>http://www.yyjjssnn.cn/articles/849.html

其它笔记

* th:action    <form id="login" th:action="@{/login}">......</form>    定义后台控制器的路径
* th:each        循环List集合: <tr th:each="user,iterStat : ${list}"> <td th:text="${user.userName}">Onions</td> </tr> iterStat:下标
                      循环Map集合: <div th:each="mapS:${map}"> <div th:text="${mapS}"></div> </div>
                      循环数组:        <div th:each="arrayS:${arrays}"> <div th:text="${arrayS}"></div> </div>
* th:field        
* th:href        定义超链接,类似<a>标签的href 属性。value形式为@{/login}
* th:id            类似html标签中的id属性。    <div class="user" th:id = "(${index})"></div>
* th:if            <span th:if="${Sex} == 1" > <input type="redio" name="se" th:value="男" /> </span> 
                     <span th:if="${Sex} == 2"> <input type="redio" name="se" th:value="女" /> </span>
* th:include
* th:fragment
* th:object
* th:src            外部资源引入    <script th:src="@{/static/js/jquery-2.4.min.js}"></script>
* th:replace
* th:text           <input th:text=${param} />
* th:value        <input th:value=${param} />
 
条件判断可以这样写:<input th:text="(${user.isAdmin}?'管理员':'普通用户')"></input>
 
 
Hello, [[${user.name}]]! //[[]]写法会html转义
Hello, [(${user.name})]! //[()]写法不会html转义
 
thymeleaf的配置文件说明 
#spring.thymeleaf.cache = true #启用模板缓存。 
#spring.thymeleaf.check-template = true #在呈现模板之前检查模板是否存在。
#spring.thymeleaf.check-template-location = true #检查模板位置是否存在。
#spring.thymeleaf.content-type = text / html #Content-Type值。 
#spring.thymeleaf.enabled = true #启用MVC Thymeleaf视图分辨率。 
#spring.thymeleaf.encoding = UTF-8 #模板编码。 
#spring.thymeleaf.excluded-view-names = #应该从解决方案中排除的视图名称的逗号分隔列表。 
#spring.thymeleaf.mode = HTML5 #应用于模板的模板模式。另请参见StandardTemplateModeHandlers。 
#spring.thymeleaf.prefix = classpath:/ templates / #在构建URL时预先查看名称的前缀。 
#spring.thymeleaf.suffix = .html #构建URL时附加到查看名称的后缀。 
#spring.thymeleaf.template-resolver-order = #链中模板解析器的顺序。 
#spring.thymeleaf.view-names = #可以解析的视图名称的逗号分隔列表。/ templates / #在构建URL时先查看名称的前缀。 
#spring.thymeleaf.suffix = .html #构建URL时附加到查看名称的后缀。 
#spring.thymeleaf.template-resolver-order = #链中模板解析器的顺序。 
#spring.thymeleaf.view-names = #可以解析的视图名称的逗号分隔列表。/ templates / #在构建URL时先查看名称的前缀。 
#spring.thymeleaf.suffix = .html #构建URL时附加到查看名称的后缀。 
#spring.thymeleaf.template-resolver-order = #链中模板解析器的顺序。 
#spring.thymeleaf.view-names = #可以解析的视图名称的逗号分隔列表。

 

 

其它待研究知识点

thymeleaf中的内联[ [ ] ]==>https://www.cnblogs.com/suncj/p/4031486.html

 

参考

thymeleaf的使用及配置==>https://www.cnblogs.com/gqymy/p/9216686.html

关于thymeleaf+layout布局的使用方式【纯转】==>https://www.cnblogs.com/whatlonelytear/p/11308836.html

posted @ 2018-05-11 09:50  苦涩泪滴  阅读(268)  评论(0编辑  收藏  举报