从零开始,手把手教你实现基于 Websocket 的微服务

这篇具有很好参考价值的文章主要介绍了从零开始,手把手教你实现基于 Websocket 的微服务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

从零开始,手把手教你实现基于 Websocket 的微服务

1. Websocket 简介

Websocket 协议是为了解决 HTTP 协议缺陷而产生的一种通信协议,它能够在客户端和服务器之间建立持久性的连接,并且允许双向通信。

HTTP 协议的请求与响应模式,其实并不适合实时通信的场景。比如聊天室、在线游戏等应用,都需要实时地推送消息到客户端,而 HTTP 协议则需要进行频繁的请求和响应操作,这就会导致网络延迟和更多的带宽消耗。

而 Websocket 则是允许服务器主动向客户端发送消息,而不需要客户端发起请求,从而提高了通信效率和实时性。因此,在微服务架构中,Websocket 技术非常适合作为微服务之间的通信方式。

2. 构建基于 Websocket 的微服务应用

2.1 准备工作

首先需要在项目中引入 Spring Boot 的 Websocket 模块依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

然后创建一个 Spring Boot 的 Web 应用,并在启动类中添加 @EnableWebSocket 注解。

2.2 编写服务端代码

在服务端,需要定义一个 WebsocketConfig 类,并实现 WebSocketConfigurer 接口。在这个类中,可以自定义 Websocket 消息处理器,并注册到 Websocket 服务中。

@Configuration
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*");
    }

    private static class MyWebSocketHandler extends TextWebSocketHandler {

        private final List<WebSocketSession> sessions = new ArrayList<>();

        @Override
        public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
            for (WebSocketSession s : sessions) {
                s.sendMessage(message);
            }
        }

        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            sessions.add(session);
        }

        @Override
        public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
            sessions.remove(session);
        }
    }
}

上述代码中,MyWebSocketHandler 是自定义的消息处理器,可以处理客户端发送来的消息,并将消息发送给所有连接的客户端。其中,afterConnectionEstablished() 方法会在客户端和服务器之间建立连接时被调用,afterConnectionClosed() 方法则会在连接关闭时调用。

2.3 编写客户端代码

在客户端,需要构建一个基于 Websocket 的连接,并向服务端发送消息。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Websocket Demo</title>
</head>
<body>
    <div id="output"></div>
    <input type="text" id="input">
    <button onclick="sendMessage()">Send</button>

    <script>
        const socket = new WebSocket("ws://localhost:8080/ws");

        socket.onmessage = function(event) {
            const output = document.getElementById("output");
            const message = event.data;
            output.innerHTML += "<p>" + message + "</p>";
        }

        function sendMessage() {
            const input = document.getElementById("input");
            const message = input.value;
            socket.send(message);
        }
    </script>
</body>
</html>

上述代码中,WebSocket() 构造函数中的 ws://localhost:8080/ws 是服务端的 Websocket 地址。在发送消息时,则是调用 socket.send() 方法向服务端发送消息。而在收到服务端的消息时,则会触发 socket.onmessage() 回调函数,并将消息展示在网页中。

3. 技术实践案例:基于 Websocket 的在线聊天室

3.1 界面设计

本案例采用前后端分离的方式,使用 React 框架构建客户端界面

3.2 服务端实现

3.2.1 WebSocket 配置

创建一个 WebSocketConfig 类,并实现 WebSocketConfigurer 接口。在这个类中,注册自定义的 Websocket 消息处理器,并设置允许跨域请求。

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new ChatWebSocketHandler(), "/chat")
                .setAllowedOrigins("*")
                .addInterceptors(new HttpSessionHandshakeInterceptor());
    }

    private static class ChatWebSocketHandler extends TextWebSocketHandler {

        private final List<WebSocketSession> sessions = new ArrayList<>();

        @Override
        public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
            for (WebSocketSession s : sessions) {
                if (s != session) {
                    s.sendMessage(message);
                }
            }
        }

        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            sessions.add(session);
        }

        @Override
        public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
            sessions.remove(session);
        }
    }
}

