AJAX无刷新聊天室实现(压缩包附件下载)

8 篇文章 0 订阅
8 篇文章 0 订阅
之前也写了一个小的聊天室DEMO,在另外一篇博客中
[url]http://lvp.iteye.com/blog/343236[/url],也提供了附件下载。
但是这个示例中页面自动刷新 带来的体验感不好,且当聊天内容到达最后一行时,滚动条的滚动是用了非常耍赖的方法来解决的,因此,在此基础之上,做了一些改进。

我觉得,写代码,不见得一定要写很多的DEMO,但是力争每一个DEMO都永远比上一个好。有可能一直在写同一个示例,但是每一次的实现一定在改进,在推敲。所以我也一直在做这么一件事情,尽可能把每个小DEMO写好,永远比上一次要好,永远比上一次要碰到更多的问题,永远比上一次要多懂得一些解决这些问题的方法,我觉得这是初学者应该要懂得的一个道理。不应该过于贪多,认真的把一个问题给解决,分析与总结。

所以,对于我来说,这个示例只是比上一个示例要好了一些,但是也不是终点。

并且,为了对下载的朋友负责的态度,凡是提供下载的代码一定都是经过自己手动实现,并非抄袭他人,代码是齐全的,有数据库的就一定提供数据库,所以这些代码可以帮助你们解决一些具有同类功能的问题。

代码描述部分,红色字体是我碰到的问题,后来都解决了,大家可以查看是否遇到过。

[color=red][b]这次的DEMO,主要解决了以下这些问题,或者说实现了以下的功能。[/b][/color]
[color=red]
1.窗体的控制,只显示合适的窗体大小。
2.用户名从已经登陆用户中检查,是否已经存在同名的情况.ajax后台调用查找.
3.登录后主窗体显示,登陆窗体关闭
4.显示已经登录者,在线人数,可以发表信息
5.信息显示,发表消息,上线与下线,都感觉不到页面的刷新,ajax实现
6.滚动条的控制,有时需要看上面的消息,有时需要自动滚动,由你控制
7.点击退出时,关闭页面,其它窗体显示下线信息.[/color]

DEMO 的 ajax实现靠手工代码形式完成,页面布局和窗体定位也都是通过手写代码 css+div完成。


列出图片,说出主要功能实现以及流程
1.登陆页面,自动验证登陆名称是否被占用
[img]http://lvp.iteye.com/upload/picture/pic/35123/5fa200b4-979a-3414-9d15-84d627648d58.png[/img]

2.登陆之后,登陆界面消失,聊天主界面消失掉。在线用户应该显示为 1人的,因为这是之前截取的,所以就没有修改。
[img]http://lvp.iteye.com/upload/picture/pic/35121/075d430b-21ae-3e89-8cf7-f848f6a91117.png[/img]

3.再使用Simon lv这个名称就不行了,因为之前已经有这个用户。
[img]http://lvp.iteye.com/upload/picture/pic/35119/9aa01e9e-fb00-3b27-b449-cf34ac623066.png[/img]

4.换一个名字,就能登陆,登陆后的效果
[img]http://lvp.iteye.com/upload/picture/pic/35117/aa6a6f27-a2ea-322f-862d-33f143ac3f76.png[/img]

5.多弄几个用户登陆进入
[img]http://lvp.iteye.com/upload/picture/pic/35129/2f90eaee-6f42-33a1-80b6-d84b37b05562.png[/img]

6.无刷新显示消息
[img]http://lvp.iteye.com/upload/picture/pic/35127/ebe15deb-8929-39c1-a627-f5eb36ba0ccf.png[/img]

7.张三退出后,聊天室信息显示离开,且在线人数马上发生改变
[img]http://lvp.iteye.com/upload/picture/pic/35125/e45956d4-c15b-3582-af12-57ffb199b8aa.png[/img]

以上为图片部分,代码部分和流程部分看下面内容。

请求的首页为index.jsp
立马转向到 login.jsp,这时将自身关闭,打开 login.jsp页面时,改变打开的大小.

<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<script type="text/javascript">
function openlogin(){
window.open("login.jsp","","width=600px,height=460px");
window.opener=null;
this.close();
}
</script>
</head>
<body onload="openlogin()">
</body>
</html>

