MVC 三層核心職責
| 層次 | 組件 | 核心職責 | 關鍵技術點 |
| Model (模型層) | JavaBean、Service、DAO | 資料持久化、業務邏輯封裝 | Bean 封裝屬性、Service 組合 DAO、事務控制 |
| View (視圖層) | JSP、EL、JSTL | 資料展示、用戶交互 | 域對象 (request/session/application) 生命週期、標籤庫 |
| Controller (控制層) | Servlet、Filter | 請求分發、參數校驗、流程控制 | 從 Model 取數據、放入域、轉發/重定向至 View |
為什麼 View 不應包含業務邏輯
- JSP 本質是 Servlet,能寫 Java 代碼,但會導致視圖臃腫、難維護、難測試。
- 遵循「關注點分離」:View 只負責渲染,Controller 負責流程,Model 負責數據。
- EL/JSTL 提供
${bean.prop}、<c:forEach> 等標籤,足以支援大多數展示邏輯。
Controller 精簡之路:DAO + Factory 模式
傳統 Servlet 痛點
// Servlet 直接寫 JDBC、業務邏輯 → 代碼耦合、難復用
public class UserServlet extends HttpServlet {
protected void doGet(...) {
Connection conn = DriverManager.getConnection(...);
PreparedStatement ps = conn.prepareStatement("select * from user where id=?");
// ... 大量樣板代碼
}
}
分層重構步驟
- 定義介面 (DAO):
UserDao { User findById(int id); List<User> findAll(); }
- 實現類 (DAOImpl):封裝 JDBC 細節,處理異常轉換。
- 工廠類 (DaoFactory):
static UserDao getUserDao() { return new UserDaoImpl(); }
- Servlet 調用:
UserDao dao = DaoFactory.getUserDao(); User u = dao.findById(id);
進階:Service 層整合事務
public class UserService {
private UserDao dao = DaoFactory.getUserDao();
public void transfer(int from, int to, double amount) {
// 事務邊界在 Service 控制
try (Connection conn = DataSourceUtils.getConnection()) {
conn.setAutoCommit(false);
dao.deduct(conn, from, amount);
dao.add(conn, to, amount);
conn.commit();
} catch (SQLException e) { throw new RuntimeException(e); }
}
}
域對象生命週期與選型
| 域 | 生命週期 | 適用場景 |
| request | 單次請求 | 表單回顯、頁面間傳遞臨時數據 |
| session | 用戶會話 (默認 30 分鐘) | 登入用戶資訊、購物車 |
| application | 整個 Web 應用生命週期 | 全局配置、緩存字典、線程安全計數器 |
新手避坑清單
- JSP 大量 Java 代碼 → 移至 Servlet/Service/TagLib。
- Servlet 直接 new DAOImpl → 引入 Factory 或 Spring IOC。
- 忽略域生命週期 → Session 放過大對象導致 OOM。
- 業務邏輯分散在 Controller/View → 集中到 Service,保持 Controller 薄。
總結
MVC 不只是三個字母,而是「職責單一、依賴倒置、關注點分離」的工程落地。從「Servlet 全包」到「DAO/Service/Factory 分層」,再到 Spring IOC/AOP 全自動裝配,是每個 Java Web 開發者必經的成長路徑。