-
如果网页不刷新,服务端有新消息如何推送到浏览器?
-
解决方案,采用轮询的方式。即:通过js不断的请求服务器,查看是否有新数据,如果有,就获取到新数据。
这种解决方法是否存在问题呢?
当然是有的,如果服务端一直没有新的数据,那么js也是需要一直的轮询查询数据,这就是一种资源的浪费。
那么,有没有更好的解决方案? 有!那就是采用WebSocket技术来解决。
-
- 什么是WebSocket
- WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 WebSocket是真正实现了全双工通信的服务器向客户端推的互联网技术。 它是一种在单个TCP连接上进行全双工通讯协议。Websocket通信协议与2011年倍IETF定为标准RFC 6455,Websocket API被W3C定为标准。
- 专业词语自行百度吧.
- WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 WebSocket是真正实现了全双工通信的服务器向客户端推的互联网技术。 它是一种在单个TCP连接上进行全双工通讯协议。Websocket通信协议与2011年倍IETF定为标准RFC 6455,Websocket API被W3C定为标准。
- http与websocket的区别
- http
- http协议是短连接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开链接。
- websocket
- WebSocket协议是一种长链接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接进行通讯。
- http
- 搭建项目:pom
-
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!--spring boot的支持--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> </parent> <packaging>war</packaging> <dependencies> <!--<dependency>--> <!--<groupId>javax</groupId>--> <!--<artifactId>javaee-api</artifactId>--> <!--<version>7.0</version>--> <!--<scope>provided</scope>--> <!--</dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies> <build> <plugins> <!-- java编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8082</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project>
-
-
websocket的相关注解说明
-
@ServerEndpoint("/websocket/{uid}") 申明这是一个websocket服务 需要指定访问该服务的地址,在地址中可以指定参数,需要通过{}进行占位 @OnOpen 用法:public void onOpen(Session session, @PathParam("uid") String uid) throws IOException{} 该方法将在建立连接后执行,会传入session对象,就是客户端与服务端建立的长连接通道 通过@PathParam获取url申明中的参数 比如前面请求的uid @OnClose 用法:public void onClose() {} 该方法是在连接关闭后执行 @OnMessage 用法:public void onMessage(String message, Session session) throws IOException {} 该方法用于接收客户端发来的消息 message:发来的消息数据 session:会话对象(也是通道) 发送消息到客户端 用法:session.getBasicRemote().sendText("你好"); 通过session进行发送。
-
-
测试案例:
-
import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; @ServerEndpoint("/websocket/{uid}") public class MyWebSocket { @OnOpen public void onOpen(Session session, @PathParam(value = "uid")String uid) throws IOException { System.out.println("websocket已经连接" + session); // 给客户端响应,欢迎登陆(连接)系统 session.getBasicRemote().sendText(uid+",你好!欢迎登陆系统"); } @OnClose public void onClose(Session session){ System.out.println("websocket已经关闭" + session); } @OnMessage public void onMessage(String message, Session session) throws IOException { System.out.println("收到客户端发来的消息 --> " + message); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } //给客户端一个反馈 session.getBasicRemote().sendText("消息已收到"); } }
-
-
测试工具:
-
1.chrome插件,Simple WebSocket Client
-
2.在线工具 百度搜索: WebSocket测试工具 很多自己选一个就行 (推荐)
-
-
js代码: 使用websocket不需要再引入js或者组件. 因为浏览器内置了websocket对象.
-
const socket = new WebSocket("ws://localhost:8082/websocket/1"); socket.onopen = (ws) => { console.log("建立连接!", ws); } socket.onmessage = (ws) => { console.log("接收到消息 >> ", ws.data); } socket.onclose = (ws) => { console.log("连接已断开!", ws); } socket.onerror = (ws) => { console.log("发送错误!", ws); }// 2秒后向服务端发送消息 setTimeout(() => { socket.send("发送一条消息试试"); }, 2000); // 5秒后断开连接 setTimeout(() => { socket.close(); }, 5000);
-
-
SpringBoot整合WebSocket
-
pom文件中javaee-api 去掉. 因为springboot内部会继承Tomcat的包, 会和这个包冲突
-
启动类上不需要加什么特殊的注解.
-
主需要在具体的类上加 @EnableWebSocket 注解启动websocket
-
-
在Spring中,处理消息的具体业务逻辑需要实现WebSocketHandler接口,继承TextWebSocketHandler就可以了。
-
import org.springframework.stereotype.Component; 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; @Component public class MyHandler extends TextWebSocketHandler { @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { System.out.println("获取到消息 >> " + message.getPayload()); // 向客户端发送消息 session.sendMessage(new TextMessage("消息已收到")); //处理获取的参数 if (message.getPayload().equals("10")) { for (int i = 0; i < 10; i++) { session.sendMessage(new TextMessage("消息 -> " + i)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { Integer uid = (Integer) session.getAttributes().get("uid"); session.sendMessage(new TextMessage(uid + ", 你好!欢迎连接到ws服务")); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { System.out.println("断开连接!"); } }
-
-
编写配置类
-
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; 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 WebSocketConfig implements WebSocketConfigurer { @Autowired private MyHandler myHandler; @Autowired private MyHandshakeInterceptor myHandshakeInterceptor; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //注册myHandler , 并给请求的路径. registry.addHandler(this.myHandler, "/ws") //允许跨域请求 .setAllowedOrigins("*"); } }
-
-
websocket拦截器
-
在Spring中提供了websocket拦截器,可以在建立连接之前写些业务逻辑
-
import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; import java.util.Map; @Component public class MyHandshakeInterceptor implements HandshakeInterceptor { /** * 握手之前,若返回false,则不建立链接 * * @param request * @param response * @param wsHandler * @param attributes * @return * @throws Exception */ @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { //将用户id放入socket处理器的会话(WebSocketSession)中 attributes.put("uid", 1001); System.out.println("开始握手。。。。。。。"); return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { System.out.println("握手成功啦。。。。。。"); } }
-
将拦截器添加到websocket服务中
-
在配置类上添加@bean注解 即:
-
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; 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 WebSocketConfig implements WebSocketConfigurer { @Autowired private MyHandler myHandler; @Autowired private MyHandshakeInterceptor myHandshakeInterceptor; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //注册myHandler 并分配请求地址 registry.addHandler(this.myHandler, "/ws") //允许跨域请求 .setAllowedOrigins("*") //启用拦截器 .addInterceptors(this.myHandshakeInterceptor); } }
-
请求测试
-
-
-
-
SpringBoot集成WebSocket
最新推荐文章于 2024-05-23 10:50:00 发布