SpringBoot整合WebSocket

WebSokcet案例-聊天框

依赖包

<parent>
    <groupId>org.springframework.boot</groupId>
    <version>2.3.7.RELEASE</version>
    <artifactId>spring-boot-parent</artifactId>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--devtools热部署-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
        <scope>true</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

启动类

@SpringBootApplication
public class WebSocketApp {
    public static void main(String[] args) {
        SpringApplication.run(WebSocketApp.class, args);
    }
}

登录模拟

public class User {
    private String username;
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public User() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
@RestController
public class UserController {

    @RequestMapping("/login")
    public Result login(User user, HttpSession session){
        Result result = new Result();
        if (user!=null&&"123".equals(user.getPassword())){
            result.setFlag(true);
            session.setAttribute("user",user.getUsername());
        }else {
            result.setFlag(false);
            result.setMessage("登录失败");
        }
        return result;
    }

    @RequestMapping("/getUsername")
    public String getUsername(HttpSession session){
        String username = (String) session.getAttribute("user");
        return username;
    }
}

消息实体类

响应数据

这里用来响应前端数据,供模拟登录使用

/**
 * Result:由于登录响应回给浏览器的数据
 */
public class Result {
    private boolean flag ;
    private String message;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

浏览器=>服务器

接收浏览器发来的数据格式

/**
 * Message:浏览器发送 给服务器的websocket数据
 */
public class Message {
    private String toName;
    private String message;

    public String getToName() {
        return toName;
    }

