vue+webrtc(腾讯云) 实现直播功能 pc端+移动端

Websocket实现私聊和群聊

  • 1. websocket的概念
    • 1.1. 全双工概念
  • 2. websocket实现聊天室
    • 2.1. WebSocket API
      • 2.1.1. 构造方法
        • 2.1.1.1. 语法
        • 2.1.1.2. 参数
        • 2.1.1.3. 抛出异常
      • 2.1.2. 常量
      • 2.1.3. 属性
      • 2.1.4. 方法
      • 2.1.5. 事件
  • 3. websocket实现群聊或私聊或图片发送
    • 3.1. 项目的最终目录结构
    • 3.2. 依赖注入
    • 3.3. yml文件配置
    • 3.4. 注入ServerEndpointExporter
    • 3.5. Controller代码
    • 3.5. websocket实现群聊
      • 3.5.1. 服务器端代码
      • 3.5.2. 客户端代码
      • 3.5.3. 测试结果
    • 3.6. websocket实现私聊+群聊
      • 3.6.1. 服务器端代码
      • 3.6.2. 客户端代码
      • 3.6.3. SocketConfig代码
      • 3.6.4. 测试结果
    • 3.7. websocket实现聊天图片发送
      • 3.7.1. 服务端代码
      • 3.7.2. 客户端代码
      • 3.7.3. SocketConfig代码
      • 3.7.4. 测试结果

1. websocket的概念

websocket是一种在单个TCP连接上进行全双工通信的协议。websocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在websocket API中浏览器和服务器只需要完成一次握手,两者之间就可以直接创建持久性的连接,并进行双向数据传输。

1.1. 全双工概念

全双工是通讯传输的一个术语。通信允许数据在两个方面上同时传输,它在能力上相当于两个单工通信方式的结合。全双工指可以同时进行信号的双向传输(A—>B的同时B—>A)。单工指:只允许A向B传送信息,而B不能向A传送。

2. websocket实现聊天室

2.1. WebSocket API

WebSocket对象提供了用户创建和管理WebSocket连接,以及通过该连接发送和接收数据的API。

2.1.1. 构造方法
2.1.1.1. 语法

WebSocket(url [, protocols]);

2.1.1.2. 参数
  1. url:要连接的url,WebSocket服务器的url
  2. protocols:可选参数,一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议,这样单个服务器可以实现多个WebSocket子协议。如果不指定协议字符串,则假定为空字符串。
2.1.1.3. 抛出异常

SECURITY_ERR:正在尝试连接的端口被阻止。

2.1.2. 常量
  1. WebSocket.CONNECTING == 0 连接中
  2. WebSocket.OPEN == 1 已连接
  3. WebSocket.CLOSING == 2 正在关闭
  4. WebSocket.CLOSED == 3 已关闭
2.1.3. 属性
  1. WebSocket.binaryType

    使用二进制的数据类型连接

  2. WebSocket.bufferedAmount(只读)

    未发送至服务器的字节数

  3. WebSocket.extensions(只读)

    服务器选择的扩展

  4. WebSocket.onopen

    用户指定连接成功后的回调函数

  5. WebSocket.onmessage

    用户指定从服务器接收到信息时的回调函数

  6. WebSocket.onerror

    用于指定连接失败后的回调函数

  7. WebSocket.onclose

    用于指定连接关闭后的回调函数

  8. WebSocket.url

    websocket的绝对路径

  9. WebSocket.readyState(只读)

    当前的连接状态

  10. WebSocket.protocol(只读)

    服务器选择的下属协议

2.1.4. 方法
  1. WebSocket.close([code, reason])

    关闭当前连接

  2. WebSocket.send(data)

    对要传输的数据进行排队

2.1.5. 事件

使用addEventListener()监听或将一个事件监听器赋值给本接口的oneventname属性,来监听下面的事件:

  1. open

    当一个WebSocket连接成功时触发,也可以通过onopen属性来设置

  2. message

    当一个WebSocket收发数据时触发,也可以通过onmessage属性来设置

  3. error

    当一个WebSocket连接因错误而关闭时触发,也可以通过onerror属性来设置

  4. close

    当一个WebSocket连接被关闭时触发,也可以通过onclose属性来设置

3. websocket实现群聊或私聊或图片发送

本文使用springboot+freemarker+websocket实现代码

3.1. 项目的最终目录结构

本图片分为三个小的项目:1.websocket实现群聊;2.websocket实现群聊和私聊;3.websocket实现聊天内容可以为图片

