问题引入
当直接访问HTML
文件时,可以访问到的部分静态资源可能由于路径配置的原因,在Springboot中报错,我们希望能在不影响当前网页功能、不破坏结构的情况下修改路径达到效果
又或者在前端各页面中存在大量雷同的代码块,例如博客项目中存在Navigation Bar和footer等布局大量相同的情况,如果想对这些布局中等元素进行统一修改将会非常麻烦
而Thymeleaf很好的解决了这样的痛点
项目示例
以下将做几个博客中简单的示例:
我们定义一个Thymeleaf模版_fragment.html
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
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head th:fragment="head(title)"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title th:replace="${title}">博客详情</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.2.4/dist/semantic.min.css"> <link rel="stylesheet" href="../static/css/typo.css" th:href="@{/css/typo.css}"> <link rel="stylesheet" href="../static/css/me.css" th:href="@{/css/me.css}"> <link rel="stylesheet" href="../static/css/animate.css" th:href="@{/css/animate.css}"> <link rel="stylesheet" href="../static/lib/prism/prism.css" th:href="@{/lib/prism/prism.css}"> <link rel="stylesheet" href="../static/lib/tocbot/tocbot.css" th:href="@{/lib/tocbot/tocbot.css}"> <link rel="stylesheet" href="../static/lib/editormd/css/editormd.css" th:href="@{/lib/editormd/css/editormd.css}"> </head> <body> <nav th:fragment="menu(n)" class="ui inverted attached segment m-padded-tb-mini m-shadow-small"> <div class="ui container"> <div class="ui inverted secondary stackable menu"> <h2 class="ui teal header item">Blog</h2> <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==1}?'active'"><i class="home icon"></i>首页</a> <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==2}?'active'"><i class="idea icon"></i>分类</a> <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==3}?'active'"><i class="tags icon"></i>标签</a> <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==4}?'active'"><i class="clone icon"></i>归档</a> <a href="#" class="m-item item m-mobile-hide" th:classappend="${n==5}?'active'"><i class="info icon"></i>关于我</a> <div class="right item m-mobile-hide"> <div class="ui icon inverted transparent input"> <input type="text" placeholder="Search...."> <i class="search link icon"></i> </div> </div> </div> </div> <a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show"> <i class="sidebar icon"></i> </a> </nav>
<footer th:fragment="footer" class="ui inverted vertical segment m-padded-tb-massive"> ...... </footer>
<th:block th:fragment="script"> <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/jquery.scrollto@2.1.3/jquery.scrollTo.min.js"></script> <script src="../static/lib/prism/prism.js" th:src="@{/lib/prism/prism.js}"></script> <script src="../static/lib/tocbot/tocbot.min.js" th:src="@{/lib/tocbot/tocbot.min.js}"></script> <script src="../static/lib/qrcode/qrcode.min.js" th:src="@{/lib/qrcode/qrcode.min.js}"></script> <script src="../static/lib/waypoint/jquery.waypoints.min.js" th:src="@{/lib/waypoint/jquery.waypoints.min.js}"></script> <script src="../../static/lib/editormd/editormd.js" th:src="@{/lib/editormd/editormd.js}"></script> </th:block> </body> </html>
|
其中
- head块中,引入参数title,用于替换标签页标题“博客详情”字样
- menu块中,引入参数n,不同的n对应不同的顶栏按钮被追加
active
属性
- footer和script块也为类似模版代码
- 注意到src路径在Springboot中由于静态资源的路径问题,不生效,我们改由Thymeleaf使用
th:href
和th:src
标签引入static下的新路径
具体调用方法如下:
在博客首页index.html
中:
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
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head th:replace="_fragments :: head(~{::title})"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>首页</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.2.4/dist/semantic.min.css"> <link rel="stylesheet" href="../static/css/me.css"> </head> <body>
<nav th:replace="_fragments :: menu(1)" class="ui inverted attached segment m-padded-tb-mini m-shadow-small"> <div class="ui container"> <div class="ui inverted secondary stackable menu"> <h2 class="ui teal header item">Blog</h2> <a href="#" class="m-item item m-mobile-hide"><i class="home icon"></i>首页</a> <a href="#" class="m-item item m-mobile-hide"><i class="idea icon"></i>分类</a> <a href="#" class="m-item item m-mobile-hide"><i class="tags icon"></i>标签</a> <a href="#" class="m-item item m-mobile-hide"><i class="clone icon"></i>归档</a> <a href="#" class="m-item item m-mobile-hide"><i class="info icon"></i>关于我</a> <div class="right item m-mobile-hide"> <div class="ui icon inverted transparent input"> <input type="text" placeholder="Search...."> <i class="search link icon"></i> </div> </div> </div> </div> <a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show"> <i class="sidebar icon"></i> </a> </nav> <footer th:replace="_fragments :: footer" class="ui inverted vertical segment m-padded-tb-massive"> ............ </footer> <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>
<script> $('.menu.toggle').click(function (){ $('.m-item').toggleClass('m-mobile-hide'); }); </script> </body> </html>
|
- 通过
th:replace="_fragments :: head(~{::title})"
的方式,我们从原先inedx
的代码块中获取到了title
的值并将它覆盖到了_fragments
对应模版上,随后使用模版替换了当前代码块
- 通过
th:replace="_fragments :: menu(1)"
加入了参数n = 1
,触发了_fragments
中对首页按钮追加的active
属性,随后使用模版替换了代码块(甚至导航整块删除后Springboot访问仍然不受影响,因为已经被Thymeleaf替换了,但是本地静态网页渲染时结构会遭到破坏)
- 通过加入
<!--/*/<th:block th:replace="_fragments :: script">/*/-->
和<!--/*/</th:block>/*/-->
注释的方式,我们可以让浏览器直接加载HTML时忽略外部的包裹,而实际Springboot启动时,Thymeleaf代码块会视其为有效
PS:Thymeleaf的妙处就在这里,在本地打开对应的HTML时,Thymeleaf代码不生效,使用对应的本地路径,可以确保浏览器正常渲染,而使用Springboot时,Thymeleaf会注入模版和参数,按照我们之前配置的形式去运行,我们只需要对对应代码块加入一个标签就能实现托管
类似的我们还可以使用th:inline
对Javascript和jQuery代码进行修改
例如,在博客输入页面中,我们引入了markdown-editor部件,并引入了css和js文件(已经通过Thymeleaf完成了路径替换)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head th:replace="_fragments :: head(~{::title})"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>博客发布</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.2.4/dist/semantic.min.css"> <link rel="stylesheet" href="../../static/lib/editormd/css/editormd.css"> <link rel="stylesheet" href="../../static/css/me.css"> </head> <body> .................. <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script> <script src="../../static/lib/editormd/editormd.js"></script> ................. </body>
|
关键在于为了markdown对正常使用,官方使用了一段jQuery代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script> var contentEditor; $(function() { contentEditor = editormd("md-content", { width : "100%", height : 640, syncScrolling : "single", path : "../../static/lib/editormd/lib/", tex: true, flowChart : true, sequenceDiagram : true }); }); </script>
|
对应资源目录如下:
本地环境下浏览器渲染运行无问题
而部署到Springboot上时,插件开始转圈,并且无法加载:
显然由于路径配置问题,"../../static/lib/editormd/lib/"
路径下的js和css文件不能生效,爆出404错误
这里我们采用th:inline
对jQuery进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script th:inline="javascript"> var contentEditor; $(function() { contentEditor = editormd("md-content", { width : "100%", height : 640, syncScrolling : "single", path : "../../static/lib/editormd/lib/", tex: true, flowChart : true, sequenceDiagram : true }); }); </script>
|
由于引入了注释,本地访问时浏览器仍然会去请求"../../static/lib/editormd/lib/"
目录,而使用Springboot进行部署时,Thymeleaf会使用@{/lib/editormd/lib/}
路径对原先路径进行替换
如图样式加载正常:
达到了预期效果