java使用comet4j即時聊天--客戶端消息推送

1.準備工作:

1、下載comet4j.js

2、下載comet4j-tomcat7.jar  這個現在只支持tomcat6和7兩個版本  一定要對應上了,我這邊測試的  在tomcat8下面是用comet4j-tomcat7.jar這個jar文件也是可以推送的

2.maven配置

因爲comet4j-tomcat6.jar這個jar文件在maven遠程倉庫中不存在,所以需要將jar包放到lib下面,但是maven打包的時候會找不到這個jar文件  所以在pom.xml中加入下面代碼即可

<dependency> 
            <groupId>comet4j-tomcat7</groupId> 
            <artifactId>test</artifactId> 
            <version>1.0</version> 
            <scope>system</scope> 
            <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/comet4j-tomcat7.jar</systemPath>
</dependency>

3.修改tomcat配置文件conf/server.xml

修改之前爲:

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

修改之後爲:

<Connector connectionTimeout="20000" port="8080"  protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443" URIEncoding="UTF-8"/>

4.修改web.xml配置

<listener>
        <description>Comet4J容器偵聽</description>
        <listener-class>org.comet4j.core.CometAppListener</listener-class>
    </listener>
    
    <listener>
        <description>監聽我們自己的推送類</description>
        <listener-class>com.util.CometUtil</listener-class>
    </listener>
    <servlet>
        <description>客戶端訪問入口</description>
        <servlet-name>CometServlet</servlet-name>
        <servlet-class>org.comet4j.core.CometServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CometServlet</servlet-name>
        <url-pattern>/conn</url-pattern>
    </servlet-mapping>

5.java後端推送工具類

CometUtil.java

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.comet4j.core.CometConnection;
import org.comet4j.core.CometContext;
import org.comet4j.core.CometEngine;
import org.comet4j.core.event.ConnectEvent;
import org.comet4j.core.listener.ConnectListener;

import com.Comet;

public class CometUtil extends ConnectListener implements ServletContextListener {
     /**
      * 初始化上下文
      */
     public void contextInitialized(ServletContextEvent arg0) {
             // CometContext : Comet4J上下文,負責初始化配置、引擎對象、連接器對象、消息緩存等。
             CometContext cc = CometContext.getInstance();
             // 註冊頻道,即標識哪些字段可用當成頻道,用來作爲向前臺傳送數據的“通道”
             cc.registChannel(Constant.CHANNEL_MSGCOUNT);
             cc.registChannel(Constant.CHANNEL_MSG_DATA);
             //添加監聽器  
             CometEngine engine = CometContext.getInstance().getEngine();  
             engine.addConnectListener(this); 
     }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // TODO Auto-generated method stub
    }
    @Override
    public boolean handleEvent(ConnectEvent connEvent){
        // TODO Auto-generated method stub
        final CometConnection conn = connEvent.getConn();
           Object userId = conn.getRequest().getSession().getAttribute("currentUserId");
        CacheManager.putContent(userId.toString(), connEvent);
        return true;
    }
    private void doCache(final CometConnection conn,String userId) {  
        if (userId != null) {  
            CacheManager.putContent(conn.getId(), String.valueOf(userId), Constant.EXPIRE_AFTER_ONE_HOUR);  
        }  
    }
    /**
     * 推送給所有的客戶端
     * @param comet
     */
    public void pushToAll(Comet comet){
        try {
            CometEngine engine = CometContext.getInstance().getEngine();
               //推送到所有客戶端  
               engine.sendToAll(Constant.CHANNEL_MSGCOUNT,comet.getMsgCount());
               engine.sendToAll(Constant.CHANNEL_MSG_DATA,comet.getMsgData());
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(e.getMessage());
        }
           
    }
    /**
     * 推送給指定客戶端
     * @param comet
     */
    public void pushTo(Comet comet){
        try {
            ConnectEvent connEvent = (ConnectEvent) CacheManager.getContent(comet.getUserId()).getValue();
            final CometConnection conn = connEvent.getConn();
               //建立連接和用戶的關係  
               doCache(conn,comet.getUserId());
               final String connId = conn.getId(); 
               CometEngine engine = CometContext.getInstance().getEngine();
               if (CacheManager.getContent(connId).isExpired()) {  
                   doCache(conn,comet.getUserId());  
               }
               //推送到指定的客戶端  
              engine.sendTo(Constant.CHANNEL_MSGCOUNT, engine.getConnection(connId), comet.getMsgCount());
              engine.sendTo(Constant.CHANNEL_MSG_DATA, engine.getConnection(connId), comet.getMsgData());
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(e.getMessage());
        }
    }

 

