文章目录

  • 一、数据库搭建
  • 二、后端搭建
    • 2.1 引入关键依赖
    • 2.2 WebSocket配置类
    • 2.3 配置跨域
    • 2.4 发送消息的控制类
    • 2.5 R类
  • 三、前端搭建
    • 3.1 自定义文件websocket.js
    • 3.2 main.js中全局引入websocket
    • 3.3 App.vue中声明websocket对象
    • 3.4 聊天室界面.vue
    • 3.5 最终效果

一、数据库搭建

很简单的一个user表,加两个用户admin和wskh

二、后端搭建

2.1 引入关键依赖

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

2.2 WebSocket配置类

WebSocketConfig的作用是:开启WebSocket监听

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @Author:WSKH* @ClassName:WebSocketConfig* @ClassType:配置类* @Description:WebSocket配置类* @Date:2022/1/25/12:21* @Email:1187560563@qq.com* @Blog:https://blog.csdn.net/weixin_51545953?type=blog*/
@Configuration
public class WebSocketConfig {/*** 开启webSocket* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

WebSocketServer里写了一些事件,如发送消息事件,建立连接事件,关闭连接事件等

import com.wskh.chatroom.util.FastJsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.EOFException;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;@ServerEndpoint("/websocket/{sid}")
@Component
public class WebSocketServer {private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);private static int onlineCount = 0;private static ConcurrentHashMap<String,WebSocketServer> webSocketServerMap = new ConcurrentHashMap<>();private Session session;private String sid;@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {this.sid = sid;this.session = session;webSocketServerMap.put(sid, this);addOnlineCount();log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());try {sendInfo("openSuccess:"+webSocketServerMap.keySet());} catch (IOException e) {e.printStackTrace();}}@OnClosepublic void onClose() {webSocketServerMap.remove(sid);subOnlineCount();log.info("有一连接关闭!当前在线人数为" + getOnlineCount());try {sendInfo("openSuccess:"+webSocketServerMap.keySet());} catch (IOException e) {e.printStackTrace();}}@OnMessagepublic void onMessage(String message) throws IOException {if("ping".equals(message)) {sendInfo(sid, "pong");}if(message.contains(":")) {String[] split = message.split(":");sendInfo(split[0], "receivedMessage:"+sid+":"+split[1]);}}@OnErrorpublic void onError(Session session, Throwable error) {if(error instanceof EOFException) {return;}if(error instanceof IOException && error.getMessage().contains("已建立的连接")) {return;}log.error("发生错误", error);}/*** 实现服务器主动推送*/public void sendMessage(String message) throws IOException {synchronized (session) {this.session.getBasicRemote().sendText(message);}}public static void sendObject(Object obj) throws IOException {sendInfo(FastJsonUtils.convertObjectToJSON(obj));}public static void sendInfo(String sid,String message) throws IOException {WebSocketServer socketServer = webSocketServerMap.get(sid);if(socketServer != null) {socketServer.sendMessage(message);}}public static void sendInfo(String message) throws IOException {for(String sid : webSocketServerMap.keySet()) {webSocketServerMap.get(sid).sendMessage(message);}}public static void sendInfoByUserId(Long userId,Object message) throws IOException {for(String sid : webSocketServerMap.keySet()) {String[] sids =  sid.split("id");if(sids.length == 2) {String id = sids[1];if(userId.equals(Long.parseLong(id))) {webSocketServerMap.get(sid).sendMessage(FastJsonUtils.convertObjectToJSON(message));}}}}public static Session getWebSocketSession(String sid) {if(webSocketServerMap.containsKey(sid)) {return webSocketServerMap.get(sid).session;}return null;}public static synchronized void addOnlineCount() {onlineCount++;}public static synchronized void subOnlineCount() {onlineCount--;}public static synchronized int getOnlineCount() {return onlineCount;}
}

