thymeleaf 是一个很好用的模版引擎,其中 fragment 关键字可以让我们重用一些 html 元素,我们知道可以通过设定 Model 的 Attribute 来向 thymeleaf 传递 fragment 参数,那么能不能通过这种方式来使用不同的 fragment 呢?
本文假定已经有了一个配置好的包含 thymeleaf 的 springboot 项目。首先,创建一个 TestController
:
@Controller
public class TestController {
@RequestMapping(path = "test")
public ModelAndView test(ModelAndView mav) {
mav.setViewName("test");
return mav;
}
}
所以我们的 resources/templates 下应该有一个 test.html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="bootstrap-4.3.1-dist/css/bootstrap.min.css">
</head>
<body>
test.html body
</body>
</html>
接下来我们在这个基础上展示如何使用 fragment
我们可以新建一个 fragments.html 来存放 fragment:
<body>
<div th:fragment="fragment1()">
this is fragment 1
</div>
<div th:fragment="fragment2()">
this is fragment 2
</div>
</body>
然后,我们修改 test.html 的 body 来使用 fragment:
<body>
test.html body <br>
<div th:replace="fragments :: fragment1()"></div>
</body>
运行这个程序后,在浏览器访问 localhost:8080/test,应该可以看到以下结果
test.html body
this is fragment 1
接下来我们试试把 fragment1 替换成参数
首先修改一下 TestController
, 增加参数 frag
@Controller
public class TestController {
@RequestMapping(path = "test")
public ModelAndView test(ModelAndView mav) {
mav.addObject("frag", "fragments :: fragment1()");
mav.setViewName("test");
return mav;
}
}
然后在页面上输出 frag,看有没有正确传递给 thymeleaf
<body>
test.html body <br>
<p th:text="${frag}"></p>
<div th:replace="fragments :: fragment1()"></div>
</body>
修改完成后访问 localhost:8080/test,浏览器应该有以下输出:
test.html body
fragments :: fragment1()
this is fragment 1
所以 thymeleaf 可以正确拿到 frag 的值,那我们能不能让 th:replace
也使用 frag 呢?我们把 test.html 修改成这样:
<body>
test.html body <br>
<p th:text="${frag}"></p>
<div th:replace="${frag}"></div>
</body>
再次访问 localhost:8080/test,结果是报错,你可以在 stacktrace 中找到以下提示:
Caused by: org.attoparser.ParseException: Error resolving template [fragments :: fragment1()], template might not exist or might not be accessible by any of the configured Template Resolvers (template: "test" - line 9, col 8)
at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
... 48 more
Caused by: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [fragments :: fragment1()], template might not exist or might not be accessible by any of the configured Template Resolvers (template: "test" - line 9, col 8)
模版引擎没有办法解析这个模版,可是如果写明 th:replace="fragments :: fragment1()"
,就不会有问题,这是一个让人很困惑的问题,先说我们如何解决,让我们修改一下 test.html
<body>
test.html body <br>
<p th:text="${frag}"></p>
<div th:replace="__${frag}__"></div>
</body>
再访问 localhost:8080/test:
test.html body
fragments :: fragment1()
this is fragment 1
成功了!我们可以在代码中把 frag 的值修改为 fragment2,再试一下结果,这里就不赘述了
「__${frag}__」 的写法在 thymeleaf 中称作 预处理 ,所以我们可以推测, thymeleaf 拿到字符串后会做一次处理,比如把 ${frag} 替换为 fragment1,然后就当成新字符串拿来使用了,但是其实我们是要使用字符串所代表的模版,这个时候就要告诉 thymeleaf,解析成字符串只是第一步,接下来我们还要转换成模版使用。