Constant.java

public class Constant {
    public static long EXPIRE_AFTER_ONE_HOUR = 30; //cache過期時間
    public static String CHANNEL_MSGCOUNT= "msgCount";
    public static String CHANNEL_MSG_DATA= "msgData";
}

Comet.java

import Java.util.List;
import java.util.Map;

public class Comet {
    private String userId;
    private String msgCount;
    private List<Map> msgData;
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getMsgCount() {
        return msgCount;
    }
    public void setMsgCount(String msgCount) {
        this.msgCount = msgCount;
    }
    public List<Map> getMsgData() {
        return msgData;
    }
    public void setMsgData(List<Map> msgData) {
        this.msgData = msgData;
    }
}

 

Cache.java

public class Cache {
     private String key; 
     private Object value; 
     private long timeOut; 
     private boolean expired; 
     public Cache() { 
             super(); 
     } 
              
     public Cache(String key, String value, long timeOut, boolean expired) { 
             this.key = key; 
             this.value = value; 
             this.timeOut = timeOut; 
             this.expired = expired; 
     } 
 
     public String getKey() { 
             return key; 
     } 
 
     public long getTimeOut() { 
             return timeOut; 
     } 
 
     public Object getValue() { 
             return value; 
     } 
 
     public void setKey(String string) { 
             key = string; 
     } 
 
     public void setTimeOut(long l) { 
             timeOut = l; 
     } 
 
     public void setValue(Object object) { 
             value = object; 
     } 
 
     public boolean isExpired() { 
             return expired; 
     } 
 
     public void setExpired(boolean b) { 
             expired = b; 
     }
}

CacheManager.java

public class CacheManager {
    private static HashMap cacheMap = new HashMap(); 
     
    /**
     * This class is singleton so private constructor is used.
     */ 
    private CacheManager() { 
            super(); 
    } 

    /**
     * returns cache item from hashmap
     * @param key
     * @return Cache
     */ 
    private synchronized static Cache getCache(String key) { 
            return (Cache)cacheMap.get(key); 
    } 

    /**
     * Looks at the hashmap if a cache item exists or not
     * @param key
     * @return Cache
     */ 
    private synchronized static boolean hasCache(String key) { 
            return cacheMap.containsKey(key); 
    } 

    /**
     * Invalidates all cache
     */ 
    public synchronized static void invalidateAll() { 
            cacheMap.clear(); 
    } 

    /**
     * Invalidates a single cache item
     * @param key
     */ 
    public synchronized static void invalidate(String key) { 
            cacheMap.remove(key); 
    } 

    /**
     * Adds new item to cache hashmap
     * @param key
     * @return Cache
     */ 
    private synchronized static void putCache(String key, Cache object) { 
       cacheMap.put(key, object); 
    } 

    /**
     * Reads a cache item's content
     * @param key
     * @return
     */ 
    public static Cache getContent(String key) { 
             if (hasCache(key)) { 
                    Cache cache = getCache(key); 
                    if (cacheExpired(cache)) { 
                            cache.setExpired(true); 
                    } 
                    return cache; 
             } else { 
                     return null; 
             } 
    } 

    /**
     * 
     * @param key
     * @param content
     * @param ttl
     */ 
    public static void putContent(String key, Object content, long ttl) { 
            Cache cache = new Cache(); 
            cache.setKey(key); 
            cache.setValue(content); 
            cache.setTimeOut(ttl + new Date().getTime()); 
            cache.setExpired(false); 
            putCache(key, cache); 
    } 
    public static void putContent(String key, Object content) { 
        Cache cache = new Cache(); 
        cache.setKey(key); 
        cache.setValue(content); 
        cache.setExpired(false); 
        putCache(key, cache); 
} 
     
