Ftl 文件未在 Apache Camel+Springboot+Email 集成中呈现

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

Apache Camel+Springboot+电子邮件集成。 我正在尝试渲染一个 ftl 模板作为对发送到我的后端聊天机器人的电子邮件查询的回复。但是,我的 .ftl 文件无法渲染,并出现如下错误。我是 FTL 新手。任何我出错的地方或如何解决这个问题的建议都将非常好,非常感谢!

reemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> ftlDataMap  [in template "MyFtl.ftl" at line 61, column 14]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
FTL stack trace ("~" means nesting-related):
    - Failed at: #if ftlDataMap.replyMessages?size  [in template "MyFtl.ftl" at line 61, column 9]

MyFtl.ftl:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Email Reply</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }
        .email-container {
            width: 100%;
            max-width: 800px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
            background-color: #fff;
        }
        .title-ribbon {
            background-color: #007bff;
            color: #fff;
            padding: 10px;
            border-radius: 5px 5px 0 0;
            font-size: 20px;
            font-weight: bold;
            text-align: center;
        }
        .reply-section {
            margin: 20px 0;
        }
        .reply-section p {
            margin: 10px 0;
        }
        .content-html {
            background-color: #f9f9f9;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            word-wrap: break-word;
        }
        .original-message {
            border-top: 1px solid #ddd;
            padding-top: 20px;
        }
        .separator {
            margin: 20px 0;
            border-top: 2px dashed #ddd;
        }
    </style>
</head>
<body>
    <div class="email-container">
        <div class="title-ribbon">
            Email Reply
        </div>

        <#if ftlDataMap.replyMessages?size > 0>
            <#list ftlDataMap.replyMessages as reply>
                <#if reply.replyMessage?size > 0>
                    <#list reply.replyMessage?reverse as item>
                        <#if item.type == "AI Reply">
                            <p><strong>AI Reply:</strong> ${item.value}</p>
                        <#else>
                            <div class="content-html">${item.value?html}</div>
                        </#if>
                    </#list>
                <#else>
                    <p>No replies found.</p>
                </#if>
            </#list>
        <#else>
            <p>No reply messages found.</p>
        </#if>

        <div class="separator"></div>

        <div class="original-message">
            <p><strong>-----Original Message-----</strong></p>
            <#if ftlDataMap.replyMessages?size > 0>
                <#list ftlDataMap.replyMessages[0].originalMessage as item>
                    <p><strong>${item.label}</strong> ${item.value}</p>
                </#list>
            <#else>
                <p>No original message content found.</p>
            </#if>
        </div>
    </div>
</body>
</html>

我的Java课程:

public class CamelIMAPProcessor implements Processor {

    private static final Logger LOG = LoggerFactory.getLogger(CamelIMAPProcessor.class);

    @Override
    public void process(Exchange exchange) throws Exception {
        
        Map<String, Object> ftlDataMap = new LinkedHashMap<>();
        List<ValueExampleObject> originalMessage = new ArrayList<>();
        Map<String, Object> reply = new LinkedHashMap<>();
        List<Object> previousResp = new ArrayList<>();
        List<ValueExampleObject> chatBotReply = new ArrayList<>();

        String backendResponse = exchange.getIn().getBody(String.class);
        String originalEmailBody = (String) exchange.getProperty("originalEmailBody");
        String user_message = "";
        String fromAddress = exchange.getProperty("From", String.class);
        String toAddress = exchange.getIn().getHeader("To", String.class);
        String subject = exchange.getIn().getHeader("Subject", String.class);
        String timeStamp = exchange.getIn().getHeader("Date", String.class);

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(backendResponse);
        JsonNode groupInfo = rootNode.path("group_info");
        JsonNode conversationObjects = groupInfo.path("conversation_objects");

        // Extract "chat-text" and "html-embed" objects
        for (JsonNode objectNode : conversationObjects) {
            String objectType = objectNode.path("object_type").asText();
            JsonNode objectContent = objectNode.path("object_content");

            if ("chat-text".equals(objectType)) {
                LOG.info("Inside chat-text....");
                String myBackendResponseResponse = objectContent.path("response").path("textData").asText();
                user_message = objectContent.path("query").asText();
                chatBotReply.add(new ValueExampleObject("AI Reply", myBackendResponseResponse));
            }

            if ("html-embed".equals(objectType)) {
                LOG.info("Inside html-embed-response....");
                String htmlContent = objectContent.path("content").asText();
                chatBotReply.add(new ValueExampleObject("Embedded Content", htmlContent));
            }
        }
        reply.put("replyMessage", chatBotReply);
        originalMessage.add(new ValueExampleObject("-----Original Message-----", ""));
        originalMessage.add(new ValueExampleObject("From: ", fromAddress));
        originalMessage.add(new ValueExampleObject("Sent: ", timeStamp != null ? timeStamp : ""));
        originalMessage.add(new ValueExampleObject("To: ", toAddress));
        originalMessage.add(new ValueExampleObject("Subject: ", subject != null ? subject : ""));
        originalMessage.add(new ValueExampleObject("User Query:", user_message));
        originalMessage.add(new ValueExampleObject("", ""));
        reply.put("originalMessage", originalMessage);
        if (!reply.isEmpty()) {
            previousResp.add(reply);
            ftlDataMap.put("replyMessages", previousResp);
        }
        String output = createHtmlFromFreeMarkerTemplate(ftlDataMap);
        exchange.getIn().setBody(output);
    }

    private String createHtmlFromFreeMarkerTemplate(Map<String, Object> obj {
        try {
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
            cfg.setClassForTemplateLoading(CamelIMAPProcessor.class, "/templates");
            cfg.setDefaultEncoding("UTF-8");
            cfg.setLocale(Locale.US);
            cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

            Template template = cfg.getTemplate("MyFtl.ftl");
            StringWriter writer = new StringWriter();
            template.process(obj, writer);

            return writer.toString();
        } catch (Exception e) {
            // handle exc
        }
    }
}
apache-camel freemarker spring-camel
1个回答
0
投票

您有这个 Java 局部变量

Map<String, Object> ftlDataMap
,但它的名称对所有内容都是透明的,因为它只是一个局部变量。所以你不能在模板中引用它。无论如何,您正在使用
Map
数据模型的根,因此
Map
中的键是模板中的顶级变量名称。因此,您应该写
ftlDataMap.replyMessages
,而不是
replyMessages

另外

<#if ftlDataMap.replyMessages?size > 0>
也不正确,
>
中的
> 0
将关闭标签。请使用
<#if ftlDataMap.replyMessages?size != 0>
代替。 (当你确实需要使用
>
运算符时,如果由于某种原因它尚未在括号内,则必须改为编写
gt
。)

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