首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

JFreeChart 實戰指南:JSP 整合動態圖表生成完整範例

     編輯:關於JSP

Java 圖表引擎 JFreeChart 在 Web 應用中的完整應用

JFreeChart 是 Java 生態最成熟的開源圖表庫,支援多種圖表類型、高度可客製化。本文以時間序列折線圖為例,示範從資料集建立、圖表配置、Servlet 整合到 JSP 顯示的完整流程。

核心類別架構

  • Dataset:資料模型介面 (XYDataset, CategoryDataset, PieDataset)
  • ChartFactory:工廠建立 JFreeChart 物件
  • JFreeChart:圖表核心模型,包含標題、圖例、繪圖區
  • Plot:繪圖區域 (XYPlot, CategoryPlot) - 座標軸、格線、渲染器
  • Renderer:資料視覺化邏輯 (XYLineAndShapeRenderer, BarRenderer) - 線型、形狀、顏色

完整 Java Bean 實作 (LineXYChart.java)

package com.example.chart;

import java.awt.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import javax.servlet.http.HttpSession;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.servlet.ServletUtilities;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.*;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleInsets;

public class LineXYChart {

    public String generateChart(HttpSession session, PrintWriter pw) throws IOException {
        // 1. 建立資料集
        XYDataset dataset = createDataset();
        
        // 2. 建立圖表 (時間序列折線圖)
        JFreeChart chart = ChartFactory.createTimeSeriesChart(
            "股價走勢圖",           // 標題
            "日期",                 // X 軸標籤
            "價格",                 // Y 軸標籤
            dataset,                // 資料集
            true,                   // 顯示圖例
            true,                   // 顯示工具提示
            false                   // 不生成 URL
        );
        
        // 3. 客製化外觀
        customizeChart(chart);
        
        // 4. 渲染為 PNG 並儲存至 Session (由 ServletUtilities 管理)
        ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
        String fileName = ServletUtilities.saveChartAsPNG(chart, 800, 400, info, session);
        
        // 5. 輸出 ImageMap (支援工具提示/點擊熱區)
        ChartUtilities.writeImageMap(pw, fileName, info, false);
        
        return fileName;
    }

    private void customizeChart(JFreeChart chart) {
        // 背景與標題
        chart.setBackgroundPaint(Color.WHITE);
        chart.setTitle(new TextTitle("台股加權指數走勢", new Font("微軟正黑體", Font.BOLD, 18)));
        chart.addSubtitle(new TextTitle("資料來源: 證交所", new Font("微軟正黑體", Font.PLAIN, 12)));
        
        // 圖例字體
        chart.getLegend().setItemFont(new Font("微軟正黑體", Font.PLAIN, 12));
        
        // 取得繪圖區
        XYPlot plot = (XYPlot) chart.getPlot();
        plot.setBackgroundPaint(new Color(0xF5F5F5));
        plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
        plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
        plot.setAxisOffset(new RectangleInsets(5, 5, 5, 5));
        plot.setDomainCrosshairVisible(true);
        plot.setRangeCrosshairVisible(true);
        
        // 渲染器設定:顯示資料點、填滿形狀
        XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
        renderer.setBaseShapesVisible(true);
        renderer.setBaseShapesFilled(true);
        renderer.setDrawSeriesLineAsPath(true);  // 平滑曲線
        
        // Y 軸格式化:兩位小數
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMinimumFractionDigits(2);
        rangeAxis.setNumberFormatOverride(nf);
        
        // 工具提示格式
        renderer.setToolTipGenerator(new StandardXYToolTipGenerator(
            "{0}: {1} = {2}", 
            new SimpleDateFormat("yyyy-MM-dd"), 
            nf
        ));
        
        // X 軸日期格式
        DateAxis domainAxis = (DateAxis) plot.getDomainAxis();
        domainAxis.setDateFormatOverride(new SimpleDateFormat("MM/dd"));
        domainAxis.setTickLabelFont(new Font("微軟正黑體", Font.PLAIN, 10));
    }

    private XYDataset createDataset() {
        TimeSeriesCollection dataset = new TimeSeriesCollection();
        TimeSeries series = new TimeSeries("加權指數", Day.class);
        
        // 模擬資料 (實際應從資料庫/服務取得)
        series.add(new Day(1, 1, 2024), 17500.25);
        series.add(new Day(2, 1, 2024), 17620.50);
        series.add(new Day(3, 1, 2024), 17480.30);
        series.add(new Day(4, 1, 2024), 17710.80);
        series.add(new Day(5, 1, 2024), 17850.10);
        // ... 更多資料點
        
        dataset.addSeries(series);
        dataset.setDomainIsPointsInTime(true);
        return dataset;
    }
}

web.xml 配置圖表顯示 Servlet

<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>/servlet/DisplayChart</url-pattern>
</servlet-mapping>

JSP 頁面整合顯示

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.example.chart.LineXYChart" %>
<%@ page import="java.io.PrintWriter" %>
<%
    LineXYChart chartBean = new LineXYChart();
    String fileName = chartBean.generateChart(session, new PrintWriter(out));
    String chartUrl = request.getContextPath() + "/servlet/DisplayChart?filename=" + fileName;
%>
<!DOCTYPE html>
<html>
<head>
    <title>JFreeChart 動態圖表示範</title>
    <meta charset="UTF-8">
</head>
<body>
    <h2>即時股價走勢圖</h2>
    <!-- usemap 對應 ImageMap 實現熱區/提示 -->
    <img src="<%= chartUrl %>" width="800" height="400" border="0" usemap="<%= fileName %>" />
</body>
</html>

進階客製化技巧

需求實作方式
多條線對比建立多個 TimeSeries 加入同一 TimeSeriesCollection
區域填色renderer.setSeriesFillPaint(seriesIndex, new Color(0,0,255,50))
標記特殊點使用 XYItemAnnotation 或自訂 Renderer 在特定座標繪製
對數座標軸plot.setRangeAxis(new LogarithmicAxis("Label"))
匯出高解析度ChartUtilities.saveChartAsPNG(file, chart, 1600, 900, info)
中文顯示統一指定支援中文字體 (微軟正黑體、Noto Sans CJK)

常見問題排查

  • 中文亂碼/方塊字:確認伺服器安裝中文字體,代碼中明確指定 `Font("微軟正黑體", ...)` 或載入 `.ttf` 檔
  • 圖片不顯示:檢查 `DisplayChart` Servlet mapping、Session 同步、檔案儲存權限
  • 記憶體洩漏:`ServletUtilities` 會在 Session 中暫存圖片檔,需定期清理或配置 `web.xml` 中的 `tempDir`、`maxAge`
  • 效能瓶頸:大量並發生成圖表時,考慮快取圖片、非同步生成、或改用前端圖表庫 (ECharts/Chart.js)

現代架構建議

傳統「後端生成圖片 → `` 顯示」模式存在狀態管理、擴展性、互動性限制。新專案建議:

  1. 後端只提供 JSON 資料 API (RESTful)
  2. 前端使用 ECharts、Chart.js、Highcharts、Apache ECharts** 直接渲染
  3. 優點:零伺服器狀態、豐富互動 (縮放、篩選、動畫)、響應式、離線可用

JFreeChart 仍適合:PDF 報表嵌入圖表、伺服器端批次生成靜態圖片、無前端環境的後台任務。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved