package com.service.core;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import java.util.Iterator;
import java.util.Map.Entry;
import net.sf.json.JSONObject;
import com.model.Data;
import com.model.JSONtype;
import com.model.SysCode;
import com.model.Type;
import com.model.UserServerPojo;
import com.tools.ServerLog;
/**
* 服务器队列
*
* @author Allen
* @date 2016年12月13日
*
*/
public class ServerThread implements Runnable {
JSONObject json;
public ServerThread(JSONObject json) {
this.json = json;
}
public ServerThread() {
this.json = new JSONObject();
}
/**
* 服务器队列
*
* @param json
* @author Allen
* @date 2016年12月13日
*/
public void execute(JSONObject json, Channel channel) {
if (Data.onlineCustomer.size() == 0) {
// 没有在线的客服
json.put("result", SysCode.admin_Offline);
json.put("note", Data.sysConfig.get("offlineNote"));
channel.writeAndFlush(new TextWebSocketFrame(json.toString()));
}
if (Data.serverQueue.size() > 0)
Data.serverQueue.add(channel);
else
regThread(channel, true);
}
/**
* 注册到队列
*
* @param flag
* = true 则考虑是否插入到服务器队列</br> flag = false 则直接发送最新队列状态index
*
* @author Allen
* @date 2016年12月15日
*/
public synchronized void regThread(Channel channel, Boolean flag) {
String channelId = findCustomer();
// 没有空闲的客服
if (channelId == null) {
int serverSize = Integer.parseInt(Data.sysConfig.get("serverQueue").toString());
if (flag && Data.serverQueue.size() < serverSize) {
json = new JSONObject();
// 有队可以排
Data.serverQueue.add(channel);
json.put("result", SysCode.queue_Start);
json.put("position", Data.serverQueue.size());
channel.writeAndFlush(new TextWebSocketFrame(json.toString()));
} else if (!flag) {
sendServerThreadPosition();
} else {
json.put("result", SysCode.queue_Max);
channel.writeAndFlush(new TextWebSocketFrame(json.toString()));
// 这里可以选择清空该用户,也可以选择不清空
// 清空则踢下线,不清空则等待前端再次尝试连接等
}
} else {
send(channel, channelId);
if (!flag) {
Data.serverQueue.remove(channel);
ServerThread.sendServerThreadPosition();
}
}
}
/**
* 将消息发送到用户与客服 并绑定双方数据关系
*
* @param channel
* @param channelId
* @author Allen
* @date 2016年12月15日
*/
private void send(Channel channel, String channelId) {
// 客服信息
UserServerPojo customerPojo = Data.onlineCustomer.get(channelId);
// 用户信息
UserServerPojo userPojo = Data.onlineUser.get(channel.id().toString());
// 将用户channel绑定到到客服
// 通知客服新用户进入
Data.onlineCustomer.get(channelId).getCustomerThread().add(channel);
JSONObject customerJson = new JSONObject();
customerJson.put("type", JSONtype.USERCOMING);
customerJson.put("user", bindPojo(userPojo));
customerPojo.getUserChannel().writeAndFlush(new TextWebSocketFrame(customerJson.toString()));
// 将客服channel绑定到用户
// 将客服信息通知给用户
Data.onlineUser.get(channel.id().toString()).setCustomerChannel(customerPojo.getUserChannel());
this.json.put("customer", bindPojo(customerPojo));
channel.writeAndFlush(new TextWebSocketFrame(this.json.toString()));
}
/**
* 找到服务人数最少的客服
*/
private String findCustomer() {
String channelId = null;
int size = Integer.parseInt(Data.sysConfig.get("customerQueue").toString());
Iterator<Entry<String, UserServerPojo>> it = Data.onlineCustomer.entrySet().iterator();
while (it.hasNext()) {
Entry<String, UserServerPojo> entry = it.next();
if (entry.getValue().getCustomerThread().size() == 0) {
channelId = entry.getKey();
break;
} else if (entry.getValue().getCustomerThread().size() < size) {
size = entry.getValue().getCustomerThread().size();
channelId = entry.getKey();
}
}
return channelId;
}
/**
* 组装pojo
*
* @param userPojo
* @return
* @author Allen
* @date 2016年12月15日
*/
private JSONObject bindPojo(UserServerPojo userPojo) {
JSONObject userJson = new JSONObject();
userJson.put("userName", userPojo.getUserName());
userJson.put("userHead", userPojo.getUserHead());
userJson.put("userId", userPojo.getUserId());
userJson.put("cId", userPojo.getUserChannel().id().toString());
return userJson;
}
/**
* 发送队列新位置消息
*
* @see sync
* @author Allen
* @date 2016年12月15日
*/
public static void sendServerThreadPosition() {
for (int i = 0; i < Data.serverQueue.size(); i++) {
JSONObject queueJson = new JSONObject();
queueJson.put("type", JSONtype.QUEUESTATUS);
queueJson.put("position", i + 1);
Data.serverQueue.get(i).writeAndFlush(new TextWebSocketFrame(queueJson.toString()));
}
}
/**
* 队列入会
*
* @author Allen
* @date 2016年12月15日
*/
private void threadJoinMeeting(int i) {
// 排队异常准备
JSONObject successJSON = new JSONObject();
successJSON.put("type", JSONtype.QUEUESUCCESS);
if (Data.serverQueue.size() == 0)
return;
if (Data.onlineCustomer.size() == 0) {
// 没有在线的客服
JSONObject json = new JSONObject();
json.put("type", JSONtype.QUEUEERROR);
json.put("result", SysCode.admin_Offline);
json.put("note", Data.sysConfig.get("offlineNote"));
Data.serverQueue.get(i).writeAndFlush(new TextWebSocketFrame(json.toString()));
} else {
regThread(Data.serverQueue.get(i), false);
}
}
@Override
public void run() {
// 队列监听系统状态有位置则进入
long t = Long.valueOf(Data.sysConfig.get("serverQueueTime").toString());
while (true) {
try {
threadJoinMeeting(0);
Thread.sleep(t);
} catch (Exception e) {
ServerLog.print(Type.ERROR, e, SysCode.sys_unknownException);
}
}
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
实现了用户与客服功能,客服服务队列,服务器排队 详见: http://blog.csdn.net/crazyzxljing0621/article/details/53690505 系统概要 1. 用户通过websocket与netty创建通讯 2. 用户链接到服务器队列中 3. 队列通过轮训机制判定netty是否有可以服务的客服 4. 如果有则将队列中的用户channel转给客服进行点对点通讯 5. 队列有自己的最大容载量 6. 每个客服可以同时服务N个用户 7. 没有空闲客服的时候用户们只能在队列中慢慢排队 8. 队列状态及实时位置由队列向队列内用户推送 9. 当有空闲位置的时候,轮训机制会将队列中首位用户放到netty中进行与客服的通讯挂钩 10. 其实对于服务器队列可以抽出来做到一个单独的项目中,用户先访问队列项目,队列项目再将用户channel发送给处理消息的netty项目
资源推荐
资源详情
资源评论
收起资源包目录
callServer.rar (55个子文件)
callServer
bin
log4j.properties 916B
com
tools
IniConf.class 2KB
ServerLog.class 2KB
model
Data.class 907B
UserServerPojo.class 3KB
JSONtype.class 841B
Type.class 681B
SysCode.class 1KB
StartMsgService.class 654B
service
core
ServerThread.class 6KB
action
Create.class 715B
Msg.class 4KB
Join.class 5KB
DbService.class 2KB
ContainerChange.class 4KB
Server$1.class 2KB
MsgExecute.class 2KB
Server$3.class 1KB
Server.class 4KB
Server$2.class 676B
WebSocketHandler.class 2KB
MsgHandler.class 3KB
SysConfig.properties 503B
.settings
org.eclipse.core.resources.prefs 157B
org.eclipse.jdt.core.prefs 598B
src
log4j.properties 916B
com
tools
ServerLog.java 2KB
IniConf.java 1KB
model
Type.java 416B
Data.java 907B
UserServerPojo.java 2KB
JSONtype.java 813B
SysCode.java 2KB
StartMsgService.java 290B
service
Server.java 4KB
core
ContainerChange.java 4KB
action
Join.java 5KB
Msg.java 4KB
Create.java 426B
ServerThread.java 6KB
DbService.java 1KB
MsgHandler.java 2KB
MsgExecute.java 2KB
WebSocketHandler.java 1KB
SysConfig.properties 503B
.project 386B
.classpath 812B
lib
ezmorph-1.0.6.jar 84KB
commons-beanutils-1.8.0.jar 226KB
commons-logging.jar 52KB
commons-lang-2.4.jar 256KB
commons-collections-3.2.jar 558KB
log4j-1.2.17.jar 478KB
json-lib-2.4-jdk15.jar 155KB
netty-all-4.1.6.Final.jar 3.37MB
共 55 条
- 1
is丶Allen
- 粉丝: 43
- 资源: 19
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 应用开发-画布技术-时钟-功能性小程序-画布时钟小程序.zip
- 一份关于navicat的大纲教程!!!!
- 一份关于maven的教程!!!!!!!!
- 关闭系统自带杀毒Windows Defender安全中心移除系统自带杀毒软件(防止软件被拦截打不开工具包)
- 基于SSM框架的局域网多人在线聊天系统
- 一份关于网络安全的大纲教程!!!!!!!
- SAPIEN PowerShell Studio 2024 v5.8.240 是一款功能强大且全面的集成开发环境(IDE)
- 计算机网络基础.zip
- 一份关于vue开发大纲的教程!!!!!!
- Xceed Ultimate Suite 24.1.25154.0957 是一款全面的 .NET 组件和控件集合
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
前往页