Web后台向前台推送消息(comet4j的使用)

一、简介:

        Comet4J(Comet for Java)是一个纯粹基于AJAX(XMLHTTPRequest)的服务器推送框架,消息以JSON方式传递,具备长轮询、长连接、自动选择三种工作模式。它是一个微型的即时推送框架(类似于goeasy),它分为服务端与客户端两部分,你只要将服务器端(JAR文件,目前仅支持Tomcat6、7)放入WEB-INF\lib,客户端(JavaScript文件)引入到页面,那么你的应用就具备了向客户端推送信息的能力,而你仅需要在服务器端调用Comet4J所提供发送方法,信息就会被主动的推送到客户的浏览器上。

二、使用前准备工作:

1. 修改tomcat配置文件conf/server.xml
    修改之前为:
        
    修改之后为:

        

2. 引入jar文件:

项目中引入comet4j-tomcat7.jar和comen4j.js(下载地址:)https://download.csdn.net/download/dai_haijiao/9985319)。

目前网上只流传有comet4j-tomcat7.jar和comet4j-tomcat6.jar两个版本,先说明一下:

若项目tomcat容器用的是tomcat7,则引用comet4j-tomcat7.jar,

若用的是tomcat6则引用comet4j-tomcat6.jar

3. 修改web.xml配置文件

        
		Comet4JListener
		org.comet4j.core.CometAppListener
	
	
		ListenerClass
		com.abc.tools.comet4j.CometUtil
	
	
		ClientEntrance
		CometServlet
		org.comet4j.core.CometServlet
	
	
		CometServlet
		/conn
	

4. 创建推送工具类

    a. Comet.java

package com.abc.tools.comet4j;

public class Comet {

	/**
	 * 人像布控告警
	 */
	public static final String DISPATCHE_ALARM = "100001";

	/**
	 * 设备告警
	 */
	public static final String DEVICE_ALARM = "100002";

	/**
	 * 被迫下线
	 */
	public static final String FORCED_LOGOUT = "-1";

	private String userId = "";

	private String msgStatus = "";

	private Object msgData = new Object();

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getMsgStatus() {
		return msgStatus;
	}

	public void setMsgStatus(String msgStatus) {
		this.msgStatus = msgStatus;
	}

	public Object getMsgData() {
		return msgData;
	}

	public void setMsgData(Object msgData) {
		this.msgData = msgData;
	}

}

    b.Constant.java

package com.abc.tools.comet4j;

public class Constant {

	public static long EXPIRE_AFTER_ONE_HOUR = 30; // cache过期时间

	public static String CHANNEL_MSGSTATUS = "msgStatus";

	public static String CHANNEL_MSG_DATA = "msgData";
}

    c. Cache.java

package com.abc.tools.comet4j;

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 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;
	}

}

    d. CacheManager.java

package com.abc.tools.comet4j;

import java.util.Date;
import java.util.HashMap;

public class CacheManager {

	@SuppressWarnings("rawtypes")
	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
	 */
	@SuppressWarnings("unchecked")
	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;
		}
	}
}

e. CometUtil.java

package com.abc.tools.comet4j;

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;

public class CometUtil extends ConnectListener implements ServletContextListener {
	/**
	 * 初始化上下文
	 */
	public void contextInitialized(ServletContextEvent arg0) {
		// CometContext : Comet4J上下文,负责初始化配置、引擎对象、连接器对象、消息缓存等。
		CometContext cc = CometContext.getInstance();
		// 注册频道,即标识哪些字段可用当成频道,用来作为向前台传送数据的“通道”
		cc.registChannel(Constant.CHANNEL_MSGSTATUS);
		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("userId");// userId是当前登录用户的id,用户登录成功后存于session中
		if (null == userId) {
			return false;
		}
		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_MSGSTATUS, comet.getMsgStatus());
			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 {
			Cache cache = CacheManager.getContent(comet.getUserId());
			if (null == cache) {
				return;
			}
			ConnectEvent connEvent = (ConnectEvent) cache.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_MSGSTATUS, engine.getConnection(connId), comet.getMsgStatus());
			engine.sendTo(Constant.CHANNEL_MSG_DATA, engine.getConnection(connId), comet.getMsgData());
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}

三、后台进行推送实例

用法1(进行消息推送):

后台代码

package com.abc.controller.univiewinterface;

import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.abc.entity.DeviceAlarm;
import com.abc.entity.DispatcheAlarm;
import com.abc.entity.Result;
import com.abc.service.DeviceAlarmService;
import com.abc.service.DispatcheAlarmService;
import com.abc.tools.comet4j.Comet;
import com.abc.tools.comet4j.CometUtil;

import net.sf.json.JSONObject;
 
/**
 * 告警控制层
 * 
 * @author DaiHaijiao
 *
 */
@Controller
@RequestMapping("/alarm/*")
public class AlarmController {

	@Autowired
	private DeviceAlarmService deviceAlarmService;

	@Autowired
	private DispatcheAlarmService dispatcheAlarmService;

	private static Map map = null;

	private static CometUtil cometUtil = null;

	/**
	 * 设备告警
	 * 
	 * @param param
	 */
	@SuppressWarnings("unlikely-arg-type")
	@RequestMapping(value = "common.do", method = RequestMethod.POST, consumes = "application/json")
	public @ResponseBody Result commonAlarm(@RequestBody String param) {
		JSONObject json = JSONObject.fromObject(param);
		// 保存设备告警到本地数据库
		DeviceAlarm deviceAlarm = new DeviceAlarm();
		String alarmContet = json.getString("contet");
		deviceAlarm.setContent(alarmContet);// 告警内容
		String alarmTime = json.getString("time");
		deviceAlarm.setTime(alarmTime);// 告警时间
		deviceAlarm = deviceAlarmService.add(deviceAlarm);
		// 实例化消息推送类
		if (cometUtil == null) {
			cometUtil = new CometUtil();
		}
		// 进行推送消息设置
		map.put("id", deviceAlarm.getId() + "");
		map.put("msgStatus", Comet.DEVICE_ALARM);
		map.put("content", alarmContet);
		map.put("time", alarmTime);
		// 推送消息到所有用户
		Comet comet = new Comet();
		comet.setMsgStatus(Comet.DEVICE_ALARM);
		comet.setMsgData(map);
		cometUtil.pushToAll(comet);
		return Result.genSuccess();
	}

	/**
	 * 布控告警
	 * 
	 * @param param
	 */
	@SuppressWarnings("unlikely-arg-type")
	@RequestMapping(value = "faceSurveillance.do", method = RequestMethod.POST, consumes = "application/json")
	public @ResponseBody Result faceSurveillanceAlarm(@RequestBody String param) {
		JSONObject json = JSONObject.fromObject(param);
		// 保存布控告警到本地数据库
		DispatcheAlarm dispatcheAlarm = new DispatcheAlarm();
		String alarmTime = json.getString("time");// 告警时间
		String alarmContet = json.getString("contet");// 告警内容
		String userId = json.getString("userId");// 要推送的用户
		dispatcheAlarm.setContent(alarmContet);
		dispatcheAlarm.setTime(alarmTime);
		dispatcheAlarm = dispatcheAlarmService.add(dispatcheAlarm);
		// 实例化消息推送类
		if (cometUtil == null) {
			cometUtil = new CometUtil();
		}
		// 进行推送消息设置
		map = new HashMap();
		map.put("id", dispatcheAlarm.getId() + "");
		map.put("msgStatus", Comet.DISPATCHE_ALARM);
		map.put("content", alarmContet);
		map.put("time", alarmTime);
		// 推送消息到指定用户
		Comet comet = new Comet();
		comet.setUserId(userId);
		comet.setMsgStatus(Comet.DISPATCHE_ALARM);
		comet.setMsgData(map);
		cometUtil.pushTo(comet);
		return Result.genSuccess();
	}

}

页面接收消息       

     接收前准备:页面引入

    

    在页面初始化js里增加消息接收相关代码,效果如下:

    $(function() {
		//...
		//...Something...
		//...

		// 建立连接,conn 即web.xml中 CometServlet的
		JS.Engine.start('../../conn');//根据自己项目情况进行修改
		// 监听后台某个频道
		JS.Engine.on({
			// 对应服务端 “频道1” 的值 msgStatus
			msgStatus : function(msgStatus) {
                              
			},
			// 对应服务端 “频道2” 的值 msgData
			msgData : function(msgData) {
				if (msgData.msgStatus == "100001") {//布控告警
					var id = msgData.id;
					var content = msgData.content;
					var time = msgData.time;
					//...值已经拿到
					//...To do something
					//...
				} else if (msgData.msgStatus == "100002") {//设备告警
					var id = msgData.id;
					var content = msgData.content;
					var time = msgData.time;
					//...值已经拿到
					//...To do something
					//...
				}
			},
		});

		//...
		//...Something...
		//...
	})

用法2(实现同一个账号只能在一个地方登陆):

    后台代码

        /**
	 * 用户登录
	 *
	 * @param username
	 * @param password
	 * @return Result
	 */
	@RequestMapping(value = "login.do")
	public @ResponseBody Result login(String username, HttpSession session, String password) {
		try {
			//用户登录
			Subject subject = SecurityUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);
			token.setRememberMe(true);
			subject.login(token);
			Object userId = (User) subject.getPrincipal().getId();

			CometUtil cometUtil = new CometUtil();// 实例化消息推送类
			// set值
			Comet comet = new Comet();
			comet.setUserId(userId + "");
			comet.setMsgStatus(Comet.FORCED_LOGOUT);
			// (个推)推送消息到频道1
			cometUtil.pushTo(comet);

			session.setAttribute("userId", userId);//登录成功后session中放入userId(个推用)
			return Result.genSuccess();
		} catch (Exception e) {
			e.printStackTrace();
			return Result.genResult(Result.USER_PASSWORD_WRONG);
		}
	}

页面代码(页面除了需要引用comet4j.js还有引入jquery.cookie.js)

增加cookie是为了避免用户收到"您的账号在另一地点登录,您已被迫下线!"提示以后直接刷新页面!

        $(function() {
		var loginStatus = $.cookie("main_loginStatus");//登录状态
		if (typeof (loginStatus) == "undefined") {
			$.cookie("main_loginStatus", false);//false:用户不掉线标识
		} else if (loginStatus == true || loginStatus == "true") {
			$.cookie("main_loginStatus", null);//删除登录状态cookie
			window.location.href = "../../logout";//请求登出方法
			return false;
		}

		// 建立连接,conn 即web.xml中 CometServlet的
		JS.Engine.start('../../conn');
		// 监听后台某个频道
		JS.Engine.on({
			// 对应服务端 “频道1” 的值 msgStatus
			msgStatus : function(msgStatus) {
				if (msgStatus == "-1") {
					$.cookie("main_loginStatus", true);//true:让用户自动掉线
					
					//给用户提示(然后不管用户点击的是确定还是取消,都让他自动退出)
					if (confirm("您的账号在另一地点登录,您已被迫下线!")) {
						$.cookie("main_loginStatus", null);//删除登录状态cookie
						window.location.href = "../../logout";//请求登出方法
					} else {
						$.cookie("main_loginStatus", null);//删除登录状态cookie
						window.location.href = "../../logout";//请求登出方法
					}
				}
			},
			// 对应服务端 “频道2” 的值 msgData
			msgData : function(msgData) {
				 
			},
		});
	})

用法3(自行去研究...)

四、使用中发现

1. 项目中引入comet4j-tomcat7.jar,且tomcat为8.0.X时,使用一切正常,“F12”查看控制台的“Network”,会发现“conn?cmd=conn&cv=0.0.2&ram=0.7725908122133494”访问正常,点击进去,控制台显示:

<{data:{channel:["msgStatus","msgData"],ws:"stream",timeout:60000,cld:"08be33b1-c409-4177-ba79-74e551379923"},channel:"",time:"1527580183535}">

2. 项目中引入comet4j-tomcat7.jar,且tomcat为8.5.X时,eclipse控制台会报错,信息如下:

五月 29, 2018 4:14:31 下午 org.apache.catalina.core.StandardHostValve invoke
严重: Exception Processing /conn
java.lang.NoClassDefFoundError: org/apache/catalina/comet/CometProcessor
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2277)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:811)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1254)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	at org.apache.catalina.core.StandardWrapper.servletSecurityAnnotationScan(StandardWrapper.java:1128)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.catalina.comet.CometProcessor
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	... 23 more

五月 29, 2018 4:16:27 下午 org.apache.catalina.core.StandardHostValve invoke
严重: Exception Processing /conn
java.lang.NoClassDefFoundError: org/apache/catalina/comet/CometProcessor
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(Unknown Source)
	at java.security.SecureClassLoader.defineClass(Unknown Source)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2277)
	at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:811)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1254)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	at org.apache.catalina.core.StandardWrapper.servletSecurityAnnotationScan(StandardWrapper.java:1128)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.catalina.comet.CometProcessor
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	... 23 more

“F12”查看控制台的“Network”,会发现“conn?cmd=conn&cv=0.0.2&ram=0.7725908122133494”有“500”错误,点击进去,控制台显示如同eclipse控制台所报错误信息:

HTTP Status 500 – Internal Server Error

Type Exception Report

Message org/apache/catalina/comet/CometProcessor

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

java.lang.NoClassDefFoundError: org/apache/catalina/comet/CometProcessor
	java.lang.ClassLoader.defineClass1(Native Method)
	java.lang.ClassLoader.defineClass(Unknown Source)
	java.security.SecureClassLoader.defineClass(Unknown Source)
	org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2277)
	org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:811)
	org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1254)
	org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
	org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	java.lang.Thread.run(Unknown Source)
Root Cause

java.lang.ClassNotFoundException: org.apache.catalina.comet.CometProcessor
	org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285)
	org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	java.lang.ClassLoader.defineClass1(Native Method)
	java.lang.ClassLoader.defineClass(Unknown Source)
	java.security.SecureClassLoader.defineClass(Unknown Source)
	org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2277)
	org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:811)
	org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1254)
	org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
	org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	java.lang.Thread.run(Unknown Source)
Note The full stack trace of the root cause is available in the server logs.

综上,总结出:tomcat8.0.X版本是可以结合comet4j-tomcat7.jar进行使用的。

你可能感兴趣的:(Java,Web,Comet4j,Web推送,推送,Comet4j)