上述代码中,ChatWebSocketHandler 是自定义的消息处理器,其中 handleTextMessage() 方法实现了用户发送消息到服务端,并将消息发送给所有连接的客户端。而 afterConnectionEstablished() 和 afterConnectionClosed() 方法则分别在建立连接和关闭连接时被调用。

3.2.2 Spring Security 配置

为了保证聊天室的安全性,需要对聊天室进行认证和授权。使用 Spring Security 可以方便地实现这个功能。

首先,需要添加 Spring Security 的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后创建一个 SecurityConfig 类,用于配置 Spring Security。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/chat")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER");
    }
}

上述代码中,configure() 方法用于配置 Spring Security 的认证和授权规则。其中,“/login” 路径不需要认证就可以访问,“/chat” 路径则需要进行认证才能访问。同时,使用 inMemoryAuthentication() 方法可以在内存中定义用户和角色。

3.2.3 Controller 实现

在 Controller 中,需要分别对登录和聊天功能进行处理。

@Controller
public class ChatController {

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @GetMapping("/chat")
    public String chat() {
        return "chat";
    }
}

3.3 客户端实现

客户端使用 React 框架构建,并使用 axios 库进行网络请求。具体代码如下:

import React, { Component } from "react";
import axios from "axios";

class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      username: "",
      password: "",
    };
  }

  handleUsernameChange = (event) => {
    this.setState({ username: event.target.value });
  };

  handlePasswordChange = (event) => {
    this.setState({ password: event.target.value });
  };

  handleSubmit = (event) => {
    event.preventDefault();

    const { username, password } = this.state;

    axios
      .post("/login", { username, password })
      .then((res) => {
        this.props.history.push("/chat");
      })
      .catch((error) => {
        console.log(error);
      });
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Username:
          <input
            type="text"
            value={this.state.username}
            onChange={this.handleUsernameChange}
          />
        </label>
        <br />
        <label>
          Password:
          <input
            type="password"
            value={this.state.password}
            onChange={this.handlePasswordChange}
          />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

export default Login;
import React, { Component } from "react";
import axios from "axios";

class Chat extends Component {
  constructor(props) {
    super(props);
    this.state = {
      message: "",
      messages: [],
    };
  }

  componentDidMount() {
    const socket = new WebSocket("ws://localhost:8080/chat");

    socket.onmessage = (event) => {
      const message = event.data;
      this.setState((prevState) => ({
        messages: [...prevState.messages, message],
      }));
    };

    this.socket = socket;
  }

  componentWillUnmount() {
    this.socket.close();
  }

  handleMessageChange = (event) => {
    this.setState({ message: event.target.value });
  };

  handleSubmit = (event) => {
    event.preventDefault();

    const message = this.state.message;
    this.socket.send(message);

    this.setState({ message: "" });
  };

  render() {
    return (
      <div>
        <ul>
          {this.state.messages.map((message, index) => (
            <li key={index}>{message}</li>
          ))}
        </ul>
        <form onSubmit={this.handleSubmit}>
          <input
            type="text"
            value={this.state.message}
            onChange={this.handleMessageChange}
          />
          <button type="submit">Send</button>
        </form>
      </div>
    );
  }
}

export default Chat;

4. 总结

本文介绍了 Websocket 协议在微服务架构中的应用,并以基于 Websocket 的在线聊天室为例,详细介绍了服务端和客户端的实现方式。通过使用 Spring Boot 和 React 等流行的框架,可以方便地构建高效稳定的基于 Websocket 的微服务应用。文章来源地址https://www.toymoban.com/news/detail-677809.html

到了这里,关于从零开始,手把手教你实现基于 Websocket 的微服务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 应用实践|基于Python手把手教你实现雪花算法

    📫 作者简介:「六月暴雪飞梨花」,专注于研究Java,就职于科技型公司后端工程师 🏆 近期荣誉:华为云云享专家、阿里云专家博主、 🔥 三连支持:欢迎 ❤️关注、👍点赞、👉收藏三连,支持一下博主~ 分布式策略ID的主要应用在互联网网站、搜索引擎、社交媒体、在线

    2024年02月21日
    浏览(56)
  • pytorch实战7:手把手教你基于pytorch实现VGG16

    前言 ​ 最近在看经典的卷积网络架构,打算自己尝试复现一下,在此系列文章中,会参考很多文章,有些已经忘记了出处,所以就不贴链接了,希望大家理解。 ​ 完整的代码在最后。 本系列必须的基础 ​ python基础知识、CNN原理知识、pytorch基础知识 本系列的目的 ​ 一是

    2023年04月19日
    浏览(38)
  • 手把手教你基于【SpringBoot+MyBatis】实现员工管理系统‍【附完整源码】

    Hello,你好呀,我是 灰小猿 ,一个超会写 BUG 的程序猿🙊! 近期在学习springboot框架相关的内容,相比于SSM, SpringBoot最大的特点就是集成了Spring和SpringMVC,让之前繁琐的配置工作变得更加简洁, 同时对于业务逻辑层的处理也更加的友好, 所以今天就使用 SpringBoot整合MyBati

    2023年04月08日
    浏览(33)
  • 手把手教你实现—基于OpenCV的车流量统计和车速检测代码

             本章将实现了一个简单的车辆速度估计和车流量统计的GUI应用,它使用了Haar级联检测器和相关跟踪器来检测和跟踪视频中的车辆,并通过图像处理和数学计算来估计车辆的速度。         1.首先,该代码需要cv2:用于图像处理和计算机视觉任务;dlib:用于对象

    2024年02月04日
    浏览(34)
  • 手把手教你从0开始在服务器上部署stable diffusion

    验证是否有nvidia驱动 如果没有显示出显卡信息(如下) 则需要参考 ubuntu安装nvidia驱动 https://blog.csdn.net/Perfect886/article/details/119109380 远程连接服务器工具:VS Code https://code.visualstudio.com/Download VS Code 插件:Remote 文件传输工具 FileZilla https://www.filezilla.cn/download 下载地址: https:

    2024年02月06日
    浏览(35)
  • Swagger:手把手教你从0开始配置idea中swagger,全步骤配图文版。

    Swagger 是一组用于设计、构建、文档化和使用 RESTful Web 服务的开源工具和框架。它允许开发团队设计、构建和测试 API,并提供易于理解的文档,以便开发人员和消费者能够快速了解和使用 API。Swagger 通常与各种编程语言和框架一起使用,以简化 API 的开发和维护过程。 1.文件

    2024年02月04日
    浏览(42)
  • 基于python+opencv的人脸识别打卡(手把手教你)

    2.1新建members.csv文件 文件内容依次是id,First_name,Last_name,如图: 2.2新建face文件夹 里面存放采集的人脸信息,用于训练 2.3注意事项 脸部识别特征模块 Path路径为你创建环境下的cv2包中haarcascade_frontalface_default.xml对应的地址 只加了opencv中脸部特征,没加眼部识别。(cv2包中还有眼

    2024年02月02日
    浏览(34)
  • 手把手教你安装RabbitMQ(基于CentOS7系统)

    RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。 可靠性 灵活的路由 消息集群 高可用 插件机制 多种协议 多语言客户端 管理界面 跟踪机制 先安装一些必要的依赖

    2023年04月08日
    浏览(30)
  • 手把手教你本地CPU环境部署清华大模型ChatGLM-6B,利用量化模型,本地即可开始智能聊天,达到ChatGPT的80%

    大家好,我是微学AI,今天教你们本地CPU环境部署清华大ChatGLM-6B模型,利用量化模型,每个人都能跑动大模型。ChatGLM-6B是一款出色的中英双语对话模型,拥有超过62亿个参数,可高效地处理日常对话场景。与GLM-130B模型相比,ChatGLM-6B在对话场景处理能力方面表现更加卓越。此

    2024年02月01日
    浏览(32)
  • 手把手教你实现SpringBoot的监控!

    任何一个服务如果没有监控,那就是两眼一抹黑,无法知道当前服务的运行情况,也就无法对可能出现的异常状况进行很好的处理,所以对任意一个服务来说,监控都是必不可少的。 就目前而言,大部分微服务应用都是基于 SpringBoot 来构建,所以了解 SpringBoot 的监控特性是非

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包