WebSocket Day 01:入门案例

前言

欢迎来到WebSocket入门案例系列的第一天!在今天的博客中,我们将一起探索WebSocket的基础知识和使用方法。本系列将以一个简单的入门案例为基础,带领您逐步了解WebSocket的原理和用法。

一、什么是 WebSocket ?

WebSocket是一种在Web应用程序中实现实时双向通信的协议。它提供了一种持久连接,允许服务器主动向客户端推送数据,而不需要客户端发起请求。

传统的Web应用程序使用HTTP协议进行通信,这种通信方式是基于请求-响应模式的。客户端发送请求给服务器,服务器响应请求并返回相应的数据。但是这种方式存在一些限制,特别是对于实时性要求较高的应用场景,如聊天室、股票行情等。

WebSocket通过引入新的协议,提供了一种更高效、更低延迟的通信方式。相对于HTTP,WebSocket具有以下特点:

  1. 双向通信:WebSocket允许客户端和服务器之间进行双向通信,服务器可以主动向客户端推送数据,而不仅仅是响应客户端的请求。这使得实时性要求较高的应用程序能够更加高效地进行数据传输。

  2. 持久连接:WebSocket在建立连接后,保持持久的连接状态,而不需要每次通信都重新建立连接。这消除了每次请求建立连接和断开连接的开销,减少了网络流量和延迟。

  3. 低开销:相对于传统的HTTP请求-响应模式,WebSocket协议的数据帧头部较小,有效减少了通信过程中的数据开销。此外,由于使用持久连接,减少了连接建立和断开的开销。

  4. 兼容性:WebSocket协议基于TCP协议,通过HTTP/HTTPS进行握手协商,并在握手成功后升级为WebSocket连接。由于握手过程使用标准的HTTP/HTTPS协议,因此WebSocket可以通过大多数防火墙和代理服务器。

WebSocket在现代Web应用程序中被广泛应用,特别是对于需要实时通信和即时更新的应用场景。它为开发者提供了一种更加便捷、高效的方式来构建实时性强的Web应用程序。无论是聊天应用、实时博客评论、多人协作工具还是股票行情等都可以借助WebSocket实现更好的用户体验和数据交互。

二、为什么要使用 WebSocket 

WebSocket作为一种实现实时双向通信的协议,具有以下优点,这也是为什么要使用WebSocket的原因:

  1. 实时双向通信:传统的Web应用程序都是基于HTTP协议进行请求和响应的,无法实现实时双向通信。而WebSocket协议可以在客户端和服务器之间建立持久连接,实现实时双向通信,从而满足实时性比较强的应用场景。

  2. 低延迟:与HTTP协议相比,WebSocket协议的数据帧头部较小,有效减少了通信过程中的数据开销。由于使用持久连接,减少了连接建立和断开的开销,降低了延迟,提高了应用程序的响应速度和用户体验。

  3. 更好的扩展性:WebSocket协议采用标准的TCP协议,通过HTTP/HTTPS进行握手协商,并在握手成功后升级为WebSocket连接。由于握手过程使用标准的HTTP/HTTPS协议,WebSocket可以通过大多数防火墙和代理服务器。这使得应用程序更容易部署和扩展。

  4. 更低的网络流量:由于WebSocket协议使用二进制帧传输数据,相对于HTTP协议使用文本格式传输数据,WebSocket可以减少网络流量,提高应用程序的效率和性能。

总之,WebSocket协议提供了一种更高效、更低延迟、更实时、更灵活的通信方式,使得实时性较强的应用场景(如聊天室、在线游戏、多人协作工具等)更容易实现。如果您需要构建这些类型的应用程序,那么WebSocket将是您不错的选择。

三、实现一个单的 Hello WebSocket

1、新建项目,结构如下

