WebSocket-黑马好客租房

文章目录

  • 网站中的消息功能如何实现?
  • 什么是WebSocket?
  • http与websocket的区别
    • http
    • websocket
  • 浏览器支持情况
  • 快速入门
    • 创建itcast-websocket工程
    • websocket的相关注解说明
    • 实现websocket服务
    • 测试
    • 编写js客户端
  • SpringBoot整合WebSocket
    • 导入依赖
    • 编写WebSocketHandler
    • 编写配置类
    • 编写启动类
    • 测试
    • websocket拦截器

网站中的消息功能如何实现?

思考:像这样的消息功能怎么实现? 如果网页不刷新,服务端有新消息如何推送到浏览器?
解决方案,采用轮询的方式。即:通过js不断的请求服务器,查看是否有新数据,如果有,就获取到新数据。
这种解决方法是否存在问题呢?
当然是有的,如果服务端一直没有新的数据,那么js也是需要一直的轮询查询数据,这就是一种资源的浪费。
那么,有没有更好的解决方案? 有!那就是采用WebSocket技术来解决。

什么是WebSocket?

WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 WebSocket是真正实现了全双工通信的服务器向客户端推的互联网技术。 它是一种在单个TCP连接上进行全双工通讯协议。Websocket通信协议与2011年倍IETF定为标准RFC 6455,Websocket API被W3C定为标准。

全双工和单工的区别?

  • 全双工(Full Duplex)是通讯传输的一个术语。通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合。全双工指可以同时(瞬时)进行信号的双向传输(A→B且B→A)。指A→B的同时B→A,是瞬时同步的。
  • 单工、半双工(Half Duplex),所谓半双工就是指一个时间段内只有一个动作发生,举个简单例子,一条窄窄的马路,同时只能有一辆车通过,当目前有两辆车对开,这种情况下就只能一辆先过,等到头儿后另一辆再开,这个例子就形象的说明了半双工的原理。早期的对讲机、以及早期集线器等设备都是基于半双工的产品。随着技术的不断进步,半双工会逐渐退出历史舞台。

http与websocket的区别

http

http协议是短连接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开链接。
在这里插入图片描述

websocket

WebSocket协议是一种长链接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接进行通讯。

在这里插入图片描述

浏览器支持情况

在这里插入图片描述

快速入门

创建itcast-websocket工程

pom.xml

<?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>
<groupId>cn.itcast.websocket</groupId>
<artifactId>itcast-websocket</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</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申明中的参数

@OnClose
用法:public void onClose() {}
该方法是在连接关闭后执行

@OnMessage
用法:public void onMessage(String message, Session session) throws IOException {}
该方法用于接收客户端发来的消息
message:发来的消息数据
session:会话对象(也是通道)
发送消息到客户端
用法:session.getBasicRemote().sendText(“你好”);
通过session进行发送。

实现websocket服务

package cn.itcast.websocket;
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("uid") String uid) throws IOException {
		// 连接成功
		session.getBasicRemote().sendText(uid + ",你好,欢迎连接WebSocket!");
	}
	@OnClose
	public void onClose() {
		System.out.println(this + "关闭连接");
	}
	@OnMessage
	public void onMessage(String message, Session session) throws IOException {
		System.out.println("接收到消息:" + message);
		session.getBasicRemote().sendText("消息已收到.");
	}
	@OnError
	public void onError(Session session, Throwable error) {
		System.out.println("发生错误");
		error.printStackTrace();
	}
}

编写完成后,无需进额外的配置,直接启动tomcat即可。

测试

可以通过安装chrome插件或者通过在线工具进行测试:
chrome插件,Simple WebSocket Client:

https://chrome.google.com/webstore/detail/simple-websocket-client/pfdhoblngboilpfeibdedpjgfnlcodoo

在这里插入图片描述

在线工具:https://wstool.js.org/
在这里插入图片描述

编写js客户端

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
	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);
</script>
</body>
</html>

测试:
在这里插入图片描述

SpringBoot整合WebSocket

Spring对WebSocket做了支持,下面我们看下在springboot中如何使用。

导入依赖

<?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>
<groupId>cn.itcast.websocket</groupId>
<artifactId>itcast-websocket</artifactId>
<version>1.0-SNAPSHOT</version>
<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>

编写WebSocketHandler

在Spring中,处理消息的具体业务逻辑需要实现WebSocketHandler接口。

