comet4j消息推送,先向项目中加入comet4j的jar包,注意有tomcat6和tomcat7的区分
tomcat中需要将conf/server.xml文件的
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
改成
<Connector port="8080" URIEncoding="UTF-8" connectionTimeout="20000" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443" />
comet4j.js 及comet4j-tomcat6.jar / comet4j-tomcat7.jar 下载链接
1.因为需要用到在普通的类中调用service方法,所以先放个SpringContextUtil,用来调用service方法,这里只用到了getBean(name)
package com.utils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; // 实现 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } public static Object getBean(String name) throws BeansException { try { return applicationContext.getBean(name); } catch (Exception e) { throw new RuntimeException("获取的Bean不存在!"); } } @SuppressWarnings("unchecked") public static <T> T gtBeanByName(Class<T> clazz) throws BeansException{ try { char[] cs = clazz.getSimpleName().toCharArray(); cs[0] += 32; return (T)applicationContext.getBean(String.valueOf(cs)); } catch (Exception e) { e.printStackTrace(); return null; } } public static <T> T getBean(String name, Class<T> requiredType) throws BeansException { return applicationContext.getBean(name, requiredType); } public static boolean containsBean(String name) { return applicationContext.containsBean(name); } public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { return applicationContext.isSingleton(name); } public static Class<? extends Object> getType(String name) throws NoSuchBeanDefinitionException { return applicationContext.getType(name); } public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { return applicationContext.getAliases(name); } }
2.ApplicationContextAware需要注入
在spring-mvc.xml中配置一下
<bean id="SpringContextUtil" class="com.utils.SpringContextUtil"></bean>
3.comet4j实现的java类,需要的时候自己写方法获取数据源
package com.meeting.news.controller; import java.util.Timer; import java.util.TimerTask; 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.meeting.news.model.CacheConstant; import com.meeting.news.model.CacheManager; import com.meeting.news.service.impl.NewsServiceImpl; import com.utils.SpringContextUtil; public class NewsComet4j2 extends ConnectListener implements ServletContextListener { private static final String CHANNEL_1 = "result"; @Override public void contextInitialized(ServletContextEvent arg0) { // CometContext : Comet4J上下文,负责初始化配置、引擎对象、连接器对象、消息缓存等。 CometContext context = CometContext.getInstance(); // 注册频道,即标识哪些字段可用当成频道,用来作为向前台传送数据的“通道” context.registChannel(CHANNEL_1); CometEngine engine = CometContext.getInstance().getEngine(); engine.addConnectListener(this); } @Override public void contextDestroyed(ServletContextEvent arg0) { } @Override public boolean handleEvent(ConnectEvent conEvent) { final CometConnection conn = conEvent.getConn(); doCache(conn); final String connId = conn.getId(); Timer timer = new Timer(true); TimerTask task = new TimerTask() { NewsServiceImpl newsserviceImpl = (NewsServiceImpl) SpringContextUtil.getBean("newsServiceImpl");//根据自己的项目需要写 @Override public void run() { CometEngine engine = CometContext.getInstance().getEngine(); if(CacheManager.getContent(connId).isExpired()){ doCache(conn); } Long newsCount = simulateService(conn, newsserviceImpl); if(newsCount != 0){ engine.sendTo(CHANNEL_1, engine.getConnection(connId), newsCount); } } }; timer.schedule(task, 10000, 1000*5); return false; } public void doCache(final CometConnection conn){ Object userId = conn.getRequest().getSession().getAttribute("loginUserId"); if(userId != null){ CacheManager.putContent(conn.getId(), String.valueOf(userId), CacheConstant.EXPIRE_AFTER_ONE_HOUR); } } //这是从数据库中获取未读消息的数量,自己根据项目做调整获取数据源 public Long simulateService(CometConnection conn,NewsServiceImpl newsService){ Long newsCount = newsService.selectCountUnread(new Long(conn.getRequest().getSession().getAttribute("loginUserId").toString()));//根据自己项目需要自己调整修改 if(newsCount == 0){ return 0L; } return newsCount; } }
4.在web.xml中添加listener,注意conn的配置路径,/views/center/是WebContent下页面的路径,如果不按页面路径配置会报404的错误
<!-- comet4j 消息监听 --> <listener> <listener-class>org.comet4j.core.CometAppListener</listener-class> </listener> <listener> <description>newsComet4jController</description> <listener-class>com.meeting.news.controller.NewsComet4j2</listener-class> </listener> <servlet> <display-name>cometServlet</display-name> <servlet-name>cometServlet</servlet-name> <servlet-class>org.comet4j.core.CometServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>cometServlet</servlet-name> <url-pattern>/views/center/conn</url-pattern> </servlet-mapping>
5.补充上面的Java类,Cache,CacheConstant,CacheManager
Cache类
package com.meeting.news.model; public class Cache { private String key; private Object value; private Long timeOut; private boolean expired; public Cache() { super(); } public Cache(String key, Object value, Long timeOut, boolean expired) { super(); this.key = key; this.value = value; this.timeOut = timeOut; this.expired = expired; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } public Long getTimeOut() { return timeOut; } public void setTimeOut(Long timeOut) { this.timeOut = timeOut; } public boolean isExpired() { return expired; } public void setExpired(boolean expired) { this.expired = expired; } // }
CacheConstant类
package com.meeting.news.model; public class CacheConstant { public static long EXPIRE_AFTER_ONE_HOUR = 0;//自己配置时间 }
CacheManager类
package com.meeting.news.model; import java.util.Date; import java.util.HashMap; public class CacheManager { private static HashMap cacheMap = new HashMap<>(); private CacheManager(){ super(); } private synchronized static Cache getCache(String key){ return (Cache)cacheMap.get(key); } private synchronized static boolean hasCache(String key){ return cacheMap.containsKey(key); } public synchronized static void invalidateAll(){ cacheMap.clear(); } public synchronized static void invalidate(String key){ cacheMap.remove(key); } public synchronized static void putCache(String key,Cache object){ cacheMap.put(key, object); } public static Cache getContent(String key){ if(hasCache(key)){ Cache cache = getCache(key); if(cacheExpired(cache)){ cache.setExpired(true); } return cache; }else{ return null; } } 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); } private static boolean cacheExpired(Cache cache){ if(cache == null){ return false; } long milisNow = new Date().getTime(); long milisExpire = cache.getTimeOut(); if(milisExpire < 0){ return false; }else if(milisNow >= milisExpire){ return true; }else{ return false; } } }
6.用的jsp
需引comet4j.js
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path; %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="<%=basePath %>/js/jquery1.8.3.min.js"></script> <script type="text/javascript" src="<%=basePath%>/js/comet4j.js"></script> </head> <script type="text/javascript"> function init(){ var number_1 = document.getElementById("number_1"); JS.Engine.start("conn"); JS.Engine.on( { result:function(res){ number_1.innerHTML = res; } } ) } </script> <body onload="init()"> <span id="number_1"></span> </body> </html>
7.comet4j.js 及comet4j-tomcat6.jar / comet4j-tomcat7.jar 下载链接
8.补充一下
获取消息的top是引用的,每个页面都有,所以web.xml中配置时候路径不能固定成一个,所以就配置成了
<url-pattern>*.conn</url-pattern>相应的页面代码也需要将conn改成.conn
JS.Engine.start(".conn");