1 問題の説明
Java EE 関連技術を使用して、単純な Web チャット ルーム システムを実装する具体的な要件は次のとおりです。
(1) ログイン情報にはユーザー名とパスワードが含まれており、それぞれログイン情報を送信およびリセットします。
(2) リクエストの割り当てを通じてユーザーが送信したログイン情報を処理するサーブレット プログラム Main.java を作成します。 ユーザー名がこのグループのメンバーの名前であり、パスワードが対応する学生番号である場合、次のページにジャンプします。 LoginSuccess 表示チャット インターフェイス (QQ グループ チャット インターフェイスと同様、HTML でフレームセット タグを使用して 2 つのウィンドウを生成できます。1 つはユーザー情報の入力用、もう 1 つはすべてのユーザー チャット レコードの表示用です)。ページが表示され、ユーザーに再度ログインするよう求められます (注: このページには以前のログイン インターフェイスが含まれている必要があります)。
(3) 「情報入力」ウィンドウと「チャット記録表示」ウィンドウの内容をそれぞれ表示する 2 つのサーブレットプログラムを作成します。ユーザーは「情報入力」ウィンドウにチャットの内容を入力し、「送信」ボタンをクリックします。 「チャット履歴表示」ウィンドウには、メッセージを送信したユーザーの名前とチャットの内容が表示されます。ヒント: これを実現するには、HTML で textarea タグを使用します。
(4) ログインインターフェースにユーザー名とパスワードを記憶する機能を実装し、ユーザーがこの機能を選択してログインに成功すると、次回からはユーザー名とパスワードを入力せずにログインできるようにします。ヒント: この機能は 2 つの Cookie を通じて利用できます。
次の関数を選択します:
(5) セッションの作成と破棄イベントを監視するリスナー プログラムを作成し、現在オンライン (ログイン) している人の数をカウントし、チャット インターフェイスに表示します。
(6) このシステム内のすべてのサーブレットプログラムをフィルタリングするためのフィルターを追加します。このフィルターは、リクエストオブジェクトとレスポンスオブジェクトのエンコード形式の設定を実装します(この機能を実装すると、サーブレットはパラメータ情報を取得せずにリクエストオブジェクトから直接取得できます)。リクエスト形式のエンコーディングを実装します)。 Filterと他のリソース間のプログラムの実行順序を[GlassFish Server]ビューに出力します。
2 解決策
2.1 期待される結果
図 1: オンラインチャットシステムの動作の概略図
2.2 システム構造の概略図
図 2: システム構造図
welcome.jsp 専用ページ:
図 3: welcome.jsp の実際の動作図
2.3 具体的なコーディング
(1) Main.java (Servlet クラス) は、JSP のユーザーによって送信されたログインを処理します。割り当て情報を要求することで、login.jsp ページにアクセスします (また、Cookie を使用して、ユーザーのログイン ユーザー名とパスワードを記憶する機能を実装します)。成功した場合は、welcome.jsp にジャンプし、失敗した場合は、login.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>
ログイン成功ページwelcome.jspページコード (ここではフレームセットタグが使用されており、ヘッダー、左側、中央のホームページの 3 つの部分に分かれており、それぞれ 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>
Chat head 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>
チャットの左側にある 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>
チャット ホーム ページ 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