使用 Spring Boot 处理单个 Thymeleaf 片段

问题描述 投票:0回答:5

在我的 Spring Boot 应用程序中,我需要处理单个 Thymeleaf 片段以获得其渲染的 HTML 输出。

我正在注射

@Autowired
private SpringTemplateEngine templateEngine;

然后尝试

Context context = new Context();
context.setVariable("key", value);

String html = this.templateEngine.process("fragments/foo :: bar(key=${key})", context);

foo.html
位于
src/main/resources/templates/fragments
:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head></head>
<body>
...

<th:block th:fragment="bar(key)">
    <!-- doing fancy stuff with key... -->
</th:block>

...
</body>
</html>

我没有更改 Thymeleaf 的任何自动配置值。

运行此代码,出现以下异常:

org.thymeleaf.exceptions.TemplateInputException: Error resolving template "fragments/foo :: bar(key=${key})", template might not exist or might not be accessible by any of the configured Template Resolvers
    at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:246) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1104) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:924) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:898) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    ...

我在这里做错了什么吗?如果我创建一个仅包含内容的文件

src/main/resources/templates/fragments/test.html
,那么整个事情就会开始工作

<div th:replace="fragments/foo :: bar(key=${key})"></div>

并通过

处理它
String html = this.templateEngine.process("fragments/test", context);

这将是一个可能的解决方案,但对我来说似乎有点黑客......

java spring-boot thymeleaf
5个回答
2
投票

肯的答案有效,但我用更简单的方式做到了:

templateEngine.process("nameTemplate", context, new DOMSelectorFragmentSpec("DOM selector"));

还有其他方法可以过滤处理后的模板,记录在这里


1
投票

SpringTemplateEngine
不解析片段。因此,模板名称不应包含片段声明。要处理片段,您必须使用另一个重载的
SpringTemplateEngine.process()
方法,并手动解析片段:

Context context = new Context();
context.setVariable("key", value);
ProcessingContext processingContext = new ProcessingContext(context);

StandardFragment fragmentSpec = 
    StandardFragmentProcessor.computeStandardFragmentSpec(templateEngine.getConfiguration(),
         processingContext, "fragments/foo :: #bar", "SpringStandard", "fragment");

String html = templateEngine.process("fragments/foo", 
    context, fragmentSpec.getFragmentSpec());

实际上,我没有使用

<th:block>
作为片段。我的片段如下所示:

<body>
...

   <div id="bar" th:remove="tag">
       <!-- doing fancy stuff with key... -->
       <span th:text="${key}"></span>
   </div>

...
</body>

正如您所指出的,我通过

#bar
div 的 id 选择了这个片段。


1
投票

使用 Thymeleaf 3.0.6 这非常简单。我没有找到直接的答案,所以我附上我的答案。 我有一个包含片段的文件(

myFragments.html
):

<html xmlns:th="http://www.thymeleaf.org">
<div th:fragment="firstFragment">
    <p th:text="${message}"></p>
</div>
<div th:fragment="secondFragment">
    <p th:text="${message}"></p>
</div>
</html>

我可以使用这个片段在 Java 代码中生成 HTML 输出,如下所示:

 import com.google.common.collect.Sets;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.thymeleaf.TemplateEngine;
 import org.thymeleaf.context.Context;
 import java.util.Set;

 @Service
 public ContentBuildService {
 @Autowired
 private TemplateEngine templateEngine;

     private String buildContent(String myMessage) {
        Context context = new Context();
        context.setVariable("message", myMessage);
        Set<String> fragmentsSelectors = 
                 Sets.newHashSet("firstFragment");

        return templateEngine.process("myFragments",fragmentsSelectors, context);
    }
}

我正在使用 Guava 库来创建 HashSet,但您当然可以创建简单的

new HashSet()
并添加具有片段名称的元素。


0
投票

我在 Thymeleaf 3 中为这个问题苦苦挣扎了一段时间,在搜索时找不到任何答案。对于遇到此问题的其他人,它在 TL 3 中进行了更改。现在您使用

Set<String>
参数,该参数没有在任何地方记录,但工作原理如下:

final Set<String> params = new HashSet<>();
params.add("/dashboard-fragment");
params.add("list");
final String result = engine.process("/dashboard-fragment", params, context);

这相当于使用

/dashboard-fragment :: list
片段规范。有效!

当 Java 9 最终发布时,我想您可以使用

Set.of()
工厂方法将其减少为一行。


0
投票

我使用的是Spring 3.2.0。上面的答案,尤其是

user2959589
帮助我做出了以下内容:

   private final SpringTemplateEngine templateEngine;

   private String renderFragment(String templateName, String fragmentName, ModelMap model) {
        Context context = new Context();
        context.setVariables(model);
        final Set<String> params = new HashSet<>();
        //        params.add(templateName);
        params.add(fragmentName);

        return templateEngine.process(templateName, params, context);
    }

请注意,

params.add(templateName)
已被注释掉 - 对我来说,它是否存在没有任何区别。

此代码还允许您向下传递模型,您不需要将参数添加到片段名称中(例如:

fragment/block :: myFragment(...)

这样称呼:

   ModelMap model = new ModelMap();
   model.addAttribute("fragmentVars", "vars");

   String html = renderFragment("/fragments/blocks", "myFragment", model);

我想你可以修改 renderFragment 以获取未更改的

/fragments/block :: myFragment
并将正确的部分放置在正确的位置,但这已经是我需要的了。

© www.soinside.com 2019 - 2024. All rights reserved.