最近做项目需要后端实时推送消息给前端指定用户,比较理想的方案是集成websocket。网上找了一下,不是太老了,就是比较凌乱,基本都是集成tomcat的,没有集成JFinal推荐的undertow-websockets。最后结合官网文档和其他网友经验,终于搞定,发上来供其他人参考。
【后端代码】
1、添加undertow和对应webscoket集成到pom.xml
<!-- jfinal-undertow 开发、部署一体化 web 服务器 --> <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>
2、在undertow启动添加websocket集成
public static void main(String[] args) {
UndertowServer.create(AppConfig.class)
.configWeb(builder -> {
// 配置WebSocket需使用ServerEndpoint注解
builder.addWebSocketEndpoint(WebSocket.class);
})
.start();
System.out.println("系统服务启动完成.......");
}备注:AppConfig.class替换为自己的配置文件,WebSocket.class为后面添加的websocket方法
3、不拦截websocket的访问(AppConfig.class配置文件)
public void configHandler(Handlers me) {
// 不拦截websocket
me.add(new UrlSkipHandler("^/websocket.ws", false));
}4、编写WebSocket.class的方法(代码可以直接使用,不过代码没考虑session分布式,只是单服务器用)
import com.alibaba.fastjson.JSONObject;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 〈webSocket功能〉
*
* @author foam103
* @create 2020/3/15
*/
@ServerEndpoint("/websocket.ws/{userId}")
public class WebSocket {
private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();
private Session session;
private String userId;
@OnOpen
public void onOpen(@PathParam("userId") String userId, Session session) throws IOException {
this.userId = userId;
this.session = session;
clients.put(userId, this);
//System.out.println("已连接");
}
@OnClose
public void onClose(Session session) {
clients.remove(userId);
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
@OnMessage
public void onMessage(String message) {
// message是json格式
JSONObject obj = JSONObject.parseObject(message);
String user = obj.get("userId").toString();
String mes = obj.get("message").toString();
// 判断是否在线,如果在线发送信息
for (WebSocket item : clients.values()) {
if (item.userId.equals(user)) {
item.session.getAsyncRemote().sendText(mes);
}
}
}
}5、其他业务地方触发消息发送(message可以用json格式,这样便于传递更多信息到前端)
// 引用websocket
private WebSocket ws = new WebSocket();
// websocket推送回复消息
ws.onMessage("{\"userId\":\"" + receiver + "\",\"message\":{\"tp\":\"" + type + "\",\"mes\":\"" + content + "\"}}");【前端代码】
1、编写js代码(setMessage方法需要自己写,其他的不动)
// websocket方法
function ws(userId) {
var websocket = null;
var host = document.location.host;
var Protocol = window.location.protocol.split(':')[0];
//判断当前浏览器是否支持WebSocket
if (window.WebSocket) {
if (Protocol == 'https') {
websocket = new WebSocket('wss://' + host + '/websocket.ws/' + userId);
} else {
websocket = new WebSocket('ws://' + host + '/websocket.ws/' + userId);
}
} else {
alert('当前浏览器不支持websocket');
}
//连接发生错误的回调方法
websocket.onerror = function () {
//alert('WebSocket连接发生错误');
};
//连接成功建立的回调方法
websocket.onopen = function () {
//alert('WebSocket连接成功');
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessage(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
//alert('WebSocket连接关闭');
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
websocket.close();
}
//将消息显示在网页上
function setMessage(message) {
//这里解析message,然后用js赋值给前端就行
}
}2、前端html页面调用
<script type="text/javascript" src="/plugins/js/ws.js"></script> // 适当的地方加载websocket ws(userid);
【结束语】
代码是最简单模式,很方便读懂,供大家参考。如有不完善,请大家多指教。