栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java+Springboot+Websocket在线聊天室

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java+Springboot+Websocket在线聊天室

1、什么是websocket?

websocket是由HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。它是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

2、为啥要实现web在线聊天程序?

最近在学习过程中看到了websocket协议,于是就有了一个想法想使用springboot+websocket实现一个web在线聊天的demo。

花了一点时间,边学习边搭建,最终实现了下面的一个简单的web在线聊天的demo,特在这里记录一下。既是为了分享给大家,也是为了给自己的学习留下一个痕迹,用以不断夯实自己的技术能力。

3、实现结果

先上几个截图,提前展示一下实现结果


4、实现过程

4.1、创建一个springboot项目,命名为chat,并在pom.xml文件中添加需要的maven依赖


		
    
        org.springframework.boot
        spring-boot-starter
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
    
        com.alibaba
        fastjson
        RELEASE
    
    
    
        org.springframework.boot
        spring-boot-starter-websocket
    

4.2、添加yml配置信息

server:
  port: 8090
  servlet:
    context-path: /chatroom

spring:
  resources:
    static-locations: classpath:/,classpath:/static/

4.3、修改springboot启动类

package com.crwl.chatroom;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@SpringBootApplication
public class ChatroomApplication {

    public static void main(String[] args) {
        SpringApplication.run(ChatroomApplication.class, args);
    }
	//将ServerEndpointExporter 注册为一个spring的bean
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

4.4、准备websocket的工具类,dto类以及enum类
WsTool .java(websocket工具类)

package com.crwl.chatroom.util;

import com.alibaba.fastjson.JSON;
import com.crwl.chatroom.dto.ChatMsg;
import com.crwl.chatroom.dto.ChatUser;
import com.crwl.chatroom.enums.ChatEnum;

import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class WsTool {
    public static final Map LIVING_SESSIONS_CACHE = new ConcurrentHashMap<>();
    public static final Map  LIVING_USER_CACHE = new ConcurrentHashMap<>();

    public static void sendMessageAll(ChatMsg chatMsg) {
        LIVING_SESSIONS_CACHE.forEach((sessionId, session) -> {
            sendMessage(session, chatMsg);
        });
    }
    
    public static void sendMessage(Session session, ChatMsg chatMsg) {
        if (session == null) {
            return;
        }
        final RemoteEndpoint.Basic basic = session.getBasicRemote();
        if (basic == null) {
            return;
        }
        try {
            basic.sendText(JSON.toJSONString(chatMsg));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void refreshOnlineUserList(){
        ChatMsg chatMsg = new ChatMsg();
        chatMsg.setType(ChatEnum.USER_LIST.getCode());
        List userList = new ArrayList(WsTool.LIVING_USER_CACHE.values());
        chatMsg.setOnlineUserList(userList);
        sendMessageAll(chatMsg);
    }
}

ChatMsg.java(聊天信息Dto)

package com.crwl.chatroom.dto;

import java.util.List;

public class ChatMsg {
    //消息类型 1:聊天信息  2:刷新在线用户列表
    private String sendUserBh;
    private String sendUserXm;
    private String type;
    private String msg;
    private List onlineUserList;

    public String getSendUserBh() {
        return sendUserBh;
    }

    public void setSendUserBh(String sendUserBh) {
        this.sendUserBh = sendUserBh;
    }

    public String getSendUserXm() {
        return sendUserXm;
    }

    public void setSendUserXm(String sendUserXm) {
        this.sendUserXm = sendUserXm;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public List getOnlineUserList() {
        return onlineUserList;
    }

    public void setOnlineUserList(List onlineUserList) {
        this.onlineUserList = onlineUserList;
    }
}

ChatUser.java(聊天用户信息Dto)

package com.crwl.chatroom.dto;

public class ChatUser {
    private String userBh;
    private String userName;
    private String onlineTime;

    public String getUserBh() {
        return userBh;
    }

    public void setUserBh(String userBh) {
        this.userBh = userBh;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getOnlineTime() {
        return onlineTime;
    }

    public void setOnlineTime(String onlineTime) {
        this.onlineTime = onlineTime;
    }
}

Result.java (封装Http请求的返回对象Dto)

package com.crwl.chatroom.dto;


import java.io.Serializable;


public class Result implements Serializable {
    private static final long serialVersionUID = 3337439376898084639L;

    
    private Integer code;

    
    private String msg;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

ChatEnum.java(聊天类型枚举类)

package com.crwl.chatroom.enums;

public enum ChatEnum {
    PUBLIC_MSG("1","公共聊天消息"),
    PRIVATE_MSG("2","私秘聊天信息"),
    CLOSE_SOCKET("3","关闭socket连接"),
    USER_LIST("4","在线用户列表"),
    JOIN_CHAT("5","加入聊天室");

    private String code;
    private String data;

    private ChatEnum(String code, String data) {
        this.code = code;
        this.data = data;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

ResultEnum.java(返回信息状态枚举类)

websocket工具类package com.crwl.chatroom.enums;

public enum ResultEnum {
    SUCCESS(0,"成功"),
    FAILURE(-1,"失败");

    private Integer code;
    private String data;

    private ResultEnum(Integer code, String data) {
        this.code = code;
        this.data = data;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

4.5、前端实现,前端采用iview框架+jquery,聊天输入框使用百度编辑器(ueditor)
chatroom.html




    
    
    聊天室
    
    
    
    
    
    
    
    
    
    


	
	    
	        
Java+Springboot+Websocket在线聊天室
{{loadMsg}}
连接服务器 退出
发送
成员列表
清除选中
  • {{item.userName}}{{item.onlineTime}}
连接 取消

chat.css

html,body,#app,.el-container,.el-row{
    
    padding: 0px;
    
    margin: 0px;
    
    height: 100%;
}
.chatbody{
    height:calc(100%);
    margin:15px;
    box-shadow:2px 3px 5px #888888;
}
.toolBar{
    padding:5px 10px;
    height:45px
}
.chatArea{
    height:calc(100% - 45px);
    margin-top:0px;
    
    padding:5px;
}
.chatLeft{
    
    height: calc(100% );
    padding:5px;
}
.chatView{
    height:calc(100% - 250px);
    
    padding:5px;
    background:#fff;
    overflow-y: auto;
}

.inputArea{
    height:240px;
}
.inputForm{
    height:200px;
}
.sendTool{
    text-align:right;
    height:50px;
    line-height:50px;
}


.chatUserList{
    
    height:calc(100% - 10px);
    margin:5px 0;
    padding:5px;
    background:#fff;
}
.userTitle{
    border-bottom: 1px solid #dfdfdf;
    font-size:16px;
    padding:5px 0;
    clear:both;
}
.clearfix{
    clear:both;
}
.userTitle .title{
    float:left;
}
.userBtnArea{
    float:left;
    margin-left:10px;
    margin-top:-5px;
}
.chatUserList ul li{
    list-style-type:none;
    height:35px;
    line-height:35px;
    cursor:pointer;
    clear:both;
    padding: 0 5px;
}
.loginDate{
    float:right;
}
.selUser{
    background: #2d8cf0;
    color: #fff;
}
.iconArea{
    height:45px;
    position:relative;
}
.icon{
    height:25px;
    width:25px;
    vertical-align: middle;
    margin-top: -5px;
}
.fl{float:left;}
.fr{float:right;}
.iconDiv{
    position: absolute;
    top:45px;
    background: #fff;
    height: 160px;
    width: 370px;
    z-index: 10;
    box-shadow: 1px 2px 15px #888;
    padding: 5px;
}
.welcome{
    color: #15c02e;
}
.warning{
    color:red;
}
.msg{
    margin:10px 0;
    position:relative;
}
.userTitleOther{
    float: left;
    width: 90px;
    margin-top: 5px;
}
.otherMsgContent{
    float:left;
    margin-left: 10px;
    padding: 10px 20px;
    background: #eaeaea;
    border-radius: 5px;
}
.triangle-left {
    position: absolute;
    left: 80px;
    width: 0;
    height: 0;
    border-width: 10px;
    border-style: solid;
    border-color:#FFF #eaeaea #FFF #FFF ;
    top: 5px;
}
.userTitleSelf{
    float: right;
    width: 90px;
    margin-top: 5px;
    padding-left: 15px;
}
.selfMsgContent{
    float:right;
    margin-right: 10px;
    padding: 10px 20px;
    background: #18cb2f;
    color:#fff;
    border-radius: 5px;
}
.triangle-right {
    position: absolute;
    right: 80px;
    width: 0;
    height: 0;
    border-width: 10px;
    border-style: solid;
    border-color: #FFF #FFF #FFF #18cb2f;
    top: 5px;
}
.private{
    background: red;
    color: #fff;
    border-radius: 20px;
    padding: 3px;
}

common.js

var commonFunc ={};
var constants ={
    localCurl : "http://localhost:8090/chatroom",
    styleSize:'small'
}


commonFunc.submit=function(url,submitType, parameter, fnSuccess, fnError,contentType, Async){
    //判断是否需要同步ajax
    if (typeof (Async) == "undefined") {
        Async = true;
    };
    if(contentType == "obj"){
        parameter = JSON.stringify(parameter);
        contentType = "application/json; charset=utf-8";
    }else if(contentType == "upload"){
        //contentType = "application/x-www-form-urlencoded;charset=UTF-8";
    }else {
        contentType = "application/x-www-form-urlencoded;charset=UTF-8";
    }
    url = constants.localCurl+url;
    $.ajax({
        type: submitType,
        data: parameter,
        dataType: 'json',
        contentType:contentType,
        url: url,
        cache:false,
        beforeSend: function(XMLHttpRequest) {

        },
        crossDomain: true == !(document.all),
        xhrFields: {
            withCredentials: true
        },
        async: Async,
        success: function(data) {
            //服务器返回响应,根据响应结果,分析是否登录成功;
            var code=data.code+"";
            if (code == 1000) {
                return;
            } else if(code=="0"){
                fnSuccess(data);
            }else{
                fnError(data);
            }
        },
        complete: function (data) {
        },
        error: function (xhr, type, errorThrown) {
            //异常处理;
            fnError(xhr, type, errorThrown);
            console.log(xhr);
            console.log(type);
            console.log(JSON.stringify(errorThrown));
        }
    });
}

chatroom.js

$(function() {
    var height = $(window).height()-160;
    var _this = null;
    var vue = new Vue({
        el: '#app',
        data: {
            styleSize:constants.styleSize,
            fullScreenloading: false,
            loadMsg:'',
            ws:null,
            sendUser:{
                userBh:'',
                userName:''
            },
            formData:{
                content:''
            },
            chatUserList:[],
            msgList:[],
            toUser:'',
            timeoutObj:null,
            connectModal:false,
            editRulevalidate: {
                userBh:{required:true,message:'请输用户Id',trigger: 'blur'},
                userName:{required:true,message:'请输用户昵称',trigger: 'blur'}
            },
        },
        created:function(){
        },
        mounted :function(){
            var _this = this;
            this.connectServer();
            this.startHeart();
            this.ueditor = UE.getEditor('editor',{
                toolbars: [
                    ['emotion']
                ],
                wordCount:false,                //统计字数
                elementPathEnabled:false,       //元素路径
                enableAutoSave:false,           //自动保存
            });
            this.ueditor.ready(function() {
                $(".edui-editor-messageholder.edui-default").css({ "visibility": "hidden" });
                _this.ueditor.setHeight(170);

                _this.ueditor.setContent("")
                _this.ueditor.focus()
            });
            //监听浏览器关闭,关闭前先关闭webSocket
            window.onbeforeunload = function () {
                if(null != this.ws){
                    this.ws.close();
                }
            };
        },
        methods: {
            openConnectWin(){
                this.sendUser.userBh = "";
                this.sendUser.userName = "";
                this.connectModal = true;
            },
            cancelFunc(){
                this.connectModal = false;
            },
            connectServer(userBh, userName){
                var _this = this;
                this.$refs['editValidate'].validate((valid) => {
                    if (valid) {
                        if (null == this.ws) {
                            var urlPrefix = 'ws://localhost:8090/chatroom/connect/';
                            var url = urlPrefix + "/" + this.sendUser.userBh + "/" + this.sendUser.userName;
                            this.ws = new WebSocket(url);
                            this.connectModal = false;
                            this.ws.onopen = function () {
                                console.log("建立 websocket 连接...");
                            };
                            this.ws.onmessage = function (event) {
                                //服务端发送的消息
                                //console.log(event);
                                var data = JSON.parse(event.data);
                                //console.log(data);
                                if (null != data && (data.type == 1 || data.type == 2)) { //聊天信息
                                    var msg = data.msg;
                                    if (data.sendUserBh == _this.sendUser.userBh) {
                                        if (data.type == 1) {  //公共聊天信息
                                            msg = "" + _this.sendUser.userName + " " +
                                                '' + msg + '';
                                        }
                                        if (data.type == 2) {   //私人聊天信息
                                            msg = "私" + _this.sendUser.userName + " " +
                                                '' + msg + '';
                                        }
                                        _this.msgList.push("" + msg + "");
                                    } else {
                                        if (data.type == 1) {  //公共聊天信息
                                            msg = "" + data.sendUserXm + " " +
                                                '' + msg + '';
                                        }
                                        if (data.type == 2) {   //私人聊天信息
                                            msg = "" + data.sendUserXm + "私 " +
                                                '' + msg + '';
                                        }
                                        _this.msgList.push("" + msg + "");
                                    }
                                    //+''
                                }
                                //刷新在线列表
                                if (null != data && data.type == 4) {
                                    _this.chatUserList = data.onlineUserList;
                                }

                                //用户进入聊天室
                                if (null != data && data.type == 5) {
                                    msg = "用户[" + (data.sendUserXm) + "]进入了聊天室!";
                                    _this.msgList.push(msg);
                                }

                                //用户离线
                                if (null != data && data.type == 3) {
                                    msg = "用户[" + (data.sendUserXm) + "]已经离开聊天室!";
                                    _this.msgList.push(msg);
                                }

                                _this.toBottom();
                            };
                            this.ws.onclose = function (event) {
                                _this.ws = null;
                                _this.chatUserList.splice(0, _this.chatUserList.length);
                                _this.toBottom();
                            }
                            this.ws.onerror = function (event) {
                                //console.log(event.data);
                                _this.ws = null;
                                _this.sendUser = {
                                    userBh: '',
                                    userName: ''
                                }
                            };
                        } else {
                            this.$Message.error("已经建立服务器连接,请不要重复连接");
                        }
                    }
                });
            },
            quitServer(){
                if(null != this.ws){
                    this.ws.close()
                    this.ws = null;
                }
            },
            toBottom(){
                setTimeout(function(){
                    $('.chatView').scrollTop($('.chatView').get(0).scrollHeight+150);
                },200)
            },
            sendMsg(){
                var _this =this;
                if(null != this.ws) {
                    var content = this.ueditor.getContent();
                    if (null == content || "" == content.trim()) {
                        this.$Message.error("请输入聊天信息");
                        return;
                    }
                    content = content.trim();
                    if(null == this.toUser || this.toUser == ""){
                        this.ws.send(content)
                    }else{
                        var sendUserBh = this.sendUser.userBh;
                        var url = "/privateSend/"+sendUserBh+"/to/"+this.toUser+"?message="+content
                        commonFunc.submit(url,"get",{},function(data){
                            if(data.code != "0"){
                                _this.$Message.error("发送信息失败");
                            }
                        },function(data){
                            _this.$Message.error("发送信息失败");
                        });
                    }
                    this.ueditor.setContent("")
                    this.ueditor.focus(true);
                    $("#ueditor_0").html("");
                }else{
                    this.$Message.error("请先点击【连接服务器】建立网络连接");
                }
            },
            chooseUser(toUser){
                if(toUser != this.sendUser.userBh){
                    this.toUser = toUser;
                }
            },
            clearChooseUser(){
                if(null != this.toUser && '' != this.toUser){
                    this.toUser='';
                }else{
                    this.$Message.error("您未选择私聊用户");
                }
            },
            startHeart: function () {   //设置心跳程序,避免nginx(设置的5分钟)超时断开长连接
                var _this = this;
                this.timeoutObj && clearTimeout(this.timeoutObj);
                this.timeoutObj = setTimeout(function () {
                    //这里发送一个心跳,后端收到后,返回一个心跳消息,
                    //onmessage拿到返回的心跳就说明连接正常
                    if(null != _this.ws){
                        _this.ws.send("HeartBeat");
                        console.log('ping');
                        _this.startHeart();
                    }
                }, 5*60*1000)
            }
        }
    });
    //此处将vue对象作用域上提至window返回,用户实现ueditor的crtl+enter事件
    window.vue = vue;
});

到此,整个web在线聊天的demo程序就搭建完成。

其中输入框的快捷键发送(crtl+enter)需要在ueditor.all.js文件中的指定位置增加一段内容,先搜索“autosubmit”,在execCommand代码块中加入以下内容

if(null != window.vue){
    window.vue.sendMsg();
}

5、程序的运行

选中项目启动类ChatroomApplication.java,右键鼠标,单击Run’ChatroomApplication’启动项目。

启动成功后,打开浏览器,输入http://localhost:8090/chatroom/web/chatroom.html即可进入聊天室

点击连接服务器,弹出连接服务器弹窗,输入用户Id以及用户昵称,点击【连接】按钮即可以连接进聊天服务器
直接输入信息,快捷键输入crtl+enter组合键或者点击【发送】按钮直接群发聊天信息,如果需要一对一私聊,可以先在右边在线用户列表中选择需要聊天的用户后输入私聊信息,快捷键输入crtl+enter组合键或者点击【发送】按钮向指定用户私人发送聊天信息
到此,web在线聊天程序记录积分享结束。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/306831.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号