[Project Combat] - Realize a chat program based on SpringBoot+WebScoket

1. Project introduction

Implement a simple web chat program on the basis of WebScoket based on browser and back-end SpringBoot

1.1 Project Design

  1. Requirements analysis (simple understanding of what functions and effects customer needs have)
  2. Conceptual design stage (prototype design, data design model-ER diagram)
  3. Detailed design phase (UML design diagram - use case diagram, sequence diagram)
  4. Coding stage (technical selection, basic structure)
  5. Software testing phase (black box, white box testing - interface stress testing, concurrent programming testing)
  6. Project Deployment – ​​Software Development Closed Loop

1.1 Technology selection

  1. Front-end: HTML+CSS+JavaScript Tool: VSCode
  2. Server: SpringBoot+WebSocket

2. Overview of the implementation effect

3. Use case and timing display

4. Framework construction and implementation

4.1 Backend implementation

1. SpringBoot project construction

1.java runtime environment configuration

1. The java-bin path is configured in the environment variable path
insert image description here
2. The java-jre-bin is configured in the environment variable path
insert image description here
and then opened with cmd, and the content output of the java command and the javac command means that the environment variable is configured

2. maven

1. Enter maven official website

https://maven.apache.org/
insert image description here

insert image description here

2. After downloading and decompressing the maven package, configure the bin path to the path system environment variable

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-ykbKYWFz-1681262704532)(note picture/image-20230411152129522.png)]
insert image description here

3. Maven modifies the settings.xml file in the conf directory

insert image description here
Modify the local warehouse directory

<?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"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository>本地仓库位置复制到这里</localRepository>
  <pluginGroups>
  
  </pluginGroups>
  
  <proxies>
  
  </proxies>
  
  <servers>
  
  </servers>
  
  <mirrors>
       <mirror>
            <id>nexus-aliyun</id>
            <mirrorOf>*,!jeecg,!jeecg-snapshots,!getui-nexus</mirrorOf>
            <name>Nexus aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        </mirror> 
  </mirrors>
  
  <profiles>
  
  </profiles>
  
</settings>

3. Use idea to build springboot project

insert image description here
After creating the project, click Settings to re-set the location of the maven warehouse.
insert image description here
Run the startup class.
insert image description hereinsert image description here
The effect shown in the figure above means that the project has started successfully!

If you need to modify the port number, there is a global configuration file of application.properties in the resources directory

# 设置SpringBoot启动的端口号
server.port=9010

2. SpringBoot integrates WebSocket

Overview of WebSockets

Purpose of use: To use TCP to realize fast and long-lasting Socket communication between client and server
Full-duplex communication, and the long link
is generally suitable for terminal machines (Android, ios, Hongmeng), client web script fast and service terminal communication technology.
Solve the HTTP problem: not suitable for use in real-time communication scenarios

insert image description here

Three scenarios packaged by webScoket

  1. Unicast

    1 to 1 send

  2. Broadcast (BroadCast)

    1 to all send

  3. Multicast (Mulitcast)

    1 to a specific group

3. springBoot introduces WebSocket dependency

insert image description here

<!-- 服务端WebSocket需要的依赖 -->      
 <dependency>           
   <groupId>org.springframework.boot</groupId>            
   <artifactId>spring-boot-starter-websocket</artifactId>       
</dependency>

<!--  引入web开发三个包 -->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
        
<!-- 阿里fastjson -->
<dependency>
           <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.80</version>
</dependency>

insert image description here

4. To configure a chat server

WebSocket configuration class

package com.cqgyzyjsxy.liaotianservice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

import javax.websocket.server.ServerEndpointConfig;

/**
 * 模块名称:
 * 模块类型:
 * 编码人:高靖博
 * 创建时间:2023/4/12
 * 联系电话:18587388612
 */

@Configuration
public class WebScoketConfig {
    
    

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
    
    
        return new ServerEndpointExporter();
    }

}

chat processing class

package com.cqgyzyjsxy.liaotianservice.config;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 模块名称: 聊天程序服务端WebSocket配置
 * 模块类型:
 * 编码人:高靖博
 * 创建时间:2023/4/12
 * 联系电话:18587388612
 */
// LiaoTianSocket springBoot组件放入Spring容器中
@Component
// 客户端要连接聊天服务器时,指定的服务端地址
// 客户端连接服务器聊天服务的地址案例: ws://服务器ip地址:服务端口号/qqserver
@ServerEndpoint("/qqserver/{qqNumber}")
public class LiaoTianSocket {
    
    

    static{
    
    
        System.out.println("----------------------------------");
        System.out.println("------   WebSocket服务启动   -------");
        System.out.println("---------                ----------");
        System.out.println("----------------------------------");
    }

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    /**
     * QQ号
     */
    private String qqNumber;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    //虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
    //  注:底下WebSocket是当前类名
    private static CopyOnWriteArraySet<LiaoTianSocket> webSockets =new CopyOnWriteArraySet<>();