2、导入依赖
<!-- websocket 依赖 -->
        <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- 打印日志 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.3.8</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>

 下面是每个依赖项的作用:

  1. javax.websocket-api:这是一个Java API,用于支持WebSocket通信协议。WebSocket允许在客户端和服务器之间进行双向通信,实时地发送消息和数据。这个依赖项提供了WebSocket的核心接口和类。

  2. logback-classic:这是一个Java日志框架,用于在应用程序中记录和输出日志信息。logback-classic是logback框架的核心组件,它提供了强大的日志记录功能和灵活的配置选项。

  3. lombok:这是一个Java库,通过注解自动化简化了Java代码的编写。使用lombok可以减少样板代码,例如自动生成getter、setter、构造函数等。它提供了一些注解来简化代码的编写和维护,提高开发效率。

3、 编写 controller 类
@ServerEndpoint("/connect")
@Slf4j
public class WebSocketServer {


    /**
     * 打开连接的方法,当有一个客户端连接服务端的时候
     * 这个方法就会调用一次
     *
     * @OnOpen注解:表示连接
     *
      */
    @OnOpen
    public void onOpen(){
        log.info("客户端已连接" );
    }

    /**
     * 客户端发送消息的方法
     */
    @OnMessage
    public void onMessage(String message,Session session) throws IOException {
        log.info("消息:" + message);
        // 向当前客户端发送一个消息
         session.getBasicRemote().sendText(message);

    }

    /**
     * 当客户端断开连接后调用此方法
     */
    @OnClose
    public void onClose(Session session){
        log.info("客户端已断开连接");
    }

}

 在给出每个注解的用途之前,需要说明这段代码是Java中使用WebSocket的示例代码,使用了javax.websocket包提供的注解。

  1. @ServerEndpoint("/connect"):

    • 作用:将Java类标记为WebSocket服务器端点。
    • 解释:这个注解用于标识一个类是WebSocket的服务器端点,指定了客户端连接的URL路径。在上述示例中,客户端需要通过连接至"/connect"路径来与该服务器端点进行通信。
  2. @OnOpen:

    • 作用:定义打开连接时调用的方法。
    • 解释:当有客户端连接到WebSocket服务器端点时,被该注解标记的方法将会被调用。在示例中,onOpen()方法在客户端连接成功后执行,并打印出连接成功的消息。
  3. @OnMessage:

    • 作用:定义接收客户端消息时调用的方法。
    • 解释:当WebSocket服务器端点接收到客户端发送的消息时,被该注解标记的方法将会被调用。在示例中,onMessage()方法接收两个参数:String类型的message表示接收到的消息内容,Session类型的session表示与该客户端的会话。该方法在接收到消息后,会将消息原样发送回客户端。
  4. @OnClose:

    • 作用:定义客户端断开连接时调用的方法。
    • 解释:当与WebSocket服务器端点建立连接的客户端断开连接时,被该注解标记的方法将会被调用。在示例中,onClose()方法接收一个参数:Session类型的session,表示与断开连接的客户端的会话。该方法在客户端断开连接后执行,并打印出断开连接的消息。

这些注解是Java WebSocket API提供的一部分,通过使用这些注解,可以方便地定义WebSocket服务器端点的行为,包括连接建立、消息接收和断开连接等操作。

这个类是一个示例的WebSocket服务器端点类,用于处理客户端与服务器之间的WebSocket通信。主要功能如下:

  1. 打开连接:当有客户端连接到WebSocket服务器端点时,会调用onOpen()方法,并打印出连接成功的消息。

  2. 接收消息:当WebSocket服务器端点接收到客户端发送的消息时,会调用onMessage()方法,并打印出接收到的消息。同时,该方法会将接收到的消息原样发送回客户端。

  3. 断开连接:当与WebSocket服务器端点建立连接的客户端断开连接时,会调用onClose()方法,并打印出断开连接的消息。

这个类是使用了Java WebSocket API提供的注解来定义WebSocket服务器端点的行为。通过这些注解,可以方便地处理WebSocket的连接、消息接收和断开连接等操作。

4、编写一个 html 页面接收数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>websocket 客户端</h1>

