首页
苏兮影视
随笔记
壁纸
更多
直播
时光轴
友联
关于
统计
Search
1
软件添加id功能按钮
708 阅读
2
v2ray节点搭建
508 阅读
3
typecho非常有特色的模块
460 阅读
4
QQxml消息卡片生成源码
421 阅读
5
Linux下提权常用小命令
366 阅读
谈天说地
建站源码
经验教程
资源分享
动漫美图
登录
Search
标签搜索
java
flutter
springboot
rust
安卓
linux
vue
docker
joe
快捷键
git
fish shell
maven
redis
netty
dart
groovy
js
设计模式
rpc
尽意
累计撰写
95
篇文章
累计收到
38
条评论
首页
栏目
谈天说地
建站源码
经验教程
资源分享
动漫美图
页面
苏兮影视
随笔记
壁纸
直播
时光轴
友联
关于
统计
搜索到
95
篇与
的结果
Spring Boot 整合 Swagger3
Swagger3 基于 OpenAPI 3 标准,支持自动生成直观的交互式 API 文档页面。快速集成1. 引入依赖在 pom.xml 中添加以下依赖:<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>2. 配置 Swagger创建配置类 SwaggerConfig,定义基本的 Swagger 配置:package com.example.swaggerdemo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; @Configuration public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.example.swaggerdemo")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Swagger3 API 文档") .description("Spring Boot 整合 Swagger3 示例") .version("1.0.0") .build(); } }3. 创建测试接口新增 HelloController 用于测试:package com.example.swaggerdemo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1") public class HelloController { @GetMapping("/hello") public String sayHello() { return "Hello, Swagger3!"; } }4. 启动并访问启动项目后,在浏览器中访问以下地址:http://localhost:8080/swagger-ui/您将看到一个交互式的 API 文档页面。常见问题1. 无法访问 Swagger UI确保依赖和配置无误。检查 basePackage 是否正确。2. 修改访问路径在 application.yml 中自定义路径:spring: web: path-mapping: swagger-ui: "/custom/swagger-ui"重新访问:http://localhost:8080/custom/swagger-ui/
2024年12月05日
39 阅读
0 评论
1 点赞
2024-12-04
Spring Boot 集成 JWT 简单实现
一、JWT 简介JSON Web Token (JWT) 是一种用于客户端与服务端之间安全传递信息的轻量级协议。它通常用于:用户认证:登录成功后颁发 Token,后续请求中携带该 Token。授权管理:通过 Token 判断用户是否有权限。JWT 的组成部分:Header:描述令牌的类型和算法。Payload:包含用户信息及其他声明。Signature:由 Header、Payload 和密钥生成,用于验证 Token 的完整性。二、项目依赖在项目的 pom.xml 中引入以下依赖:<dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> </dependency> </dependencies>三、创建 JWT 配置类1. 定义 JwtProperties通过 @ConfigurationProperties 注解加载外部配置:package com.example.jwt.config; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "jwt") public class JwtProperties { private String secret; // 秘钥 private long expiration; // 过期时间(秒) public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public long getExpiration() { return expiration; } public void setExpiration(long expiration) { this.expiration = expiration; } }2. 激活配置类package com.example.jwt.config; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(JwtProperties.class) public class JwtConfig { }3. 在 application.yml 中添加配置jwt: secret: my-secret-key expiration: 3600 # 单位:秒四、编写 JWT 工具类创建 JwtUtils,用于生成和验证 Token:package com.example.jwt.utils; import com.example.jwt.config.JwtProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.stereotype.Component; import java.util.Date; @Component public class JwtUtils { private final JwtProperties jwtProperties; public JwtUtils(JwtProperties jwtProperties) { this.jwtProperties = jwtProperties; } // 生成 JWT public String generateToken(String username) { return Jwts.builder() .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 1000)) .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecret()) .compact(); } // 验证 JWT public Claims validateToken(String token) { try { return Jwts.parser() .setSigningKey(jwtProperties.getSecret()) .parseClaimsJws(token) .getBody(); } catch (Exception e) { return null; // Token 无效 } } }五、实现登录接口1. 控制器 AuthControllerpackage com.example.jwt.controller; import com.example.jwt.utils.JwtUtils; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/auth") public class AuthController { private final JwtUtils jwtUtils; public AuthController(JwtUtils jwtUtils) { this.jwtUtils = jwtUtils; } // 登录接口 @PostMapping("/login") public Map<String, String> login(@RequestBody Map<String, String> request) { String username = request.get("username"); // 简单验证用户(实际中应使用数据库或其他认证机制) if ("admin".equals(username)) { String token = jwtUtils.generateToken(username); Map<String, String> response = new HashMap<>(); response.put("token", token); return response; } else { throw new RuntimeException("Invalid username or password"); } } }2. 测试接口使用 curl 测试登录接口:curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin"}'返回结果:{ "token": "eyJhbGciOiJIUzI1NiIsInR..." }六、实现简单的认证拦截器为了验证 Token 是否有效,我们可以使用拦截器来处理请求。1. 创建拦截器 JwtInterceptorpackage com.example.jwt.interceptor; import com.example.jwt.utils.JwtUtils; import io.jsonwebtoken.Claims; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class JwtInterceptor implements HandlerInterceptor { private final JwtUtils jwtUtils; public JwtInterceptor(JwtUtils jwtUtils) { this.jwtUtils = jwtUtils; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); // 去掉 "Bearer " Claims claims = jwtUtils.validateToken(token); if (claims != null) { // 将用户名放入请求属性中 request.setAttribute("username", claims.getSubject()); return true; } } response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("Unauthorized"); return false; } }2. 注册拦截器package com.example.jwt.config; import com.example.jwt.interceptor.JwtInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { private final JwtInterceptor jwtInterceptor; public WebConfig(JwtInterceptor jwtInterceptor) { this.jwtInterceptor = jwtInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") .excludePathPatterns("/auth/login"); // 登录接口不拦截 } }七、验证拦截功能添加受保护接口package com.example.jwt.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/user/info") public String getUserInfo(@RequestAttribute("username") String username) { return "Hello, " + username; } }测试接口访问受保护接口(无 Token):curl http://localhost:8080/user/info返回结果:Unauthorized携带 Token 访问:curl http://localhost:8080/user/info \ -H "Authorization: Bearer <your-jwt-token>"返回结果:Hello, admin
2024年12月04日
11 阅读
0 评论
1 点赞
基于 Maven 多模块的 SpringCloud 微服务架构实战
随着微服务架构的普及,越来越多的项目开始采用分布式服务模式。在本文中,我们基于 SpringCloud Alibaba 构建一套简单但功能齐全的微服务架构。技术栈包括 Nacos、OpenFeign、SpringCloud Gateway、OkHttp 等,架构基于 Maven 的多模块项目管理方式。目标架构本项目采用多模块 Maven 项目管理,结构如下:springcloud-demo ├── pom.xml # 父 POM ├── gateway-service # 网关服务模块 ├── service-a # 服务 A 模块 ├── service-b # 服务 B 模块 └── nacos-server # Nacos 配置说明功能概览服务注册与发现:Nacos 作为服务注册中心,实现动态服务注册与发现。服务通信:使用 OpenFeign 实现跨服务的 HTTP 调用,支持负载均衡。统一网关:通过 SpringCloud Gateway 实现统一入口和路由管理。连接池优化:结合 OkHttp 提高 OpenFeign 的网络连接效率。配置管理:通过 Nacos 实现动态的集中配置管理。技术栈解析1. Nacos作用:作为服务注册与配置中心,支持动态服务发现和配置热更新。使用场景:服务注册发现、集中化配置管理。2. OpenFeign作用:基于声明式的 REST 客户端,简化服务间调用。优势:自动负载均衡,支持多种序列化方式和超时配置。3. SpringCloud Gateway作用:提供统一网关入口,支持路由转发、限流、熔断等功能。优势:对微服务访问统一管理,提升扩展性与安全性。4. OkHttp作用:为 OpenFeign 提供底层连接池支持,提高网络通信效率。优势:轻量高效,支持连接复用。父项目 POM 配置在父项目的 pom.xml 中,定义公共依赖和子模块:<modules> <module>gateway-service</module> <module>service-a</module> <module>service-b</module> </modules> <dependencyManagement> <dependencies> <!-- SpringCloud Alibaba 依赖管理 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2021.0.5.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- Spring Boot 基础依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- Nacos 服务发现 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- OpenFeign 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- SpringCloud Gateway 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies>各子模块实现1. Nacos 配置从 Nacos 官方 下载,启动命令:# 单机模式 sh startup.sh -m standaloneNacos 默认端口为 8848,访问 http://localhost:8848/nacos 查看管理界面,默认用户名和密码均为 nacos。2. Service A功能:提供简单的 REST 接口。依赖:Nacos 服务注册。application.ymlserver: port: 8081 spring: application: name: service-a cloud: nacos: discovery: server-addr: 127.0.0.1:8848Controller 示例@RestController @RequestMapping("/service-a") public class ServiceAController { @GetMapping("/hello") public String hello() { return "Hello from Service A"; } }3. Service B功能:调用 Service A 的接口。依赖:OpenFeign,Nacos 服务注册。application.ymlserver: port: 8082 spring: application: name: service-b cloud: nacos: discovery: server-addr: 127.0.0.1:8848Feign Client@FeignClient(name = "service-a") public interface ServiceAFeignClient { @GetMapping("/service-a/hello") String callServiceA(); }Controller 示例@RestController @RequestMapping("/service-b") public class ServiceBController { @Autowired private ServiceAFeignClient serviceAFeignClient; @GetMapping("/call") public String call() { return serviceAFeignClient.callServiceA(); } }4. Gateway 服务功能:通过网关统一路由到服务 A 和服务 B。依赖:SpringCloud Gateway,Nacos 服务注册。application.ymlserver: port: 8080 spring: application: name: gateway-service cloud: gateway: routes: - id: service-a-route uri: lb://service-a predicates: - Path=/service-a/** - id: service-b-route uri: lb://service-b predicates: - Path=/service-b/** nacos: discovery: server-addr: 127.0.0.1:8848配置 OkHttp 连接池为 OpenFeign 配置 OkHttp 优化性能: FeignConfig@Configuration public class FeignConfig { @Bean public OkHttpClient okHttpClient() { return new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .build(); } @Bean public OkHttpFeignClient feignClient(OkHttpClient okHttpClient) { return new OkHttpFeignClient(okHttpClient); } }在 service-b 的 Feign Client 中即可使用配置的 OkHttp 连接池。测试流程启动 Nacos:确保 Nacos 服务运行在 8848 端口。启动各服务:按照顺序启动 gateway-service、service-a、service-b。访问接口:通过 Gateway 访问服务:http://localhost:8080/service-a/hello 返回 Hello from Service A。http://localhost:8080/service-b/call 通过 Feign 调用 Service A。
2024年12月04日
18 阅读
0 评论
2 点赞
RabbitMQ 消息队列详解及 Spring Boot 实战教程
2024年11月26日
29 阅读
0 评论
3 点赞
2024-11-26
RabbitMQ 是一个高效、可靠的消息代理中间件,广泛应用于分布式系统中,用于实现微服务之间的异步通信和解耦。一、RabbitMQ 基本概念1.1 核心概念队列(Queue):存储消息的容器,消息由生产者发送到队列,消费者从队列中取出进行处理。支持点对点(P2P)模式。交换机(Exchange):负责根据路由规则将消息分发到队列。常见交换机类型:Direct、Fanout、Topic。绑定(Binding):连接交换机和队列的规则,结合路由键(Routing Key)定义消息的路由方式。消息模型:点对点模式(P2P): 一条消息只能被一个消费者消费。发布订阅模式(Pub/Sub): 一条消息可以被多个消费者消费。二、三种交换机详解2.1 Direct 交换机路由方式: 消息根据路由键(Routing Key)精准匹配到指定队列。优点: 简单、高效,适用于明确路由需求的场景。缺点: 需要为每个队列绑定具体的路由键,维护成本较高。应用场景: 点对点通知,如订单支付成功通知。2.2 Fanout 交换机路由方式: 广播消息到所有绑定队列,无需路由键。优点: 适合广播场景,无需复杂路由配置。缺点: 不支持消息过滤,容易造成资源浪费。应用场景: 全网公告或系统事件通知。2.3 Topic 交换机路由方式: 根据通配符模糊匹配路由键。* 匹配一个单词,# 匹配零个或多个单词。优点: 灵活的路由规则,支持复杂消息分发需求。缺点: 配置复杂,性能略低于其他类型交换机。应用场景: 新闻分类推送或订阅系统。三、Spring Boot 与 RabbitMQ 整合3.1 项目依赖在 pom.xml 文件中添加 RabbitMQ 依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>3.2 RabbitMQ 配置两种方式方法一:使用 application.yml 配置在 application.yml 文件中配置 RabbitMQ:spring: rabbitmq: host: localhost port: 5672 username: guest password: guest方法二:通过配置类创建连接工厂import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQFactoryConfig { @Bean public ConnectionFactory connectionFactory() { CachingConnectionFactory factory = new CachingConnectionFactory(); factory.setHost("localhost"); factory.setPort(5672); factory.setUsername("guest"); factory.setPassword("guest"); return factory; } }3.3 交换机、队列及绑定的两种创建方式方法一:直接使用 new 创建import org.springframework.amqp.core.*; @Configuration public class RabbitMQDirectConfig { @Bean public Queue directQueue() { return new Queue("direct.queue"); } @Bean public DirectExchange directExchange() { return new DirectExchange("direct.exchange"); } @Bean public Binding bindingDirect(Queue directQueue, DirectExchange directExchange) { return BindingBuilder.bind(directQueue).to(directExchange).with("direct.key"); } }方法二:通过工厂类创建import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQFactoryConfig { @Bean public Queue fanoutQueue() { return QueueBuilder.durable("fanout.queue").build(); } @Bean public FanoutExchange fanoutExchange() { return ExchangeBuilder.fanoutExchange("fanout.exchange").durable(true).build(); } @Bean public Binding bindingFanout(Queue fanoutQueue, FanoutExchange fanoutExchange) { return BindingBuilder.bind(fanoutQueue).to(fanoutExchange); } }3.4 消息生产者与消费者消息生产者import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Component; @Component public class MessageProducer { private final RabbitTemplate rabbitTemplate; public MessageProducer(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } public void sendDirectMessage(String message) { rabbitTemplate.convertAndSend("direct.exchange", "direct.key", message); } public void sendFanoutMessage(String message) { rabbitTemplate.convertAndSend("fanout.exchange", "", message); } public void sendTopicMessage(String message) { rabbitTemplate.convertAndSend("topic.exchange", "topic.test", message); } }消息消费者import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class MessageConsumer { @RabbitListener(queues = "direct.queue") public void receiveDirectMessage(String message) { System.out.println("Received Direct Message: " + message); } @RabbitListener(queues = "fanout.queue") public void receiveFanoutMessage(String message) { System.out.println("Received Fanout Message: " + message); } }3.5 单元测试使用 JUnit 测试消息发送功能:import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class RabbitMQTest { @Autowired private MessageProducer messageProducer; @Test public void testDirectMessage() { messageProducer.sendDirectMessage("Test Direct Exchange"); } @Test public void testFanoutMessage() { messageProducer.sendFanoutMessage("Test Fanout Exchange"); } }四、总结本文通过介绍 RabbitMQ 的核心概念,分析了三种交换机的优缺点及适用场景,并通过 Spring Boot 实现了 MQ 的完整配置与消息生产、消费功能。提供的两种实现方式(application.yml 配置和配置类方式,以及直接 new 和工厂创建方式)为不同项目需求提供了灵活选择。
Vue 3 和 WebRTC 实现点对点聊天应用
使用 Vue 3 和 WebRTC 来实现一个简单的点对点聊天应用,服务端使用 WebSocket (ws) 来建立信令服务器,用于连接和交换 WebRTC 所需的 SDP 和 ICE 候选信息。1. 项目初始化首先,我们创建一个基于 Vue 3 的项目:npm init vue@latest webrtc-chat cd webrtc-chat npm install然后,安装 WebSocket 依赖:npm install ws2. 创建 WebSocket 信令服务器我们使用 Node.js 和 ws 模块来创建信令服务器:// server.js const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', (ws) => { ws.on('message', (message) => { // 将消息广播给其他客户端 wss.clients.forEach((client) => { if (client !== ws && client.readyState === WebSocket.OPEN) { client.send(message); } }); }); // 向新连接的客户端发送欢迎消息 ws.send(JSON.stringify({ type: 'welcome', message: 'Connected to WebSocket server' })); }); console.log('WebSocket server is running on ws://localhost:8080');运行服务器:node server.js3. 创建 Vue 3 应用在 src 文件夹中创建 components/Chat.vue 组件。<template> <div> <h2>点对点聊天</h2> <textarea v-model="message" placeholder="输入消息..."></textarea> <button @click="sendMessage">发送</button> <button @click="createOffer">发送 Offer</button> <div v-for="(msg, index) in messages" :key="index">{{ msg }}</div> </div> </template> <script> export default { data() { return { message: '', messages: [], peerConnection: null, dataChannel: null, ws: null }; }, mounted() { this.initializeWebSocket(); // 初始化 WebSocket this.initializePeerConnection(); // 初始化 PeerConnection }, methods: { // 初始化 WebSocket 连接 initializeWebSocket() { this.ws = new WebSocket('ws://localhost:8080'); // 接收来自信令服务器的消息 this.ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'offer') { this.handleOffer(data); // 处理接收到的 Offer } else if (data.type === 'answer') { this.handleAnswer(data); // 处理接收到的 Answer } else if (data.type === 'candidate') { this.addIceCandidate(data); // 添加接收到的 ICE 候选 } }; }, // 初始化 PeerConnection 和数据通道 initializePeerConnection() { this.peerConnection = new RTCPeerConnection(); // 监听 ICE 候选事件 this.peerConnection.onicecandidate = (event) => { if (event.candidate) { this.ws.send(JSON.stringify({ type: 'candidate', candidate: event.candidate })); // 将 ICE 候选发送到信令服务器 } }; // 创建数据通道 this.dataChannel = this.peerConnection.createDataChannel('chat'); this.dataChannel.onmessage = (event) => { this.messages.push(`Peer: ${event.data}`); // 接收消息并更新聊天记录 }; // 监听远程数据通道 this.peerConnection.ondatachannel = (event) => { this.dataChannel = event.channel; this.dataChannel.onmessage = (event) => { this.messages.push(`Peer: ${event.data}`); }; }; }, // 创建并发送 Offer async createOffer() { const offer = await this.peerConnection.createOffer(); await this.peerConnection.setLocalDescription(offer); this.ws.send(JSON.stringify({ type: 'offer', sdp: offer })); // 发送 Offer }, // 处理接收到的 Offer async handleOffer(data) { await this.peerConnection.setRemoteDescription(new RTCSessionDescription(data.sdp)); const answer = await this.peerConnection.createAnswer(); await this.peerConnection.setLocalDescription(answer); this.ws.send(JSON.stringify({ type: 'answer', sdp: answer })); // 发送 Answer }, // 处理接收到的 Answer async handleAnswer(data) { await this.peerConnection.setRemoteDescription(new RTCSessionDescription(data.sdp)); }, // 添加接收到的 ICE 候选 async addIceCandidate(data) { if (data.candidate) { await this.peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate)); } }, // 发送消息 sendMessage() { if (this.dataChannel && this.message) { this.dataChannel.send(this.message); // 通过数据通道发送消息 this.messages.push(`Me: ${this.message}`); // 更新本地聊天记录 this.message = ''; // 清空输入框 } } } }; </script> <style> textarea { width: 100%; height: 100px; margin-bottom: 10px; } button { display: block; margin-bottom: 10px; } </style>4. 启动应用运行以下命令以启动 Vue 应用:npm run dev打开浏览器开两个窗口访问 http://localhost:3000,点击发送offer即可进行实时的点对点聊天。
2024年11月15日
50 阅读
0 评论
3 点赞
1
2
3
...
19