3.2. 依赖注入

<?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>com.AttackingApe.demo</groupId><artifactId>webSocket</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.6.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>net.sourceforge.nekohtml</groupId><artifactId>nekohtml</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.72</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><resources><resource><directory>src/main/resources</directory></resource></resources></build>
</project>

3.3. yml文件配置

server:port: 20713tomcat:uri-encoding: UTF-8
spring:freemarker:suffix: .ftlcharset: UTF-8content-type: text/htmlhttp:encoding:charset: UTF-8force: trueenabled: true

3.4. 注入ServerEndpointExporter

package com.AttackingApe.demo.webSocket.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @author PengPan* @version 1.0* @date 2020/7/14 18:50*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}

3.5. Controller代码

package com.AttackingApe.demo.webSocket.Controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;import java.io.IOException;
import java.util.Map;/*** websocket应用* @author PengPan* @version 1.0* @date 2020/7/13 14:34*/
@RestController
@Slf4j
public class WebsocketController {@RequestMapping("/websocketTest")public ModelAndView sendMessage(Map<String, Object> map) throws IOException{try{log.info("跳转到websocket页面上");return new ModelAndView("webSocketClients", map);}catch (Exception e){log.info("页面跳转发生错误:{}", e.getMessage());map.put("msg", "请求错误");return new ModelAndView("error", map);}}
}

3.5. websocket实现群聊

实现内容:连接websocket的用户都可以进行聊天并显示所有人聊天以及对应的昵称。

