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

手把手教你搭建 Java Servlet + MySQL + Tomcat 開發環境:從零到 CRUD 完整實戰

     編輯:Java 相關知識

前言

Servlet 是 Java Web 開發的基石,Spring MVC、Struts 等框架底層皆封裝於此。本文針對初學者,記錄在 Eclipse (或 IDEA) 中搭建 **Servlet + MySQL + Tomcat 9/10** 開發環境的完整步驟:環境配置、專案建立、資料庫準備、JDBC 封裝、Servlet CRUD 實作、部署驗證,並記錄常見坑點與解決方案。

一、開發環境準備

  1. JDK 11/17/21:安裝並配置 `JAVA_HOME`、`PATH`。
  2. Eclipse IDE for Enterprise Java Developers (或 IntelliJ IDEA Ultimate/Community)。
  3. Apache Tomcat 9.0 / 10.1:下載 zip 解壓,無需安裝。注意:Tomcat 10+ 遷移至 `jakarta.servlet` 套件,Servlet 5.0+,代碼需調整 import。
  4. MySQL 8.0:安裝服務,建立資料庫 `servlet_demo`,用戶 `root`/密碼 `123456` (生產請修改)。
  5. MySQL Connector/J 8.0+:`mysql-connector-j-8.x.x.jar`。

二、Eclipse 整合 Tomcat

  1. 菜單 `Window` → `Preferences` → `Server` → `Runtime Environments` → `Add` → 選擇對應 Tomcat 版本 → `Next` → 指定解壓目錄 → `Finish`。
  2. 專案右鍵 `Properties` → `Targeted Runtimes` → 勾選剛添加的 Tomcat → `Apply`。

三、建立 Dynamic Web Project

  1. `File` → `New` → `Dynamic Web Project`。
  2. Project name: `ServletMySQLDemo`,Target runtime: 選擇 Tomcat,Dynamic web module version: 4.0 (Tomcat 9) / 5.0 (Tomcat 10)。
  3. 勾選 `Generate web.xml deployment descriptor` → `Finish`。
  4. 專案結構:`src/main/java` (源碼)、`src/main/webapp/WEB-INF/lib` (放 jar 包)、`web.xml`。

四、導入依賴 Jar 包

將 `mysql-connector-j-8.x.x.jar` 複製到 `WEB-INF/lib` 目錄 (Eclipse 會自動加入 Build Path)。或使用 Maven 專案管理依賴 (推薦)。

五、資料庫準備

CREATE DATABASE servlet_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE servlet_demo;

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(100) NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO users (username, password, email) VALUES
('admin', '123456', 'admin@example.com'),
('test', 'abc123', 'test@example.com');

六、JDBC 工具類封裝 (DBUtil)

public class DBUtil {
    private static final String URL = "jdbc:mysql://localhost:3306/servlet_demo?useSSL=false&serverTimezone=Asia/Taipei&allowPublicKeyRetrieval=true";
    private static final String USER = "root";
    private static final String PASSWORD = "123456";

    static {
        try { Class.forName("com.mysql.cj.jdbc.Driver"); }
        catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); }
    }

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
        try { if (stmt != null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
        try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); }
    }
}

七、實體類與 DAO 層

public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private Timestamp createdAt;
    // Getter/Setter/toString 略
}

public class UserDAO {
    public List findAll() {
        String sql = "SELECT * FROM users";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql);
             ResultSet rs = ps.executeQuery()) {
            List list = new ArrayList<>();
            while (rs.next()) list.add(mapRow(rs));
            return list;
        } catch (SQLException e) { throw new RuntimeException(e); }
    }

    public User findById(int id) {
        String sql = "SELECT * FROM users WHERE id=?";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setInt(1, id);
            try (ResultSet rs = ps.executeQuery()) {
                return rs.next() ? mapRow(rs) : null;
            }
        } catch (SQLException e) { throw new RuntimeException(e); }
    }

    public boolean insert(User user) {
        String sql = "INSERT INTO users(username,password,email) VALUES(?,?,?)";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, user.getUsername());
            ps.setString(2, user.getPassword());
            ps.setString(3, user.getEmail());
            return ps.executeUpdate() > 0;
        } catch (SQLException e) { throw new RuntimeException(e); }
    }
    // update、delete 同理
    private User mapRow(ResultSet rs) throws SQLException { /* 映射邏輯 */ }
}

