最近公司想要给公司的网站上添加一个在线客服功能,不让使用第三方插件只能自己制作.于是上网上找些例子,http://blog.csdn.net/luojia_wang/article/details/8825929给了不小的启发.推送技术基本是其之上改进的,非常感谢. 基于dwr3的在线客服系统
der.xml配置文件,跟web.xml在一层下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
<dwr>
<allow>
<create creator="new" javascript="MessagePush">
<param name="class" value="com.dwr.service.MessagePush"/>
</create>
<create creator="new" javascript="SendMessage">
<param name="class" value="com.dwr.service.SendMessage"/>
</create>
</allow>
</dwr>
web.xml
<!-- application监听 -->
<listener>
<listener-class>com.dwr.listener.MyApplicationListener</listener-class>
</listener>
<!-- session监听 -->
<listener>
<listener-class>com.dwr.listener.MySessionListener</listener-class>
</listener>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>crossDomainSessionSecurity</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>allowScriptTagRemoting</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>classes</param-name>
<param-value>java.lang.Object</param-value>
</init-param>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>initApplicationScopeCreatorsAtStartup</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>maxWaitAfterWrite</param-name>
<param-value>3000</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>WARN</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>LoginAction</servlet-name>
<servlet-class>com.dwr.login.LoginAction</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginAction</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
信息发送模块,
/**
* 信息发送模块
* @author Joker
*
*/
public class SendMessage {
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private Date date = new Date();
/**
* userId: 被推送页面ID, otherId: 对方页面Id, message:发送内容
*/
public void sendMessage(final String userId, final String otherId, final String message, String user){
System.out.println("sendMessage()==>userId:" + userId + "\t otherId:" + otherId + "\t message:" + message + "\t userName:" + user);
if(user == null){
user = "系统提示 " + format.format(date);
}else{
user += format.format(date);
}
final String autoMessage = "{\"otherId\":\""+otherId+"\",\"message\":\""+message+"\",\"userName\":\""+user+"\"}";
Browser.withAllSessionsFiltered(new ScriptSessionFilter(){
public boolean match(ScriptSession session) {
if(session.getAttribute("userId") == null)
return false;
else
return session.getAttribute("userId").equals(userId);
}
}, new Runnable(){
ScriptBuffer script = new ScriptBuffer();
public void run() {
script.appendCall("showMessage", autoMessage);
Collection<ScriptSession> sessions = Browser.getTargetSessions();
for(ScriptSession scriptSession : sessions){
scriptSession.addScript(script);
}
}
});
}
}
/**
* 创建相应的ScriptSession
* @author Joker
*
*/
public class MessagePush implements Comparator<User>{
/**
* 创建ScriptSession
* (k-客服,f-访客,m-发送的是对话,i-发送的是对方的Id);
*/
@SuppressWarnings("unchecked")
public void onLoadPage(String userId, String identity){
System.out.println("onLoadPage()==>userId:" + userId + "\t identity:" + identity);
SendMessage sendMessage = new SendMessage();
ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
scriptSession.setAttribute("userId", userId);
DwrScriptSessionManagerUtil dwrScriptSessionMessageUtil = new DwrScriptSessionManagerUtil();
dwrScriptSessionMessageUtil.init(userId);
if("f".equals(identity)){//判断为访客
User user = getUser();
if(user.getId() == null){
//客服轮空
sendMessage.sendMessage(userId, null, "客服正忙请稍等", null);
}else{
//当值客服
sendMessage.sendMessage(userId, user.getId().toString(), user.getId() + "号客服为您服务!", null);//发送给访客
sendMessage.sendMessage(user.getId().toString(), userId, null, null);//发送给当值客服
HttpSession session = WebContextFactory.get().getSession();
session.setAttribute(userId, user);
ServletContext application = WebContextFactory.get().getServletContext();
Hashtable<Long, Object> ht = (Hashtable<Long, Object>)application.getAttribute("userList");
user.setCount(user.getCount() + 1);
ht.put(user.getId(), user);
}
}
}
/**
* 获取客服
*/
@SuppressWarnings("unchecked")
public User getUser(){
ServletContext application = WebContextFactory.get().getServletContext();
Hashtable<Long, Object> ht = (Hashtable<Long, Object>)application.getAttribute("userList");
Set<Long> keys = ht.keySet();
List<User> users = new ArrayList<User>();
for(Long key : keys){
User user = new User();
user = (User)ht.get(key);
if(user.getCount() == 0){
return user;
}
if(user.getCount() == 10){//阀值跳过
continue;
}
users.add(user);
}
if(users.size() == 0){
return new User();
}
Collections.sort(users,new MessagePush());
return users.get(0);
}
/**
* 比较器
*/
public int compare(User o, User t) {
if(o.getCount() > t.getCount()){
return 1;
}else if(o.getCount() == t.getCount()){
if(o.getId() > t.getId()){
return 1;
}else if(o.getCount() == t.getCount()){
return 0;
}else{
return -1;
}
}else{
return -1;
}
}
}
public class DwrScriptSessionManagerUtil {
public void init(final String userId){
Container container = ServerContextFactory.get().getContainer();
ScriptSessionManager manager = container.getBean(ScriptSessionManager.class);
ScriptSessionListener listener = new ScriptSessionListener(){
public void sessionCreated(ScriptSessionEvent event) {
event.getSession().setAttribute("userId", userId);
}
@SuppressWarnings("unchecked")
public void sessionDestroyed(ScriptSessionEvent event) {
String userid = (String) event.getSession().getAttribute("userId");
HttpSession session = WebContextFactory.get().getSession();
User user = (User)session.getAttribute(userid);
if(user != null){
ServletContext application = WebContextFactory.get().getServletContext();
Hashtable<Long, Object> ht = (Hashtable<Long, Object>)application.getAttribute("userList");
if(user.getCount() <= 0){
user.setCount(0L);
}else{
user.setCount(user.getCount() - 1);
}
ht.put(user.getId(), user);
}
}};
manager.addScriptSessionListener(listener);
}
}
application监听,用来储存在线客服
/** * application监听 * @author Joker * */ public class MyApplicationListener implements ServletContextListener { private Hashtable<Long, Object> ht = new Hashtable<Long, Object>(); public void contextDestroyed(ServletContextEvent arg0) { // TODO Auto-generated method stub } public void contextInitialized(ServletContextEvent event) { System.out.println("项目初始化()..."); ServletContext application = event.getServletContext(); application.setAttribute("userList", ht); } }
/** * session监听 * @author Joker * */ public class MySessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent arg0) { // TODO Auto-generated method stub } @SuppressWarnings("unchecked") public void sessionDestroyed(HttpSessionEvent event) { User user = (User)event.getSession().getAttribute("user"); if(user != null){ ServletContext application = WebContextFactory.get().getServletContext(); Hashtable<Long, Object> ht = (Hashtable<Long, Object>)application.getAttribute("userList"); ht.remove(user.getId()); } } }
客服页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type='text/javascript' src='js/jquery-1.5.1.js'></script> <script type='text/javascript' src='/web_dwr/dwr/engine.js'></script> <script type='text/javascript' src='/web_dwr/dwr/interface/MessagePush.js'></script> <script type='text/javascript' src='/web_dwr/dwr/interface/SendMessage.js'></script> <script type='text/javascript' src='/web_dwr/dwr/util.js'></script> <title>客服页面</title> <style type="text/css"> #all_div{width: 1440px; height: 690px; border:1px solid red;} #left_div{width: 75%; height: 100%; float: left; border-right: 1px solid red} #right_div{width: 24.5%; height: 100%; float: left} </style> <script type="text/javascript"> $(function(){ dwr.engine.setActiveReverseAjax(true); dwr.engine.setNotifyServerOnPageUnload(true); MessagePush.onLoadPage(${user.id}, "k"); }); function showMessage(data){ var arr = jQuery.parseJSON(data); var callerId = arr.otherId; var message = arr.message; var userName = arr.userName; if($("#" +callerId + "div").length == 0){ $("#right_div").append("<a href=\"javascript:add_div("+callerId+");\">新访客:"+callerId+"</a><br/>"); } var old_message = $("#" +callerId + "div").find(".show_message").find("textarea").val(); $("#" +callerId + "div").find(".show_message").find("textarea").val(old_message + "\r" + userName + "\r " + message); }; function sendMessage(div_Id){ var old_message = $("#" + div_Id).find(".show_message").find("textarea").val(); var new_message = $("#" + div_Id).find(".send_message").find("textarea").val(); SendMessage.sendMessage(div_Id.substring(0, div_Id.length-3), ${user.id}, new_message, "客服("+${user.id}+")" ); $("#" + div_Id).find(".show_message").find("textarea").val(old_message + "\r客服("+${user.id}+")\t"+getNowFormatDate()+":\r " + new_message); $("#" + div_Id).find(".send_message").find("textarea").val(""); }; function close_div(div_Id){ $("#" + div_Id).remove(); }; function add_div(callerId){ if($("#" +callerId + "div").length == 0){ var new_div = $(".message_box").clone(); new_div.attr("id", callerId + "div"); new_div.removeClass("message_box"); new_div.find(".box_title").append("<span style=\"line-height: 25px;\">[新访客:"+callerId+"]</span><span style=\"display: block; line-height: 25px; float: right; cursor: pointer;\" οnclick=\"close_div('"+callerId+"div')\">[关闭]</span>"); new_div.find(".send_message").append("<img class=\"send_button\" src=\"images/send.jpg\" style=\"width: 16%; height: 99%; cursor: pointer;\" οnclick=\"sendMessage('"+callerId+"div')\"/>"); $("#left_div").append(new_div); new_div.show(); } } function getNowFormatDate() { var day = new Date(); var Year = 0; var Month = 0; var Day = 0; var Hour = 0; var Minute = 0; var Second = 0; var CurrentDate = ""; //初始化时间 //Year = day.getYear();//有火狐下2008年显示108的bug Year = day.getFullYear();//ie火狐下都可以 Month = day.getMonth()+1; Day = day.getDate(); Hour = day.getHours(); Minute = day.getMinutes(); Second = day.getSeconds(); CurrentDate += Year + "-"; if (Month >= 10 ){ CurrentDate += Month + "-"; }else{ CurrentDate += "0" + Month + "-"; } if (Day >= 10 ){ CurrentDate += Day + " "; }else{ CurrentDate += "0" + Day ; } if (Hour >= 10 ){ CurrentDate += Hour + ":"; }else{ CurrentDate += "0" + Hour + ":" ; } if (Minute >= 10 ){ CurrentDate += Minute + ":"; }else{ CurrentDate += "0" + Minute + ":" ; } if (Second >= 10 ){ CurrentDate += Second ; }else{ CurrentDate += "0" + Second ; } return CurrentDate; } </script> </head> <body> 客服编号:<input name="userId" value="${user.id}"/> 客服名称:<input name="userId" value="${user.name}"/> <div id="all_div"> <div id="left_div"></div> <div id="right_div"></div> </div> </body> <div class="message_box" style="width: 55%; height: 60%; border: 4px solid black; display: none"> <div class="box_title" style="width: 100%; height: 25px; background-color: #ACFFF0;"> </div> <div class="show_message" style="width: 100%; height: 73%; border-bottom: 2px solid blue;"> <textarea style="width: 99%; height: 99%" readonly="readonly"></textarea> </div> <div class="send_message" style="width: 100%; height: 20%; border-bottom: 2px solid blue;"> <textarea style="width: 80%; height: 93%"></textarea> </div> </div> </html>
访客页面<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type='text/javascript' src='js/jquery-1.5.1.js'></script> <script type='text/javascript' src='/web_dwr/dwr/engine.js'></script> <script type='text/javascript' src='/web_dwr/dwr/interface/MessagePush.js'></script> <script type='text/javascript' src='/web_dwr/dwr/interface/SendMessage.js'></script> <script type='text/javascript' src='/web_dwr/dwr/util.js'></script> <title>访客页面</title> <style type="text/css"> body{margin:0px;background:#FFF;overflow:hidden; font-size:12px} body img{ display:block;} .lt{ padding-right:139px;} .lt_top{ height:48px; background:url(images/zx_03.jpg);} .lt_top .l{ float:left;} .lt_top .r{ float:right;} .lt_top span{ float:left; padding:20px 0px 0px 6px; color:#000; color:#404799;} .lt_main{ padding-left:9px; background:url(images/zx_10.jpg) left repeat-y;padding-right:9px; position:relative;} .lt_main .text{ padding:5px; overflow:auto; background:#eee;font-size:14px; border:0px; width:99%;} .lt_main .kz{ position:absolute;right:0px;top:0px; width:11px; background:url(images/zx_16.jpg);} .lt_main .kz img{ position:absolute;top:50%; margin-top:-24px; cursor:pointer;} .lt_xx{ background:url(images/zx_18.jpg); height:110px; position:relative; padding:29px 100px 0px 12px;} .lt_xx .l{ position:absolute;left:0px;top:0px;} .lt_xx textarea{ border:0px; overflow:auto; width:99%;height:80px; font-size:14px; padding:2px;} .lt_xx .an{ position:absolute;right:0px;top:0px; cursor:pointer;} .lt_right{ position:absolute;right:0px;top:0px; height:400px; width:139px; background:url(images/zx_12.jpg);} .lt_right .t{ position:absolute;top:0px;right:0px;} .lt_right .tu{ position:absolute;top:94px;right:7px;} .lt_right .b{ position:absolute; bottom:0px;right:0px;} </style> <script type="text/javascript"> var userId = Math.random().toString().substr(2, 11); $(function(){ var h = $(window).height(); $(".lt_main .text").css("height",h-197); $(".lt_main .kz").css("height",h-187); $(".lt_right").css("height",h); $(window).resize(function(){ h = $(window).height(); $(".lt_main .text").css("height",h-197); $(".lt_main .kz").css("height",h-187); $(".lt_right").css("height",h); }); }); $(function(){ dwr.engine.setActiveReverseAjax(true); dwr.engine.setNotifyServerOnPageUnload(true); MessagePush.onLoadPage(userId, "f"); }) function showMessage(date){ var arr = jQuery.parseJSON(date); var callerId = arr.otherId; var message = arr.message; var userName = arr.userName; var old_message = $("[name=\"show_message\"]").val(); $("[name=\"callerId\"]").val(callerId); $("[name=\"show_message\"]").val(old_message + "\r" + userName + "\r " + message); }; function sendMessage(){ var callerId = $("[name=\"callerId\"]").val(); var new_message = $("[name=\"send_message\"]").val(); var old_message = $("[name=\"show_message\"]").val(); SendMessage.sendMessage(callerId, userId, new_message, "访客("+userId+")"); $("[name=\"show_message\"]").val(old_message + "\r访客("+callerId+")\t"+getNowFormatDate()+":\r " + new_message); $("[name=\"send_message\"]").val(""); }; function getNowFormatDate() { var day = new Date(); var Year = 0; var Month = 0; var Day = 0; var Hour = 0; var Minute = 0; var Second = 0; var CurrentDate = ""; //初始化时间 //Year = day.getYear();//有火狐下2008年显示108的bug Year = day.getFullYear();//ie火狐下都可以 Month = day.getMonth()+1; Day = day.getDate(); Hour = day.getHours(); Minute = day.getMinutes(); Second = day.getSeconds(); CurrentDate += Year + "-"; if (Month >= 10 ){ CurrentDate += Month + "-"; }else{ CurrentDate += "0" + Month + "-"; } if (Day >= 10 ){ CurrentDate += Day + " "; }else{ CurrentDate += "0" + Day ; } if (Hour >= 10 ){ CurrentDate += Hour + ":"; }else{ CurrentDate += "0" + Hour + ":"; } if (Minute >= 10 ){ CurrentDate += Minute + ":"; }else{ CurrentDate += "0" + Minute + ":" ; } if (Second >= 10 ){ CurrentDate += Second ; }else{ CurrentDate += "0" + Second ; } return CurrentDate; } </script> </head> <body> <input name="callerId" type="hidden"/> <div class="lt"> <!--头部--> <div class="lt_top"><img src="images/zx_01.jpg" class="l"><span>欢迎您的来访</span><img src="images/zx_05.jpg" class="r"></div> <!--头部 结束--> <!--信息展示--> <div class="lt_main"> <textarea name="show_message" class="text" readonly="readonly"></textarea> <div class="kz"><img src="images/zx_14.jpg"></div> </div> <!--信息展示 结束--> <!--消息发送--> <div class="lt_xx"> <img src="images/zx_09.jpg" class="l"> <textarea name="send_message"></textarea> <img src="images/zx_20.jpg" class="an" οnclick="sendMessage()"> </div> <!--消息发送 结束--> <div class="lt_right"> <img src="images/zx_06.jpg" class="t"> <img src="images/zx_26.jpg" width="125" height="184" class="tu"> <img src="images/zx_22.jpg" class="b"> </div> </div> </body> </html>