| 項目 | 技術棧 |
|---|---|
| 開發工具 | MyEclipse 10 / JDK 1.6 / Tomcat 7.0 (32位) / MySQL 5.7.13 |
| 運行環境 | Windows 10 |
| 核心功能 | 用戶登錄、註冊、退出登錄 |
| 架構模式 | Model 2 (JSP 視圖 + Servlet 控制器 + JavaBean 模型 + JDBC 持久層) |
圖一:系統整體架構
(原文圖片缺失,建議補全:瀏覽器 → JSP → Servlet → JavaBean → JDBC → MySQL)
圖二:邏輯層交互關系
JSP 僅負責展示與收集參數,Servlet 接收請求分發業務,JavaBean 封裝數據訪問邏輯
@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if ("login".equals(method)) login(req, resp);
else if ("logout".equals(method)) logout(req, resp);
else if ("register".equals(method)) register(req, resp);
else resp.getWriter().println("invalid request!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
private void login(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username == null || password == null) {
resp.sendRedirect("login.jsp"); return;
}
UserBean ub = new UserBean();
if (ub.valid(username, password)) {
req.getSession().setAttribute("username", username);
resp.sendRedirect("welcome.jsp");
} else {
resp.sendRedirect("login.jsp");
}
}
private void logout(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.getSession().removeAttribute("username");
resp.sendRedirect("login.jsp");
}
private void register(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String username = req.getParameter("username");
String pwd1 = req.getParameter("password1");
String pwd2 = req.getParameter("password2");
String email = req.getParameter("email");
if (username == null || pwd1 == null || pwd2 == null || !pwd1.equals(pwd2)) {
resp.sendRedirect("register.jsp"); return;
}
UserBean ub = new UserBean();
if (!ub.isExist(username)) {
ub.add(username, pwd1, email);
resp.sendRedirect("login.jsp");
} else {
resp.sendRedirect("register.jsp");
}
}
}
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/UserServlet</url-pattern> <!-- 關鍵:去掉 /servlet 前綴 -->
</servlet-mapping>
血淚教訓:默認生成 /servlet/UserServlet 會導致轉發時 URL 變為 /servlet/welcome.jsp,Tomcat 找不到編譯類報 404。**務必手動移除 `/servlet` 前綴**。
public class UserBean {
public boolean valid(String username, String password) {
DBAccess db = new DBAccess();
if (db.createConn()) {
String sql = "SELECT * FROM userInfo WHERE username=? AND password=?";
// 使用 PreparedStatement 防注入
boolean valid = db.query(sql, username, password);
db.closeAll(); return valid;
}
return false;
}
// isExist(), add() 同理...
}
createConn()/closeConn()update(sql)query(sql)/next()/getValue(field)| 問題 | 解決方案 |
|---|---|
| URL 映射含 /servlet 導致轉發 404 | web.xml 中 |
| SQL 拼接注入風險 | 全面改用 PreparedStatement + 參數綁定 |
| 資源未關閉洩漏連接 | finally 塊分別關閉 rs/stmt/conn,或用 try-with-resources (JDK7+) |
| 密碼明文存儲 | 引入 BCrypt/SCrypt 加鹽哈希 |
| 無驗證碼/限流防暴力破解 | 登錄接口加圖形驗證碼 + IP 限流 |
這個 Demo 雖簡陋,但完整展示了 Java Web 經典 MVC 的骨架與血肉。理解它,才能看清現代框架解決了什麼問題、怎麼解決的。