八、Servlet 實作 (UserServlet)

@WebServlet("/users/*")
public class UserServlet extends HttpServlet {
    private UserDAO dao = new UserDAO();
    private ObjectMapper mapper = new ObjectMapper(); // Jackson 處理 JSON

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String pathInfo = req.getPathInfo(); // /users/1, /users, /users/add
        resp.setContentType("application/json;charset=UTF-8");
        try {
            if (pathInfo == null || pathInfo.equals("/")) {
                // 列表
                List list = dao.findAll();
                mapper.writeValue(resp.getWriter(), list);
            } else if (pathInfo.matches("/\\d+")) {
                // 單條查詢 /users/1
                int id = Integer.parseInt(pathInfo.substring(1));
                User user = dao.findById(id);
                if (user != null) mapper.writeValue(resp.getWriter(), user);
                else resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            } else {
                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            }
        } catch (Exception e) {
            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 新增 /users (JSON Body)
        User user = mapper.readValue(req.getInputStream(), User.class);
        boolean ok = dao.insert(user);
        resp.setStatus(ok ? HttpServletResponse.SC_CREATED : HttpServletResponse.SC_BAD_REQUEST);
        mapper.writeValue(resp.getWriter(), Map.of("success", ok));
    }
    // doPut、doDelete 同理
}

九、部署與驗證

  1. 專案右鍵 `Run As` → `Run on Server` → 選擇 Tomcat → `Finish`。
  2. 瀏覽器/Postman 測試:
    `GET https://localhost:8080/ServletMySQLDemo/users` → 返回用戶列表 JSON。
    `POST https://localhost:8080/ServletMySQLDemo/users` Body: `{"username":"new","password":"123","email":"new@test.com"}` → 返回創建結果。
    `GET https://localhost:8080/ServletMySQLDemo/users/1` → 返回單條用戶。

十、常見坑點與解決

問題原因解決
ClassNotFoundException: DriverJar 未放入 WEB-INF/lib 或 Maven 依賴範圍錯誤確認 Jar 存在於部署後的 WEB-INF/lib
Communications link failureMySQL 服務未啟動、端口錯誤、防火牆、URL 時區參數缺失檢查服務、URL 加 `serverTimezone=Asia/Taipei`
Public Key Retrieval is not allowedMySQL 8 密碼插件 caching_sha2_passwordURL 加 `allowPublicKeyRetrieval=true` 或改用 mysql_native_password
中文亂碼請求/響應編碼未設定、資料庫連線編碼Filter 統一設定 UTF-8、URL 加 `characterEncoding=utf8`
Tomcat 10 jakarta.servlet 找不到類Servlet 5.0 包名變更 javax → jakarta代碼 import 改為 jakarta.servlet.* 或降級 Tomcat 9

十一、進階建議

  • 引入 **Maven** 管理依賴,`pom.xml` 替代手動 Jar。
  • 使用 **連線池 HikariCP** 替換 `DriverManager`。
  • 採用 **分層架構**:Controller (Servlet) → Service → DAO → DB。
  • 整合 **Jackson** 處理 JSON,**Bean Validation** (Hibernate Validator) 做參數校驗。
  • 學習 **Spring Boot**:內嵌 Tomcat、自動配置、Starter 依賴,將樣板碼減少 90%。

十二、結語

完成這個 Servlet + MySQL + Tomcat 專案,你已掌握 Java Web 開發最核心的「請求 → Servlet → JDBC → MySQL → 響應」完整鏈路。雖然生產環境多使用 Spring Boot,但理解底層 Servlet API、JDBC 事務、Tomcat 部署機制,是排查框架疑難雜症、設計高性能系統的不可或缺的內功。

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