    public void setToName(String toName) {
        this.toName = toName;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

服务器=>浏览器

向浏览器响应的数据格式

/**
 * ResultMessage:服务端发送给浏览器的websocket数据
 */
public class ResultMessage {
    private boolean isSystem;
    private String fromName;
    private Object message; // 如果是系统消息是数组

    public boolean isSystem() {
        return isSystem;
    }

    public void setSystem(boolean system) {
        isSystem = system;
    }

    public String getFromName() {
        return fromName;
    }

    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    public Object getMessage() {
        return message;
    }

    public void setMessage(Object message) {
        this.message = message;
    }
}

消息工具类

用于创建一个ResultMessage消息

public class MessageUtils {
    public static String getMessage(boolean isSystemMessage,String fromName,Object message){
        try {
            ResultMessage result = new ResultMessage();
            result.setSystem(isSystemMessage);
            result.setMessage(message);
            if (fromName!=null){
                result.setFromName(fromName);
            }
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(result);
        }catch (JsonProcessingException e){
            e.printStackTrace();
        }
        return null;
    }
}

消息核心处理类

  • @ServerEndpoint(value = “/chat”, configurator = GetHttpSessionConfigurator.class)
    • 标识该类为WebSocket的消息处理类
    • value:请求路径(前端格式:ws://localhost:8080/chat
    • configurator:与httpSession对象存储相关(单体项目,多体可以使用其他方式)
  • @Component:供Spring管理
  • @Slf4j:日志相关
  • onlineUsers:一个Map容器,static=>多个ChatEndpoint对象共享一个容器(每建立一个连接有一个新的ChatEndpoint对象)
  • Session:会话对象,用于消息发送
  • HttpSession:用于获取当前用户(单体项目)
  • @OnOpen:连接建立时调用,用于会话建立准备操作,初始化session与httpSession,并将自身放入容器,将自己推送出去(简单理解:A登录了,A的好友收到我登录的消息,好友列表展示我在线)
  • @OnMessage:接收到客户端消息时调用,负责消息的推送(将消息推送给要创达的用户)
  • @OnClose:连接断开时调用,用于会话销毁事后工作(简单理解:A下线了,A的好友们在列表上看到的是A已离线)
  • @OnError:异常时调用
package com.czk.websocket.ws;

import com.czk.websocket.pojo.Message;
import com.czk.websocket.util.MessageUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfigurator.class)
@Component
@Slf4j
public class ChatEndpoint {

    // 用来存储每个客户端对象对应的ChatEndpoint对象
    private static Map<String, ChatEndpoint> onlineUsers = new ConcurrentHashMap<>(); // 考虑线程安全,用ConcurrentHashMap
    // 声明Session对象,通过该对象可用发送消息给指定的用户
    private Session session;
    // 声明一个HttpSession对象,我们之前在HttpSession对象中存储了用户名
    private HttpSession httpSession;


    // 连接建立时被调用
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        // 将局部的session对象复制给成员session
        this.session = session;
        // 获取httpSession对象 (由GetHttpsSessionConfigurator中存入)
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        this.httpSession = httpSession;

        String username = (String) httpSession.getAttribute("user");
        // 将当前对象存储到容器(onlineUsers)中
        onlineUsers.put(username, this);
        // 将当前在线用户名推送给所有的客户端
        // 1.获取消息
        String message = MessageUtils.getMessage(true, null, getNames());
        // 2.调用方法进行系统消息的推送
        broadcastAllUsers(message);
    }

    // 获取系统中所有的登录用户
    private Set<String> getNames() {
        return onlineUsers.keySet();
    }

    // 广播,将消息推送给所有客户端
    private void broadcastAllUsers(String message) {
        log.info("开始广播:{}", message);
        try {
            Set<String> names = onlineUsers.keySet();
            for (String name : names) {
                ChatEndpoint chatEndpoint = onlineUsers.get(name);
                chatEndpoint.session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 接收到客户端发送的数据时被调用
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            // 将消息(JSON格式),转为Message
            ObjectMapper mapper = new ObjectMapper();
            Message msg = mapper.readValue(message, Message.class);
            // 获取要将数据发送给的用户
            String toName = msg.getToName();
            // 获取消息数据
            String data = msg.getMessage();
            // 获取当前登录用户
            String username = (String) httpSession.getAttribute("user");
            // 获取推送给指定用户的消息格式的数据
            String resultMessage = MessageUtils.getMessage(false, username, data);
            // 发送数据
            log.info("{}给{}发送信息:{}",username,toName,data);
            onlineUsers.get(toName).session.getBasicRemote().sendText(resultMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 连接关闭时被调用
    @OnClose
    public void onClose(Session session) {
        // 用户下线,移除用户并广播
        String username = (String) httpSession.getAttribute("user");
        onlineUsers.remove(username);
        // 获取推送的消息
        String message = MessageUtils.getMessage(true, null, getNames());
        broadcastAllUsers(message);
    }
}

ServerEndpointConfig

用于存储HttpSession对象,方便@OnOpen中获取

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        // 将httpSession对象存储到配置对象中
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}

消息配置类

ServerEndpointExporter:用于扫描@ServerEndpoint注解的bean

@Configuration
public class WebSocketConfig {
    // 注入ServerEndpointExporter bean对象,自动注册使用了@ServerEndpoint注解的bean
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

前端相关代码

登录

<script>
    $("#btn").click(function () {
    $.get("login?",$("#loginForm").serialize(),function(res){
        if (res.flag){
            console.log(res);
            location.href = "main.html";
        } else {
            console.log(res);
            $("#err_msg").html(res.message);
        }
    },"json");
})
</script>

WebSocket

<script>
    var username;
$(function () {
    var toName;
    $.ajax({
        url: "getUsername",
        success: function (res) {
            username = res;
            $("#username").html("用户:" + username + "<span>在线</span>");
            // $("#username").html("用户:123<span>在线</span>");
        },
        async: false //同步请求,只有上面好了才会接着下面
    });
	// 创建websocket对象,用于客户端与服务器通信
    var ws = new WebSocket("ws://localhost:8080/chat");
    // 对应服务端@OnOpen
    ws.onopen = function (ev) {
        $("#username").html("用户:" + username + "<span>在线</span>");
    }
    //接受消息,对应服务端@OnMessage
    ws.onmessage = function (ev) {
        var datastr = ev.data;
        var res = JSON.parse(datastr);
        //判断是否是系统消息,虽然实体类是isSystem,但这里是system
        if (res.system) {
            //好友列表
            //系统广播
            var names = res.message;
            var friends_ul = "<li style='font-size: 18px;font-weight: 800;'>好友列表:</li>"
            var userlistStr = friends_ul;
            var broadcastListStr = "";
            for (var name of names) {
                if (name != username) {
                    userlistStr += "<li><a οnclick=\"showChat(\'" + name + "\')\">" + name + "</a></li></br>";
                    broadcastListStr += "<li>您的好友:" + name + "  已上线</li>";
                }
            }
            ;
            $("#friends_ul").html(userlistStr);
            $("#broadcast_ul").html(broadcastListStr);

        } else {
            //不是系统消息
            var chat_left="<p class='chat_left'><span class='p_border'>"+res.fromName+"</span>"+res.message+"</p>"
            if (toName == res.fromName) {
                $("#chat_content").append(chat_left);
            }
            var chatdata = sessionStorage.getItem(res.fromName);
            if (chatdata != null) {
                chat_left = chatdata + chat_left;
            }
            sessionStorage.setItem(res.fromName, chat_left);

        }
        ;
    },
        // 对应服务端@OnMessage
        ws.onclose = function (ev) {
        $("#username").html("用户:" + username + "<span>离线</span>");
    }
    showChat = function (name) {
        // alert("dsaad");
        toName = name;
        //清空聊天区
        $("#chat_content").html("");
        $("#chat_top").html("当前正与" + toName + "聊天");
        var chatdata = sessionStorage.getItem(toName);
        if (chatdata != null) {
            $("#chat_content").html(chatdata);
        }
    };
    //发送消息
    $("#send").click(function () {
        //获取输入的内容
        var data = $("#message_text").val();
        $("#message_text").val("");
        var json = {"toName": toName, "message": data};
        //将数据展示在聊天区
        var chat_right = "<p class='chat_right'>"+data+"<span class='p_border'>我</span></p>"
        $("#chat_content").append(chat_right);
        var chatdata = sessionStorage.getItem(toName);
        if (chatdata != null) {
            chat_right = chatdata + chat_right;
        }
        sessionStorage.setItem(toName, chat_right);
        //发送数据
        ws.send(JSON.stringify(json));
    })
})
</script>

``

效果演示

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Spring Boot整合WebSocket,你需要进行以下步骤: 1. 首先,在pom.xml文件中添加WebSocket的相关依赖。可以使用以下两个依赖之一: - 从中提到的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` - 从中提到的依赖: ```xml <!--webSocket--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建WebSocket配置类,这个类负责配置WebSocket的相关信息。你可以按照以下方式创建一个配置类[3]: ```java package com.loit.park.common.websocket; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } ``` 3. 至此,你已经完成了WebSocket整合配置。现在,你可以在你的应用中创建WebSocket的控制器并定义你的WebSocket端点。你可以根据你的需求来实现WebSocket端点的业务逻辑。 这就是Spring Boot整合WebSocket的基本步骤。通过这种方式,你可以在Spring Boot应用中轻松地使用WebSocket进行实时通信。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [springboot整合websocket](https://blog.csdn.net/weixin_45390688/article/details/120448778)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [springboot整合websocket(详解、教程、代码)](https://blog.csdn.net/hjq_ku/article/details/127503180)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值