使用Thymeleaf在JavaScript中呈现未转义的字符

huangapple go评论85阅读模式
英文:

Rendering unescaped characters in javascript using thymeleaf

问题

private String getDataPoints() {
    ArrayList<WeightEntry> data = (ArrayList<WeightEntry>) repo.findAll();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.size(); i++) {
        LocalDateTime date = LocalDateTime.ofInstant(data.get(i).getDate().toInstant(), ZoneId.systemDefault());
        LocalDate calendar = LocalDate.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
        sb.append("{ label: \"").append(calendar.format(DateTimeFormatter.ofPattern("dd-MMM-yy"))).append("\",  y: ").append(data.get(i).getWeight()).append(" }");
        if (i < data.size() - 1) {
            sb.append(", ");
        }
    }

    return sb.toString();
}
dataPoints: [
    [(${dataPoints})]
]

期望输出:

dataPoints: [
    { label: &quot;02-Sep-20&quot;,  y: 160.0  }, { label: &quot;08-Sep-20&quot;,  y: 125.0  }
]

浏览器控制台实际输出:

dataPoints: [
    { label: &quot;02-Sep-20&quot;,  y: 160.0  }, { label: &quot;08-Sep-20&quot;,  y: 125.0  }
]

我正在使用spring-boot-starter-thymeleaf-2.3.4.RELEASE

英文:

I'm using a StringBuilder from my java controller to dynamically build a string of objects from my database for use in a JavaScript script on a Thymeleaf template web page.

Is there any way to keep an escaped quotation in java from processing as &amp;quot;from Thymeleaf? I need the quotes to escape the date string in the JavaScript code.

Edit: Specifically the statement &quot;\&quot;&quot; renders as &amp;quot; rather than &quot;.

String building method:

private String getDataPoints() {
		ArrayList&lt;WeightEntry&gt; data = (ArrayList&lt;WeightEntry&gt;) repo.findAll();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i &lt; data.size(); i++) {
			LocalDateTime date = LocalDateTime.ofInstant(data.get(i).getDate().toInstant(), ZoneId.systemDefault());
			LocalDate calender = LocalDate.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
			sb.append(&quot;{ label: \&quot;&quot; + calender.format(DateTimeFormatter.ofPattern(&quot;dd-MMM-yy&quot;)) + &quot;\&quot;,  y: &quot; + data.get(i).getWeight() + &quot;  }&quot;);
			if (i &lt; data.size() - 1) {
				sb.append(&quot;, &quot;);
			}
		}
		
		return sb.toString();
	}

Javacript with template

dataPoints: [
				[[${dataPoints}]]
			]

Expected Output:

dataPoints: [
				{ label: &quot;02-Sep-20&quot;,  y: 160.0  }, { label: &quot;08-Sep-20&quot;,  y: 125.0  }
			]

Actual output from browser console

dataPoints: [
				{ label: &amp;quot;02-Sep-20&amp;quot;,  y: 160.0  }, { label: &amp;quot;08-Sep-20&amp;quot;,  y: 125.0  }
			]

I am using spring-boot-starter-thymeleaf-2.3.4.RELEASE

答案1

得分: 0

这是因为 Thymeleaf 不知道你正在输出 JavaScript,而是将其视为 HTML。一个简单的解决方案是使用 Thymeleaf 的非转义内联语法,即 [( ... )]。(参见 Expression Inlining。)

dataPoints: [
    [(${dataPoints})]
]

然而,不要自己构建输出字符串(如果在转义时出错可能会导致安全问题),最好让 Thymeleaf 为你构建 JavaScript 表达式。(参见 Advanced inlined evaluation and JavaScript serialization)只需创建一个包含 Map 的普通 Java List,Thymeleaf 将自动将其输出为包含对象的数组:

private List<Map<String, Object>> getDataPoints() {
    ArrayList<WeightEntry> data = (ArrayList<WeightEntry>) repo.findAll();

    List<Map<String, Object>> result = new ArrayList<>(data.size());

    for (int i = 0; i < data.size(); i++) {
        LocalDateTime date = LocalDateTime.ofInstant(data.get(i).getDate().toInstant(), ZoneId.systemDefault());
        LocalDate calendar = LocalDate.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth());

        Map<String, Object> entry = new HashMap<>();
        entry.put("label", calendar.format(DateTimeFormatter.ofPattern("dd-MMM-yy")));
        entry.put("y", data.get(i).getWeight());

        result.add(entry);
    }

    return result;
}

为此,你还需要告诉 Thymeleaf 你正在输出 JavaScript,方法是在周围的脚本元素上添加属性 th:inline。同时不要自己添加数组括号,Thymeleaf 会为你创建:

<script th:inline="javascript">
  // ...
  dataPoints: [[${dataPoints}]]
  //...
</script>
英文:

This happens because Thymeleaf doesn't know you are outputting JavaScript, but thinks it's HTML. A simple solution would be to use Thymeleaf's non-escaped inline syntax which is [( ... )]. (See Expression Inlining.)

<!-- language: lang-js -->
dataPoints: [
[(${dataPoints})]
]

However instead of building the output string yourself (which can lead to security issues if you make a mistake when escaping), it would be better to let Thymeleaf build the JavaScript expression for you. (See Advanced inlined evaluation and JavaScript serialization) Just create a normal Java List containing Maps and Thymeleaf will automatically output it as an array containing objects:

<!-- language: lang-java -->
private List<Map<String, Object>> getDataPoints() {
ArrayList<WeightEntry> data = (ArrayList<WeightEntry>) repo.findAll();

    List&lt;Map&lt;String, Object&gt;&gt; result = new ArrayList&lt;&gt;(data.size());

    for (int i = 0; i &lt; data.size(); i++) {
        LocalDateTime date = LocalDateTime.ofInstant(data.get(i).getDate().toInstant(), ZoneId.systemDefault());
        LocalDate calender = LocalDate.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth());

        Map&lt;String, Object&gt; entry = new HashMap&lt;&gt;();
        entry.put(&quot;label&quot;, calender.format(DateTimeFormatter.ofPattern(&quot;dd-MMM-yy&quot;)));
        entry.put(&quot;y&quot;, data.get(i).getWeight());

        result.add(entry);
    }
    
    return result;
}

For this you also need to tell Thymeleaf that you outputting Javascript, by putting the attribute th:inline on the surroundting script element. Also don't add the array brackets yourself. Thymelead will create them for you:

<!-- language: lang-html -->
<script th:inline="javascript">
// ...
dataPoints: [[${dataPoints}]]
//...
</script>

huangapple
  • 本文由 发表于 2020年10月1日 09:31:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64147918.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定