<script>
    // 构建 websocket 的实例,连接后台 server 的请求地址
    // websocket 在第一次请求时使用 http 协议在连接服务器,告诉服务器
    // 接下来要使用 websocket 进行通信,此时服务器将进行协议升级,会在
    // http 的请求头中带有 upgrade:websocket 的头信息
    var webSocket = new WebSocket("ws://localhost:8080/connect");

    // onopen 方法
    webSocket.onopen = function () {
        // 发送一个消息
        webSocket.send("hello websocket");
    }

    // onmessage 方法,接受服务端发送的信息
    webSocket.onmessage = function (event) {
        alert("服务器的消息:" + event.data);
    }

    // onclose 方法
    webSocket.onclose = function () {
        alert("已断开连接");
    }


</script>

</body>
</html>

这段代码是一个简单的WebSocket客户端示例,用于与WebSocket服务器进行通信。它的作用是:

  1. 创建WebSocket实例:通过var webSocket = new WebSocket("ws://localhost:8080/connect");语句创建了一个WebSocket实例,并指定了连接的服务器地址。

  2. 连接建立:当WebSocket连接成功建立时,会自动触发onopen事件处理函数,其中的webSocket.onopen定义了连接建立时的操作。在示例中,onopen函数中发送了一条消息webSocket.send("hello websocket");到服务器。

  3. 接收消息:当WebSocket客户端接收到来自服务器端的消息时,会触发onmessage事件处理函数,其中的webSocket.onmessage定义了接收消息时的操作。在示例中,当接收到消息时,会通过弹窗的方式显示服务器端发送的消息。

  4. 断开连接:当WebSocket连接关闭时,会触发onclose事件处理函数,其中的webSocket.onclose定义了连接关闭时的操作。在示例中,当连接关闭时,会通过弹窗的方式提示连接已断开。

这段代码展示了一个最基本的WebSocket客户端的工作流程,包括连接建立、消息发送和接收、连接断开等操作。您可以将其用于与WebSocket服务器进行实时通信,实现双向数据传输的功能。根据具体需求,您可以根据这个示例进行定制和扩展,添加更多的业务逻辑和交互功能。

 5、运行效果

我们在前端接收到了后台发送来的信息,在后台我们也接受到前端发送的信息,这就是一个简单的多对多的群聊了。

四、实现多人群聊

1、编写 controller 

@ServerEndpoint("/connect")
@Slf4j
public class WebSocketServer {

    /**
     * 用户列表
     */
    private static final List<Session> users = new ArrayList<>();

    /**
     * 打开连接的方法,当有一个客户端连接服务端的时候
     * 这个方法就会调用一次
     *
     * @OnOpen注解:表示连接
     *
     * @param session 表示一个 websocket 客户端的连接会话
     *                每一个客户端连接就会创建一个 session 会话
      */
    @OnOpen
    public void onOpen(Session session){
        log.info("客户端已连接" );
        // 将 session 添加到用户列表中
        users.add(session);
    }

    /**
     * 客户端发送消息的方法
     */
    @OnMessage
    public void onMessage(String message,Session session) throws IOException {
        log.info("消息:" + message);

        // 获取当前时间
        String formattedTime = new SimpleDateFormat("HH:mm:ss").format(new Date());

        // 向当前客户端发送一个消息,包含发送时间
        String messageWithTime = "[" + formattedTime + "] " + message;

        for (Session user : users) {
            // 群发信息
            user.getBasicRemote().sendText(messageWithTime);
        }

    }

    /**
     * 当客户端断开连接后调用此方法
     */
    @OnClose
    public void onClose(Session session){
        log.info("客户端已断开连接");
        // 用户离线
        users.remove(session);
    }

}

 解释一下每一行代码的意思:

