comet4j
1.可做聊天室,可做推送
2.上下线、消息处理
3.客户端异常下线捕捉
在做聊天室的过程中,遇到以下几个问题:
1.退出聊天网页时,想提示其他人下线,所以关键是捕捉下线信息,可是下线情况有很多种,点击关闭网页、异常断电等,开始本来想的是客户端与服务器用ajax进行心跳检测,可是后来一想,comet本来就是长连接的机制,后来通过查资料和测试,发现addDropListener可以捕捉下线情况,只需要在里面进行相关处理即可
2.Exception in thread “CometConnectorCleaner Thread” NullPointExcaption,这个原因一般发生在我们relaoding的情况下,而restart时不会发生,也就是说我们在部署服务器时,不能relaod。(猜测原因可能是comet4j内部线程在relaod时还在运行,而我们调用的前端代码却销毁后又开启,才会导致这样)
initWebSocket:function(){
JS.Engine.start('/kjzg/conn');
var onEvent ={
start:function(cId,channelList,engine){
},
webchat:function(message) {
},
stop:function(){
// todo
}
};
JS.Engine.on(onEvent);
},
package com.webchat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.comet4j.core.CometContext;
import org.comet4j.core.CometEngine;
import org.comet4j.core.event.ConnectEvent;
import org.comet4j.core.event.DropEvent;
import org.comet4j.core.event.RevivalEvent;
import org.comet4j.core.listener.ConnectListener;
import org.comet4j.core.listener.DropListener;
import org.comet4j.core.listener.RevivalListener;
import com.common.Constants;
import net.sf.json.JSONObject;
/**
* 聊天服务器类
* @author yinboqi
*
*/
public class ChatServer implements ServletContextListener {
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); // 日期格式化
private static final String CHANNEL = "webchat";
@Override
public void contextInitialized(ServletContextEvent sce) {
// TODO Auto-generated method stub
System.out.println("初始化聊天服务程序comet4j");
CometContext cc = CometContext.getInstance();
cc.registChannel(CHANNEL);//注册应用的channel
CometEngine engine = cc.getEngine();
//用户上线监听器内部类
engine.addConnectListener(new ConnectListener() {
@Override
public boolean handleEvent(ConnectEvent arg0) {
// TODO Auto-generated method stub
System.out.println(arg0.getConn().getId()+" join-chat-----------");
return true;
}
});
//用户Drop监听器内部类
engine.addDropListener(new DropListener() {
@Override
public boolean handleEvent(DropEvent arg0) {
// TODO Auto-generated method stub
Iterator<String> it=Constants.chatRoomMap.keySet().iterator();
//遍历房间
Boolean flag=true;
while(it.hasNext() && flag){
String key=it.next();
ArrayList<String> Conns= Constants.chatRoomMap.get(key).getConns();
//遍历房间成员
for(int i=0;i<Conns.size();i++){
//找到该成员
if(Conns.get(i).equals(arg0.getConn().getId())){
Conns.remove(i);
Constants.chatRoomMap.get(key).setConns(Conns);
//发送在线人数更新命令
JSONObject mjson=new JSONObject();
mjson.put("ordernum", Constants.WEBCAHT_ONLINEUPDATE);//在线人数更新命令
mjson.put("liveId", key);
mjson.put("onlines", Constants.chatRoomMap.get(key).getConns().size());
engine.sendToAll(CHANNEL, mjson);
flag=false;//退出whille循环
break;//退出for循环
}
}
}
System.out.println(arg0.getConn().getId()+" drop-chat-----------");
return true;
}
});
//用户Revival监听器内部类
engine.addRevivalListener(new RevivalListener() {
@Override
public boolean handleEvent(RevivalEvent arg0) {
// TODO Auto-generated method stub
//复活线程
return true;
}
});
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
}
package com.webchat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.comet4j.core.CometConnection;
import org.comet4j.core.CometContext;
import org.comet4j.core.CometEngine;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.common.Constants;
import com.customer.entity.ChatRoom;
import net.sf.json.JSONObject;
/**
*主体控制类
*/
@Controller
@RequestMapping("/ctrl/chat" )
public class ChatController{
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static Logger Log = Logger.getLogger(ChatController.class);
private static final String CHANNEL = "webchat";//命令通道
@SuppressWarnings("rawtypes")
@RequestMapping("/sendMessageToAll")
@ResponseBody
//向所有人发送消息
public Map sendMessageToAll(HttpServletRequest request,HttpServletResponse response){
System.out.println("sendMessageToAll");
Map map = new HashMap();
JSONObject mjson=new JSONObject();
//当前直播间liveid
String liveId=request.getParameter("liveId");
//当前连接id
String cid=request.getParameter("cid");
//消息正文
String content=request.getParameter("content");
//用户昵称
String nickname=request.getParameter("nickname");
String sendDate=sf.format(new Date());
mjson.put("content", content);
mjson.put("date", sendDate);
mjson.put("nickname", nickname);
//获得comet4j实例
CometContext cc = CometContext.getInstance();
CometEngine engine = cc.getEngine();
//获取当前所有连接用户
List<CometConnection> conns=engine.getConnections();
for(CometConnection conn : conns){
//给自己推送
if(conn.getId().equals(cid)){
mjson.put("isSelf", 1);
engine.sendTo(liveId, conn, mjson.toString());
mjson.remove("isSelf");
//当前直播间其他人推送
}else{
engine.sendTo(liveId, conn, mjson.toString());
}
}
return map;
}
@SuppressWarnings("rawtypes")
@RequestMapping("/sendOrderToAll")
@ResponseBody
//向所有人推送命令
public Map sendOrderToAll(HttpServletRequest request,HttpServletResponse response){
System.out.println("sendOrderToAll");
Map map = new HashMap();
JSONObject mjson=new JSONObject();
//命令编码
String ordernum=request.getParameter("ordernum");
//直播间id
String liveId=request.getParameter("liveId");
mjson.put("ordernum", ordernum);
mjson.put("liveId", liveId);
//获得comet4j实例
CometContext cc = CometContext.getInstance();
CometEngine engine = cc.getEngine();
//向所有用户推送命令
engine.sendToAll(CHANNEL, mjson);
return map;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@RequestMapping("/registChatRoom")
@ResponseBody
//注册当前直播间聊天室
public Map registChatRoom(HttpServletRequest request,HttpServletResponse response){
System.out.println("registChatRoom");
Map map = new HashMap();
//当前直播间liveid
String liveId=request.getParameter("liveId");
//获得comet4j实例
CometContext cc = CometContext.getInstance();
CometEngine engine = cc.getEngine();
//封装命令体
JSONObject mjson=new JSONObject();
mjson.put("ordernum", Constants.WEBCAHT_OPEN);//开启聊天室命令
mjson.put("liveId", liveId);
try {
//判断此聊天室是否已经注册
for(String channel : cc.getAppModules()){
if(channel.equals(liveId)){
//发送开启聊天室命令
engine.sendToAll(CHANNEL, mjson);
map.put("Ret", 1);
map.put("Msg", "聊天室已注册,开启成功!");
map.put("Data", true);
//聊天状态开启
Constants.chatRoomMap.get(liveId).setStatus(1);
return map;
}
}
//直播间id号注册聊天室channel
cc.registChannel(liveId);
//发送开启聊天室命令
engine.sendToAll(CHANNEL, mjson);
} catch (Exception e) {
// TODO: handle exception
map.put("Ret", 0);
map.put("Msg", e.getMessage());
map.put("Data", false);
return map;
}
map.put("Ret", 1);
map.put("Msg", "聊天室注册成功,开启成功!");
map.put("Data", true);
//聊天状态开启
Constants.chatRoomMap.get(liveId).setStatus(1);
return map;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@RequestMapping("/closeChatRoom")
@ResponseBody
//关闭当前直播间聊天室
public Map closeChatRoom(HttpServletRequest request,HttpServletResponse response){
System.out.println("closeChatRoom");
Map map = new HashMap();
//当前直播间liveid
String liveId=request.getParameter("liveId");
//获得comet4j实例
CometContext cc = CometContext.getInstance();
CometEngine engine = cc.getEngine();
//封装命令体
JSONObject mjson=new JSONObject();
mjson.put("ordernum", Constants.WEBCAHT_CLOSE);//关闭聊天室命令
mjson.put("liveId", liveId);
try {
//发送关闭聊天室命令
engine.sendToAll(CHANNEL, mjson);
} catch (Exception e) {
// TODO: handle exception
map.put("Ret", 0);
map.put("Msg", e.getMessage());
map.put("Data", false);
return map;
}
map.put("Ret", 1);
map.put("Msg", "聊天室已关闭!");
map.put("Data", true);
//聊天状态关闭
Constants.chatRoomMap.get(liveId).setStatus(0);
return map;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@RequestMapping("/initChatRoom")
@ResponseBody
//初始化直播间聊天室
public Map initChatRoom(HttpServletRequest request,HttpServletResponse response){
System.out.println("initChatRoom");
Map map = new HashMap();
//当前直播间liveid
String liveId=request.getParameter("liveId");
//当前连接id
String cid=request.getParameter("cid");
//获得comet4j实例
CometContext cc = CometContext.getInstance();
CometEngine engine = cc.getEngine();
try {
//判断聊天室是否存在
if(Constants.chatRoomMap.containsKey(liveId)){
//判断聊天功能是否在进来之前已经开启
if(Constants.chatRoomMap.get(liveId).getStatus() ==1){
//封装命令体
JSONObject mjson=new JSONObject();
mjson.put("ordernum", Constants.WEBCAHT_OPEN);//开启聊天室命令
mjson.put("liveId", liveId);
//发送开启聊天功能命令
engine.sendTo(CHANNEL, engine.getConnection(cid), mjson);
}
}else{
//第一个人进入 增加聊天室记录
ChatRoom chatRoom=new ChatRoom();
chatRoom.setConns(new ArrayList());
chatRoom.setStatus(0);
Constants.chatRoomMap.put(liveId, chatRoom);
}
} catch (Exception e) {
// TODO: handle exception
map.put("Ret", 0);
map.put("Msg", e.getMessage());
map.put("Data", false);
return map;
}
//人数+1
ArrayList<String> Conns=Constants.chatRoomMap.get(liveId).getConns();
Conns.add(cid);
Constants.chatRoomMap.get(liveId).setConns(Conns);
//发送在线人数更新命令
JSONObject mpjson=new JSONObject();
mpjson.put("ordernum", Constants.WEBCAHT_ONLINEUPDATE);//在线人数更新命令
mpjson.put("liveId", liveId);
mpjson.put("onlines", Constants.chatRoomMap.get(liveId).getConns().size());
engine.sendToAll(CHANNEL, mpjson);
map.put("Ret", 1);
map.put("Msg", "聊天室初始化成功!");
map.put("Data", true);
return map;
}
}