2.3 配置跨域

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {@Override// 跨域配置public void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE").maxAge(3600).allowCredentials(true);}}

2.4 发送消息的控制类

/*** @Author:WSKH* @ClassName:MsgController* @ClassType:控制类* @Description:信息控制类* @Date:2022/1/25/12:47* @Email:1187560563@qq.com* @Blog:https://blog.csdn.net/weixin_51545953?type=blog*/
@ApiModel("信息控制类")
@RestController
@RequestMapping("/chatroom/msg")
public class MsgController {@ApiOperation("发送信息方法")@PostMapping("/sendMsg")public R sendMsg(String msg) throws IOException {WebSocketServer.sendInfo(msg);return R.ok().message("发送成功");}
}

至此,后端部分大体配置完毕。


2.5 R类

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.HashMap;
import java.util.Map;@Data
public class R {@ApiModelProperty(value = "是否成功")private Boolean success;@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")private Map<String, Object> data = new HashMap<String, Object>();private Object objectData;//让无参构造函数为私有,防止别人乱用private R(){}public static R ok(){//自己可以new自己,别人new不了R r = new R();r.setSuccess(true);r.setCode(ResultCode.SUCCESS);r.setMessage("成功");return r;}public static R error(){R r = new R();r.setSuccess(false);r.setCode(ResultCode.ERROR);r.setMessage("失败");return r;}// return this:当前r这个对象,方便用于链式编程public R success(Boolean success){this.setSuccess(success);return this;}public R message(String message){this.setMessage(message);return this;}public R code(Integer code){this.setCode(code);return this;}public R data(String key, Object value){this.data.put(key, value);return this;}public R data(Map<String, Object> map){this.setData(map);return this;}public static R fail(String msg) {return fail(400, msg, null);}public static R fail(String msg, Object data) {return fail(400, msg, data);}public static R fail(int code, String msg, Object data) {R r = new R();r.setCode(code);r.message(msg);r.setObjectData(data);return r;}public static R succ(Object data) {return succ(ResultCode.SUCCESS, "操作成功", data);}public static R succ(int code, String msg, Object data) {R r = new R();r.setCode(code);r.setMessage(msg);r.setObjectData(data);return r;}
}

三、前端搭建

本文使用vue-admin-template-master模板进行聊天室的前端搭建

3.1 自定义文件websocket.js

将下面文件放在api文件夹下

//websocket.js
import Vue from 'vue'// 1、用于保存WebSocket 实例对象
export const WebSocketHandle = undefined// 2、外部根据具体登录地址实例化WebSocket 然后回传保存WebSocket
export const WebsocketINI = function(websocketinstance) {this.WebSocketHandle = websocketinstancethis.WebSocketHandle.onmessage = OnMessage
}// 3、为实例化的WebSocket绑定消息接收事件:同时用于回调外部各个vue页面绑定的消息事件
// 主要使用WebSocket.WebSocketOnMsgEvent_CallBack才能访问  this.WebSocketOnMsgEvent_CallBack 无法访问很诡异
const OnMessage = function(msg) {// 1、消息打印// console.log('收到消息:', msg)// 2、如果外部回调函数未绑定 结束操作if (!WebSocket.WebSocketOnMsgEvent_CallBack) {console.log(WebSocket.WebSocketOnMsgEvent_CallBack)return}// 3、调用外部函数WebSocket.WebSocketOnMsgEvent_CallBack(msg)
}// 4、全局存放外部页面绑定onmessage消息回调函数:注意使用的是var
export const WebSocketOnMsgEvent_CallBack = undefined// 5、外部通过此绑定方法 来传入的onmessage消息回调函数
export const WebSocketBandMsgReceivedEvent = function(receiveevent) {WebSocket.WebSocketOnMsgEvent_CallBack = receiveevent
}// 6、封装一个直接发送消息的方法:
export const Send = function(msg) {if (!this.WebSocketHandle || this.WebSocketHandle.readyState !== 1) {// 未创建连接 或者连接断开 无法发送消息return}this.WebSocketHandle.send(msg)// 发送消息
}// 7、导出配置
const WebSocket = {WebSocketHandle,WebsocketINI,WebSocketBandMsgReceivedEvent,Send,WebSocketOnMsgEvent_CallBack
}// 8、全局绑定WebSocket
Vue.prototype.$WebSocket = WebSocket

3.2 main.js中全局引入websocket

import '@/utils/websocket' // 全局引入 WebSocket 通讯组件

3.3 App.vue中声明websocket对象

App.vue

<template><div id="app"><router-view /></div>
</template><script>import {getInfo} from './api/login.js';import {getToken} from './utils/auth.js'export default {name: 'App',mounted() {// 每3秒检测一次websocket连接状态 未连接 则尝试连接 尽量保证网站启动的时候 WebSocket都能正常长连接setInterval(this.WebSocket_StatusCheck, 3000)// 绑定消息回调事件this.$WebSocket.WebSocketBandMsgReceivedEvent(this.WebSocket_OnMesage)// 初始化当前用户信息this.token = getToken()getInfo(this.token).then((rep)=>{console.log(rep)this.userName = rep.data.name}).catch((error)=>{console.log(error)})},data(){return{}},methods: {// 实际消息回调事件WebSocket_OnMesage(msg) {console.log('收到服务器消息:', msg.data)console.log(msg)let chatDiv = document.getElementById("chatDiv")let newH3 = document.createElement("div")if(msg.data.indexOf('openSuccess')>=0){// 忽略连接成功消息提示}else{if(msg.data.indexOf(this.userName)==0){// 说明是自己发的消息,应该靠右边悬浮newH3.innerHTML = "<div style='width:100%;text-align: right;'><h3 style=''>"+msg.data+"</h3></div>"}else{newH3.innerHTML = "<div style='width:100%;text-align: left;'><h3 style=''>"+msg.data+"</h3></div>"}}chatDiv.appendChild(newH3)},// 1、WebSocket连接状态检测:WebSocket_StatusCheck() {if (!this.$WebSocket.WebSocketHandle || this.$WebSocket.WebSocketHandle.readyState !== 1) {console.log('Websocket连接中断,尝试重新连接:')this.WebSocketINI()}},// 2、WebSocket初始化:async WebSocketINI() {// 1、浏览器是否支持WebSocket检测if (!('WebSocket' in window)) {console.log('您的浏览器不支持WebSocket!')return}let DEFAULT_URL = "ws://" + '127.0.0.1:8002' + '/websocket/' + new Date().getTime()// 3、创建Websocket连接const tmpWebsocket = new WebSocket(DEFAULT_URL)// 4、全局保存WebSocket操作句柄:main.js 全局引用this.$WebSocket.WebsocketINI(tmpWebsocket)// 5、WebSocket连接成功提示tmpWebsocket.onopen = function(e) {console.log('webcoket连接成功')}//6、连接失败提示tmpWebsocket.onclose = function(e) {console.log('webcoket连接关闭:', e)}}}}
</script>

3.4 聊天室界面.vue

<template><div><div style="margin-top: 1vh;margin-bottom: 1vh;font-weight: bold;">聊天内容:</div><div style="background-color: #c8c8c8;width: 100%;height: 80vh;" id="chatDiv"></div><div style="margin-top: 1vh;margin-bottom: 1vh;font-weight: bold;">聊天输入框:</div><el-input v-model="text"></el-input><el-button @click="sendMsg">点击发送</el-button></div>
</template><script>import {getInfo} from '../../api/login.js';import {getToken} from '../../utils/auth.js'import msgApi from '../../api/msg.js'export default {mounted() {//this.token = getToken()getInfo(this.token).then((rep)=>{console.log(rep)this.userName = rep.data.name}).catch((error)=>{console.log(error)})},data() {return {text: "",token:"",userName:"",}},methods: {sendMsg(){let msg = this.userName+":"+this.textmsgApi.sendMsg(msg).then((rep)=>{}).catch((error)=>{})this.text = ""}}}
</script><style scoped="true">.selfMsg{float: right;}
</style>

3.5 最终效果

用两个不同的浏览器,分别登录admin账号和wskh账号进行聊天测试,效果如下(左边为admin):

【系统开发】WebSocket + SpringBoot + Vue 搭建简易网页聊天室相关推荐

  1. springboot+vue搭建简单的聊天网站,从0到上线(腾讯云)

    springboot+vue搭建简单的聊天网站,从0到上线 整体架构简单梳理 云服务器 nginx的基础配置 springboot-eureka简单梳理 聊天功能实现的基础流程 ws的实现 整体架构简 ...

  2. 简易网页聊天室DEMO

    主要实现了群聊功能 原理很简单: 本地(javascript)向服务器发送消息(图片或者文字),由服务器(php)向各个主机转发 上传图片由ajax和html5实现,可以参考我之前的博客Html5&a ...

  3. 14级团队学习成果汇报 -- 利用express+socket.io搭建简易版聊天室

    周鹏,14级数理系,信息与计算科学大三学生.在LSGO软件技术团队负责前端部分,本图文是他的一个完整作品,代码可在Github上下载.

  4. Java和WebSocket开发网页聊天室

    一.项目简介 WebSocket是HTML5一种新的协议,它实现了浏览器与服务器全双工通信,这里就将使用WebSocket来开发网页聊天室,前端框架会使用AmazeUI,后台使用Java,编辑器使用U ...

  5. 基于WebSocket实现网页聊天室

    背景 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 ...

  6. Spring Boot WebChat 网页聊天室

    使用Spring Boot +Spring Security+Spring Data Jpa+Thymeleaf+Spring websocket 搭建的简易网页聊天室. 项目源码参考:http:// ...

  7. 项目总结 -网页聊天室

    项目名称:网页聊天室 项目地址:http://101.37.14.113:8888/ 一.项目简介 本项目是基于WebSocket和Socket实现的网页聊天室.使用到的技术包括:MVC编程思想.We ...

  8. java web 聊天室_Java和WebSocket开发网页聊天室

    小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ 一.项目简介WebSocket是HTML5一种新的 ...

  9. 云彩直淘系统开发——PHP源码搭建

    导语: 云彩直淘系统开发 --PHP源码搭建 拼团模式是一种新的商业模式(也可以说并不新),这种商业模式不仅是电商需要研究,所有的消费品企业都需要研究,重点是要搞清这种模式是不是一种代表未来一段时间的 ...

最新文章

  1. sqoop数据迁移的应用
  2. @程序员,地表最强的 CSDN 原创博主大赛来了!
  3. Html引入百度富文本编辑器ueditor
  4. 面试题目集锦--链表
  5. Windows x64内核学习笔记(一)—— 环境与配置
  6. BZOJ 2282 树的直径
  7. python gui插件_Python进阶量化交易专栏场外篇17- GUI控件在回测工具上的添加
  8. PostgreSQL adminpack扩展的作用
  9. nginx哪个版本性能好_nginx性能为什么好
  10. java 实现excel样式设置(居中、字体、大小、换行、合并行,列宽、指定特定字符串样式等)
  11. Navicat Premium创建MySQL存储过程
  12. Spring Boot笔记-WebSocket的使用
  13. Android应用发布渠道汇总(更新中)
  14. 小学计算机集体备课活动记录,信息技术学科组集体备课活动记录.doc
  15. 解锁计算机桌面,电脑锁屏按什么键解锁
  16. linux perl 升级,科学网—一次Perl版本升级引发的吐槽大会 - 黄健的博文
  17. AIX 操作系统安全配置指南
  18. overflow属性的用法
  19. Chrome 的哪些功能改变了我们浏览网页的方式?
  20. Android开发本地及网络Mp3音乐播放器(五)实现专辑封面图片

热门文章

  1. UTC时间、GMT时间、CST时间
  2. 航天一院(运载火箭研究院)待遇情况
  3. 用Python爬取中国校花网后,我发现她们都有个共同点!
  4. 大头贴计算机教程,如何用电脑摄像头做大头贴
  5. HOJ 2739 The Chinese Postman Problem 带权有向图上的中国邮路问题
  6. 小米3和BlackBerry Z3“撞衫了”!
  7. 巨蟹女眼中真实的摩羯(图
  8. 安卓7.0抓包之商店包(无需root)
  9. java nfa dfa_NFA 、DFA 简述
  10. python爬虫学习笔记3.2-urllib和request练习