1)、定义了一个静态的会话列表users,用于存储所有连接到WebSocket服务端的客户端Session对象。
private static final List<Session> users = new ArrayList<>();
2)、使用@OnOpen注解声明一个方法,该方法用于处理WebSocket客户端连接到服务器后的操作。当有一个新客户端连接到服务器时,该方法会被自动调用。在该方法中,首先记录下客户端连接成功的日志信息,然后将客户端的Session对象保存到静态会话列表中。
@OnOpen
public void onOpen(Session session){
    log.info("客户端已连接" );
    // 将 session 添加到用户列表中
    users.add(session);
}
3)、使用@OnMessage注解声明一个方法,该方法用于处理WebSocket客户端发送消息的操作。当客户端向服务器发送消息时,该方法会被自动调用,并传入消息内容和对应的Session对象。在该方法中,首先记录下客户端发送的消息内容,然后获取当前时间,并将时间和消息内容拼接为一个新的字符串。最后,遍历所有连接到服务器的客户端(即静态会话列表users),并将消息广播给所有客户端。
@OnMessage
public void onMessage(String message,Session session) throws IOException {
    log.info("消息:" + message);
    // 向当前客户端发送一个消息
//         session.getBasicRemote().sendText(message);

    // 获取当前时间
    String formattedTime = new SimpleDateFormat("HH:mm:ss").format(new Date());

    // 向当前客户端发送一个消息,包含发送时间
    String messageWithTime = "[" + formattedTime + "] " + message;

    for (Session user : users) {
        // 群发信息
        user.getBasicRemote().sendText(messageWithTime);
    }

}
4)使用@OnClose注解声明一个方法,该方法用于处理WebSocket客户端断开连接的操作。当有一个客户端与服务器断开连接时,该方法会被自动调用,并传入断开连接的Session对象。在该方法中,首先记录下客户端断开连接的日志信息,然后将与断开连接的客户端对应的Session对象从静态会话列表中移除。
@OnClose
public void onClose(Session session){
    log.info("客户端已断开连接");
    // 用户离线
    users.remove(session);
}
2、编写一个页面发送信息
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h1>聊天室</h1>
<div id="msg"></div>
<input id="message" type="text"/>
<input type="button" value="发送"/>
<script>
    //创建websocket对象
    let ws = new WebSocket("ws://localhost:8080/connect");
    //接收服务端的消息
    ws.onmessage = function(event){
        let message = event.data;
        //将消息放入聊天框
        $('#msg').append(message + '<br>');
    }

    $(function(){
        $(':button').on('click',function(){
            //获取文本消息
            let msg = $('#message').val();
            //发送消息
            ws.send(msg);
            //清空发送框
            $('#message').val('');
        });
    })
</script>

</body>
</html>

这段代码是一个简单的HTML页面,它实现了一个基本的聊天室功能。具体功能如下:

  1. 在页面上显示一个标题为"聊天室"的大标题。
  2. 有一个用于显示聊天消息的<div>元素,它的id属性为"msg"。
  3. 有一个<input>元素,用于输入要发送的消息,它的id属性为"message"。
  4. 有一个<input>按钮,用于发送消息,按钮上显示"发送"。
  5. 使用JavaScript和jQuery库来处理页面上的交互逻辑。

在脚本部分,代码实现了以下功能:

  1. 创建了一个WebSocket对象,通过指定WebSocket服务器的URL来建立与服务器的连接。在这个例子中,服务器的URL是"ws://localhost:8080/connect"。
  2. 设置了一个事件处理程序(ws.onmessage),当接收到来自服务器的消息时,会触发该事件,并将消息显示在聊天框中。
  3. 使用jQuery库,在页面加载完成后,绑定了按钮的点击事件处理程序。当按钮被点击时,获取输入框中的文本消息,并通过WebSocket发送给服务器。然后清空输入框,以便输入下一条消息。

通过将这段代码部署到一个能够处理WebSocket协议的服务器上,你可以创建一个简单的聊天室页面,用户可以在其中实时地发送和接收消息。当用户在输入框中输入消息并点击发送按钮时,消息将通过WebSocket发送给服务器,在服务器上处理后,会将消息广播给所有连接的客户端,以便显示在聊天框中。这样就实现了简单的聊天室功能。 

