英文:
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: "02-Sep-20", y: 160.0 }, { label: "08-Sep-20", y: 125.0 }
]
浏览器控制台实际输出:
dataPoints: [
{ label: "02-Sep-20", y: 160.0 }, { label: "08-Sep-20", 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 &quot;
from Thymeleaf? I need the quotes to escape the date string in the JavaScript code.
Edit: Specifically the statement "\""
renders as &quot;
rather than "
.
String building method:
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 calender = LocalDate.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
sb.append("{ label: \"" + calender.format(DateTimeFormatter.ofPattern("dd-MMM-yy")) + "\", y: " + data.get(i).getWeight() + " }");
if (i < data.size() - 1) {
sb.append(", ");
}
}
return sb.toString();
}
Javacript with template
dataPoints: [
[[${dataPoints}]]
]
Expected Output:
dataPoints: [
{ label: "02-Sep-20", y: 160.0 }, { label: "08-Sep-20", y: 125.0 }
]
Actual output from browser console
dataPoints: [
{ label: &quot;02-Sep-20&quot;, y: 160.0 }, { label: &quot;08-Sep-20&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 Map
s 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<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 calender = LocalDate.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
Map<String, Object> entry = new HashMap<>();
entry.put("label", calender.format(DateTimeFormatter.ofPattern("dd-MMM-yy")));
entry.put("y", 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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论