问题: JAVA项目消息实时推送的问题
解决方案:
1、 首先,开始想到的是Ajax定时轮询数据库。但是项目需求是后台有新消息的时候才进行消息推送。如果采用Ajax轮询的话效率上会不尽如人意。
2、后来想到使用WebSocket,但是websocket是广播机制,貌似不能实现点对点的消息推送。最主要的是websocket需要jdk1.8以上版本。
3、最终采用Comet4j技术模拟实现的消息点对点的实时推送,由服务器端主动向客户端推送消息。主要原理是前端页面与服务端通过频道的概念建立通信机制,客户端监听服务器端推送的消息。
具体步骤:
1、环境准备:comet4j.js,tomcat 修改server.xml中:
<Connector URIEncoding="UTF-8" port="8888" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
redirectPort="8443" />
其中的protocol是重点啊。
2、前端页面引入comet4j.js
主要前端代码:
JS.Engine.on({
channelE : cometdCallback
});
JS.Engine.start('conn')
//该方法实际上是回调函数,text为后台推送到前端的内容,其中text可以为list
function cometdCallback(text){
}
3、服务端代码
建立Servlet,继承ConnectListener,实现ServletContextListener
public void contextInitialized(ServletContextEvent arg0) {
CometContext.getInstance().registChannel(“channelE ”);
//添加监听器
CometContext.getInstance().getEngine().addConnectListener(this);
}
public boolean handleEvent(ConnectEvent connEvent) {
final CometConnection conn = connEvent.getConn();
final String connId = conn.getId();
final String userId=conn.getRequest().getSession().getAttribute("user").toString();
/*模拟业务逻辑*/
Timer timer = new Timer(true);
TimerTask task = new TimerTask() {
@Override
public void run() {
CometEngine engine = CometContext.getInstance().getEngine();
if (CacheManager.getContent(connId).isExpired()) {
//doCache(conn);
}
//推送到指定的客户端
try {
engine.sendTo(“channelE ”, engine.getConnection(connId), getTanpingByTel(userId));
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
timer.schedule(task, 1000, (1000 * 5));
return true;
}
注意: 后台向前台每5s推送一次,模拟消息实时推送。
4、配置web.xml中的Servlet
<listener>
<listener-class>org.comet4j.core.CometAppListener</listener-class>
</listener>
<listener>
<listener-class>com.crm.txlgl.action.ServletE</listener-class>
</listener>
<servlet>
<servlet-name>CometServlet</servlet-name>
<servlet-class>org.comet4j.core.CometServlet</servlet-class>
</servlet>