    /** @modelguid {172828D6-3AB2-46C4-96E2-E72B34264031} */ 
    private static boolean cacheExpired(Cache cache){ 
            if (cache == null) { 
                    return false; 
            } 
            long milisNow = new Date().getTime(); 
            long milisExpire = cache.getTimeOut(); 
            if (milisExpire < 0) {                // Cache never expires  
                    return false; 
            } else if (milisNow >= milisExpire) { 
                    return true; 
            } else { 
                    return false; 
            } 
    }
}

6、前端jsp代碼

在前段要顯示推送的頁面引入js

​
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="ctx" value="${pageContext.request.contextPath}" />

<script type="text/JavaScript" src="${ctx }/js/comet4j.js"></script>

<script type="text/javascript">
var count = 0;
window.onload = function(){
    // 建立連接,conn 即web.xml中 CometServlet的<url-pattern>
    JS.Engine.start('${ctx}/conn');
    <%  

         //保存用戶id到session中

         session.setAttribute("currentUserId",user.getId().toString());
    %>  
    // 監聽後臺某個頻道
    JS.Engine.on(
         { 
            // 對應服務端 “頻道1” 的值 msgCount
            msgCount : function(msgCount){
                $("#msgCount").html(msgCount);
            },
            // 對應服務端 “頻道2” 的值 msgData
            msgData : function(msgData){
                $("#msgData").html(msgData);
            },
        }
    );
}
</script>

<body>

消息數量:<span id="msgCount"></span>

消息數據:<span id="msgData"></span>

</body>

​

經過以上的工作,我們就可以實現推送了 ,項目啓動後,在任何類中調用下面的代碼就可以推送給前端了,例如:

//所有客戶端推送:

Comet comet = new Comet();
comet.setMsgCount(String.valueOf(msgCount));
comet.setMsgData(resultList);

new CometUtil()..pushToAll(comet);

//精準推送給某個客戶端

Comet comet = new Comet();
comet.setUserId("1");//前端到session中的用戶id

comet.setMsgCount(String.valueOf(msgCount));
comet.setMsgData(resultList);

new CometUtil()..pushTo(comet);

 

那麼怎麼實現實時推送呢 ,我用的是spring定時任務  定時掃描需要推送的內容  然後在調用推送工具類

spring定時器配置

1、pom.xml中引入依賴

<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.3</version>
        </dependency>

2、spring.xml文件加入下面代碼

<!--     消息推送定時任務 -->
    <!-- 定時器配置 -->
    <bean id="pushMessageTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject">
            <bean class="com.util.timeTask.PushMessageTimer"/>        
        </property><!-- 指定任務類 -->
        <property name="targetMethod" value="doit"></property><!-- 指定任務方法 -->
    </bean>
    <!-- 定義時間間隔觸發器 -->
    <bean id="pushMessageTigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="pushMessageTask"></property>
        <property name="cronExpression">
            <value>*/10 * * * * ?</value><!-- 10秒執行一次 -->
        </property>
    </bean>

  <!-- 啓動定時器 -->
    <bean id="startQuertz" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="pushMessageTigger"/>  
        </list>
    </property>

3、PushMessageTimer.java

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import com.MessageMapper;
import com.Comet;
import com.util.CometUtil;

public class PushMessageTimer {
    @Autowired
    MessageMapper messageMapper;
    
    private static CometUtil cometUtil = null;
    public void doit(){
        if(cometUtil == null){
            cometUtil = new CometUtil();
        }
        List<Map> resultList = null;
        int msgCount = 0;
        try {
//            String userId = (String) request.getSession().getAttribute("currentUserId");//精準推送需要獲取前端保存到session的用戶id
            resultList = messageMapper.getUnReadMessageList(null);
            msgCount   = messageMapper.getUnReadMessageCount(null);
            //推送消息
            Comet comet = new Comet();
//            comet.setUserId(userId);
            comet.setMsgCount(String.valueOf(msgCount));
            comet.setMsgData(resultList);
            cometUtil.pushToAll(comet);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章