最近公司想要给公司的网站上添加一个在线客服功能,不让使用第三方插件只能自己制作.于是上网上找些例子,http://blog.youkuaiyun.com/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;\" onclick=\"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;\" onclick=\"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" onclick="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>