[color=red]
中间的 window.opener=null; 不加的话,将会出现一个问题,就是在关闭 index.jsp自身时,会跳出一个提示框,提示是否需要关闭本页面,所以加上这句话就可以解决这个问题.[/color]

login.jsp中
检查用户是否存在部分

<td >
用户名:
</td>
<td >
<input type="text" class="normalTxt" name="name" onblur="checkUserIsExits()">
</td>


checkUserIsExits 函数异步请求另外的一个页面

login.jsp

<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<title>聊天室登录</title>
<link rel="stylesheet" type="text/css" href="css/styles.css">
<script language="javascript">
function showMess(mess){
document.getElementById("mess").innerHTML="<font color='red'>"+mess+"</font>";
}
//检查用户名是否登录
function checkUserIsExits(){
var objName = document.myform.name;

if(objName.value==""){
objName.focus();
showMess("请输入用户名!");
return;
}else{
for(var i=0;i<objName.value.length;i++){
var ch = objName.value.charAt(i);
if(ch=='<' || ch =='>' || ch=='-' || ch=='/' || ch=='\\'){
objName.focus();
showMess("不能含有<,>,-等特殊字符!");
return;
}
}
}
var url = "checkUser.jsp?user="+objName.value;
sendRequest(url);
}

//定义XMLHttpRequest对象
var xmlRequest;
//创建对象
function createXMLHttpRequest(){
if(window.XMLHttpRequest) { //Mozilla 浏览器
xmlRequest = new XMLHttpRequest();
}else if (window.ActiveXObject) { // IE浏览器
try {
xmlRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
}

//发送请求函数
function sendRequest(url){
createXMLHttpRequest(); //创建对象
url=encodeURI(url);
url=encodeURI(url);
xmlRequest.open("GET",url,true);
xmlRequest.onreadystatechange = checkResponse; //响应的函数
xmlRequest.send(null);
}

//响应的函数
function checkResponse(){
if(xmlRequest.readyState==4){
if(xmlRequest.status ==200) {
//信息已经成功返回
showloginInfo();
}else{
showMess("您所请求的页面有异常!");
}
}
}

//显示函数
function showloginInfo(){
//取得 checkUser.jsp返回的XML文本
var message = xmlRequest.responseXML.getElementsByTagName("userinfo")[0].firstChild.nodeValue;
showMess(message);
//因为之前解析XML 一直出现错误 所以改用了XML文本 先显示 后取出来
if(message=="可以使用"){
showMess("<font color='blue'>可以使用该名称!</font>");
document.getElementById("sub").disabled=false; //使按钮可用
}
}
</script>
</head>
<body>
<div id="mainDiv">
<form action="dologin.jsp" name="myform" method="post">
<table align="left" width="300">
<caption align="left"><font color="blue" size="6" face="隶书">o 蝈蝈岛聊天室 O</font></caption>
<tr >
<td >
用户名:
</td>
<td >
<input type="text" class="normalTxt" name="name" onblur="checkUserIsExits()">
</td>
</tr>

<tr>
<td colspan="2">
<input type="submit" id="sub" class="normalBtn" value="登 录" disabled="true">
 
<input type="reset" class="normalBtn" value="重 置">
 
</td>
</tr>
<tr>
<td colspan="2" align="right">
<label id="mess"> </label>
</td>
</tr>
<tr>
<td colspan="2">
<br>
<br>
<br>
Ajax 无刷新 简单多人聊天室DEMO,可到 <a href="http://lvp.iteye.com" target="_blank">http://lvp.iteye.com</a>下载
    <a href="javascript:close()">退出</a></td>
</tr>
</table>
</form>
</div>
</body>
</html>




注意,在login.jsp里面有一个函数

//发送请求函数
function sendRequest(url){
createXMLHttpRequest(); //创建对象
url=encodeURI(url);
url=encodeURI(url);
xmlRequest.open("GET",url,true);
xmlRequest.onreadystatechange = checkResponse; //响应的函数
xmlRequest.send(null);
}


[color=red]出现两次,为什么一定要加上两次,我也没有深究,在传递中文参数之前这样编码一下,
url=encodeURI(url);
url=encodeURI(url);
然后在请求到的处理页面做一些解码动作
name = URLDecoder.decode(name,"UTF-8");
中文问题就不存在,所以也没有为什么,只是这样做了,问题就解决了。
并且一定要注意,在ajax里操作的字符编码格式都是 UTF-8,所以统一起来就没有什么问题.[/color]
与login.jsp紧密相关的checkUser.jsp页面

<%@ page language="java" pageEncoding="UTF-8"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.net.URLDecoder"%>
<%
//获得参数 用户名
String name = request.getParameter("user");
//name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
name = URLDecoder.decode(name,"UTF-8");
//System.out.print("检查用户输入的是:"+name);
String responseText = "可以使用"; //响应字符串
//从application中取出所有已登录者的信息
ArrayList<String> list = (ArrayList<String>)application.getAttribute("users");

if(list!=null){
for(String string:list){
if(string.equals(name)){
responseText = "这个名称已经被占用!";
break;
}
}
}

//设置输出信息的格式及字符集
response.setContentType("text/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
out.print("<response>");
out.print("<userinfo>");
out.print(responseText);
out.print("</userinfo>");
out.print("</response>");
%>



流程:index.jsp 转到 login.jsp
login.jsp 中
checkUser.jsp是用来查看用户是否存在的。
dologin.jsp 是用来处理登陆的。

dologin.jsp 有这几部分逻辑:
1.得到用户,放入到 session中
2.放入到 application中

ArrayList<String> messageList = (ArrayList<String>)application.getAttribute("messages");

if(messageList==null){
messageList = new ArrayList<String>();
}

messageList.add("\n欢迎,欢迎,大家热列欢迎!"+name+" , 进入聊天室了.....\n");
application.setAttribute("messages",messageList);


3.转向

<script language="javascript">
//显示新窗口
function newchat(){
location.href="main.jsp";
}
</script>
</head>
<body onload="newchat()">



聊天主页面 main.jsp

<div id="contentDiv">
<div id="titleDiv">
<marquee direction="left" scrolldelay="200"><%=name%>..欢迎来到蝈蝈岛聊天室..o(∩_∩)o..
</marquee>
</div>
<div id="chatDiv">
<iframe src="chat.jsp" name="chat" frameborder="1" scrolling="auto"
height="350px" width="470px">
</iframe>
<span id="divMess" style="width:240px;">请输入内容(100字以内)! </span>
<div style="display:inline; text-align: right;width:200px"><a
href="javascript:setAuto()">自动滚动</a> <a
href="javascript:clearAuto()">取消滚动</a>
 <a href="dolayout.jsp">退出</a></div>
<div>
<textarea rows="3" cols="56" id="message" onclick="clearTxt()"></textarea>
</div>
<div style="text-align: right; padding-right: 0px;">
<input type="button" value="确定" class="longBtn"
onclick="sendMessage()">
</div>
</div>
<div id="userDiv">
<iframe src="user.jsp" name="userframe" frameborder="1" scrolling="auto"
height="440px" width="110px">
</iframe>
</div>
</div>


[color=red]main.jsp的构成部分,是由 user.jsp和chat.jsp为主的页面构建起来的。
user.jsp是显示用户页面,chat.jsp是显示聊天信息显示页面,它们都是通过 iframe插入到 main.jsp中,但是在数据显示的处理方式上,我特意使用了两种方式。[/color]对于chat.jsp 中几乎没有什么内容
<%@ page language="java" pageEncoding="GBK"%>

<html>
<head>
<style type="text/css">
body{
font-size:12px;
margin:0px;
line-height:18px;
padding-left:5px;
border:2px inset #eeebbb;
}
</style>
</head>
<body >
</body>
</html>


但是 user.jsp中就不一样

<%@ page language="java" pageEncoding="GBK"%>

<html>
<head>
<style type="text/css">
body{
font-size:12px;
margin:0px;
line-height:18px;
padding-left:5px;
}
</style>
<script language="javascript">
//用户请求数据
var xmlRequestUser;

//创建对象
function createXMLHttpRequest(){
if(window.XMLHttpRequest) { //Mozilla 浏览器
return new XMLHttpRequest();
}else if (window.ActiveXObject) { // IE浏览器
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
}
function sendGetUserRequest(){
var url = "getUser.jsp";
xmlRequestUser = createXMLHttpRequest();
xmlRequestUser.open("GET",url,true);
xmlRequestUser.onreadystatechange = getUserResponse;
xmlRequestUser.send(null);
}

function getUserResponse(){
if(xmlRequestUser.readyState==4){
if(xmlRequestUser.status ==200) {
//信息已经成功返回
showUserInfo();
}else{
showMess("您所请求的页面有异常!");
}
}
}

function showUserInfo(){
var message = xmlRequestUser.responseXML.getElementsByTagName("userinfo")[0].firstChild.nodeValue;
document.body.innerText = message;
}
//每隔10秒读取一次新用户
window.setInterval("sendGetUserRequest()",1000);
</script>
</head>
<body onload="sendGetUserRequest()">

</body>
</html>


[color=red]这两者的区别在于:
1.user.jsp中自己发送请求,去请求 getUser.jsp 页面,自己显示。
2.chat.jsp只负责显示,请求部分是 main.jsp页面完成的,在main.jsp中调用chat.jsp页面来显示异步请求后返回的数据。[/color]

main.jsp中调用chat.jsp显示聊天信息的数据时,有这一部分代码

function showChatMessage(){
var message = xmlRequest.responseXML.getElementsByTagName("message")[0].firstChild.nodeValue;
document.frames("chat").document.body.innerText = message;
}


document.frames("chat").document.body 就是来显示数据的。



//每隔三秒钟查询一次
window.setInterval("sendRequest('doinput.jsp')",1000);
var id ;
function setAuto(){
id = setInterval("document.frames('chat').document.body.scrollTop=document.frames('chat').document.body.scrollHeight",1000);
}
function clearAuto(){
clearInterval(id);
}


[color=red]后面两个方法,就是用来解决聊天室信息总显示最后一行的,可以让滚动条自动滚动,也可以取消自动滚动,这个解决方法,很多人都在找,希望能看到这里。[/color]

以上是一部分关键代码,具体内容还是下载附件,功能的实现都不难,就是要细心的做一件事情比较困难。

源码环境 jdk1.6 + myeclipse ,tomcat 即可,无数据库,代码自写亲测,放心下载!


[color=red]注意:IE版本不同,打开的效果可能有不一样,例如首页一打开,在有的IE浏览器上一闪就马上关闭了,不能看到登陆页面,如果是这种情况,请查看 index.jsp页面的代码[/color]

function openlogin(){   
window.open("login.jsp","","width=600px,height=460px");
//window.opener=null;//注释掉这句话就可以了 ,但是会冒出一个提示让你关闭index.jsp页面
this.close();
}


关于用户不是点击退出关闭连接退出聊天室,而是关闭窗体而退出聊天室,即时退出的效果已经解决,这个例子中没有写,但是之后就把这个功能实现了,给大家一个提示,实现起来也非常简单。

我下次可以在重新传一个上来。

提示就是:在关闭窗体 窗体卸载事件之前,使用xmlhttprequest对象发送一个请求到服务器端,清掉会话状态,且从application中清除此用户即可。


--- 关于上面的提示,我简单补充一下:关于窗体关闭的流程,不是单击关闭超级链接关闭,而是用户关闭浏览器时,触发事件,事件中请求服务器端清空用户即可。

//事件
window.onunload = closeWindow;

function closeWindow(){
if(confirm("确认要退出聊天室吗?")){
//发送请求到客户端删除此用户
clearUser();
}else{
//已经点击了关闭浏览器操作 ,如果不退出就重新打开一次就可以了
window.open("main.jsp","","width=600px,height=460px");
}
}

function clearUser(){
var url = "dolayout.jsp";
xmlRequest = createXMLHttpRequest(); //创建对象
//状态改变
xmlRequest.onreadystatechange = clearStatus;
xmlRequest.open("GET",url,true);
xmlRequest.send(null); // 发送请求
}



清空登录信息 清空用户

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%
String user = (String)session.getAttribute("sessionuser");
if(user==null){
response.sendRedirect("index.jsp");
return;
}

ArrayList<String> list = (ArrayList<String>)application.getAttribute("users");

if(list!=null){
for(String string:list){
if(string.equals(user)){
list.remove(string);
application.setAttribute("users",list);
break;
}
}
}
ArrayList<String> messageList = (ArrayList<String>)application.getAttribute("messages");

if(messageList==null){
messageList = new ArrayList<String>();
}

messageList.add("\n"+user+" , 离开聊天室了.....\n");
application.setAttribute("messages",messageList);

response.sendRedirect("index.jsp");
%>


例子重新上传一个吧!
大家如果要下载的话,就再去下载 20090412-ajax 无刷新聊天室-补充.rar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值