package cn.itcast.websocket.spring;
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;
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 {
		session.sendMessage(new TextMessage("欢迎连接到ws服务"));
	}
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		System.out.println("断开连接!");
	}
}

编写配置类

package cn.itcast.websocket.spring;
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 {
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(myHandler(), "/ws").setAllowedOrigins("*");
	}
	@Bean
	public WebSocketHandler myHandler() {
		return new MyHandler();
	}
}

编写启动类

package cn.itcast.websocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
	}
}

测试

在这里插入图片描述

websocket拦截器

在Spring中提供了websocket拦截器,可以在建立连接之前写些业务逻辑,比如校验登录等

package cn.itcast.websocket.spring;
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服务中:

package cn.itcast.websocket.spring;
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 MyHandshakeInterceptor myHandshakeInterceptor;
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(myHandler(), "/ws")
		.setAllowedOrigins("*").addInterceptors(this.myHandshakeInterceptor);
	}
	@Bean
	public WebSocketHandler myHandler() {
		return new MyHandler();
	}
}

获取uid:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/337907.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

全网最高质量文章:重新学习Java中的HashMap!!

前言 本文参考了美团技术团队的科普文章Java 8系列之重新认识HashMap - 知乎 (zhihu.com) 这篇文章的质量极其高&#xff0c;高到很有可能是全网介绍HashMap这个知识点最优秀的文章&#xff0c;没有之一&#xff01;&#xff01;&#xff01;因此&#xff0c;我决定在我自己的…

智能安全帽定制_基于联发科MT6762平台的智能安全帽方案

智能安全帽是一种具备多项功能的高科技产品&#xff0c;其功能集成了视频通话监控、高清图像采集、无线数据传输、语音广播对讲、定位轨迹回放、静默报警、危险救援报警、脱帽报警、碰撞报警、近电报警以及智能调度系统等&#xff0c;同时还支持多功能模块的自由添加&#xff0…

设计模式-责任链

之前写代码的时候看到过有审批场景使用了责任链&#xff0c;当时大概看了一下代码实现&#xff0c;今天终于有时间抽出来梳理一下&#xff0c;下面是本文的大纲&#xff1a; 使用场景 审批场景的普遍应用 实际案例&#xff1a;HttpClient中的责任链模式 责任链模式在事件处理、…

RocketMQ学习总结

一、架构 1、NameServer&#xff1a;注册中心。Broker信息注册到NameServer&#xff1b;producer/consumer根据某个topic通过NameServer获取对应broker的路由信息 &#xff1b; 2、Broker&#xff1a;负责存储、拉取、转发消息&#xff1b; 3、Producer&#xff1a;消息生产者…

creature_summon_groups

字段介绍 这个表保存了关于临时召唤生物的数据 creature_summon_groups summonerId&#xff08;召唤者ID&#xff09; summonerType 0 时&#xff0c;此处为 creature 的 entrysummonerType 1 时&#xff0c;此处为 gameobject 的 entrysummonerType 2 时&#xff0c;此处…

从设备维修到机器视觉:我的职业发展之路

大家好&#xff01;我是学员向工&#xff0c;今天很高兴有机会与大家分享我的职业经历。十年前&#xff0c;18岁中专毕业的那年&#xff0c;我踏入社会&#xff0c;至今已经过去了十年。一开始&#xff0c;我主要从事设备的维修、装配、钳工和电工等多岗位工作。 然而&#xff…

大数据关联规则挖掘:Apriori算法的深度探讨

文章目录 大数据关联规则挖掘&#xff1a;Apriori算法的深度探讨一、简介什么是关联规则挖掘&#xff1f;什么是频繁项集&#xff1f;什么是支持度与置信度&#xff1f;Apriori算法的重要性应用场景 二、理论基础项和项集支持度&#xff08;Support&#xff09;置信度&#xff…

༺༽༾ཊ—Unity之-02-简单工厂模式—ཏ༿༼༻

首先我们打开一个项目 在这个初始界面我们需要做一些准备工作 建基础通用包 创建一个Plane 重置后 缩放100倍 加一个颜色 任务&#xff1a;使用【简单工厂模式】生成四种不同怪物 【按不同路径移动】 首先资源商店下载四个怪物模型 接下来我们选取四个怪物作为预制体并分别起名…

【Java并发】聊聊concurrentHashMap扩容核心流程