    // 用来存在线连接用户信息( 线程安全 )
    // key: QQ号  value: 每个客户端的session对象
    private static ConcurrentHashMap<String,Session> sessionPool = new ConcurrentHashMap<String,Session>();

    // 1. 当客户端连接时做什么事情
    @OnOpen
    public void onOpen(Session session,@PathParam(value="qqNumber") String qqNumber){
    
    
        System.out.println("--客户端连接[qq:"+qqNumber+"]--");
        this.session = session;
        this.qqNumber = qqNumber;
        sessionPool.put(qqNumber,session);
        webSockets.add(this);
    }

    // 2.当客户端发送消息给服务器时做什么事情
    // 参数message就是客户端给服务器发送的消息内容
    @OnMessage
    public void onMsg(String message){
    
    
        // 实现群发功能

        try {
    
    
            sendAllMsg(message);
        } catch (IOException e) {
    
    
            System.err.println("发送消息异常");
            e.printStackTrace();
        }
    }

    // 3.当客户端断开连接时要做什么事情
    @OnClose
    public void onClose(){
    
    
        System.out.println("客户端断开连接~!~!!");
    }

    // 4.当客户端发送消息、连接或断开连接时错误做什么事情
    @OnError
    public void onErr(Throwable error){
    
    
        error.printStackTrace();
        System.out.println("服务器或客户端异常!!!!");
    }

    /**
     * 群发功能
     * @param msg 群发的消息
     */
    public void sendAllMsg(String msg) throws IOException {
    
    
        System.out.println("--群发消息:"+msg);
        // 遍历所有已经连接到服务器的客户端对象
        for(LiaoTianSocket socket:webSockets){
    
    

            if(socket.session.isOpen()){
    
    // 判断客户端是否在线
                socket.session.getAsyncRemote().sendText(msg);
            }
        }
    }

}


4.2 Front-end implementation

test page

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试</title>
    <style>
        /* 历史信息窗口样式 */
        .hsDiv{
      
      
            border:1px solid black;
            border-radius: 11px;
            width: 100%;
            height: 500px;
            overflow: auto;
            box-sizing: border-box;
            padding: 8px;
        }

        /* 消息的时间文字样式 */
        .time{
      
      
            font-size: 10px;
            color:gray;
        }

        /* 消息的文字内容样式 */
        .msgText{
      
      
            color:blue;
        }
        /* 发送人信息 */
        .person{
      
      
            font-size: 7px;
            color:black;   
        }
    </style>
</head>
<body>
    <span id="state">离线</span>
    <span id="qqNumber"></span>
    <input id="nickName" placeholder="定义一个你的昵称" />
    <button onclick="toConect()">连接</button>
    <hr/>
    <button onclick="sendMsg()">发送</button>
    <input id="msg" placeholder="请输入消息...." />
    <hr/>
    <!-- 历史信息框体 -->
    <div class="hsDiv" id="hsDiv">

        


    </div>

</body>

<script>
var qqNumber;

var webScoket;

var htmls = ""; // 所有历史信息html

var nikeName = ""; // 客户端昵称

// 连接到服务器
function toConect(){
      
      

    // 生成一个唯一的数字
    qqNumber  = parseInt(Math.random()*10000000000000);

    webScoket = new WebSocket("ws://localhost:9010/qqserver/"+qqNumber);

    // 定义一个连接成功的回调函数
    webScoket.onopen = function (){
      
      
        console.dir("-连接成功!");
        document.getElementById("state").innerHTML = "在线";
        document.getElementById("qqNumber").innerHTML = qqNumber;
        // 获取连接的昵称信息
        var nikeNames = document.getElementById("nickName").value;
        nikeName = nikeNames;
    }

    // 定义一个服务器发送消息给客户端的回调函数
    webScoket.onmessage = function(data){
      
      
        console.dir("-接收到消息:"+data.data);
        // QQ信息$消息内容$发送时间$昵称
        var msgArr = data.data.split("$");

        htmls += '<span class="time">时间:'+msgArr[2]+'</span><br/>'+
        '<span class="person">['+msgArr[3]+']</span><br/>'+
        '<span class="msgText">'+msgArr[1]+'</span>'+
        '<hr/>';

        // 动态html代码段添加进入聊天历史信息框中
        document.getElementById("hsDiv").innerHTML = htmls;

    }

}


// 发送消息方法
function sendMsg(){
      
      

    // 得到要发送的信息文字
    var msg = document.getElementById("msg").value;

   //  发送消息的格式:
   // QQ信息$消息内容$发送时间$昵称

   var nowDate = new Date();
   var sendMsgStr = qqNumber+"$"+msg+"$"+(nowDate.getFullYear() +"-"+nowDate.getMonth()+"-"+nowDate.getDate()+" "+nowDate.getHours()+":"+nowDate.getMinutes()+":"+nowDate.getSeconds()+"$"+nikeName)

    webScoket.send(sendMsgStr); // 消息发送给服务器了

}




</script>

</html>

insert image description here

gitee warehouse source code
https://gitee.com/gdones/cqgy-webqq/blob/master/README.md

Guess you like

Origin blog.csdn.net/gjb760662328/article/details/130098360