java实现聊天室(websocket)
生活随笔
收集整理的這篇文章主要介紹了
java实现聊天室(websocket)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
引入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.1.3.RELEASE</version></dependency>Controller層,打開(kāi)聊天室界面
import com.shangfei.response.WebResponse; import com.shangfei.service.socket.WebSocketService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView;/*** @authoer:majinzhong* @Date: 2022/11/7* @Description: websocket的具體實(shí)現(xiàn)類(lèi)* 使用springboot的唯一區(qū)別是要@Component聲明下,而使用獨(dú)立容器是由容器自己管理websocket的,* 但在springboot中連容器都是spring管理的。* 雖然@Component默認(rèn)是單例模式的,但springboot還是會(huì)為每個(gè)websocket連接初始化一個(gè)bean,* 所以可以用一個(gè)靜態(tài)set保存起來(lái)。*/@RestController public class WebSocketController {@AutowiredWebSocketService webSocketService;/*** 打開(kāi)發(fā)送消息頁(yè)面* @return*/@RequestMapping("/webSocketPage")public ModelAndView page(){return new ModelAndView("index");}/*** 獲得在線人信息* @return*/@RequestMapping("/members")public WebResponse members(){return webSocketService.members();}}Service層,實(shí)時(shí)監(jiān)聽(tīng)并轉(zhuǎn)發(fā)消息
import cn.hutool.core.collection.CollectionUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.shangfei.mapper.plan.UserMapper; import com.shangfei.pojo.socket.SocketMsg; import com.shangfei.response.WebResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.CrossOrigin;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet;/*** @authoer:majinzhong* @Date: 2022/11/16* @description:*/ @Component @ServerEndpoint(value = "/websocket/{nickname}") @CrossOrigin @Service public class WebSocketService {@AutowiredUserMapper userMapper;/*** 用來(lái)存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象。**/private static CopyOnWriteArraySet<WebSocketService> webSocketSet = new CopyOnWriteArraySet<>();/*** 與某個(gè)客戶端的連接會(huì)話,需要通過(guò)它來(lái)給客戶端發(fā)送數(shù)據(jù)**/private Session session;/*** 用戶名稱**/private String nickname;/*** 用來(lái)記錄sessionId和該session進(jìn)行綁定**/private static Map<String,Session> map = new HashMap<String, Session>();public WebResponse members(){Set<String> members = map.keySet();if(!CollectionUtil.isEmpty(members)) {List<Map<String,String>> userList=new ArrayList<>();for(String member:members){//通過(guò)工號(hào)查詢名字Map<String, String> user = userMapper.selectName(member);if(!CollectionUtil.isEmpty(user)){userList.add(user);}else{Map<String, String> userMap = new HashMap<>();userMap.put("username",member);userMap.put("name","");userList.add(userMap);}}return WebResponse.success(userList);}else{return WebResponse.success(members);}}/*** 連接建立成功調(diào)用的方法*/@OnOpenpublic void onOpen(Session session,@PathParam("nickname") String nickname) {this.session = session;this.nickname=nickname;map.put(nickname, session);webSocketSet.add(this);System.out.println("有新連接加入:"+nickname+",當(dāng)前在線人數(shù)為" + webSocketSet.size());this.session.getAsyncRemote().sendText("恭喜:"+nickname+" 成功連接上WebSocket(其頻道號(hào):"+session.getId()+")-->當(dāng)前在線人數(shù)為:"+webSocketSet.size());}/*** 連接關(guān)閉調(diào)用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);List<String> nickname = this.session.getRequestParameterMap().get("nickname");for(String nick:nickname) {map.remove(nick);}System.out.println("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + webSocketSet.size());}/*** 收到客戶端消息后調(diào)用的方法*/@OnMessagepublic void onMessage(String message, Session session,@PathParam("nickname") String nickname) {System.out.println("來(lái)自客戶端的消息-->"+nickname+": " + message);//從客戶端傳過(guò)來(lái)的數(shù)據(jù)是json數(shù)據(jù),所以這里使用jackson進(jìn)行轉(zhuǎn)換為SocketMsg對(duì)象,// 然后通過(guò)socketMsg的type進(jìn)行判斷是單聊還是群聊,進(jìn)行相應(yīng)的處理:ObjectMapper objectMapper = new ObjectMapper();SocketMsg socketMsg;try {socketMsg = objectMapper.readValue(message, SocketMsg.class);if(socketMsg.getType() == 1){//單聊.需要找到發(fā)送者和接受者.socketMsg.setFromUser(nickname);Session fromSession = map.get(socketMsg.getFromUser());Session toSession = map.get(socketMsg.getToUser());//發(fā)送給接受者.if(toSession != null){//發(fā)送給發(fā)送者.fromSession.getAsyncRemote().sendText(nickname+"->"+toSession.getPathParameters().get("nickname")+":"+socketMsg.getMsg());toSession.getAsyncRemote().sendText(nickname+"->"+toSession.getPathParameters().get("nickname")+":"+socketMsg.getMsg());}else{//發(fā)送給發(fā)送者.fromSession.getAsyncRemote().sendText("系統(tǒng)消息:對(duì)方不在線或者您輸入的頻道號(hào)不對(duì)");}}else{//群發(fā)消息broadcast(nickname+": "+socketMsg.getMsg());}} catch (Exception e) {e.printStackTrace();}}/*** 發(fā)生錯(cuò)誤時(shí)調(diào)用*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("發(fā)生錯(cuò)誤");error.printStackTrace();}/*** 群發(fā)自定義消息*/public void broadcast(String message) {for (WebSocketService item : webSocketSet) {/*** 同步異步說(shuō)明參考:http://blog.csdn.net/who_is_xiaoming/article/details/53287691** this.session.getBasicRemote().sendText(message);**/item.session.getAsyncRemote().sendText(message);}} }resources.templates下index.html代碼,調(diào)用websocket服務(wù)
<body> <header><meta http-equiv="Content-Type" charset="utf-8"> </header> <div><input type="text" id="nickname"/><button onclick="connectWebSocket()">連接WebStock</button><button onclick="closeWebSocket()">斷開(kāi)連接</button><hr/><br/>消息:<input id="text" type="text"/>頻道號(hào):<input id="toUser" type="text"/><button onclick="send()">發(fā)送消息</button><div id="message"></div> </div> <script type="text/javascript">var websocket = null;function connectWebSocket() {var nickname = document.getElementById("nickname").value;if (nickname === "") {alert("請(qǐng)輸入昵稱");return;}//判斷當(dāng)前瀏覽器是否支持WebSocketif ('WebSocket' in window) {websocket = new WebSocket("ws://localhost:8080/websocket/" + nickname);} else {alert('Not support websocket')}//連接發(fā)生錯(cuò)誤的回調(diào)方法websocket.onerror = function () {setMessageInnerHTML("error");};//連接成功建立的回調(diào)方法websocket.onopen = function (event) {console.log(event)setMessageInnerHTML("Loc MSG: 成功建立連接");}//接收到消息的回調(diào)方法websocket.onmessage = function (event) {console.log(event)setMessageInnerHTML(event.data);}//連接關(guān)閉的回調(diào)方法websocket.onclose = function (event) {console.log(event)setMessageInnerHTML("Loc MSG:關(guān)閉連接");}//監(jiān)聽(tīng)窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒(méi)斷開(kāi)就關(guān)閉窗口,server端會(huì)拋異常。window.onbeforeunload = function () {websocket.close();}}//將消息顯示在網(wǎng)頁(yè)上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//關(guān)閉連接function closeWebSocket() {websocket.close();}//發(fā)送消息function send() {//獲取輸入的文本信息進(jìn)行發(fā)送var message = document.getElementById('text').value;var toUser = document.getElementById('toUser').value;var socketMsg = {msg: message, toUser: toUser};if (toUser == '') {//群聊.socketMsg.type = 0;} else {//單聊.socketMsg.type = 1;}websocket.send(JSON.stringify(socketMsg));} </script> </body>config配置文件
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @authoer:majinzhong* @Date: 2022/11/7* @description:*/ @Configuration public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();} }總結(jié)
以上是生活随笔為你收集整理的java实现聊天室(websocket)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 混淆矩阵的计算方式
- 下一篇: 美学原理-杨宁课堂笔记