扩容 什么时候扩容 链表转红黑树。需要判断数组长度&#xff0c;触发扩容调用putAll() , 触发tryPresize() 方法数据量达到阈值 tryPresize-初始化数组 // 扩容前操作&#xff0c;putAll or 链表转红黑树 // size是原数组长度 * 2private final void tryPresize(int size) {…

如何在Servlet中获取请求参数的值

看看这个大佬做的动图吧&#xff01; 在Servlet中&#xff0c;你可以使用HttpServletRequest对象来获取请求参数的值。HttpServletRequest对象提供了一些方法&#xff0c;允许你访问从客户端发送的请求信息。以下是一些获取请求参数的常用方法&#xff1a; getParameter(String…

《SPSS统计学基础与实证研究应用精解》视频讲解:变量和样本观测值基本操作

《SPSS统计学基础与实证研究应用精解》4.1 视频讲解 视频为《SPSS统计学基础与实证研究应用精解》张甜 杨维忠著 清华大学出版社 一书的随书赠送视频讲解4.1节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。本书旨在手把手教会使…

k8s-ingress一

Comfigmap&#xff1a;存储数据 Date&#xff1a; Key&#xff1a;value 挂载的方式&#xff0c;把配置信息传给容器 生产当中的yml文件很长&#xff1a; 有deployment 容器的探针 资源限制 Configmap 存储卷 Service Ingress K8s的对外服务&#xff0c;ingress Se…

2023年总结我所经历的技术大变革

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…

只需要1天+10元,上线我的第①个工具站 - 50个工具站打卡计划

2023年用了一整年的时间探索技术变现的方式&#xff0c;学习到了特别多的理论知识。2024年到了爆发的时间了。今年计划上线50款出海工具站计划&#xff0c;我会详细记录开发工具站的全部流程。 工具站的核心任务是找到关键字&#xff0c;找对关键词并成功注册到适当的域名&…

logstack 日志技术栈-04-opensource 开源工具 SigNoz+Graylog

3. SigNoz SigNoz 是一个日志收集和分析工具&#xff0c;可以收集和管理来自各种来源的日志、指标、跟踪和异常。 它为使用 OpenTelemetry 检测应用程序提供本机支持&#xff0c;以防止供应商锁定&#xff0c;将收集到的数据存储在 ClickHouse 中&#xff0c;然后在用户友好的…

༺༽༾ཊ—Unity之-01-单例模式—ཏ༿༼༻

在游戏开发过程中&#xff0c;我们会创建各种各样的类&#xff0c;再用new生成实例&#xff0c;有些时候我们需要这个类在整个游戏中是唯一出现的&#xff0c;比如一些管理器比如声音管理器等&#xff0c;没必要创建很多实例&#xff0c;就算有很多模块需要各种声音功能&#x…

NSIS来打包windows安装程序,开源免费简单小巧,支持中文

NSIS (Nullsoft脚本安装系统)是一个专业的开源系统&#xff0c;用于创建 Windows 安装程序。它被设计成尽可能小和灵活&#xff0c;因此非常适合互联网分发&#xff0c;并且原生支持中文&#xff0c;不像inno setup还需要你单独安装一个中文语言包。 NSIS官网&#xff1a;NSIS…

二叉树进阶oj题目

二叉树进阶oj题目 两个结点的最近公共祖先前序中序&#xff08;中序后序&#xff09;还原二叉树 1、两个结点的最近公共祖先&#xff08;两种方法&#xff09; leetcode链接 题目描述&#xff1a;给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共…

【Linux系统编程】环境变量详解

文章目录 1. 环境变量的基本概念2. 如何理解呢&#xff1f;&#xff08;测试PATH&#xff09;2.1 切入点1查看具体的环境变量原因剖析常见环境变量 2.2 切入点2给PATH环境变量添加新路径将我们自己的命令拷贝到PATH已有路径里面 2.3 切入点3 3. 显示所有环境变量4. 测试HOME5. …

【浅谈Linux中批量化注释和批量化去注释】

这篇博客主要是关于Linux中注释与去注释&#xff0c;在Linux和vs等编译器中代码行的注释和去注释会有很大不同&#xff0c;Linux中主要使用指令的方式来进行。 目录 批量化注释 批量化去注释 批量化注释 操作 ctrlv,hjkl区域选择&#xff08;主要使用j-下移&#xff09;&…