3.5.1. 服务器端代码
package com.AttackingApe.demo.webSocket.util;import com.AttackingApe.demo.webSocket.Pojo.SocketConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;/*** @author PengPan* @version 1.0* @date 2020/7/15 18:23*/
@ServerEndpoint(value = "/websocket/{nickname}")
@Component
@Slf4j
public class MyWebsocket {private static Map<String, Session> map = new HashMap<>();private static CopyOnWriteArraySet<MyWebsocket> clients = new CopyOnWriteArraySet<>();private Session session;private String nickname;@OnOpenpublic void onOpen(Session session, @PathParam("nickname") String nickname){this.session = session;this.nickname = nickname;clients.add(this);log.info("有新用户加入,当前人数为:", clients.size());this.session.getAsyncRemote().sendText(nickname + "已加入连接,当前人数为:" + clients.size());}@OnClosepublic void onClose(){clients.remove(this);log.info("有用户断开连接,当前人数为:{}", clients.size());}@OnMessagepublic void onMessage(String message, Session session, @PathParam("nickname") String nickname){log.info("来自客户端:{}发来的消息:{}", nickname, message);broadcast(nickname + ":" + message);}@OnErrorpublic void onError(Session session, Throwable error){log.error("出现错误");error.printStackTrace();}/*** 自定义群发消息* @param message*/public void broadcast(String message){for (MyWebsocket websocket : clients){//异步发送消息websocket.session.getAsyncRemote().sendText(message);}}
}
3.5.2. 客户端代码
<!DOCTYPE HTML>
<html>
<head><meta charset="UTF-8"><title>My WebSocket</title><style>#message{margin-top:40px;border:1px solid gray;padding:20px;}</style>
</head>
<body>
昵称:<input type="text" id="nickname"/>
<button οnclick="conectWebSocket()">连接WebSocket</button>
<button οnclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消  息:<input id="text" type="text" /><button οnclick="send()">发送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">var websocket = null;function conectWebSocket(){var nickname = document.getElementById("nickname").value;if(nickname == "" || nickname == null){alert("请输入昵称");return;}//判断当前浏览器是否支持WebSocketif ('WebSocket'in window) {websocket = new WebSocket("ws://10.4.4.83:20713/websocket/" + nickname);} else {alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function() {setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(event) {setMessageInnerHTML("Loc MSG: 成功建立连接");}//接收到消息的回调方法websocket.onmessage = function(event) {setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function() {setMessageInnerHTML("Loc MSG:关闭连接");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {websocket.close();}}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;websocket.send(message);}
</script>
</html>
3.5.3. 测试结果

在这里插入图片描述在这里插入图片描述

3.6. websocket实现私聊+群聊

实现内容:A可以在公屏上输入内容,大家都可以看见。也可以选择输入频道,只和每一个人聊天。

3.6.1. 服务器端代码
package com.AttackingApe.demo.webSocket.util;import com.AttackingApe.demo.webSocket.Pojo.SocketConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;/*** @author PengPan* @version 1.0* @date 2020/7/15 18:23*/
@ServerEndpoint(value = "/websocket/{nickname}")
@Component
@Slf4j
public class MyWebsocket {private static Map<String, Session> map = new HashMap<>();private static CopyOnWriteArraySet<MyWebsocket> clients = new CopyOnWriteArraySet<>();private Session session;private String nickname;@OnOpenpublic void onOpen(Session session, @PathParam("nickname") String nickname){this.session = session;this.nickname = nickname;map.put(session.getId(), session);clients.add(this);log.info("有新用户加入,当前人数为:", clients.size());this.session.getAsyncRemote().sendText(nickname + "已成功连接(其频道号为:" + session.getId() + "),当前在线人数为:" + clients.size());}@OnClosepublic void onClose(){clients.remove(this);log.info("有用户断开连接,当前人数为:{}", clients.size());}@OnMessagepublic void onMessage(String message, Session session, @PathParam("nickname") String nickname){log.info("来自客户端:{}发来的消息:{}", nickname, message);SocketConfig socketConfig;ObjectMapper objectMapper = new ObjectMapper();try{socketConfig = objectMapper.readValue(message, SocketConfig.class);if(socketConfig.getType() == 1){  //私聊socketConfig.setFromUser(session.getId());Session fromSession = map.get(socketConfig.getFromUser());Session toSession = map.get(socketConfig.getToUser());if(toSession != null){  //接受者存在,发送以下消息给接受者和发送者fromSession.getAsyncRemote().sendText(nickname + ":" + socketConfig.getMsg());toSession.getAsyncRemote().sendText(nickname + ":" + socketConfig.getMsg());}else{  //发送者不存在,发送以下消息给发送者fromSession.getAsyncRemote().sendText("频道号不存在或对方不在线");}}else{  //群聊broadcast(nickname + ":" + socketConfig.getMsg());}}catch (Exception e){log.error("发送消息出错");e.printStackTrace();}}@OnErrorpublic void onError(Session session, Throwable error){log.error("出现错误");error.printStackTrace();}/*** 自定义群发消息* @param message*/public void broadcast(String message){for (MyWebsocket websocket : clients){//异步发送消息websocket.session.getAsyncRemote().sendText(message);}}
}
3.6.2. 客户端代码
<!DOCTYPE HTML>
<html>
<head><meta charset="UTF-8"><title>My WebSocket</title><style>#message{margin-top:40px;border:1px solid gray;padding:20px;}</style>
</head>
<body>
昵称:<input type="text" id="nickname"/>
<button οnclick="conectWebSocket()">连接WebSocket</button>
<button οnclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消  息:<input id="text" type="text" />
频道号:<input id="toUser" type="text"/>
<button οnclick="send()">发送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">var websocket = null;function conectWebSocket(){var nickname = document.getElementById("nickname").value;if(nickname == "" || nickname == null){alert("请输入昵称");return;}//判断当前浏览器是否支持WebSocketif ('WebSocket'in window) {websocket = new WebSocket("ws://10.4.4.83:20713/websocket/" + nickname);} else {alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function() {setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(event) {setMessageInnerHTML("Loc MSG: 成功建立连接");}//接收到消息的回调方法websocket.onmessage = function(event) {setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function() {setMessageInnerHTML("Loc MSG:关闭连接");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {websocket.close();}}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;var toUser = document.getElementById('toUser').value;var socketConfig = {msg:message,toUser:toUser};if(toUser == "" || toUser == null){socketConfig.type = 0;}else{socketConfig.type = 1;}websocket.send(JSON.stringify(socketConfig));}
</script>
</html>
3.6.3. SocketConfig代码
package com.AttackingApe.demo.webSocket.Pojo;import lombok.Data;/*** @author PengPan* @version 1.0* @date 2020/7/16 15:41*/
@Data
public class SocketConfig {//聊天类型 0:群聊  1:私聊private int type;//发送者private String fromUser;//接受者private String toUser;//消息private String msg;//消息类型 1:文本  2:图片private int code;
}
3.6.4. 测试结果

在这里插入图片描述在这里插入图片描述在这里插入图片描述

3.7. websocket实现聊天图片发送

实现内容:聊天的时候可以传入图片。

3.7.1. 服务端代码
package com.AttackingApe.demo.webSocket.util;import com.AttackingApe.demo.webSocket.Pojo.SocketConfig;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;/*** @author PengPan* @version 1.0* @date 2020/7/15 18:23*/
@ServerEndpoint(value = "/websocket/{nickname}")
@Component
@Slf4j
public class MyWebsocket {private static Map<String, Session> map = new HashMap<>();private static CopyOnWriteArraySet<MyWebsocket> clients = new CopyOnWriteArraySet<>();private Session session;private String nickname;@OnOpenpublic void onOpen(Session session, @PathParam("nickname") String nickname){this.session = session;this.nickname = nickname;map.put(session.getId(), session);clients.add(this);log.info("有新用户加入,当前人数为:", clients.size());JSONObject jsonObject = new JSONObject();jsonObject.put("msg",nickname + "已成功连接(其频道号为:" + session.getId() + "),当前在线人数为:" + clients.size());jsonObject.put("code", 1);this.session.getAsyncRemote().sendText(jsonObject.toJSONString());}@OnClosepublic void onClose(){clients.remove(this);log.info("有用户断开连接,当前人数为:{}", clients.size());}@OnMessagepublic void onMessage(String message, Session session, @PathParam("nickname") String nickname){log.info("来自客户端:{}发来的消息:{}", nickname, message);SocketConfig socketConfig;ObjectMapper objectMapper = new ObjectMapper();JSONObject jsonObject = new JSONObject();jsonObject.put("code", JSONObject.parseObject(message).get("code"));try{socketConfig = objectMapper.readValue(message, SocketConfig.class);jsonObject.put("nickname", nickname + ":");if(socketConfig.getType() == 1){  //私聊socketConfig.setFromUser(session.getId());Session fromSession = map.get(socketConfig.getFromUser());Session toSession = map.get(socketConfig.getToUser());if(toSession != null){  //接受者存在,发送以下消息给接受者和发送者jsonObject.put("msg", socketConfig.getMsg());fromSession.getAsyncRemote().sendText(jsonObject.toJSONString());toSession.getAsyncRemote().sendText(jsonObject.toJSONString());}else{  //发送者不存在,发送以下消息给发送者jsonObject.put("msg", "频道号不存在或对方不在线");fromSession.getAsyncRemote().sendText("频道号不存在或对方不在线");}}else{  //群聊jsonObject.put("msg", socketConfig.getMsg());broadcast(jsonObject.toJSONString());}}catch (Exception e){log.error("发送消息出错");e.printStackTrace();}}@OnErrorpublic void onError(Session session, Throwable error){log.error("出现错误");error.printStackTrace();}/*** 自定义群发消息* @param message*/public void broadcast(String message){for (MyWebsocket websocket : clients){//异步发送消息websocket.session.getAsyncRemote().sendText(message);}}
}
3.7.2. 客户端代码
<!DOCTYPE HTML>
<html>
<head><meta charset="UTF-8"><title>My WebSocket</title><style>#message{margin-top:40px;border:1px solid gray;padding:20px;}</style>
</head>
<body>
昵称:<input type="text" id="nickname"/>
<button οnclick="conectWebSocket()">连接WebSocket</button>
<button οnclick="closeWebSocket()">断开连接</button>
<hr />
<br />
消  息:<input id="text" type="text" />
频道号:<input id="toUser" type="text"/>
<button οnclick="send()">发送消息</button>
<input type="file" id="file" οnchange="chooseFile()"/>
<div id="message"></div>
</body>
<script type="text/javascript">var websocket = null;function conectWebSocket(){var nickname = document.getElementById("nickname").value;if(nickname == "" || nickname == null){alert("请输入昵称");return;}//判断当前浏览器是否支持WebSocketif ('WebSocket'in window) {websocket = new WebSocket("ws://10.4.4.83:20713/websocket/" + nickname);} else {alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function() {setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(event) {setMessageInnerHTML("Loc MSG: 成功建立连接");}//接收到消息的回调方法websocket.onmessage = function(event) {var json = JSON.parse(event.data);if(json.code == 1){setMessageInnerHTML(json.nickname + json.msg);}else if(json.code == 2){setMessageInnerHTML(json.nickname);setIconInnerHTML(json.msg);}}//连接关闭的回调方法websocket.onclose = function() {setMessageInnerHTML("Loc MSG:关闭连接");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {websocket.close();}}//将文本消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//将图片消息显示在网页上function setIconInnerHTML(innerHTML) {document.getElementById('message').innerHTML = document.getElementById('message').innerHTML + '<img width="150px" src='+innerHTML+'>' + '<br/>';}//关闭连接function closeWebSocket() {websocket.close();}//发送文本消息function send() {var message = document.getElementById('text').value;var toUser = document.getElementById('toUser').value;var socketConfig = {code:1,msg:message,toUser:toUser};if(toUser == "" || toUser == null){socketConfig.type = 0;}else{socketConfig.type = 1;}websocket.send(JSON.stringify(socketConfig));}//发送图片消息function chooseFile() {var fileList = document.getElementById("file").files;var type = fileList[0].type;var toUser = document.getElementById('toUser').value;if(fileList.length > 0){var fileReader = new FileReader();fileReader.readAsDataURL(fileList[0]);fileReader.onload = function (e) {var socketConfig = {msg: e.target.result,toUser: toUser,code: 2};if (toUser == "" || toUser == null) {socketConfig.type = 0;} else {socketConfig.type = 1;}websocket.send(JSON.stringify(socketConfig));}}}
</script>
</html>
3.7.3. SocketConfig代码
package com.AttackingApe.demo.webSocket.Pojo;import lombok.Data;/*** @author PengPan* @version 1.0* @date 2020/7/16 15:41*/
@Data
public class SocketConfig {//聊天类型 0:群聊  1:私聊private int type;//发送者private String fromUser;//接受者private String toUser;//消息private String msg;//消息类型 1:文本  2:图片private int code;
}
3.7.4. 测试结果

在这里插入图片描述在这里插入图片描述在这里插入图片描述

# websocket# javascript

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React+TS前台项目实战(七)-- 全局常用组件Select封装

文章目录 前言Select组件1. 功能分析2. 代码详细注释说明3. 使用方式4. 效果展示&#xff08;1&#xff09;鼠标移入效果&#xff08;2&#xff09;下拉框打开效果&#xff08;3&#xff09;回调输出 总结 前言 今天这篇主要讲全局select组件封装&#xff0c;可根据UI设计师要…

188. 买卖股票的最佳时机 IV

188. 买卖股票的最佳时机 IV 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;代码解释类级变量与初始化动态规划初始化递归函数 dfs_maxProfit Integer.MIN_VALUE / 5 的作用总结 参考代码&#xff1a;_188买卖股票的最佳时机IV 错误经验吸取 原题链接&#xf…

全面升级,票据识别新纪元:合合信息TextIn多票识别2.0

票据识别 - 自动化业务的守门员 发票、票据识别&#xff0c;是OCR技术和RPA、CMS系统结合的一个典型场景&#xff0c;从覆盖率、覆盖面的角度来说&#xff0c;应该也是结合得最成功的场景之一。 产品简介 国内通用票据识别V2.0&#xff08;简称“多票识别2.0”&#xff09;是…

Java 集合框架详谈及代码分析(Iterable->Collection->List、Set->各接口实现类、Map->各接口实现类)

目录 Java 集合框架详谈及代码分析&#xff08;Iterable->Collection->List、Set->各接口实现类、Map->各接口实现类&#xff09;1、集合概述1-1&#xff1a;Java 集合概述1-2&#xff1a;List、Set、Map 三者的区别&#xff1f;1-3&#xff1a;集合框架底层数据结…

SM4 国密——加密,解密

SM4 国密的使用 前言——引用管理包SM4解密——ECB模式SM4加密——ECB模式SM4解密——CBC模式SM4加密——CBC模式SM4工具类SM4主体类SM4实体类 前言——引用管理包 引用NuGet管理包BouncyCastle.Crypto SM4解密——ECB模式 public string CiphertextParsing(string json) {tr…

四十八、openlayers地图调色总结——锐化、模糊、浮雕滤镜,调整地图色相、饱和度、亮度

这篇是对滤镜的总结&#xff0c;方便工作中直接使用。 想要调整图层的颜色&#xff0c;有两种方法。 方法一&#xff1a; 加载图层时使用tileLoadFunction函数拿到context添加canvas滤镜效果。 this.imagery new TileLayer({source: new XYZ({url: "https://server.arc…

android串口助手apk下载 源码 演示 支持android 4-14及以上

android串口助手apk下载 1、自动获取串口列表 2、打开串口就开始接收 3、收发 字符或16进制 4、默认发送at\r\n 5、android串口助手apk 支持android 4-14 &#xff08;Google seral port 太老&#xff09; 源码找我 需要 用adb root 再setenforce 0进入SELinux 模式 才有权限…

关于docker无法正常下载镜像的问题

文章目录 之前还可以正常下载镜像&#xff0c;但是一段时间之后就无法下载了&#xff0c;猜测可能是政治原因&#xff0c;无法连接到国外服务器&#xff0c;所以我设置了阿里云的镜像加速器。 配置方法如下&#xff1a; 前往阿里云&#xff08;https://help.aliyun.com/zh/acr/…

理解HTTP请求格式

HTTP概念 HTTP全称HyperTextTransfer Protocol(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议&#xff1b;HTTP是一个客户端&#xff08;用户&#xff09;和服务端&#xff08;网站&#xff09;之间请求和响应的标准。 HTTP 协议是以 ASCII 码传输&…

Ethena 更新代币经济学,逼着空投用户作长期 Hodler?

撰文&#xff1a;Yangz&#xff0c;Techub News 本文来源香港Web3媒体Techub News 6 月 18 日&#xff0c;Ethena 更新代币经济学&#xff0c;计划在 Ethena 生态和即将推出的 Ethena Chain 中引入通用再质押机制&#xff0c;并对任何通过空投获得 ENA 的用户实施「锁定」要求…

【黑马TS】学习资料Day4

五、在 React 中使用 TypeScript 现在&#xff0c;我们已经掌握了 TS 中基础类型、高级类型的使用了。但是&#xff0c;如果要在前端项目开发中使用 TS&#xff0c;还需要掌握 React、Vue、Angular 等这些库或框架中提供的 API 的类型&#xff0c;以及在 TS 中是如何使用的。 …

基于Redis提高查询性能(保持数据一致性)

Redis实战篇 | Kyles Blog (cyborg2077.github.io) 目录 背景 商户查询缓存(根据ID查询&#xff09; 根据店铺类型查询&#xff08;List型&#xff09; 缓存更新策略&#xff08;保证数据一致性&#xff09; 案例&#xff08;利用缓存更新策略&#xff09; 背景 起初客户端…

Hadoop3:MapReduce中的Shuffle机制

一、流程图 Shuffle是Map方法之后&#xff0c;Reduce方法之前的数据处理过程称。 二、图解说明 1、数据流向 map方法中context.write(outK, outV);开始&#xff0c;写入环形缓冲区&#xff0c;再进行分区排序&#xff0c;写到磁盘 reduce方法拉取磁盘上的数据&#xff0c;…

JavaSE 面向对象程序设计高级 方法引用 2024详解

在编程中&#xff0c;方法引用&#xff08;Method Reference&#xff09;是一种技术&#xff0c;它让你能够直接引用一个现有的函数或方法&#xff0c;而无需通过对象实例来调用。这种方法在函数式编程和高阶函数中非常有用&#xff0c;因为它提供了简洁的方式来传递函数行为&a…

【归档】maven的使用

学习自波波酱老师SSM企业级框架最全教学视频 maven篇 maven的设置 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…

【ARMv8/ARMv9 硬件加速系列 3 -- SVE 硬件加速向量运算 1】

文章目录 SVE 使用介绍SVE 特点SVE2 特点 SVE 寄存器扩展的向量寄存器可扩展的谓词寄存器.d 与 .b 后缀的区别举例介绍使用 .d 后缀进行64位元素操作使用 .b 后缀进行8位元素操作 ptrue 指令小结 FFR 寄存器 SVE 使用介绍 前面文章:【ARMv8/ARMv9 硬件加速系列 1 – SVE | NEO…

AttributeError: module ‘numpy‘ has no attribute ‘int‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

C++ Windows Hook使用

GitHub - microsoft/Detours: Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form. /*挂载钩子 setdll /d:C:\Users\g\source\repos\LotTest\Release\lotDll.dll C:\Users\g\source\repos\LotTest…

React 通信:深层传递(Props、Context、Children Jsx)

在之前的文章 探讨&#xff1a;围绕 props 阐述 React 通信 中总结了关于“父子”组件传值&#xff0c;但是当需要在组件树中深层传递参数以及需要在组件间复用相同的参数时&#xff0c;传递 props 就会变得很麻烦。 实际案例&#xff1a; 下述展示有两种状态&#xff1a;① 详…

【无线传感网】LEACH路由算法

1、LEACH路由算法简介 LEACH协议,全称是“低功耗自适应集簇分层型协议” (Low Energy Adaptive Clustering Hierarchy),是一种无线传感器网络路由协议。基于LEACH协议的算法,称为LEACH算法。 2、LEACH路由算法的基本思想 LEACH路由协议与以往的路由协议的不同之处在于其改变…