本文將詳細介紹如何運用 Java EE 技術(Servlet、JSP、Filter、Listener、Cookie 等)建構一個功能完整的 Web 聊天室系統。系統包含使用者登入驗證、記住密碼、聊天訊息即時顯示、線上人數統計等核心功能,並採用 frameset 框架佈局模擬類 QQ 群聊介面。
系統採用 MVC 模式,核心元件如下:
Login.jsp 在頁面載入時讀取請求中的 Cookie,若存在 username 與 password 則自動填入表單:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String username = "", password = "";
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("username".equals(cookie.getName())) {
username = java.net.URLDecoder.decode(cookie.getValue(), "UTF-8");
} else if ("password".equals(cookie.getName())) {
password = java.net.URLDecoder.decode(cookie.getValue(), "UTF-8");
}
}
}
%>
<form action="Main" method="post">
使用者名稱: <input type="text" name="username" value="<%=username%>"><br>
密碼: <input type="password" name="password" value="<%=password%>"><br>
<input type="checkbox" name="save_password" value="save"> 記住密碼
<input type="submit" value="登入" name="login">
<input type="reset" value="重置">
</form>
核心邏輯:驗證帳密對照表、管理 Cookie 存活期、請求轉發與重導向:
@WebServlet("/Main")
public class Main extends HttpServlet {
private static final String[] VALID_USERS = {"柳真","劉仁傑","吳超","張浩東","陳初相"};
private static final String[] VALID_PWDS = {"201421092073","201421092068","201421092077","201421092082","201421092119"};
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userName = request.getParameter("username");
String passWord = request.getParameter("password");
String savePwd = request.getParameter("save_password");
// 驗證帳密
boolean valid = false;
for (int i = 0; i < VALID_USERS.length; i++) {
if (VALID_USERS[i].equals(userName) && VALID_PWDS[i].equals(passWord)) {
valid = true; break;
}
}
if (valid) {
// 存入 Session
request.getSession().setAttribute("nameSession", userName);
// 處理記住密碼 Cookie
if ("save".equals(savePwd)) {
Cookie uCookie = new Cookie("username", URLEncoder.encode(userName, "UTF-8"));
Cookie pCookie = new Cookie("password", URLEncoder.encode(passWord, "UTF-8"));
uCookie.setMaxAge(60*60*24*3); // 3 天
pCookie.setMaxAge(60*60*24*3);
response.addCookie(uCookie);
response.addCookie(pCookie);
}
request.getRequestDispatcher("welcome.jsp").forward(request, response);
} else {
response.sendRedirect("loginFail.jsp");
}
}
}
<frameset rows="100,*" cols="*" frameborder="no" border="0" framespacing="0">
<frame src="header.jsp" name="topFrame" scrolling="auto" noresize="noresize" />
<frameset cols="213,*" frameborder="no" border="0" framespacing="0">
<frame src="left.jsp" name="leftFrame" scrolling="no" noresize="noresize" />
<frame src="main.jsp" name="mainFrame" scrolling="auto" />
</frameset>
</frameset>
<td align="center">
歡迎 <%=session.getAttribute("nameSession")%> 訪問!
當前在線人數為 <%=application.getAttribute("peopleOnline")%> 人
</td>
<form action="InputInformation" method="post" target="mainFrame">
<textarea name="show_textarea" cols="105" rows="25" readonly>
<%=request.getAttribute("input_textarea") != null ? request.getAttribute("input_textarea") : ""%>
</textarea><br>
<textarea name="input_textarea" cols="105" rows="5"></textarea><br>
<input type="submit" value="發送">
</form>
注意:此處使用實例變數儲存聊天記錄僅供示範,實際生產環境應使用資料庫或共享快取:
@WebServlet("/InputInformation")
public class InputInformation extends HttpServlet {
private String chatRecord = ""; // 簡易記憶體儲存
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String msg = request.getParameter("input_textarea");
String user = (String) request.getSession().getAttribute("nameSession");
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
chatRecord += user + " " + msg + " " + time + "\n";
request.setAttribute("input_textarea", chatRecord);
request.getRequestDispatcher("main.jsp").forward(request, response);
}
}
@WebFilter(filterName = "CodeFilter", urlPatterns = {"/*"})
public class CodeFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request, response);
}
}
@WebListener
public class OnlineListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer count = (Integer) ctx.getAttribute("peopleOnline");
ctx.setAttribute("peopleOnline", (count == null) ? 1 : count + 1);
}
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer count = (Integer) ctx.getAttribute("peopleOnline");
if (count != null && count > 0) ctx.setAttribute("peopleOnline", count - 1);
}
}
<web-app version="3.0" ...>
<listener>
<listener-class>com.liuzhen.chart.OnlineListener</listener-class>
</listener>
<servlet>
<servlet-name>Main</servlet-name>
<servlet-class>com.liuzhen.chart.Main</servlet-class>
</servlet>
<servlet>
<servlet-name>InputInformation</servlet-name>
<servlet-class>com.liuzhen.chart.InputInformation</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Main</servlet-name>
<url-pattern>/Main</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>InputInformation</servlet-name>
<url-pattern>/InputInformation</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
系統成功運行於 GlassFish Server,測試場景:
完整程式碼已上傳至 Coding.net:專案連結
本專案完整展示了 Java Web 核心技術的整合應用:Servlet 處理業務邏輯、JSP 負責視圖渲染、Filter 解決編碼問題、Listener 實現應用層級狀態統計、Cookie 實現客戶端狀態持久化。雖然使用 frameset 與記憶體儲存聊天記錄屬於教學示範架構,但核心設計模式為後續學習 WebSocket、Spring Boot 等現代框架奠定了堅實基礎。