在线客服代码
第一次写,感觉很乱,后面直接上代码吧,代码也有注释,想看思路的朋友可以看前面。有什么建议和意见欢迎砸过来。
功能:
1、客服需登录进入客服页面。用户无需登录,进入用户页面,直接获取sessionId作为id值。
2、用户进入页面并且发送消息时,客服才会获取到该用户,并在左侧列表显示。
3、点击用户名即可切换聊天对象,正在聊天的用户,用户名为选中状态。
4、每条消息的时间显示在本条消息上方(水平居中)。消息时间间隔不足1分钟,则此不显示时间。
5、每次读取的消息均为最新消息。
6、客服未与其正在聊天的用户发送新消息时应有新消息提示。
客服界面将清空与下线用户的聊天窗口,且下线用户不显示在左侧列表中。
8、用户长时间无回应置为下线后,刷新可继续在线与客服聊天。
9、发送:1)输入框未输入消息时,提示“发送内容不能为空”。
2)未选择用户时,提示“请选择用户”。
数据库表:
三张表:客服(user),用户(customer),聊天记录(cs_chat_record)。
客服表主要字段:id,name,password,online,currentPeople;
用户表主要字段:id,name,online,headImg;
聊天记录表主要字段:id,userId,customerId,usercontent,customerContent,time;
主要思路:
1、用户进入页面:查看当前用户有没有正在被客服人员接待
①正在被接待:设置用户为在线状态(因为刷新会有下线操作)。
②未被接待:获取所有在线客服每个人正在接待的用户人数,并给该用户分配一个当前接待人数少的客服。
修改此客服正在接待的人数,将用户添加到用户表中(设置为在线状态)。
将用户和客服均存到session中。
2、客服进入页面:常规验证。
4、用户和客服发送消息时,都先将信息保存到数据库。
5、用户和客服界面,都是一秒刷新一次获取最新消息。
6、客服页面:当前正在沟通的用户列表,每秒获取一次,将不在线的用户在列表清除。
7、长时间无回复的用户置为下线,用到数据库定时器。
8、用户关闭浏览器置为下线,用到的是window.onbeforeunload方法。
9、新消息提醒:保存用户消息将用户头像设置成有红点的,获取消息时将用户头像设置为无红点的。
知识点:
1、获取用户id:getrequest().getSession().getId();
2、获取最新聊天记录时,聊天记录表的id是在前端存储的,一定不要在后台用全局变量存储,方便用户刷新页面时再次获取之前所有聊天记录。
3、c:foreach标签只能在服务器端使用,在页面加载完成后需要用js的for循环。
4、用户列表的显示是foreach循环得到的,为显示用户名的label设置class属性,用户点击切换用户时使用。
列表用户正在聊天的用户用户名设置为选中状态:$("p#"+id).css('background','#00ffff');
其他用户取消选中状态:$(".CustomerBG").css('background','#ffffff');
( ps:这里不是很懂,所以给p设置了两个属性,给背景色和取消背景色用到的不是一个属性。)
5、循环得到的用户名:<label id='labelId' class='checkLabel' style='font-size: 12pt;'data_id='" +cId +"'>"
1)点击用户名触发的事件,此方法在$(function(){})外写,能监听js中拼接的节点(此客服系统用的此方法):
$(document).off("click", ".checkLabel").on("click", ".checkLabel", function(){
//点击用户名之后要执行的内容
});
2)此方法在$(function(){})内写,不能监听到js中拼接的节点,
$(".checkLabel").click(function(){
//要执行的内容
})
attr:1)$(this).attr("data_id");拿到自定义的属性的值。
2)$(this).attr("data_id",“value”);给自定义的属性赋值。
6、清空p中的所有内容:
$("#pId").empty();
$("#pId").html("");
7、地址栏不能拼接时间参数,时间格式有空格,地址以空格为终点。
8、给myclass的span节点的内容加样式。
<p class="myclass" ><span>样式体现在这</span></p>
.myclass span{
//要写的样式
}
9、数据库定时器的格式
DElimitER $$
ALTER defineR=`root`@`localhost` EVENT `test` ON SCHEDULE EVERY 1 MINUTE STARTS '2018-04-26 18:40:32' ON COMPLETION NOT PRESERVE ENABLE DO BEGIN
//要执行的sql语句
END$$
DELIMITER ;
10、将30分钟内未发送消息的用户置为下线(觉得不是很容易写,半个多小时才写出来,记录一下)
UPDATE customer SET online=0
WHERE id IN
(SELECT customerId FROM
(SELECT customerId,MAX(`time`) maxTime FROM cs_chat_record GROUP BY customerId) temp
WHERE maxTime <CURRENT_TIMESTAMP - Interval 30 MINUTE);
未解决的问题:
1、每秒一次获取用户列表,页面会有闪烁。
2、火狐浏览器只在关闭页面时执行window.onbeforeunload方法,关闭整个浏览器时不执行。
3、“发送内容不为空”和“请选择用户”的判断都是在后台做的,感觉应该在前端做。
主要代码:
客服页:
<!DOCTYPE html>
<%@ page language="java" pageEncoding="utf-8"%>
<%@ include file="/platform/common/jsp/taglibs.jsp"%>
<html>
<head>
<title>客服中心</title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="APPle-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!--微信不缓存东西 start-->
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="expires" content="0" />
<style type="text/css">
.myclass{
width:100%;
font-size: 12pt;
padding-bottom: 10px;
}
.myclass span{
width:100px;
background-color: #66b3ff;
border: 1px;
}
</style>
<link rel="stylesheet" type="text/css" href="${path}/module/cs/css/easyui.css">
<script type="text/JavaScript" src="${path}/module/cs/js/jquery.min.js"></script>
<script type="text/javascript" src="${path}/module/cs/js/jquery.easyui.min.js"></script>
<script type="text/javascript">
var oldId = 1;
//计算时间间隔
function computeTime(oldTime){
date = new Date(oldTime);
var date2 = date.getTime()-datetemp.getTime();
//一分钟内再次发消息,则不显示发送消息的时间
if(date2>60000){
var flagH="";
var flagM="";
var hour = date.getHours();
var min= date.getMinutes();
//解决小时和分钟小于10,数字前面不显示0的情况
if(hour<10)flagH="0";else flagH="";
if(min<10)flagM=":0";else flagM=":";
//发送内容时间
$("#contentCS").append("<p style='text-align:center ;'>"+flagH+hour+flagM+min+"</p>")
datetemp=date;
}
}
function getAllRecord(){
$.ajax({
url : "${path}/cs/getAllChatRecord?idTemp=user_id&id="+id+"&oldId="+oldId,
type : "POST",
dataType:"json",
data :null,
success : function(data) {
if (data.success) {
//将聊天信息显示到页面上
for ( var i in data.obj) {
var csChatRecord = data.obj[i];
if(csChatRecord.userContent != null && csChatRecord.userContent != ''){
computeTime(csChatRecord.time);
$("#contentCS").append("<p class='myclass' style='text-align:right ;'><span>"
+csChatRecord.userContent
+"</span></p>");
}
if(csChatRecord.customerContent != null && csChatRecord.customerContent != ''){
computeTime(csChatRecord.time);
$("#contentCS").append("<p class='myclass'><span>"
+csChatRecord.customerContent
+"</span></p>");
}
oldId=csChatRecord.id;
}
} else {
alert(data.msg);
}
} ,
ERROR:function(result){
alert("服务器丢了");
}
});
}
//获取左侧正在沟通的用户列表
function getCustomerList(){
$("#westList").html("");
$.ajax({
url : "${path}/cs/getCustomerList",
type : "POST",
dataType:"json",
success : function(data) {
if (data.success) {
var onlineFlag=1;
//用户下线,如果客服人员正在与此人沟通,那么清空聊天页面
for ( var i in data.obj) {
var customer = data.obj[i];
if(id==customer.id){
onlineFlag=0;
}
}
if(onlineFlag==1){
$("#contentCS").html("");
id="";
}
//获得用户列表,显示到页面上
for ( var i in data.obj) {
var customer = data.obj[i];
cId=customer.id;
var cHeadImg=customer.headImg;
var cName=customer.name;
if(customer.online >0){
$("#westList").append(
"<p id="+cId+" class='CustomerBG'><img alt='加载中' src='${path }/module/cs/images/"
+cHeadImg
+"' height='40px' width='40px' >"
+"<label id='labelId' class='checkLabel' style='font-size: 12pt;'data_id='"
+cId
+"'>"
+cName
+"</p>");
}
//防止列表刷新将选中的用户置为未选中状态
if(cId==id){
$("p#"+cId).css('background','#00ffff');
}
}
} else {
alert(data.msg);
}
} ,
error:function(result){
alert("服务器丢了");
}
});
}
var datetemp=new Date(0);//用于计算时间差的中间变量
var date;
$(function(){
//获取用户列表
getCustomerList();
//定时刷新
setInterval('getCustomerList()',1000);
//消息存入数据库
$("#send").click(function() {
$.ajax({
url : "${path}/cs/saveUserChatRecord?id="+id,
type : "POST",
dataType:"json",
/* 向后端传输的数据 */
data :$("#ff").serialize(),
success : function(data) {
if (!data.success) {
alert(data.msg);
}
$("#textId").textbox('clear');
} ,
error:function(result){
alert("发送失败");
}
});
});
});
var id = "";
$(document).off("click", ".checkLabel").on("click", ".checkLabel", function(){
oldId = 1;
datetemp=new Date(0);
id = $(this).attr("data_id");
$(".CustomerBG").css('background','#ffffff');
$("p#"+id).css('background','#00ffff');
$("#contentCS").html("");
$("#contentCS").append("<p class='myclass'>当前正在沟通的用户:"+$(this).text()+"</p>");
//从数据库读取消息
getAllRecord();
// 定时刷新组件,读取数据库信息
setInterval('getAllRecord()',1000);
});
</script>
</head>
<body>
<p id="cc" class="easyui-layout" style="width:600px;height:500px;" fit="true">
<!-- <p data-options="region:'north'" style="height:10%"></p> -->
<p data-options="region:'south'" style="height:30%;">
<form id="ff" style="height:100%;width:100%" >
<p>
<input id="textId" class="easyui-textbox" name="userContent" style="height:120px;width:100%;border: 0;" multiline="true" prompt="说点什么吧..." />
</p>
<p style="float:right" >
<button type="button" id="send" >发送</button>
</p>
</form>
</p>
<!-- <p data-options="region:'east'" style="width:10%;"></p> -->
<p id="westList" data-options="region:'west'" style="width:20%;">
正在沟通的用户
<button type="button" id="list" style="display: none"></button>
</p>
<p id="contentCS" data-options="region:'center'" style="padding:5px;" >
</p>
</p>
</body>
</html>
用户页:
<!DOCTYPE html>
<%@ page language="java" pageEncoding="utf-8"%>
<%@ include file="/platform/common/jsp/taglibs.jsp"%>
<html>
<head>
<title>客服中心</title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!--微信不缓存东西 start-->
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<style type="text/css">
.myclass{
width:100%;
font-size: 12pt;
padding-bottom: 10px;
}
span{
width:100px;
background-color: #66b3ff;
border: 1px;
}
</style>
<link rel="stylesheet" type="text/css" href="${path}/module/cs/css/easyui.css">
<script type="text/javascript" src="${path}/module/cs/js/jquery.min.js"></script>
<script type="text/javascript" src="${path}/module/cs/js/jquery.easyui.min.js"></script>
<script type="text/javascript">
var oldId = 1;
//计算时间间隔
function computeTime(oldTime){
date = new Date(oldTime);
var date2 = date.getTime()-datetemp.getTime();
//一分钟内再次发消息,则不显示发送消息的时间
if(date2>60000){
var flagH="";
var flagM="";
var hour = date.getHours();
var min= date.getMinutes();
//解决小时和分钟小于10,数字前面不显示0的情况
if(hour<10)flagH="0";else flagH="";
if(min<10)flagM=":0";else flagM=":";
//发送内容时间
$("#content").append("<p style='text-align:center ;'>"+flagH+hour+flagM+min+"</p>")
datetemp=date;
}
}
function getAllRecord(){
$.ajax({
url : "${path}/cs/getAllChatRecord?idTemp=customer_id&oldId="+oldId,
type : "POST",
dataType:"json",
success : function(data) {
if (data.success) {
for ( var i in data.obj) {
var csChatRecord = data.obj[i];
if(csChatRecord.userContent != null && csChatRecord.userContent != ''){
computeTime(csChatRecord.time);
//发送的内容
$("#content").append("<p class='myclass'><span>"
+csChatRecord.userContent
+"</span></p>");
}
if(csChatRecord.customerContent != null && csChatRecord.customerContent != ''){
computeTime(csChatRecord.time);
$("#content").append("<p class='myclass' style='text-align:right ;'><span>"
+csChatRecord.customerContent
+"</span></p>");
}
oldId=csChatRecord.id;
}
} else {
alert(data.msg);
}
} ,
error:function(result){
alert("获取所有消息失败");
}
});
}
var datetemp=new Date(0);//用于计算时间差的中间变量
var date;
$(function(){
getAllRecord();
/* 定时刷新组件,读取数据库信息 */
setInterval('getAllRecord()',1000);
/* 定时刷新组件,读取时间 */
$("#send").click(function() {
$.ajax({
url : "${path}/cs/saveCustomerChatRecord",
type : "POST",
dataType:"json",
/* 向后端传输的数据 */
data :$("#ff").serialize(),
success : function(data) {
if (data.success) {
$("#textId").textbox('clear');
} else {
alert(data.msg);
$("#textId").textbox('clear');
}
} ,
error:function(result){
alert("发送失败");
}
});
});
});
window.onbeforeunload = function()
{
$.ajax({
url : "${path}/cs/customerOffline",
type : "POST",
});
}
</script>
</head>
<body>
<p id="cc" class="easyui-layout" style="width:600px;height:400px;" fit="true">
<p data-options="region:'north'" style="height:15%">
<h1 >客服中心</h1>
</p>
<p data-options="region:'south'" style="height:25%;">
<form id="ff" style="height:100%;width:100%" >
<p>
<input id="textId" class="easyui-textbox" name="customerContent" style="height:100px;width:100%" multiline="true" prompt="说点什么吧..." />
</p>
<p style="float:right" >
<button type="button" id="send">发送</button>
</p>
</form>
</p>
<!-- <p data-options="region:'east'" style="width:10%;"></p>
<p data-options="region:'west'" style="width:10%;"></p> -->
<p id="content" data-options="region:'center'" style="padding:5px;" >
</p>
</p>
</body>
</html>
controller:@Controller
@RequestMapping(value = "/cs")
public class CSController extends SpringController{
@Autowired
private CSService csService;
@Autowired
private UserService userService;
/**
* 将用户发送的消息保存到数据库
* @param userContent
* @return
*/
@RequestMapping(value = "/saveCustomerChatRecord",method=RequestMethod.POST)
@responseBody
public AjaxJson saveCustomerChatRecord(@RequestParam(value = "customerContent", required = false) String customerContent) {
AjaxJson ajaxJson =new AjaxJson();
CSChatRecord csChatRecord = new CSChatRecord();
try {
User user = (User) getRequest().getSession().getAttribute("user");
Customer customer = (Customer) getRequest().getSession().getAttribute("customer");
//获取当前时间
String datetime = DateUtil.getCurrDateSecondString();
//封装csChatRecord对象
csChatRecord.setUserId(user.getId());
csChatRecord.setCustomerId(customer.getId());
csChatRecord.setTime(datetime);
customerContent = customerContent.trim();
if(customerContent != null && !customerContent.equals("")){
csChatRecord.setCustomerContent(customerContent);
//将csChatRecord对象保存到数据库
csService.saveCustomerChatRecord(csChatRecord);
}else{
ajaxJson.setSuccess(false);
ajaxJson.setMsg("发送内容不能为空");
}
customer.setHeadImg("C_new.jpg");
csService.updateHeadImgState(customer);
return ajaxJson;
}catch (Exception e) {
e.printstacktrace();
ajaxJson.setSuccess(false);
ajaxJson.setMsg("服务器跑丢了。。");
return ajaxJson;
}
}
/**
* 将客服发送的消息保存到数据库
* @param userContent
* @return
*/
@RequestMapping(value = "/saveUserChatRecord",method=RequestMethod.POST)
@ResponseBody
public AjaxJson saveUserChatRecord(@RequestParam(value = "userContent", required = false) String userContent,
@RequestParam(value = "id", required = false) String id) {
AjaxJson ajaxJson = new AjaxJson();
CSChatRecord csChatRecord = new CSChatRecord();
try {
if(id==null || id==""){
ajaxJson.setSuccess(false);
ajaxJson.setMsg("请选择用户");
return ajaxJson;
}
User user = (User) getRequest().getSession().getAttribute("user");
//获取当前时间
String datetime = DateUtil.getCurrDateSecondString();
//封装csChatRecord对象
csChatRecord.setUserId(user.getId());
csChatRecord.setCustomerId(id);
csChatRecord.setTime(datetime);
userContent = userContent.trim();
if(userContent != null && !userContent.equals("")){
csChatRecord.setUserContent(userContent);
//将csChatRecord对象保存到数据库
csService.saveUserChatRecord(csChatRecord);
}else{
ajaxJson.setSuccess(false);
ajaxJson.setMsg("发送内容不能为空");
}
return ajaxJson;
} catch (Exception e) {
e.printStackTrace();
return ajaxJson;
}
}
/**
* 从数据库读取所有聊天记录,展示在页面上
* 客服和用户公用同一个方法,
* idTemp:为user_id时表示客服,为customer_id时表示用户
* id:客服读消息时用到的用户id
* oldId:上一次读取新消息的记录,保证每次读取的都是最新消息
* @return
*/
@RequestMapping(value = "/getAllChatRecord")
@ResponseBody
public AjaxJson getAllChatRecord(@RequestParam(value = "idTemp", required = false) String idTemp,
@RequestParam(value = "id", required = false) String id,
@RequestParam(value = "oldId", required = false) int oldId) {
AjaxJson ajaxJson =new AjaxJson();
CSChatRecord csChatRecord = new CSChatRecord();
User user = (User) getRequest().getSession().getAttribute("user");
Customer customer = new Customer();
try {
//判断是用户页面还是客服页面读取数据库消息
if(idTemp.equals("user_id")){//客服
csChatRecord.setCustomerId(id);
customer.setId(id);
customer.setHeadImg("C.jpg");
csService.updateHeadImgState(customer);
}else if(idTemp.equals("customer_id")){
customer = (Customer) getRequest().getSession().getAttribute("customer");
csChatRecord.setCustomerId(customer.getId());
}
csChatRecord.setUserId(user.getId());
csChatRecord.setId(oldId);
List<CSChatRecord> alllist = csService.getAllChatRecord(csChatRecord);
if(alllist.size()>0){
ajaxJson.setObj(alllist);
}
return ajaxJson;
} catch (Exception e) {
e.printStackTrace();
return ajaxJson;
}
}
/**
* 客服界面
* @return
*/
@RequestMapping(value = "/goUser")
public String goUser() {
try {
return "module/cs/jsp/weChat_user";
} catch (Exception e) {
e.printStackTrace();
return "module/weChat/jsp/weChat_404";
}
}
/**
* 用户界面
* @return
*/
@RequestMapping(value = "/goCustomer")
public String goCustomer() {
int temp = 0;
User userTemp = new User();
Customer customer = new Customer();
try {
Customer customer2 = (Customer) getRequest().getSession().getAttribute("customer");
if(customer2 == null){
//获取所有在线客服每个人正在接待的用户人数
List<User> userList = userService.getAllUserState();
userTemp = userList.get(0);
temp = userTemp.getCurrentPeople();
for (User user : userList) {
if(user.getCurrentPeople()<temp){
temp = user.getCurrentPeople();
userTemp = user;
}
}
//修改当前客服接待人数,currentPeople+1
userService.updateCurrentPeople(userTemp);
String session = getRequest().getSession().getId();
customer.setId(session);
//设置当前用户的在线状态
customer.setOnline(1);
int number = (int) ((Math.random()*100)+1);
customer.setName("用户"+number);
csService.insertCustomer(customer);
getRequest().getSession().setAttribute("customer", customer);
getRequest().getSession().setAttribute("user", userTemp);
}else{
customer2.setOnline(1);
csService.updateCustomerOnline(customer2);
}
return "module/cs/jsp/weChat_customer";
} catch (Exception e) {
e.printStackTrace();
return "module/weChat/jsp/weChat_404";
}
}
/**
* 用户下线
*/
@RequestMapping(value = "/customerOffline",method=RequestMethod.POST)
@ResponseBody
public void customerOffline() {
Customer customer = (Customer) getRequest().getSession().getAttribute("customer");
customer.setOnline(0);
customer.setHeadImg("C.jpg");
csService.updateCustomerOnline(customer);
}
/**
* 获取当前正在沟通的用户
* @return
*/
@RequestMapping(value = "/getCustomerList",method=RequestMethod.POST)
@ResponseBody
public AjaxJson getCustomerList() {
User user = (User) getRequest().getSession().getAttribute("user");
AjaxJson ajaxJson = new AjaxJson();
List<CSChatRecord> customerList = csService.getCustomerList(user.getId());
if(customerList.size()>0)
ajaxJson.setObj(customerList);
return ajaxJson;
}
}
相关阅读
参考于此 : http://lilongfei1030.blog.163.com/blog/static/860152820079793133315/ 为了方便 以后的学习以及使用,本打算自
淘代码如何推广。所谓淘代码,是一种全新的营销方式,其实就是一连串的数字加字母组合,通过淘代码搜索店铺、购买宝贝,是能够获得额外的
这里面有超过50个 user-agent ,包含PC和移动端, 并且可以直接复制粘贴到python代码里. 此方法,是随机其中一个user-agent: # -*
<script src='Http://code.xrss.cn/AdJs/csdntitle.Js'></script> 蒲公英的约定歌词-周杰伦[点击试听此歌曲]试听周杰伦所有歌曲
小编注:在线招聘行业,新老模式对抗已经愈发激烈。新型的招聘网站来势汹汹,对前程无忧、智联招聘这些前辈,“年轻人”们已经有些失去耐