赞
踩
1、最开始想到是今年的课程设计,想着做个有点意思的东西,发现关于websocket技术没有接触过,就搞了类似一个QQ的多聊天室聊天的小项目。
2、需要实现,登录,注册,等等等…当然最核心,最基础的还是我们的聊天的实现
3、采用的技术,后端java,前端vue
1、WebSocket是一种在单个TCP连接上进行全双工通信的协议
2、WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
3、简单来说,就是客户端给服务器端发消息,服务器端会有监听,并可以再给客户端发消息,客户端也有监听,对服务器端的消息进行处理。甲——>服务端——>其他用户
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
因为要实现多聊天室,多用户聊天,所以,需要一个当前聊天室的id(page),以及当前用户id(userId)
@ServerEndpoint(value = "/webSocket/{page}/{userId}")
将当前用户的会话存到一个map集合<房间id,该房间内用户sessionId集合set>
//遍历集合,将消息给该集合中的所有人
for (Session s : sessions) {
// if (!s.getId().equals(session.getId())) 可以加判断,不发给谁,
s.getBasicRemote().sendText(JSONUtil.toJsonStr(contentBo));
}
1、利用vue在data里面,定义一个变量socket
2、进行实例化操作,之后便可利用socket进行操作
if (typeof (WebSocket) === "undefined") {
alert("您的浏览器不支持socket")
} else {
// 实例化socket
this.socket = new WebSocket("ws://url(服务地址) + webSocket/" + page + "/" +userId)
}
3、4方法需要进行实时监听,建议写在vue 生命周期的mounted里面
send: function (msg) {
this.socket.send(msg)
}
package cn.itcast.config; import cn.hutool.core.bean.BeanUtil; import cn.hutool.json.JSONUtil; import cn.itcast.api.bo.ContentBo; import cn.itcast.api.entity.Content; import cn.itcast.api.entity.User; import cn.itcast.api.service.IContentService; import cn.itcast.api.service.IUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.time.LocalDateTime; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; /** * @author: zpt * @Date: 2019-09-20 15:12 * @Description: */ @Component @ServerEndpoint(value = "/webSocket/{page}/{userId}") public class WebSocket { private static IUserService userService; @Autowired public void setMyServiceImpl(IUserService userService){ WebSocket.userService = userService; } private static IContentService contentService; @Autowired public void setMyServiceImpl(IContentService contentService){ WebSocket.contentService = contentService; } private Logger log = LoggerFactory.getLogger(this.getClass()); /** * 用来记录房间及房间内用户session_id */ private static Map<String, Set> roomMap = new ConcurrentHashMap(8); /** * 用来记录session_id与用户id之间的关系 */ private static Map<String, Integer> userIdMap = new ConcurrentHashMap(8); @OnOpen public void open( @PathParam("page") String page, Session session, @PathParam("userId") Integer userId ) throws IOException { Set set = roomMap.get(page); userIdMap.put(session.getId(), userId); // 如果是新的房间,则创建一个映射,如果房间已存在,则把用户放进去 if (set == null) { set = new CopyOnWriteArraySet(); set.add(session); roomMap.put(page, set); } else { set.add(session); } } @OnClose public void close( @PathParam("page") String page, Session session, @PathParam("userId") Integer userId ) { userIdMap.remove(session.getId()); // 如果某个用户离开了,就移除相应的信息 if (roomMap.containsKey(page)) { roomMap.get(page).remove(session); } } @OnMessage public void reveiveMessage( @PathParam("page") String page, Session session, String message ) throws IOException { log.info("接受到用户{}的数据:{}", session.getId(), message); Integer userId = userIdMap.get(session.getId()); //存入数据库中 Content content = new Content(); content.setRoomId(Integer.valueOf(page)); content.setContent(message); content.setSendTime(LocalDateTime.now()); content.setSendId(userId); contentService.save(content); //查询当前用户信息 User user = userService.getById(userId); //返回给前端的Bo对象 ContentBo contentBo = new ContentBo(); BeanUtil.copyProperties(content, contentBo); BeanUtil.copyProperties(user, contentBo); // 拼接一下用户信息 //String msg = session.getId() + " : " + message; Set<Session> sessions = roomMap.get(page); // 给房间内所有用户推送信息 for (Session s : sessions) { if (!s.getId().equals(session.getId())) { s.getBasicRemote().sendText(JSONUtil.toJsonStr(contentBo)); } } } @OnError public void error( Throwable throwable ) { try { throw throwable; } catch (Throwable e) { log.error("未知错误"); } } }
new Vue({ el: '#app', data: { "roomId": null, "userId": null, "websocket": null, }, created() { //因为我是html页面引入的vue,因此页面之间的数据直接用了,location.href = "" //getQueryVariable方法起到了一个接受上一个页面传的参数的作用 this.userId = this.getQueryVariable('userId') this.roomId = this.getQueryVariable('roomId') }, mounted() { // 初始化 this.init() }, computed() { }, methods: { init: function () { if (typeof (WebSocket) === "undefined") { alert("您的浏览器不支持socket") } else { // 实例化socket this.socket = new WebSocket("ws://url(服务端地址)/webSocket/" + this.roomId + "/" + this.userId) // 监听socket连接 this.socket.onopen = this.open // 监听socket错误信息 this.socket.onerror = this.error // 监听socket消息 this.socket.onmessage = this.getMessage } }, open: function () { console.log("socket连接成功") }, error: function () { console.log("连接错误") }, send: function (msg) { this.socket.send(msg) }, close: function () { console.log("socket已经关闭") }, // 获取多个参数的时候 getQueryVariable: function (variable) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (pair[0] == variable) { return pair[1]; } } return (false); }, destroyed() { // 销毁监听 this.socket.onclose = this.close }, } )
https://blog.csdn.net/qq_43532386/article/details/111783423
https://blog.csdn.net/qq_43532386/article/details/111784152
https://blog.csdn.net/qq_43532386/article/details/111784809
链接:https://pan.baidu.com/s/1FWnDR-psILqPEC4XLeRs6w
提取码:jqzq
文件上传,直接上传的服务器,通过配置nginx进行访问。
整体仅供参考,实用意义不大!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。