3、运行效果

 五、使用局域网 IP 地址实现多人群聊

1、使用命令查看 IP 地址

win + r 打开命令提示符,输入 cmd 回车进入。在控制面板输出 : ipconfig 回车即可查询到自己本机的 IP.

2、在 client.html 页面更改 url

只需要把 localhost 换成自己本机的 IP 地址即可。

3、运行效果

改完 url 地址后,我们在浏览器就不能使用 localhost:8080 去访问了。

使用 IP 地址后的访问路径为:http://本机IP地址:8080/chat.html 

4、什么是局域网?

局域网通常用于连接位于同一地理位置的多台计算机和设备。

注意:我们使用的是局域网的 IP 地址去和同学聊天的,如果你们使用的是同一个网络就能够正常的访问这个路径去聊天,如果不在同一网络就不能。比如:教室、学校、家里的WIFI,都可以。

 六、总结

        本次案例,我们简单的讲解了实现聊天的功能。但是,这只是一个开头,我们要实现真正的聊天还有很多其他的功能要做,比如:登录,登录成功后获取用户的名称。我们这次聊天是不知道用户名的,只有时间和内容,那么在下一章节我将要讲解如何实现登录后实现聊天。

        

七、gitee 案例

地址:ch01 · qiuqiu/WebSocket-study - 码云 - 开源中国 (gitee.com)

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

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

相关文章

数据结构之队的实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

Linux Framebuffer驱动框架、接口实现和使用

Linux 驱动-Frame Buffer代码分析 Framebufferfbmem.c部分代码分析初始化 Framebuffer 对于驱动开发人员来说&#xff0c;其实只需要针对具体的硬件平台SOC和具体的LCD&#xff08;通过焊接连接到该SOC引脚上的LCD&#xff09;来进行第一部分的寄存器编程&#xff08;红色部分&…

【音视频 | opus】opus编码的Ogg封装文件详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

项目实战之安装依赖npm install

文章目录 nvmdeasync包和node-gyp报错deasync包node-gyp报错 前言&#xff1a;有些人看着还活着其实已经凉了好一会儿了。 初拿到项目 初拿到项目肯定是先看配置 package.json的啦&#xff0c;看看都需要安装什么依赖&#xff0c;然后 npm install,OK结束 皆大欢喜。 ————…

Java字符串常用函数 详解5000字 (刷题向 / 应用向)

1.直接定义字符串 直接定义字符串是指使用双引号表示字符串中的内容&#xff0c;例如"Hello Java"、"Java 编程"等。具体方法是用字符串常量直接初始化一个 String 对象&#xff0c;示例如下&#xff1a; 1. String str"Hello Java"; 或者 …

第19期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

【C++】特殊类设计

文章目录 一、设计一个类&#xff0c;不能被拷贝二、设计一个类&#xff0c;不能被继承三、设计一个类&#xff0c;只能在栈上创建对象四、设计一个类&#xff0c;只能在堆上创建对象五、设计一个类&#xff0c;只能创建一个对象(单例模式) 在某些特殊的场景下&#xff0c;我们…

使用Gorm进行高级查询

深入探讨GORM的高级查询功能&#xff0c;轻松实现Go中的数据检索 高效的数据检索是每个应用程序性能的核心。GORM&#xff0c;强大的Go对象关系映射库&#xff0c;不仅扩展到基本的CRUD操作&#xff0c;还提供了高级的查询功能。本文是您掌握使用GORM进行高级查询的综合指南。…

【雷达原理】雷达杂波抑制方法

目录 一、杂波及其特点 1.1 什么是杂波&#xff1f; 1.2 杂波的频谱特性 二、动目标显示(MTI)技术 2.1 对消原理 2.2 数字对消器设计 三、MATLAB仿真 3.1 对消效果验证 3.2 代码 一、杂波及其特点 1.1 什么是杂波&#xff1f; 杂波是相对目标回波而言的&#xff0c;…

