首页 > 解决方案 > 当呈现为 html-text 时,Thymeleaf 模板中不处理内联 javascript

问题描述

我有一个构建报告的小型 SpringBoot 应用程序,我想通过电子邮件发送此报告。为了构建报告,我使用 Thymeleaf。为了构建图表,我使用了 google-charts,我将其渲染并插入为图像。

我用来在页面上显示报告和呈现电子邮件内容的模板是相同的:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="ISO-8859-1">
    <title>Report Generator</title>
    <script
            src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet"
          href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script type="text/javascript"
            src="https://www.gstatic.com/charts/loader.js"></script>
    <!-- Bootstrap core CSS -->
    <link href="../static/css/bootstrap.css" rel="stylesheet" th:href="@{css/bootstrap.css}"/>
</head>
<body class="d-flex h-100 text-center">

<div class="container-fluid">
    <div class="p-4 p-md-5 mb-4">
        <h1>Report Generator</h1>
        <div>
            <div class="table-responsive">
                <table class="table table-striped table-sm text-center" style="font-size:1.7rem">
                    <thead>
                    <tr>
                        <th>Test plan</th>
                        <th>Name</th>
                        <th>Pass</th>
                        <th>Failed</th>
                    </tr>
                    </thead>
                    <tr th:each="data: ${allData}">
                        <td><a th:href="@{'https://jira.com/browse/' + ${data.testPlanId}}"
                               th:text="${data.testPlanId}"/></td>
                        <td th:text="${data.testExecutions[0].summary}"></td>
                        <td th:text="${data.testExecutions[0].testCaseResults.get('PASS')}"></td>
                        <td th:text="${data.testExecutions[0].testCaseResults.get('FAIL')} + ${allData[0].testExecutions[0].testCaseResults.get('NEW')}"></td>
                    </tr>
                </table>
            </div>
        </div>
    </div>

    <div class="row mb-2">
        <div class="col-md-12" th:each="data,stat:${allData}">
            <div class="col-md-12">
                <h3 th:text="${data.testExecutions[0].summary} +' ('+${data.testPlanId}+')'"/>
                <div th:id="'chart_div'+${stat.index}" class="w-100 mw-100 p-3"></div>
            </div>
        </div>

        <script th:inline="javascript">
        var testExecutionData = /*[[${testExecutionData}]]*/'noValue';
        var allData = /*[[${allData}]]*/'noValue';

        $(document).ready(function() {
            google.charts.load('current', {
                packages : [ 'corechart', 'bar' ]
            });
            google.charts.setOnLoadCallback(drawColumnChart);
        });


        function drawColumnChart() {
            for (i = 0; i < allData.length; i++) {
                var data = prepareData(allData[i].testExecutions);

                var options = {
                   colors: ['#06a10f', '#cc0808', '#ec8f6e', '#f3b49f', '#f6c7b6'],
                   annotations: {
                    alwaysOutside: true,
                      textStyle: {
                        fontSize: 14,
                        color: '#000',
                        auraColor: 'none'
                      }
                    }
                };
                var chartObj = document.getElementById('chart_div'+i);
                var chart = new google.visualization.ColumnChart(chartObj);

                google.visualization.events.addListener(chart, 'ready', function () {
                    chartObj.innerHTML = '<img src="' + chart.getImageURI() + '">';
                  });
                chart.draw(data, options);

            }
        }

        function prepareData(data){
            var chartData =  new google.visualization.DataTable();
            chartData.addColumn('string', 'Test Execution');
            chartData.addColumn('number', 'Passed');
            chartData.addColumn({type: 'string', role: 'annotation'});
            chartData.addColumn('number', 'Failed');
            chartData.addColumn({type: 'string', role: 'annotation'});
            chartData.addColumn('number', 'New');
            chartData.addColumn({type: 'string', role: 'annotation'});
            var size = (data.length < 5) ? data.length : 5;
            for(var i=0; i<size; i++){
                chartData.addRow([testExecutionData[i].key,
                data[i].testCaseResults.PASS,
                data[i].testCaseResults.PASS.toString(),
                data[i].testCaseResults.FAIL,
                data[i].testCaseResults.FAIL.toString(),
                data[i].testCaseResults.NEW,
                data[i].testCaseResults.NEW.toString()
                ]);
            }
            return chartData;
        }
        </script>
    </div>
</div>
</body>
</html>

报告按预期成功呈现并显示在页面上,但是当我呈现电子邮件(不是插入的图表的图像)时未触发 inline-js。我像这样处理电子邮件的模板:

public void sendMessageUsingThymeleafTemplate(
        String to, String subject, Map<String, Object> templateModel)
        throws MessagingException {

    Context thymeleafContext = new Context();
    thymeleafContext.setVariables(templateModel);
    String htmlBody = thymeleafTemplateEngine.process("report.html", thymeleafContext);
    sendHtmlMessage(to, subject, htmlBody);
}

为什么 Thymeleaf 在呈现页面和将其呈现为 html-text 时对内联脚本的行为不同?

标签: spring-bootgoogle-visualizationthymeleaf

解决方案


我在浏览器中打开了 thymeleafTemplateEngine 为我呈现的 html,它显示了所有图表。显然,处理 javascript 而不是 Thymeleaf 是浏览器的工作。我需要找到一种方法在发送电子邮件之前对其进行预处理,以便像在浏览器中一样插入所有这些图像

<div id="chart_div0" class="w-100 mw-100 p-3"><img src="data:image/png;base64,iVBvx...">

推荐阅读