chatClient.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="description" content="This is my page">
<!-- js部分,本应在一个js文件里,这里为了演示方便,放在一起 -->
<script type="text/javascript">
/* ajax生成后台访问的http对象 */
function getXmlHttpObject() {
var xmlHttp = null;
try {
// Firefox, Opera 8.0+, Safari
xmlHttp = new XMLHttpRequest();
} catch (e) {
// Internet Explorer
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
/* ajax执行方法,访问servlet, */
function getServerInfo() {
http = getXmlHttpObject();
var url = "getmsg?time=" + Math.random();
http.onreadystatechange = getInfoBack;
http.open("GET", url, true);
http.send(null);
}
/* 消息返回执行方法, */
function getInfoBack() {
if (http.readyState == 4) {
if (http.status == 200) {
//获取返回的消息字符串
var response = http.responseText;
//通过id找到聊天显示框把消息显示出来
document.getElementById("chatbox").innerHTML += response
+ "\r\n";
//再次执行getServerInfo方法访问servlet
getServerInfo();
}
}
}
/* 点击发送按钮执行,提交表单,把输入框清空,消息显示框显示到最底部
@param o输入框的id */
function sendok(o) {
//提交表单(直接使用form表单的名字)
myform.submit();
//通过传来的输入框的id参数o把输入框的内容清空
document.getElementById(o).value = "";
//用txt保存聊天显示框的对象
var txt = document.getElementById("chatbox");
//设置显示框显示在最底部
txt.scrollTop = txt.scrollHeight;
}
</script>
</head>
<!-- 加载时就执行getServerInfo方法,监听是否有数据输入 -->
<body οnlοad="getServerInfo()">
聊天内容:
<br>
<!-- textarae显示聊天内容,设置id方便访问该标签,设置disabled让文本框不可以输入数据,设置style背景色为白色(这些在css里设置,这里为了演示方便) -->
<textarea id="chatbox" rows="10" cols="50" disabled="disabled"
style="background-color: white;"></textarea>
<br>
<!-- 用表单来提交数据,设置name方便访问,action为servlet地址,target为跳转下面设置的页面“sform”,相当于不跳转 -->
<form name="myform" method="post" action="sendmsg" target="sform">
<!-- 输入框完成消息输入 -->
<input id="msginput" type="text" name="chatmsg" />
<!-- 发送按钮,点击执行sendok()方法 -->
<input type="button" value="发送" οnclick="sendok('msginput')" />
</form>
<!-- 设置一个空iframe,让表单提交后不跳转, -->
<iframe width="0" height="0" style="display: none" name="sform"></iframe>
</body>
</html>
chatdemo_message.java
package chat.classinfo;
/* 封装消息对象的类,这里为了演示就只设置了message一个属性 ,提供相应的set、get方法*/
public class Message {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
chatdemo_getmsg.jsva
package chat.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import chat.classinfo.Message;
/* 监听是否有消息输入,当页面加载时就会用AJAX访问该servlet, */
public class GetMsgServlet extends HttpServlet {
// 用一个Hashtable保存正在监听消息的客户端,键为每个客户端的session,值为消息对象
public static Hashtable<String, Message> waitList = new Hashtable<String, Message>();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
/* 消息监听,如果没有消息就会等待,当发送消息的servlet执行后会释放该同步锁 */
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 保存Message对象
Message msg = new Message();
// 把该对象与相应的session放到Hashtable中,
waitList.put(request.getSession(true).getId(), msg);
// 消息同步,消息刚刚创建是没有任何内容的,所以一定会先进入等待状态,等到消息值放进去之后再执行后面的操作
synchronized (msg) {
try {
// 同步等待
msg.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 当执行到这一步时,就说明消息同步已被唤醒,就说明msg里面已经把消息内容放进去了。
// 设置返回编码
response.setCharacterEncoding("utf-8");
// 用pw保存返回输出对象
PrintWriter pw = response.getWriter();
// 把消息内容通过输出对象输出
pw.print(msg.getMessage());
// 把输出对象清空关闭
pw.flush();
pw.close();
}
}
chatdemosendmsg.jsva
package chat.servlet;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import chat.classinfo.Message;
/* 当点击发送按钮提交表单执行该servlet,对消息进行处理 */
public class SendMsgSrevlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
/* 处理消息,把消息放进消息对象,把同步锁唤醒 */
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置传过来的数据编码
request.setCharacterEncoding("utf-8");
// 得到由输入的消息内容
String chatmsg = request.getParameter("chatmsg");
// 通过Set(Hashtable键)获取所有正在等待的session列表,方便使用迭代器
Set<String> sessions = GetMsgServlet.waitList.keySet();
// 使用迭代器Iterator方便遍历到所有的等待session
Iterator<String> sessionsIt = sessions.iterator();
// 遍历所有等待的session对象
while (sessionsIt.hasNext()) {
// 获取每一个等待的sessionid
String sessionId = sessionsIt.next();
// 通过sessionid获取该等待session的消息对象
Message msg = GetMsgServlet.waitList.get(sessionId);
// 在把输入框传过来的消息内容放进消息对象中时,可以用迭代器方便的把该等待session从等待列表中移除
sessionsIt.remove();
// 把消息内容放进消息对象,把同步消息唤醒
msg.setMessage(chatmsg);
// 同步唤醒所有正在等待的消息对象
synchronized (msg) {
msg.notifyAll();
}
}
}
}