Spring Boot+Thymeleaf:如何在JS中遍历Map生成动态饼图
问题:Spring Boot + Thymeleaf 实现 CanvasJS 饼图动态数据渲染
我用Spring Boot搭配Thymeleaf开发项目,之前静态HTML能正常渲染CanvasJS饼图,现在需要让饼图数据从后端的foodMap(存储食物名称与占比的BigDecimal值)动态生成。尝试在JavaScript的dataPoints数组中用Thymeleaf的th:each遍历Map,但写法无效,求正确实现方式。
相关代码
静态HTML代码(可正常渲染静态饼图)
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <script> window.onload = function() { var foodChart = new CanvasJS.Chart("foodChart", { animationEnabled: true, title: {text: "Foods"}, data: [{ type: "pie", startAngle: 240, yValueFormatString: "##0.00\"%\"", indexLabel: "{label} {y}", dataPoints: [ {y: 95.0, label: "Pizza"}, {y: 5.0, label: "French Fries"} ] }] }); foodChart.render(); } </script> </head> <body> <div id="foodChart" style="height: 300px; width: 100%;"></div> <script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script> </body> </html>
后端Java代码
Map<String,BigDecimal> foodMap = new HashMap<>(); foodMap.put("Pizza", BigDecimal.valueOf(35.0)); // 35% foodMap.put("French Fries", BigDecimal.valueOf(65.0)); // 65%
尝试的无效模板代码
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <script> window.onload = function() { var foodChart = new CanvasJS.Chart("foodChart", { animationEnabled: true, title: {text: "Foods"}, data: [{ type: "pie", startAngle: 240, yValueFormatString: "##0.00\"%\"", indexLabel: "{label} {y}", dataPoints: [ <th:each="key: ${foodMap}"> {<th:text="y: ${value}, label: ${key}" />} </th> ] }] }); foodChart.render(); } </script> </head> <body> <div id="foodChart" style="height: 300px; width: 100%;"></div> <script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script> </body> </html>
解决方案
核心修正点
- 正确遍历Map:Thymeleaf遍历Map时需通过
entry对象获取键值对,语法为th:each="entry, entryStat : ${foodMap}",其中entry.key是食物名称,entry.value是占比数值;entryStat用于判断是否为最后一个元素,避免生成多余逗号导致JavaScript语法错误。 - 格式匹配JSON:生成的dataPoints元素要符合JavaScript对象格式,label值需加引号,BigDecimal值要转为JavaScript可识别的数值类型。
完整正确模板代码
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <script> window.onload = function() { var foodChart = new CanvasJS.Chart("foodChart", { animationEnabled: true, title: {text: "Foods"}, data: [{ type: "pie", startAngle: 240, yValueFormatString: "##0.00\"%\"", indexLabel: "{label} {y}", dataPoints: [ <!-- 遍历Map的entry对象,同时获取状态变量判断是否为最后一个元素 --> <th:each="entry, entryStat : ${foodMap}"> {y: [[${entry.value.doubleValue()}]], label: "[[${entry.key}]]"} <!-- 最后一个元素不添加逗号 --> <th:if="!${entryStat.last}">,</th:if> </th:each> ] }] }); foodChart.render(); } </script> </head> <body> <div id="foodChart" style="height: 300px; width: 100%;"></div> <script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script> </body> </html>
关键说明
- 使用
[[${}]](Thymeleaf内联表达式)替代th:text,更适合在JavaScript代码中直接渲染变量,避免标签嵌套导致的格式问题。 - 调用
entry.value.doubleValue()将BigDecimal转为JavaScript的数值类型,确保饼图能正确识别占比数据。 - 通过
entryStat.last判断是否为最后一个元素,避免在dataPoints数组末尾生成多余逗号,防止JavaScript解析错误。
内容的提问来源于stack exchange,提问作者hotmeatballsoup
相关产品推荐
相关产品推荐

