Comet反向ajax技术实现客服聊天系统
说明:Comet反向Ajax是在看了燕十八老师的视频以后,结合他讲解的例子,自己用ajax+java实现了一遍。在这里把代码贴出来,以供大家学习。同时,ajax轮询技术也可以用在消息推送的功能中,下次有时间,可以把相关的代码和设计思路贴出来,一起学习学习!
客户端代码:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>客户端</title> 5 6 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 7 <meta http-equiv="description" content="this is my page"> 8 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 9 <style> 10 *{margin:0; padding:0;} 11 h1{padding-left:300px;} 12 #msg{margin:20px;width:800px;height:400px;background:#ccc;border:2px solid #000;padding-left:10px;font-family: "微软雅黑"; 13 font-size: 14px;padding:20px;overflow:auto;} 14 #msg p{line-height:20px;} 15 .say p:nth-of-type(2){text-indent: 20px;} 16 .reply{text-align:right;color:blue;} 17 #operate{margin:20px;font-family: "微软雅黑";font-size:14px;} 18 #operate #content{width:600px;height:30px;padding-left:10px;} 19 #operate input:nth-of-type(2){width:80px;height:30px;font-family: "微软雅黑";} 20 </style> 21 </head> 22 23 <body> 24 <h1>客户端发送信息</h1> 25 <div id="msg"> 26 </div> 27 <div id="operate"> 28 <input type="text" id="content" placeholder="请输入发送内容"/> 29 <input type="button" value="点击发送" onclick="sendHandler();"> 30 </div> 31 </body> 32 </html> 33 <script type="text/javascript"> 34 var xhr = new XMLHttpRequest(); 35 window.onload = function(){ 36 function autoSend(){ 37 xhr.open("POST", "getClientMsg.do",true); 38 xhr.onreadystatechange = function(){ 39 if(xhr.readyState == 4 && xhr.status == 200){ 40 if(xhr.responseText != "reload")setValue(xhr.responseText); 41 window.setTimeout(function(){ 42 autoSend(); 43 }, 500); 44 } 45 }; 46 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 47 xhr.send(null); 48 } 49 autoSend(); 50 } 51 52 function setValue(result){ 53 console.log("result",result); 54 var strs = result.split("&"); 55 var date = new Date(); 56 date = date.toLocaleDateString(); 57 document.getElementById("msg").innerHTML += "<div class='say'><p>客服中心 "+date+"</p><p>"+strs[1]+"</p></div>"; 58 } 59 //发送数据 60 function sendHandler(){ 61 var oContent = document.getElementById("content"); 62 if(null != oContent.value){ 63 var xhr = new XMLHttpRequest(); 64 xhr.open("POST", "sendMsg.do",true); 65 xhr.onreadystatechange = function(){ 66 if(xhr.readyState == 4 && xhr.status == 200){ 67 if(xhr.responseText == "success"){ 68 var date = new Date(); 69 date = date.toLocaleDateString(); 70 document.getElementById("msg").innerHTML += "<div class='reply'><p>我 "+date+"</p>"+ 71 "<p>"+oContent.value+"</p></div>"; 72 document.getElementById("content").value = ""; 73 } 74 } 75 } 76 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 77 xhr.send("sendIdentity=client&content="+oContent.value); 78 79 } 80 } 81 82 </script>
客户端获取消息代码:
package com.sgepit.ajax; import java.io.IOException; import java.sql.Connection; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import com.sgepit.ajax.entity.Msg; import com.sgepit.ajax.util.DBCon; /** * @author tengri * @since 2015-12-12 下午9:59:45 * @description: 客户端获取消息 */ @SuppressWarnings("all") @WebServlet("/getClientMsg.do") public class GetClientMsg extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { try { Connection conn = DBCon.getConnection(); QueryRunner qr = new QueryRunner(); String clientIP = req.getRemoteAddr(); String sql = "select * from msg where rec =? and isread = 0 limit 1"; Object[] param = {clientIP}; Msg msg = null; resp.setCharacterEncoding("utf-8"); long startTime = System.currentTimeMillis(); while(true){ msg = qr.query(DBCon.getConnection(), sql, new BeanHandler(Msg.class), param); if(null != msg ){ String result = msg.getPos() + "&" + msg.getContent(); System.out.println("clientMsg:" + result); resp.getWriter().write(result); sql = "update msg set isread=1 where uuid=?"; Object[] param2 = {msg.getUuid()}; qr.update(conn, sql, param2); break; } if(System.currentTimeMillis() - startTime >=5000){ resp.getWriter().write("reload"); break; } Thread.sleep(500); } } catch (Exception e) { resp.getWriter().write("error"); } } }
客服端:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>客服端</title> 5 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 6 <meta http-equiv="description" content="this is my page"> 7 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 8 <style> 9 *{margin:0; padding:0;} 10 h1{padding-left:300px;} 11 #msg{margin:20px;width:800px;height:400px;background:#ccc;border:2px solid #000;padding-left:10px;font-family: "微软雅黑"; 12 font-size: 14px;padding:20px;overflow:auto;} 13 #msg p{line-height:20px;} 14 .say p:nth-of-type(1){cursor: pointer;} 15 .say p:nth-of-type(2){text-indent: 20px;} 16 .reply{text-align:right;color:blue;} 17 #operate{margin:20px;font-family: "微软雅黑";font-size:14px;} 18 #operate #content{width:600px;height:30px;padding-left:10px;} 19 #operate input:nth-of-type(2){width:80px;height:30px;font-family: "微软雅黑";} 20 </style> 21 </head> 22 23 <body> 24 <h1>服务端回复信息</h1> 25 <div id="msg"> 26 </div> 27 <div id="operate"> 28 <p>回复人:<span id="person"></span></p><br/> 29 <input type="text" id="content" placeholder="请输入回复内容"/> 30 <input type="button" value="点击回复" onclick="replyHandler();"> 31 </div> 32 </body> 33 </html> 34 <script type="text/javascript"> 35 var xhr = new XMLHttpRequest(); 36 window.onload = function(){ 37 document.getElementById("msg").onclick = function(ev){ 38 var event = ev || window.event; 39 if(event.target.nodeName.toLowerCase() == "span"){ 40 document.getElementById("person").innerHTML = event.target.innerText; 41 } 42 } 43 44 function autoSend(){ 45 xhr.open("POST", "getServerMsg.do",true); 46 xhr.onreadystatechange = function(){ 47 if(xhr.readyState == 4 && xhr.status == 200){ 48 if(xhr.responseText != "reload")setValue(xhr.responseText); 49 window.setTimeout(function(){ 50 autoSend(); 51 }, 500); 52 } 53 }; 54 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 55 xhr.send(null); 56 } 57 autoSend(); 58 } 59 function setValue(result){ 60 var strs = result.split("&"); 61 var date = new Date(); 62 date = date.toLocaleDateString(); 63 document.getElementById("msg").innerHTML += "<div class='say'><p class='clientIp'>"+ 64 "<span>"+strs[0]+"</span> "+date+"</p><p>"+strs[1]+"</p></div>"; 65 } 66 //发送回复内容 67 function replyHandler(){ 68 var value = document.getElementById("content").value; 69 var rec = document.getElementById("person").innerText; 70 if(!rec){ 71 alert("请选择回复人"); 72 return; 73 } 74 if(null != value){ 75 var xhr = new XMLHttpRequest(); 76 xhr.open("POST", "sendMsg.do",true); 77 xhr.onreadystatechange = function(){ 78 if(xhr.readyState == 4 && xhr.status == 200){ 79 if(xhr.responseText == "success"){ 80 var date = new Date(); 81 date = date.toLocaleDateString(); 82 document.getElementById("msg").innerHTML += "<div class='reply'><p>我 "+date+"</p><p>"+value+"</p></div>"; 83 document.getElementById("content").value = ""; 84 } 85 } 86 } 87 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 88 xhr.send("sendIdentity=admin&content="+value+"&rec="+rec); 89 } 90 } 91 </script>
服务端获取消息代码:
1 package com.sgepit.ajax; 2 3 import java.io.IOException; 4 import java.sql.Connection; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.annotation.WebServlet; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import org.apache.commons.dbutils.QueryRunner; 13 import org.apache.commons.dbutils.handlers.BeanHandler; 14 15 import com.sgepit.ajax.entity.Msg; 16 import com.sgepit.ajax.util.DBCon; 17 18 19 /** 20 * @author tengri 21 * @since 2015-12-12 下午9:59:45 22 * @description: 服务端获取消息 23 */ 24 @SuppressWarnings("all") 25 @WebServlet("/getServerMsg.do") 26 public class GetServerMsg extends HttpServlet { 27 28 @Override 29 protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { 30 try { 31 Connection conn = DBCon.getConnection(); 32 QueryRunner qr = new QueryRunner(); 33 String clientIP = req.getRemoteAddr(); 34 String sql = "select * from msg where rec =? and isread = 0 limit 1"; 35 Object[] param = {"admin"}; 36 Msg msg = null; 37 resp.setCharacterEncoding("utf-8"); //处理中文乱码 38 long startTime = System.currentTimeMillis(); 39 while(true){ 40 msg = qr.query(DBCon.getConnection(), sql, new BeanHandler(Msg.class), param); 41 if(null != msg ){ 42 String result = msg.getPos() + "&" + msg.getContent(); 43 System.out.println("servler:" +result); 44 resp.getWriter().write(result); 45 sql = "update msg set isread=1 where uuid=?"; 46 Object[] param2 = {msg.getUuid()}; 47 qr.update(conn, sql, param2); 48 break; 49 } 50 if(System.currentTimeMillis() - startTime >=5000){ 51 resp.getWriter().write("reload"); 52 break; 53 } 54 Thread.sleep(500); 55 } 56 } catch (Exception e) { 57 e.printStackTrace(); 58 resp.getWriter().write("error"); 59 } 60 } 61 }
发送消息代码:客户端和客服端发送消息都是调用同一个接口,只是在后台做了相关判断。
1 package com.sgepit.ajax; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.annotation.WebServlet; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 import org.apache.commons.dbutils.QueryRunner; 12 import org.apache.commons.dbutils.handlers.BeanHandler; 13 14 import com.sgepit.ajax.entity.Msg; 15 import com.sgepit.ajax.util.DBCon; 16 17 /** 18 * @author tengri 19 * @since 2015-12-12 下午9:59:24 20 * @description: 发送消息 21 */ 22 @SuppressWarnings("all") 23 @WebServlet("/sendMsg.do") 24 public class SendMsg extends HttpServlet { 25 26 @Override 27 protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { 28 req.setCharacterEncoding("utf-8"); 29 String sendIdentity = req.getParameter("sendIdentity"); 30 String content = req.getParameter("content"); 31 String rec = "admin"; 32 String pos = "admin"; 33 try { 34 //如果是服务端发送消息,则会传过来接收者对象,如果是客户端发送消息,接收者为admin,发送端为当前ip用户 35 if("admin".equals(sendIdentity)){ 36 rec = req.getParameter("rec"); 37 }else{ 38 pos = req.getRemoteAddr(); 39 } 40 QueryRunner qr = new QueryRunner(); 41 String sql = "insert into msg(rec,pos,content,isread)values(?,?,?,0)"; 42 Object[] params = {rec,pos,content}; 43 qr.insert(DBCon.getConnection(),sql, new BeanHandler(Msg.class), params); 44 resp.getWriter().write("success"); 45 } catch (Exception e) { 46 resp.getWriter().write("error"); 47 e.printStackTrace(); 48 } 49 } 50 }
截图: