首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Tomcat + MySQL 構建動態橫幅廣告系統完整實戰

     編輯:MySQL 資料庫相關知識

項目背景

構建一個高效能的 Web 橫幅廣告輪播系統:隨機展示廣告圖片、點擊跳轉目標鏈接、記錄展示/點擊統計、支持加權輪播。技術棧:Apache Tomcat 4.1+、MySQL 4.0+、JDBC (MM MySQL 驅動)、Java Servlet。

環境搭建

1. Tomcat 安裝與 WebApp 目錄結構

[TOMCAT_HOME]/webapps/banner/
├── WEB-INF/
│   ├── classes/          # Servlet 編譯類
│   ├── lib/              # JDBC 驅動 JAR
│   └── web.xml           # Servlet 映射配置
├── images/               # 廣告圖片存放
└── index.html            # 測試頁面

2. Context 配置 (server.xml)

<Context path="/banner" docBase="webapps/banner" debug="0" reloadable="true"/>

重啟 Tomcat 生效。訪問 https://localhost:8080/banner/servlet/BannerServlet。

3. MySQL 安裝與 JDBC 驅動

  • 下載 mm.mysql-2.0.14-bin.jar (或更新版 mysql-connector-java) 放入 WEB-INF/lib/。
  • 重啟 Tomcat 載入驅動。
  • 驅動類名:org.gjt.mm.mysql.Driver (舊版) / com.mysql.cj.jdbc.Driver (新版)。
  • 連接 URL:jdbc:mysql://localhost:3306/BANNER?useSSL=false。

數據庫設計

CREATE DATABASE BANNER DEFAULT CHARACTER SET utf8mb4;
USE BANNER;

CREATE TABLE ADS (
  IMAGEFILE VARCHAR(255) NOT NULL COMMENT '圖片相對路徑',
  URL VARCHAR(500) NOT NULL COMMENT '點擊跳轉鏈接',
  CUSTOMERNAME VARCHAR(100) COMMENT '廣告主',
  NUMBEROFCLICKSPURCHASED INT DEFAULT 0 COMMENT '購買點擊數',
  NUMBEROFCLICKSREMAINING INT NOT NULL DEFAULT 0 COMMENT '剩餘點擊數',
  NUMBEROFIMPRESSIONS INT NOT NULL DEFAULT 0 COMMENT '展示次數',
  BANNERWEIGHT INT NOT NULL DEFAULT 10 COMMENT '權重,越大越易展示',
  PRIMARY KEY (IMAGEFILE)
) ENGINE=InnoDB;

加權隨機算法

展示概率 = BannerWeight / SUM(BannerWeight) * 100%。實現:計算總權重 → 隨機數落區間 → 對應廣告。

核心類設計

類職責復用性
Logger文本日志記錄,支持分隔符、方法入口/出口日志高 (通用)
DBHandlerJDBC 封裝:連接管理、PreparedStatement 執行、ResultSet 映射高 (通用)
BannerPOJO,對應 ADS 表字段,Getter/Setter中 (業務綁定)
BannerServlet核心控制器:初始化緩存、處理 image/link 請求、統計更新低 (業務核心)

DBHandler 關鍵方法

public class DBHandler {
    private Connection conn;
    private PreparedStatement pstmt;
    private String queryString;
    private Logger logger;

    public DBHandler(String driver, String url, Logger logger) { ... }
    public void setQueryString(String sql) { this.queryString = sql; }
    public ResultSet lookup(Object... params) { ... }      // SELECT
    public int executeUpdate(Object... params) { ... }     // INSERT/UPDATE/DELETE
    public void close() { ... }
}

BannerServlet 核心邏輯

public class BannerServlet extends HttpServlet {
    private Map bannerCache = new HashMap<>();
    private int totalWeight = 0;
    private Logger logger = new Logger("banner.log");
    private String dbUrl = "jdbc:mysql://localhost/BANNER";
    private String driver = "org.gjt.mm.mysql.Driver";

    public void init() {
        // 啟動時載入所有廣告到內存 HashMap,計算 totalWeight
        DBHandler db = new DBHandler(driver, dbUrl, logger);
        db.setQueryString("SELECT * FROM ADS");
        ResultSet rs = db.lookup();
        while (rs.next()) {
            Banner b = mapRow(rs);
            bannerCache.put(bannerCache.size(), b);
            totalWeight += b.getBannerWeight();
        }
        db.close();
    }

    protected void service(HttpServletRequest req, HttpServletResponse resp) {
        String type = req.getParameter("type");
        if ("image".equals(type)) {
            Banner b = getRandomBanner();
            req.getSession().setAttribute("banner", b);  // 存入 Session
            increaseImpressions(b);
            resp.sendRedirect(b.getImageFile());         // 重定向到圖片
        } else if ("link".equals(type)) {
            Banner b = (Banner) req.getSession().getAttribute("banner");
            if (b != null) {
                decreaseClicksRemaining(b);
                resp.sendRedirect(b.getUrl());           // 跳轉目標鏈接
            }
        }
    }

    private Banner getRandomBanner() {
        int r = (int) (Math.random() * totalWeight);
        int sum = 0;
        for (Banner b : bannerCache.values()) {
            sum += b.getBannerWeight();
            if (r < sum) return b;
        }
        return bannerCache.values().iterator().next(); // fallback
    }

    private void increaseImpressions(Banner b) {
        DBHandler db = new DBHandler(driver, dbUrl, logger);
        db.setQueryString("UPDATE ADS SET NUMBEROFIMPRESSIONS=NUMBEROFIMPRESSIONS+1 WHERE IMAGEFILE=?");
        db.executeUpdate(b.getImageFile());
        db.close();
        init(); // 重新載入緩存 (簡單但低效,生產建議增量更新)
    }
    // decreaseClicksRemaining 同理
}

前端調用示例

<!-- 頁面嵌入廣告位 -->
<a href="/banner/servlet/BannerServlet?type=link" target="_blank">
  <img src="/banner/servlet/BannerServlet?type=image" border="0" />
</a>

擴展方向

  • 連接池:DBHandler 整合 HikariCP/Druid,移除 init() 重載緩存,改用定時任務刷新。
  • 外部化 SQL:查詢語句提取到 properties/XML,支持熱加載。
  • 計費模型:按點擊/展示扣費、廣告主後台、報表統計。
  • 集群化:Session 共享 (Redis)、緩存同步 (廣告變更推送)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved