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

JSP + Servlet 實作投票系統:動態產生 JPEG 圓餅圖

     編輯:Java 程式設計入門

本文完整示範一個基於 JSP 與 Servlet 的簡易投票系統,包含題目顯示、投票記錄、動態圖表產生三大核心功能。系統採用文字檔儲存題目與票數,Servlet 利用 Java 2D API 繪製 3D 效果圓餅圖並輸出 JPEG 串流。

系統架構概覽

  • index.jsp:讀取 question.txt 顯示單選題,內嵌 <img src="/vote/servlet/VoteImage"> 顯示即時圖表。
  • write.jsp:接收投票參數,更新 count.txt 計數,重導向回 index.jsp。
  • VoteImage.java (Servlet):讀取 count.txt,計算百分比,繪製帶陰影旋轉效果的圓餅圖,輸出 JPEG。
  • 資料檔:question.txt(題目)、count.txt(各選項票數)。

核心程式碼片段

1. index.jsp - 顯示投票表單與圖表

<%@ page contentType="text/html;charset=gb2312" %>
<% response.setHeader("Cache-Control","no-store"); response.setDateHeader("Expires",0); %>
<%!
  public String[] getQuestion(String filePath) {
    String[] q = new String[4];
    try (RandomAccessFile rf = new RandomAccessFile(filePath, "r")) {
      for (int i=0; i<4; i++) {
        String line = rf.readLine();
        q[i] = (line != null) ? line : "None Question";
      }
    } catch (Exception e) { e.printStackTrace(); }
    return q;
  }
%>
<%
  String path = request.getRealPath("question.txt");
  String[] questions = getQuestion(path);
%>
<html><body>
<table width="180" border="1">
  <tr><td align="center">冰帆調查</td></tr>
  <form name="frm" method="post" action="write.jsp">
  <tr><td>
    <%
      for (int i=0; i<4; i++) {
        out.println("" + (char)('A'+i) + "、" + questions[i] + "
"); } %> </td></tr> <tr><td align="center"><input type="submit" value="我 投 一 票"></td></tr> <tr><td align="center"><img src="/vote/servlet/VoteImage" width="150" height="100"></td></tr> </form> </table> </body></html>

2. write.jsp - 處理投票與寫入計數

<%!
  public int[] getNumber(String filePath) { ... } // 讀取 count.txt 回傳 int[4]
  public void setNumber(String filePath, int[] counts) { ... } // 寫入 count.txt
%>
<%
  String param = request.getParameter("choice");
  if (param != null) {
    int choice = Integer.parseInt(param);
    String countPath = request.getRealPath("count.txt");
    int[] counts = getNumber(countPath);
    counts[choice]++;
    setNumber(countPath, counts);
  }
  response.sendRedirect("index.jsp");
%>

3. VoteImage.java - Servlet 動態產生 3D 圓餅圖

public class VoteImage extends HttpServlet {
  private Color[] colors = {Color.RED, Color.BLACK, Color.ORANGE, Color.GREEN};
  private int baseAngle = 30;

  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    String file = req.getRealPath("count.txt");
    float[][] data = getNumAndPercent(file); // [count, percent]
    int[] angles = new int[4];
    for (int i=0; i<3; i++) angles[i] = (int)(data[i][1] * 360);
    angles[3] = 360 - angles[0] - angles[1] - angles[2];

    resp.setHeader("Cache-Control", "no-store");
    resp.setContentType("image/jpeg");
    ServletOutputStream out = resp.getOutputStream();

    BufferedImage img = new BufferedImage(150, 100, BufferedImage.TYPE_INT_RGB);
    Graphics2D g = img.createGraphics();
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, 150, 100);

    // 3D 效果:旋轉變換 + 多層繪製
    AffineTransform at = AffineTransform.getRotateInstance(-20*Math.PI/180, 45, 37);
    g.setTransform(at);
    int r = 6;
    int dx = (int)(r * Math.cos((baseAngle + angles[0])/2.0 * Math.PI/180));
    int dy = (int)(r * Math.sin((baseAngle + angles[0])/2.0 * Math.PI/180));
    Arc2D arc = new Arc2D.Double(10+dx, 24-dy, 80, 50, baseAngle, angles[0], Arc2D.PIE);
    g.setColor(colors[0]); g.fill(arc);
    int current = baseAngle + angles[0];
    for (int i=1; i<4; i++) {
      arc = new Arc2D.Double(10, 24, 80, 50, current, angles[i], Arc2D.PIE);
      g.setColor(colors[i]); g.fill(arc);
      current += angles[i];
      if (current > 360) current -= 360;
    }
    // 恢復變換繪製圖例
    g.setTransform(AffineTransform.getRotateInstance(0, arc.getCenterX(), arc.getCenterY()));
    for (int i=0; i<4; i++) {
      g.setColor(colors[i]);
      g.fillRect(100, 15*i+20, 10, 10);
      g.drawString("" + (char)('A'+i), 120, 15*i+20+8);
    }

    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
    encoder.encode(img);
    out.close();
  }

  // 讀取計數並計算百分比
  private synchronized float[][] getNumAndPercent(String file) { ... }
}

部署與測試步驟

  1. 將 index.jsp、write.jsp、question.txt、count.txt 放在 Web 應用根目錄(如 /vote/)。
  2. 編譯 VoteImage.java 並部屬至 /vote/WEB-INF/classes/(套件結構需符合)。
  3. 在 web.xml 註冊 Servlet:
    
      VoteImage
      VoteImage
    
    
      VoteImage
      /servlet/VoteImage
    
  4. 瀏覽器訪問 https://host:port/vote/index.jsp 測試。

資料檔範例

question.txt:
Yes, I think so!
No, I don't think so!
Sorry, I don't know the answer!
(第四行留空或自訂)

count.txt:
12
9
5
9

技術亮點與注意事項

  • Java 2D 3D 效果:利用 AffineTransform 旋轉畫布,配合第一塊扇區的位移 (dx, dy) 模擬 3D 立體感。
  • 同步讀寫:getNumAndPercent 加上 synchronized 避免並發讀寫 count.txt 造成資料不一致。
  • 快取控制:回應標頭設定 no-store 確保瀏覽器每次重新請求圖表。
  • 相容性:範例使用 com.sun.image.codec.jpeg.JPEGCodec(舊版 Sun 專有 API),現代環境建議改用 javax.imageio.ImageIO.write(img, "jpg", out)。
  • 編碼問題:JSP 指定 gb2312,若環境為 UTF-8 需統一調整。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved