JavaEE(Struts2)结合websocket和quartz实现定时消息推送功能
来源:互联网 发布:sql删除重复的数据 编辑:程序博客网 时间:2024/06/01 22:05
偶尔一句:唯一让故事圆满的办法,就是由你写下结局。
昨天刘老师在上课的时候,提到了一个定时消息推送的功能:每天的特定时间给在线用户发送特定的消息。仔细一想,诶这个想法还蛮有实用性。就想着能不能在自己的项目中使用,所以抽了个课外时间来实现这个功能。由于对websocket服务端的触发机制有点不太了解,所以在实现过程中有点迷茫。在网上也没找到什么有用的资料(可能是自己使用的关键词不当吧!),于是就开始自己琢磨琢磨,最后成功了。
当然,第一步先把这些框架的jar包导入进去….
struts2中配置quartz
这里介绍一下struts2中如何配置quartz,可以参见我之前写过的文章。注意最后的监听器需要在web.xml中配置。 传送门
导入websocket的jar包,编写websocket服务器端
package ws;import javax.servlet.http.HttpSession;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.concurrent.CopyOnWriteArraySet;/** * Created by zipple on 2017/10/31. * websocket服务器 * 获取HttpSession--便能获取到当前用户 *///@ServerEndpoint(value ="/ws/getMsg",configurator=GetHttpSessionConfig.class)@ServerEndpoint("/ws/getMsg")public class WebSocketServer { private Session session; private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>(); public WebSocketServer(){ System.out.println("---------------启动webSocket服务器-----------------------"); } @OnMessage public void onMessage(Session session, String msg){ System.out.println("收到来自"+session.getId()+"的信息:"+msg); try { session.getBasicRemote().sendText("服务器收到消息:"+msg); }catch (Exception e){ e.printStackTrace(); } } @OnOpen public void onOpen(Session session, EndpointConfig config){ try { this.setSession(session); webSocketSet.add(this); //获取session的方法 // HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName()); System.out.println("当前连接数:"+webSocketSet.size()); sendToAll("用户"+session.getId()+"成功连接"+",欢迎来到易达管理系统!"); }catch (Exception e){ e.printStackTrace(); } } @OnError public void onError(Session session, Throwable throwable){ System.out.println("session id:"+session.getId()+" 连接异常. throwable"+throwable.getMessage()); webSocketSet.remove(this); } @OnClose public void onClose(Session session, CloseReason reason){ try { System.out.println("断开连接, id="+session.getId());// synchronized (sessionMap){// sessionMap.remove(session.getId());// } }catch (Exception e){ e.printStackTrace(); } } /** * 推送给所有的在线用户 * @param message 推送内容 */ public void sendToAll(String message){ for (WebSocketServer ws: webSocketSet) { try { ws.getSession().getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } public Session getSession() { return session; } public void setSession(Session session) { this.session = session; } public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() { return webSocketSet; } public static void setWebSocketSet(CopyOnWriteArraySet<WebSocketServer> webSocketSet) { WebSocketServer.webSocketSet = webSocketSet; }}
在使用struts2拦截所有请求的情况下,这样的webSocket服务器端是无法直接连接成功的。我们需要给struts2.xml配置不拦截ws请求:
<constant name="struts.action.excludePattern" value="/ws/.*,ws://.*"/> <!--过滤掉websocket请求-->
但是不知道为什么我的环境(struts2 2.3.8)中这样配置没有效果。那么我们就暴力一点,使用struts.properties文件覆盖struts.xml的constant。在src路径下再新建一个struts.properties文件。然后填写下面配置信息:
struts.action.excludePattern=/ws/.*,ws://.*
好的,这样就可以直接访问到webSocketServer服务器了。
测试websocket连接的时候发现,每次在接受前端连接请求的时候都会触发websocketServer的空构造方法。这里就是我之前不太了解的地方。以前使用websocket的时候没有考虑过他的实例化,因此直接使用了一个内部map的成员变量用来保存每次连接的session。
可是问题就来了,既然每次都会实例化websocketServer,那么这内部成员变量是怎么保存的呢(没有清空)?这一点困扰了我一段时间。有知道的同学可以私信或者留言我,不胜感激!
如果要使用quartz来定时调度,那么就必须要在quartzJob的程序中获取到webSocketServer中保存的session。所以我们肯定不能在quartzJob的程序中再new一个webSocketServer,只能另觅他途。
在quartzJob程序中获取webSocketServer保存的session
细心的同学在上面服务器端的代码中应该已经发现了:使用了static静态成员变量(线程安全)保存每一次实例化的WebSocketServer对象,在关闭连接的时候remove掉。于是我们就可以不实例化直接获取成员变量了。
下面看调度程序类:
package quartz;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import ws.WebSocketServer;import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;/** * Created by zipple on 2017/11/1. */public class WebSocketJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //每天的12点推送消息 System.out.println("启动webSocket监听"); CopyOnWriteArraySet<WebSocketServer> webSocketSet =WebSocketServer.getWebSocketSet(); if (webSocketSet.size()!=0){ for (WebSocketServer ws: webSocketSet) { try { ws.getSession().getBasicRemote().sendText("服务器每隔10s钟发送的消息"); } catch (IOException e) { e.printStackTrace(); } } }else{ System.out.println("websocket当前没有连接"); } }}
注册监听器
对应的quartz监听器别忘了:(代码很简单,复制后只需要改一下对应的job接口实现类即可)
package listener;import org.quartz.*;import org.quartz.impl.StdSchedulerFactory;import quartz.WebSocketJob;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;/** * Created by zipple on 2017/10/24. */public class WebSocketServerJobListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("实例化websocket监听器"); JobDetail jobDetail = JobBuilder.newJob(WebSocketJob.class).withIdentity("webSocketJob","group2").build(); try { Trigger trigger = TriggerBuilder .newTrigger() .withIdentity("webSocketJob", "group2") .withSchedule( CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))//更改时间 .build(); Scheduler scheduler = new StdSchedulerFactory().getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("销毁websocket监听器"); }}
web.xml别忘了注册监听器:
<listener> <listener-class> listener.WebSocketServerJobListener </listener-class> </listener>
前端连接websocket程序代码可以参见网上的代码:连接url如下
var url="ws://127.0.0.1:8080/ws/getMsg";//webSocketServer注解定义的url
- JavaEE(Struts2)结合websocket和quartz实现定时消息推送功能
- JavaEE结合quartz实现订单自动失效功能
- DWR+Quartz定时推送消息
- struts2 + websocket 实现web程序网页消息推送。
- struts2框架如何使用websocket实现web程序消息推送
- 使用Websocket实现消息推送(上)
- 使用Websocket实现消息推送(下)
- websocket 实现消息推送(转)
- websocket消息推送实现(附代码)
- 使用Websocket实现消息推送(心跳)
- resin4.0.44+websocket 实现私信功能服务端消息推送
- websocket实现android消息推送
- websocket实现android消息推送
- Spring WebSocket实现消息推送
- WebSocket实现android消息推送
- websocket实现android消息推送
- websocket实现android消息推送
- spring结合quartz实现定时
- C# 窗体程序后台线程操作窗体控件
- Java sql(1)--防止SQL注入查询
- stm8的bootloader
- iconmoon 使用说明
- webuploader简单封装
- JavaEE(Struts2)结合websocket和quartz实现定时消息推送功能
- STL---heap概述,make_heap,sort_heap,pop_heap,push_heap
- Java线程通信
- TCC 分布式事物最终一致性
- 问题 A: 统计同成绩学生人数
- 超强PCB布线设计经验谈附原理图(二)
- bash: ifconfig: command not found
- idea15搭建简单maven项目测试连接redis
- eclipse启动tomcat时不能加载项目