赞
踩
根据项目要求需要将后台消息实时推送给前端,可以在前端使用定时任务实时获取,使用websocket通信建立长连接。具体这两种谁比较占用资源没有测试过,目前自己使用的是websocket进行实现,话不多说上代码
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.配置类,WebSocketConfig,WebSocketServer
package com.hgzx.framework.config; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Component public class WebSocketConfig { /** * 使用spring boot时,使用的是spring-boot的内置容器, * 如果要使用WebSocket,需要注入ServerEndpointExporter * * @return */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
package com.hgzx.framework.config; import com.hgzx.common.utils.SecurityUtils; import com.hgzx.xdywpt.notice.domain.NoticeMessagePersonl; import com.hgzx.xdywpt.notice.mapper.NoticeMessagePersonlMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; @ServerEndpoint(value = "/websocket/{username}") @Service public class WebSocketServer { private static Logger log = LoggerFactory.getLogger(WebSocketServer.class); /** * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 */ private static CopyOnWriteArraySet<WebSocketServer> govWebSocketSet = new CopyOnWriteArraySet<>(); private Session govSession; public static Map<String, List<WebSocketServer>> govUserSessions = new HashMap<>(); public String pointsUrl; /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session,@PathParam("username") String username) { this.govSession = session; List<WebSocketServer> list = new ArrayList<>(); // 一个用户不同地方登陆所做的处理 if (govUserSessions.containsKey(username)) { list = govUserSessions.get(username); } list.add(this); govUserSessions.put(username, list); //加入set中 govWebSocketSet.add(this); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { //从set中删除 closeRemove(govWebSocketSet, govUserSessions); } private void closeRemove(CopyOnWriteArraySet<WebSocketServer> webSocketSet, Map<String, List<WebSocketServer>> userSessions) { webSocketSet.remove(this); Set<Map.Entry<String, List<WebSocketServer>>> entrySet = userSessions.entrySet(); for (Map.Entry<String, List<WebSocketServer>> entry : entrySet) { String key = entry.getKey(); boolean isFind = findRemove(key); if (isFind) { return; } } } /** * 查找移除 * * @param key * @return */ private boolean findRemove(String key) { return backOrFrontFind(key, govUserSessions); } private boolean backOrFrontFind(String key, Map<String, List<WebSocketServer>> govUserSessions) { List<WebSocketServer> list = govUserSessions.get(key); for (int i = 0; i < list.size(); i++) { if (this.equals(list.get(i))) { list.remove(i); if (list.size() > 0) { govUserSessions.put(key, list); } else { govUserSessions.remove(key); } return true; } } return false; } /** * @param error */ @OnError public void onError(Throwable error) { log.error("发生错误"); error.printStackTrace(); } /** * 实现服务器主动推送 */ public synchronized void sendMessage(String message) { try { this.govSession.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } /** * 群发自定义消息 */ public static void sendInfo(String message,@PathParam("username") String username) { log.info("推送消息到窗口推送内容:" + message); backOrFrontSend(message,username,govWebSocketSet); } private static void backOrFrontSend(String message, @PathParam("username") String username,CopyOnWriteArraySet<WebSocketServer> govWebSocketSet) { List<WebSocketServer> list = govUserSessions.get(username); if (list != null) { for (int i = 0; i < list.size(); i++) { list.get(i).sendMessage(message); } } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } WebSocketServer that = (WebSocketServer) o; return Objects.equals(govSession, that.govSession) && Objects.equals(pointsUrl, that.pointsUrl); } @Override public int hashCode() { return Objects.hash(govSession,pointsUrl); } }
在WebSocketServer中的username参数就是自定义发送给什么用户,只要保持唯一性就可以了。
3、权限问题
vue在请求websocket服务的时候很多时候会出现404forbidden这个错误,这是因为请求路径权限的问题造成的,我们需要在后台进行放开,我这里使用的是springSecurity安全框架放开权限代码
.antMatchers("/**/websocket/**").anonymous()
如果使用的是shiro安全框架的话,可以自行百度下。
4、调用
java后台向前端发送消息,只需要调用WebSocketServer里面方法就可以了
WebSocketServer.sendInfo(message,username);
以上就是JAVA后台所做的工作了,下面开始前端VUE的工作
1.定义全局变量socket
data() {
return {
socket: "",
};
},
2.页面加载完成调用socket初始化方法
mounted() {
this.init()
},
3、实现socket初始化方法
methods: { init: function () { if(typeof(WebSocket) === "undefined"){ alert("您的浏览器不支持socket") }else{ let username = sessionStorage.getItem("username");// 获取登录用户 var path = "ws://localhost:8080/websocket/"+username;// 请求路径 // 实例化socket this.socket = new WebSocket(path) // 监听socket连接 this.socket.onopen = this.open // 监听socket错误信息 this.socket.onerror = this.error // 监听socket消息 this.socket.onmessage = this.getMessage } }, open: function () { console.log("socket连接成功") }, error: function () { console.log("连接错误") }, getMessage: function (msg) { let message= parseInt(msg.data); console.log("message="+message); }, send: function () { this.socket.send(params) }, close: function () { console.log("socket已经关闭") } }
如果通信成功,java后台会调用到WebSocketServer中onOpen的方法,同时在vue页面open: function ()方法会执行打印:socket连接成功。
以上就是全部的工作,谢谢。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。