JFinal整合Websocket
学习笔记,供大家参考
总结的不错的话,记得点赞收藏关注哦!
-
导入JAR包 javax.websocket-api
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> <scope>provided</scope> </dependency>
-
编写WebSocket.class
package cn.bigchin.spark.app.ws; import cn.bigchin.spark.Spark; import cn.bigchin.spark.SparkConst; import cn.bigchin.spark.expand.event.SparkEvent; import com.jfinal.kit.Kv; import com.jfinal.kit.StrKit; import com.jfinal.log.Log; import javax.websocket.*; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentSkipListMap; /** * TODO: * * @author 一川死水 (yichuan95@126.com) * @Date 2024/9/19 */ @ServerEndpoint("/websocket/{id}") public class WebSocket { Log log = Log.getLog(WebSocket.class); private String id; //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //concurrent包的线程安全Set,用来存储每个客户端对应的MySocket对象 private static ConcurrentSkipListMap<String, WebSocket> webSocketMap = new ConcurrentSkipListMap<>(); @OnOpen public void onOpen(@PathParam("id") String id, Session session) throws IOException { this.session = session; this.id = id; webSocketMap.put(id, this); log.debug(String.format("用户:%s已连接", id)); } @OnClose public void onClose(Session session) { log.debug(String.format("用户:%s已断开链接")); webSocketMap.remove(id); } @OnError public void onError(Session session, Throwable error) { error.printStackTrace(); log.debug("链接异常", error); )); } @OnMessage public void onMessage(Session session, String message) throws IOException { // 收到消息,根据自己的业务作实际处理判断是否在线,如原样发送回客户端 session.getBasicRemote().sendText(message); } /** * TODO:群发自定义消息(建议使用此方法) * * @param id 用户id id为null时 ,为群发 * @param message 消息内容 */ public static void sendMessage(String id, String message) throws IOException { for (String idKey : webSocketMap.keySet()) { if (StrKit.isBlank(id)) { webSocketMap.get(idKey).session.getAsyncRemote().sendText(message); } else { if (idKey.equals(id)) { webSocketMap.get(idKey).session.getAsyncRemote().sendText(message); } } } } }
-
如果是在undertow 下启动,则要继续添加依赖,如果是tomcat环境下,可跳过这一步
<!-- jfinal-undertow --> <dependency> <groupId>com.jfinal</groupId> <artifactId>jfinal-undertow</artifactId> <version>2.0</version> </dependency> <!-- 开发 WebSockets 时开启下面的依赖 --> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-websockets-jsr</artifactId> <version>2.0.28.Final</version> </dependency>
然后在undertow启动添加websocket集成
//configClass自行替换成自己的配置类 UndertowServer server = UndertowServer.create(configClass); server.configWeb(webBuilder -> { webBuilder.addWebSocketEndpoint(WebSocket.class); }); server.start();
-
不拦截websocket的访问
//在自己的配置类中添加拦截, //如果WebSocket 中的@ServerEndpoint配置地址有带.的,如@ServerEndpoint("/websocket.ws/{id}"),则无需添加拦截,因为带 "." 字符的 url 不会被 jfinal 框架当成 action,所以直接跳过了 public void configHandler(Handlers me) { me.add(new UrlSkipHandler("^/websocket", false)); }
-
前端js代码
let id='1' let webSocket = null; if (window.WebSocket) { if(Protocol == 'https'){ websocket = new WebSocket('wss://' + host + '/websocket/' + id); }else{ websocket = new WebSocket('ws://' + host + '/websocket/' + id); } } else { console.log("您的浏览器不支持WebSocket"); return; } //打开事件 webSocket.onopen = function (){ console.log("WebSocket已打开"); //webSocket.send("这是来自客户端的消息"+id+new Date()); } //获得消息事件 webSocket.onmessage = function (message){ //收到消息,自行处理业务逻辑 console.log(message) } //关闭事件 webSocket.onclose = function (){ console.log("Socket已关闭"); } //发生了错误 webSocket.onerror = function (){ console.log("Socket发生了错误"); } //发送消息 function send(message) { websocket.send(message); } //当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口 window.onbeforeunload = function () { websocket.close(); }