1 問題描述 利用Java EE相關技術實現一個簡單的Web聊天室系統,具體要求如下。 (1)編寫一個登錄頁面,登錄信息中有用戶名和密碼,分別用兩個按鈕來提交和重置登錄信息。 (2)編寫一個Servlet程式Main.java通過請求指派來處理用戶提交的登錄信息,如果用戶名為本小組成員的名字且密碼為 ...
1 問題描述
利用Java EE相關技術實現一個簡單的Web聊天室系統,具體要求如下。
(1)編寫一個登錄頁面,登錄信息中有用戶名和密碼,分別用兩個按鈕來提交和重置登錄信息。
(2)編寫一個Servlet程式Main.java通過請求指派來處理用戶提交的登錄信息,如果用戶名為本小組成員的名字且密碼為對應的學號時,跳轉到LoginSuccess顯示聊天界面(類似於QQ群聊天界面,可使用HTML中的frameset標簽生成兩個視窗,一個用來實現用戶信息輸入,另一個顯示所有用戶聊天記錄的);否則跳轉到LoginFail頁面,提示用戶重新登錄(註:此頁面要包含前面的登錄界面)。
(3)編寫兩個Servlet程式,分別用來顯示“信息輸入”視窗和“聊天記錄顯示”視窗的內容;用戶在“信息輸入”視窗中鍵入聊天內容,點擊“發送”按鈕後,在“聊天記錄顯示”視窗中顯示發送消息的用戶名稱和聊天內容。提示:利用HTML中的textarea標簽來實現。
(4)在登錄界面上實現記住用戶名和密碼的功能,使得當用戶選擇了此功能併成功登錄後,在其下次登錄時可以不用再輸入用戶名和密碼即可登錄。提示:此功能可通過兩個Cookie來實現。
以下功能選做:
(5)編寫一個Listener程式來監聽會話的創建和銷毀事件,以此統計當前線上(登錄)人數,並將其顯示在聊天界面上。
(6)添加一個Filter對本系統所有的Servlet程式進行過濾,該Filter實現對請求和響應對象的編碼格式的設置(實現此功能後,Servlet可以直接從請求對象中獲取參數信息而無需實現對請求進行格式的編碼)。在【GlassFish Server】視圖中輸出程式在Filter和其它資源之間的執行順序。
2 解決方案
2.1 預期效果
圖一:網上聊天系統運行示意圖
2.2 系統結構示意圖
圖二:系統結構示意圖
具體解釋:
(1)打開瀏覽器,進入網上聊天系統首頁登錄界面login.jsp。輸入用戶名和密碼,點擊登陸;
(2)Main.java類獲取login.jsp用戶輸入的用戶名和密碼,進行邏輯驗證,驗證成功則跳轉到聊天界面welcome.jsp,否則跳轉到登陸失敗提示界面loginFail.jsp;
(3)Welcome.jsp聊天界面,其中頭部界面顯示當前登陸用戶昵稱和當前線上總人數(統計當前線上人數通過調用OnlineListener類來實現);左部為聊天好友列表界面,此處僅作展示頁面,未寫具體邏輯處理代碼;中間主體頁面main.jsp頁面實現用戶在聊天輸入框中輸入消息,發送並顯示在聊天消息顯示框中功能。(實現聊天功能通過調用InputInformation.java類來實現)具體頁面如下圖所示:
圖三:聊天頁面welcome.jsp
圖三:welcome.jsp實際運行圖
2.3 具體編碼
(1)Main.java(Servlet類)通過請求指派來處理login.jsp頁面用戶提交的登錄信息(並使用Cookie實現記住用戶登錄用戶名和密碼功能),成功則跳轉到welcome.jsp,失敗則跳轉到loginFail.jsp。具體實現如下:
網上聊天系統登陸首頁login.jsp頁面代碼:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; String username = ""; String password = ""; //String[] checkBox = request.getParameterValues("save_password"); //獲取當前站點的所有Cookie Cookie[] cookies = request.getCookies(); for (int i = 0; i < cookies.length; i++) { //對cookies中的數據進行遍歷,找到用戶名、密碼的數據 if ("username".equals(cookies[i].getName())) { //讀取時URLDecoder.decode進行解碼(PS:Cookie存取時用URLEncoder.encode進行編碼) username = java.net.URLDecoder.decode(cookies[i].getValue(),"UTF-8"); } else if ("password".equals(cookies[i].getName())) { password = java.net.URLDecoder.decode(cookies[i].getValue(),"UTF-8"); } } %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>網上聊天室登陸頁面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> <style type="text/css"> * { margin: 0; padding: 0; } body { font-size: 0px; padding: 200px; } </style> </head> <body> <form action="Main" method="post"> <div style="background:#49AFFF;font-size: 80px;text-align:center;">網上聊天室</div> <div style="background:#75FFE7;font-size: 35px;text-align:center;"> <span>用戶名:</span><input type="text" name="username" value="<%=username%>" style="border:1px solid #ccc; width:400px; height:40px;" ></div> <div style="background:#75FFE7;font-size: 35px;text-align:center;"> <span>密 碼 :</span><input type="password" name="password" value="<%=password%>" style="border:1px solid #ccc; width:400px; height:40px;" ></div> <div style="background:#75FFE7;font-size: 25px;text-align:center;"> <input type="checkbox" value="save" name="save_password">記住密碼 <input type="submit" value="登陸" name="login" style="width: 100px; height: 40px;font-size: 30px;"> <input type="reset" value="重置" name="reset" style="width: 100px; height: 40px;font-size: 30px;"></div> </form> </body> </html>
Main.java類代碼:
package com.liuzhen.chart; import java.io.IOException; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class Main extends HttpServlet { /** * Constructor of the object. */ public Main() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //response.setContentType("text/html;charset=utf-8"); //此出註解是因為使用CodeFilter類過濾所有Servlet,轉換編碼 //request.setCharacterEncoding("utf-8"); String userName = request.getParameter("username"); String passWord = request.getParameter("password"); String checkBox = request.getParameter("save_password"); System.out.println("userName:"+userName+"\n"+"passWord:"+passWord); request.getSession().setAttribute("nameSession", userName); //將用戶名存入session中 String[] name_one = {"柳真","劉仁傑","吳超","張浩東","陳初相"}; String[] pwd_one = {"201421092073","201421092068","201421092077","201421092082","201421092119"}; String name_two = ""; String pwd_two = ""; boolean login_test = false; for(int i=0;i<5;i++){ name_two = name_one[i]; pwd_two = pwd_one[i]; if(userName.equals(name_two) && passWord.equals(pwd_two)) login_test = true; } if(login_test) { if ("save".equals(checkBox)) { //Cookie存取時用URLEncoder.encode進行編碼(PS:讀取時URLDecoder.decode進行解碼) String name = URLEncoder.encode(userName,"UTF-8"); //創建兩個Cookie對象 Cookie nameCookie = new Cookie("username", name); //設置Cookie的有效期為3天 nameCookie.setMaxAge(60 * 60 * 24 * 3); String pwd = URLEncoder.encode(passWord,"UTF-8"); Cookie pwdCookie = new Cookie("password", pwd); pwdCookie.setMaxAge(60 * 60 * 24 * 3); response.addCookie(nameCookie); response.addCookie(pwdCookie); } request.getRequestDispatcher("welcome.jsp").forward(request, response); } else{ response.sendRedirect("loginFail.jsp"); // request.getRequestDispatcher("loginFail.jsp").forward(request, response); } } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here } }
登陸失敗頁面loginFail.jsp頁面代碼:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'loginFail.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="content-type" content="text/html; charset=gb2312"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <br> <br> <h1>用戶名和密碼不匹配,請重新登陸!</h1> <a href="login.jsp">重新登陸</a> </body> </html>View Code
登陸成功頁面welcome.jsp頁面代碼(此處使用frameset標簽,分為頭部、左部和中間主頁三部分,分別對象header.jsp、left.jsp和main.jsp頁面):
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>網上聊天室</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="content-type" content="text/html; charset=gb2312"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <frameset rows="100,*" cols="*" frameborder="no" border="0" framespacing="0"> <frame src="header.jsp" name="topFrame" scrolling="auto" noresize="noresize" id="topFrame"/> <frameset cols="213,*" frameborder="no" border="0" framespacing="0"> <frame src="left.jsp" name="leftFrame" scrolling="No" noresize="noresize" id="leftFrame"/> <frame src="main.jsp" name="mainFrame" scrolling="auto" id="mainFrame"/> </frameset> </frameset> <body> </body> </html>
聊天頭部header.jsp頁面代碼:
<%@ page language="java" import="java.util.*" contentType="text/html;charset=gb2312" pageEncoding="gb2312"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title></title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <meta http-equiv="Content-Type" content="text/html;charset=gb2312"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body topmargin="0" leftmargin="0" rightmargin="0"> <form action=""> <table width="100%" height="79" border="0" cellpadding="0" cellspacing="0" align=center> <tr> <td bgcolor="F9A859" valign="top"> <table width="100%" height="50" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="FBEAD0"> <tr> <td align="center" style="font-size:40px;"> 網上聊天室 </td> </tr> </table> </td> </tr> <tr> <td bgcolor="F9A859" valign="top"> <table width="100%" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td align="center" style="font-size:20px" valign="middle"> 歡迎<%=(String)request.getSession().getAttribute("nameSession") %>訪問! 當前線上人數為<%=application.getAttribute("peopleOnline")%>人 </td> </tr> </table> </td> </tr> </table> </form> </body> </html>View Code
聊天左部left.jsp頁面代碼(此處為了顯示美觀,使用了jquery-1.4.2包):
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'test.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="content-type" content="text/html; charset=gb2312"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> <style type="text/css"> * { margin: 0; padding: 0; } body { font-size: 15px; padding: 00px; } .menu { width: 500px; border-bottom: solid 1px gray; } .menu h3 { border: solid 1px gray; height: 30px; line-height: 30px; padding-left: 10px; padding:0 5px; border-bottom: none; cursor: pointer; } .menu p { border-left: solid 1px gray; border-right: solid 1px gray; padding: 20px 0; padding-left: 5px; } .changecolor{background-color:red;} </style> <script src="js/jquery-1.4.2.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $(".menu p:not(:first)").hide(); $(".menu h3").css("background", "#ccc"); $(".menu h3").hover(function () { $(this).css("background-color", "gray").siblings("h3").css ("background-color", "#ccc");}); $(".menu h3").mouseleave(function () { $(".menu h3").css("background", "#ccc");}); //離開時將其變為原來顏色 var index = $(".menu h3").index(this); $(".menu h3").click(function () { $(this).next("p").slideToggle().siblings("p").slideUp(); }); }); </script> </head> <body> <div class="menu"> <h3> 我的好友</h3> <p> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/><br/> <a href="index.jsp">周傑倫</a><br/> </p> <h3> 我的朋友</h3> <p> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/><br/> <a href="index.jsp">李連傑</a><br/> </p> <h3> 陌生人</h3> <p> <a href="index.jsp">比爾蓋茨</a><br/><br/> <a href="index.jsp">比爾蓋茨</a><br/><br/> <a href="index.jsp">比爾蓋茨</a><br/><br/> <a href="index.jsp">比爾蓋茨</a><br/><br/> <a href="index.jsp">比爾蓋茨</a><br/><br/> <a href="index.jsp">比爾蓋茨</a><br/><br/> <a href="index.jsp">比爾蓋茨</a><br/> </p> </div> </body> </html>View Code
聊天主頁main.jsp頁面代碼:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'main.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <form action="InputInformation" method=post> <textarea cols="105" rows="25" name="show_textarea"><%=request.getAttribute("input_textarea")%></textarea> <br> <textarea cols="105" rows="5" name="input_textarea"></textarea><br> <input type="submit" value="發送" name="button_one" style="width: 100px; height: 40px;font-size: 25px;"><br> </form> </body> </html>
(2)InputInformation.java(Servlet類)通過請求指派獲取main.jsp聊天輸入框中輸入信息,跳轉到main.jsp頁面,併在聊天記錄顯示框中顯示聊天信息。具體實現如下:
InputInformation.java類代碼如下:
package com.liuzhen.chart; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class InputInformation extends HttpServlet { public String chat_record = ""; //定義聊天記錄變數,此處為全局變數 /** * Constructor of the object. */ public InputInformation() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //response.setContentType("text/html;charset=utf-8"); //此出註解是因為使用CodeFilter類過濾所有Servlet,轉換編碼 //request.setCharacterEncoding("utf-8"); String input_textarea = request.getParameter("input_textarea"); Date now = new Date(); //創建日期對象,及系統當前時間 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設置日期格式 String time = dateFormat.format( now ); //按照給定的日期格式獲取系統當前時間 String t = (String)request.getSession().getAttribute("nameSession"); //獲取登陸頁面用戶名 chat_record += t+" "+input_textarea+" "+time+"\n"; //聊天記錄存儲 request.setAttribute("input_textarea",chat_record); //將當前聊天輸入內容存儲 request.getRequestDispatcher("main.jsp").forward(request,response); //跳轉到當前聊天輸入界面,即界面佈局不變 } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here } }
(3)CodeFilter.java(過濾器類)截取系統所有Servlet類,實現對請求和響應對象的編碼格式的設置,均設置為UTF-8。具體實現如下:
CodeFilter.java類代碼如下:
package com.liuzhen.chart; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //採用註解方式配置URL,此處就不必再在web.xml文件中配置。如果兩者均配置的話,系統將以web.xml文件中配置信息為準 @WebFilter(filterName="CodeFilter",urlPatterns={"/*"}) public class CodeFilter implements Filter{ @Override public void destroy() { System.out.println("destroy---CodeFilter"); } @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { System.out.println("start----doFilter--CodeFilter"); HttpServletRequest request =(HttpServletRequest) arg0; HttpServletResponse response =(HttpServletResponse) arg1; //以上是強制內型轉換,使用request對象和response對象 request.setCharacterEncoding("utf-8"); //設置過濾頁面提取數據的編碼 response.setContentType("text/html;charset=utf-8"); //設置過濾頁面顯示數據的編碼 arg2.doFilter(arg0, arg1);//在頁面跳轉之前執行此語句前面的代碼,執行完頁面的代碼之後,在執行後面的語句 System.out.println("第一個字元過濾器"); System.out.println("end------doFilter--CodeFilter"); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init----CodeFilter"); } }
(4)OnlineListener.java(監聽器類)主動監聽系統Web容器,返回當前聊天系統線上人數,具體實現如下:
OnlineListener.java類代碼如下:
package com.liuzhen.chart; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class OnlineListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent arg0) { ServletContext context = arg0.getSession().getServletContext(); Integer count = (Integer) context.getAttribute("peopleOnline"); if (count == null) { count = 1; } else { count++; } context.setAttribute("peopleOnline", count); } public void sessionDestroyed(HttpSessionEvent arg0) { ServletContext context = arg0.getSession().getServletContext(); Integer count = (Integer) context.getAttribute("peopleOnline"); count--; context.setAttribute("peopleOnline", count); } }
此處還要給OnlineListener監聽器類在web.xml文件中配置路徑,web.xml配置代碼具體如下(紅色標記代碼):
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <listener> <listener-class>com.liuzhen.chart.OnlineListener</listener-class> </listener> <servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>Main</servlet-name> <servlet-class>com.liuzhen.chart.Main</servlet-class> </servlet> <servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <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>
在調用監聽器類實現監聽系統當前線上人數時,本機上同一個瀏覽器同時登陸多個用戶,只能算作一次,本機上不同瀏覽器登陸則分別算作一次。以下分別是在IE、谷歌和360瀏覽器登陸線上人數顯示:
圖四:IE瀏覽器登陸,顯示線上人數1人
圖五:谷歌瀏覽器登陸,顯示線上人數2人
圖六:360瀏覽器登陸,顯示線上人數3人
附:本文系統代碼Coding鏈接:https://coding.net/u/LiuZhen1995/p/MyDemo/git/tree/origin_seven
參考資料: