[Servlet/Controller] → JFreeChart API → 圖表對象 → ServletUtilities.saveChartAsPNG → 臨時文件 → 返回文件名
↓ ↓
[JSP/前端] ← graphURL = /DisplayChart?filename=xxx ← 顯示 Servlet (web.xml 配置) ← 文件名
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/DisplayChart</url-pattern>
</servlet-mapping>
DisplayChart 內建 Servlet 讀取 Session 中的臨時文件流直接輸出圖片,無需控制器干預。
public String generateChartUrl(String[] series, double[][] scores, String[] categories, String title, HttpSession session) {
// 1. 數據集
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int s = 0; s < series.length; s++) {
for (int c = 0; c < categories.length; c++) {
dataset.addValue(scores[s][c], series[s], categories[c]);
}
}
// 2. 創建折線圖
JFreeChart chart = ChartFactory.createLineChart(
title, null, null, dataset,
PlotOrientation.VERTICAL, true, true, false
);
// 3. 圖表美化 (核心 API)
chart.getLegend().setPosition(RectangleEdge.RIGHT);
chart.setBackgroundPaint(Color.WHITE);
CategoryPlot plot = chart.getCategoryPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.GRAY);
plot.setDomainGridlinePaint(Color.GRAY);
plot.setBackgroundAlpha(0.8f);
// 字體設置 (解決中文亂碼)
Font titleFont = new Font("微軟雅黑", Font.BOLD, 16);
Font axisFont = new Font("微軟雅黑", Font.PLAIN, 12);
Font legendFont = new Font("微軟雅黑", Font.PLAIN, 12);
chart.getTitle().setFont(titleFont);
chart.getLegend().setItemFont(legendFont);
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setTickLabelFont(axisFont);
domainAxis.setLabelFont(axisFont);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 傾斜 45° 防重疊
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setTickLabelFont(axisFont);
rangeAxis.setLabelFont(axisFont);
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setAutoRangeIncludesZero(true);
rangeAxis.setUpperBound(3.5); // 根據業務調整
// 線條樣式
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
renderer.setShapesVisible(true); // 顯示數據點
renderer.setSeriesStroke(0, new BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f, new float[]{10f, 6f}, 0f)); // 虛線
renderer.setSeriesStroke(1, new BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f, new float[]{6f, 6f}, 0f));
renderer.setBaseItemLabelsVisible(true);
renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
// 4. 保存為臨時文件,獲取文件名
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
String fileName = null;
try {
fileName = ServletUtilities.saveChartAsPNG(chart, 700, 300, info, session);
} catch (IOException e) {
throw new RuntimeException("圖表生成失敗", e);
}
// 5. 返回訪問 URL
return "/DisplayChart?filename=" + fileName; // 相對路徑,前端直接
}
<!-- JSP -->
<% String chartUrl = chartService.generateChartUrl(series, scores, categories, "業務圖表", session); %>
<img src="<%= request.getContextPath() %><%= chartUrl %>" width="700" height="300" />
<!-- Thymeleaf -->
<img th:src="@{${chartUrl}}" width="700" height="300" />
<!-- Vue/React -->
<img :src="baseUrl + chartUrl" width="700" height="300" />
Font,Linux 服務器需安裝中文字體包DisplayChart Servlet 默認保存 Session 級,Session 失效自動清理;長期運行建議定時清理 java.io.tmpdirChartUtilities.saveChartAsPNG/JPEG 可直接生成文件供下載,無需 Servletorg.jfree:jfreechart:1.5.3 + org.jfree:jcommon:1.0.23