项目中有消息推送的需求,就用到了WebSocket。
先在菜鸟教程上抄一段介绍:
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
后台是用的Spring Boot,Java我不会,网上的文章、例子也看不懂,最后找了个视频教程千锋微信公众号和微信支付入门视频,边看边照着打,实现得功能。
把带注释的示例代码记录下来,避免下次使用。
依赖:pom.xml
在Spring Boot框架下使用WebSocket实现消息推送,首先在pom.xml中加入依赖。
配置类:WebSocketConfig.java
接着我们新建一个配置类,去注册我们的WebSocket。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration @EnableWebSocket public class WebSockectConfig implements WebSocketConfigurer {
|
拦截器类:MsgInterceptor.java
思路是将前端传过来的ws://websocket/{username}先拦截下来,通过username来确定与谁建立连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;
public class MsgInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { String url = request.getURI().toString(); String username = url.substring(url.lastIndexOf("/") + 1); attributes.put("username", username);
return super.beforeHandshake(request, response, wsHandler, attributes); }
@Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { super.afterHandshake(request, response, wsHandler, ex); } }
|
处理器类:MsgHandler.java
处理器中主要应为与业务相关的代码,此处简单作为示例,将收到的消息传给接收者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
import net.sf.json.JSONObject; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException; import java.util.HashMap; import java.util.Map;
public class MsgHandler extends TextWebSocketHandler {
|
测试页面:Msg.html
我们需要一个简单的页面去测试是否能推送消息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>msg</title> <script type="text/javascript"> var websocket = null; function connection() { var username = document.getElementById("name").value; if('WebSocket' in window) { websocket = new WebSocket("ws://localhost/websocket/" + username); } else { alert("不支持websocket") } websocket.onopen = function() { document.getElementById("message").innerHTML = '连接建立'; }; websocket.onmessage = function(event) { var data = event.data; document.getElementById("message").innerHTML = data; }; websocket.onerror = function() { document.getElementById("message").innerHTML = '异常'; }; websocket.onclose = function() { document.getElementById("message").innerHTML = '连接关闭'; };
|
配置wss
因为项目后台使用https,所以WebSocket也要从ws://改为wss://
是Spring Boot框架,所以在项目入口文件
SpringApplication.run(DemoApplication.class, args);
的启动方法下增加bean
配置。