IDEA中如何移除未使用的import

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是全栈工…

链栈的练习

链栈练习 相关内容&#xff1a;栈的链式存储结构&#xff08;链栈&#xff09; //链栈的初始化、判空、入栈、出栈、读取栈顶元素 //链栈的结点&#xff1a;数据域、指针域 #include<stdio.h> #include<stdlib.h> typedef int Status; #define OK 1 #define ERRO…

算法通关村第五关-白银挑战队列经典问题

大家好我是苏麟 , 今天带来几道经典小题 . 大纲 两数之和 两数之和 相信大家对这道题还是很眼熟的 , 打开LeetCode第一道题就是它 , 对它可真的又爱又恨 , 很多新手朋友们想刷LeetCode但又不知道从哪开始就打开了第一题 , 结果就对算法失去了信心 . 这道题找对方法还是很容易…

2022最新版-李宏毅机器学习深度学习课程-P32 Transformer

一、 seq2seq 1. 含义 输入一个序列&#xff0c;机器输出另一个序列&#xff0c;输出序列长度由机器决定。 文本翻译&#xff1a;文本至文本&#xff1b;  语音识别&#xff1a;语音至文本&#xff1b;  语音合成&#xff1a;文本至语音&#xff1b;  聊天机器人&#…

R语言_RColorBrewer包--全平台可用

R语言_RColorBrewer包–全平台可用

微服务架构——笔记(2)

微服务架构——笔记&#xff08;2&#xff09; 一、客户客户端模块 文章来源B站视频 尚硅谷SpringCloud框架开发教程(SpringCloudAlibaba微服务分布式架构丨Spring Cloud)教程 本次笔记内容为消费者订单Module模块 1.1 项目名称、目录结构 1.2 Pom.xml <?xml version&q…

【kafka】记一次kafka基于linux的原生命令的使用

环境是linux&#xff0c;4台机器&#xff0c;版本3.6&#xff0c;kafka安装在node 1 2 3 上&#xff0c;zookeeper安装在node2 3 4上。 安装好kafka&#xff0c;进入bin目录&#xff0c;可以看到有很多sh文件&#xff0c;是我们执行命令的基础。 启动kafka&#xff0c;下面的…

【使用Python编写游戏辅助工具】第三篇:鼠标连击器的实现

前言 这里是【使用Python编写游戏辅助工具】的第三篇&#xff1a;鼠标连击器的实现。本文主要介绍使用Python来实现鼠标连击功能。 鼠标连击是指在很短的时间内多次点击鼠标按钮&#xff0c;通常是鼠标左键。当触发鼠标连击时&#xff0c;鼠标按钮会迅速按下和释放多次&#xf…

自学黑客,一般人我劝你还是算了吧!

写在开篇 笔者本人 17 年就读于一所普通的本科学校&#xff0c;20 年 6 月在三年经验的时候顺利通过校招实习面试进入大厂&#xff0c;现就职于某大厂安全联合实验室。 我为啥说自学黑客&#xff0c;一般人我还是劝你算了吧&#xff01;因为我就是那个不一般的人。 首先我谈下…

Jenkins安装(Jenkins 2.429)及安装失败解决(Jenkins 2.222.4)

敏捷开发与持续集成 敏捷开发 敏捷开发以用户的需求进化为核心&#xff0c;采用迭代、循序渐进的方法进行软件开发。在敏捷开发中&#xff0c;软件项目在构建初期被切分成多个子项目&#xff0c;各个子项目的成果都经过测试&#xff0c;具备可视、可集成和可运行使用的特征。…

【Solidity】Remix在线环境及钱包申请

好久没有学习区块链方面的知识了&#xff0c;目前通过自学大致掌握了Fabric联盟链的搭建&#xff0c;链码编写、部署&#xff0c;api调用&#xff0c;可以独立开发出一些基于fabric的应用&#xff0c;感觉开发出去中心化的应用还是很有意思的&#xff0c;因为他与之前开发的ssm…