在 GitHub 上面找了一个看起来还不错的网页版聊天室, 基于 ssm 加 websocket 实现的, 特此分享一下, GitHub 地址放在文章末尾, 大家可以自行下载跑起来玩玩, 项目如何跑起来我写在 readme 里面了. 接下来简单的看一下项目和核心代码的实现.
登录页面:
首页: 可以实现单人聊天和群聊, 还有机器人自动回复功能, 还有一些个人设置, 系统设置功, 日志统计功能...
接下来看看核心代码 websocket 的实现:
首页 jsp 关于 websocket 的代码:
- var wsServer = null;
- var ws = null;
- wsServer = "ws://" + location.host+"${pageContext.request.contextPath}" + "/chatServer/${userid}";
- ws = new WebSocket(wsServer); // 创建 WebSocket 对象
- ws.onopen = function (evt) {
- layer.msg("已经建立连接", { offset: 0});
- };
- ws.onmessage = function (evt) {
- analysisMessage(evt.data); // 解析后台传回的消息, 并予以展示
- };
- ws.onerror = function (evt) {
- layer.msg("产生异常", { offset: 0});
- };
- ws.onclose = function (evt) {
- layer.msg("已经关闭连接," + evt.reason, { offset: 0});
- };
websocket server 的实现;
- package com.ccq.webSocket;
- import com.ccq.pojo.User;
- import com.ccq.utils.CommonDate;
- import.NET.sf.JSON.JSONObject;
- import org.apache.log4j.Logger;
- import javax.servlet.http.HttpSession;
- import javax.websocket.*;
- import javax.websocket.server.PathParam;
- import javax.websocket.server.ServerEndpoint;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- /**
- * @author ccq
- * @Description webSocket 服务
- * @date 2017/12/16 17:31
- */
- @ServerEndpoint(value="/chatServer/{userid}", configurator = HttpSessionConfigurator.class)
- public class ChatServer {
- private static Logger logger = Logger.getLogger(ChatServer.class);
- private static int onlineCount = 0; // 记录连接数目
- // Map < 用户 id, 用户信息 >
- private static Map<String, OnlineUser> onlineUserMap = new ConcurrentHashMap<String, OnlineUser>(); // 在线用户
- /**
- * 连接成功调用的方法
- */
- @OnOpen
- public void onOpen(@PathParam("userid") String userid , Session session, EndpointConfig config){
- logger.info("[ChatServer] connection : userid =" + userid + ", sessionId =" + session.getId());
- // 增加用户数量
- addOnlineCount();
- // 获取当前用户的 session
- HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
- User user = (User) httpSession.getAttribute("user"); // 获得当前用户信息
- // 将当前用户存到在线用户列表中
- OnlineUser onlineUser = new OnlineUser(user.getUserid(),user.getNickname(),session);
- onlineUserMap.put(user.getUserid(),onlineUser);
- // 通知所有在线用户, 当前用户上线
- String content = "[" + CommonDate.getTime24() + ":" + user.getNickname() + "加入聊天室, 当前在线人数为" + getOnlineCount() + "位" + "]";
- JSONObject msg = new JSONObject();
- msg.put("content",content);
- String message = Message.getMessage(msg.toString(),Message.NOTICE,onlineUserMap.values());
- Message.broadcast(message,onlineUserMap.values());
- }
- /**
- * 连接关闭方法
- */
- @OnClose
- public void onClose(@PathParam("userid") String userid,Session session,CloseReason closeReason){
- logger.info("[ChatServer] close : userid =" + userid + ", sessionId =" + session.getId() +
- ", closeCode =" + closeReason.getCloseCode().getCode() + ", closeReason =" +closeReason.getReasonPhrase());
- // 减少当前用户
- subOnlienCount();
- // 移除的用户信息
- OnlineUser removeUser = onlineUserMap.remove(userid);
- onlineUserMap.remove(userid);
- // 通知所有在线用户, 当前用户下线
- String content = "["+ CommonDate.getTime24() + ":" + removeUser.getNickname() + "离开聊天室, 当前在线人数为" + getOnlineCount() + "位" + "]";
- JSONObject msg = new JSONObject();
- msg.put("content",content);
- if(onlineUserMap.size()> 0){
- String message = Message.getMessage(msg.toString(), Message.NOTICE, onlineUserMap.values());
- Message.broadcast(message,onlineUserMap.values());
- }else{
- logger.info("content : ["+ CommonDate.getTime24() + ":" + removeUser.getNickname() + "离开聊天室, 当前在线人数为" + getOnlineCount() + "位" + "]");
- }
- }
- /**
- * 接收客户端的 message, 判断是否有接收人而选择进行广播还是指定发送
- * @param data 客户端发来的消息
- */
- @OnMessage
- public void onMessage(@PathParam("userid") String userid,String data){
- logger.info("[ChatServer] onMessage : userid =" + userid + ", data =" + data);
- JSONObject messageJson = JSONObject.fromObject(data);
- JSONObject message = messageJson.optJSONObject("message");
- String to = message.optString("to");
- String from = message.optString("from");
- // 将用户 id 转换为名称
- to = this.userIdCastNickName(to);
- OnlineUser fromUser = onlineUserMap.get(from);
- String sendMessage = Message.getContent(fromUser,to,message.optString("content"),message.optString("time"));
- String returnData = Message.getMessage(sendMessage, messageJson.optString("type"),null);
- if(to == null || to.equals("")){ // 进行广播
- Message.broadcast(returnData.toString(),onlineUserMap.values());
- }else{
- Message.singleSend(returnData.toString(), onlineUserMap.get(from)); // 发送给自己
- String[] useridList = message.optString("to").split(",");
- for(String id : useridList){
- if(!id.equals(from)){
- Message.singleSend(returnData.toString(), onlineUserMap.get(id)); // 分别发送给指定的用户
- }
- }
- }
- }
- /**
- * 发生错误
- * @param throwable
- */
- @OnError
- public void onError(@PathParam("userid") String userid,Session session,Throwable throwable){
- logger.info("[ChatServer] close : userid =" + userid + ", sessionId =" + session.getId() +", throwable =" + throwable.getMessage() );
- }
- public static int getOnlineCount() {
- return onlineCount;
- }
- public synchronized void addOnlineCount(){
- onlineCount++;
- }
- public synchronized void subOnlienCount(){
- onlineCount--;
- }
- /**
- * 将用户 id 转换为名称
- * @param userIds
- * @return
- */
- private String userIdCastNickName(String userIds){
- String niceNames = "";
- if(userIds != null && !userIds.equals("")){
- String[] useridList = userIds.split(",");
- String toName = "";
- for (String id : useridList){
- toName = toName + onlineUserMap.get(id).getNickname() + ",";
- }
- niceNames = toName.substring(0,toName.length() - 1);
- }
- return niceNames;
- }
- }
私聊和群聊的发送代码:
- /**
- * 广播消息
- * @param message 消息
- * @param onlineUsers 在线用户
- */
- public static void broadcast(String message,Collection<OnlineUser> onlineUsers){
- /*************************** 在线用户 ***************************/
- StringBuffer userStr = new StringBuffer();
- for(OnlineUser user : onlineUsers){
- userStr.append(user.getNickname() + ",");
- }
- userStr.deleteCharAt(userStr.length()-1);
- logger.info("[broadcast] message =" + message + ", onlineUsers =" + userStr.toString());
- /*************************** 在线用户 ***************************/
- for(OnlineUser user : onlineUsers){
- try {
- user.getSession().getBasicRemote().sendText(message);
- } catch (IOException e) {
- e.printStackTrace();
- logger.info("消息发送失败!" + e.getMessage());
- continue;
- }
- }
- }
- /**
- * 对特定用户发送消息
- * @param message
- * @param onlineUser
- */
- public static void singleSend(String message, OnlineUser onlineUser){
- logger.info("[singleSend] message =" + message + ", toUser =" + onlineUser.getNickname());
- try {
- onlineUser.getSession().getBasicRemote().sendText(message);
- } catch (IOException e) {
- e.printStackTrace();
- logger.info("消息发送失败!" + e.getMessage());
- }
- }
记住几个关键 API:
OnOpen: 建立连接
OnClose: 关闭连接
OnMessage: 接收消息
发送消息的核心方法是通过某个 session 的. getBasicRemote().sendText(message) 来发送的.
ok,websocket 大概就是这样, 你可以亲自啊跑一下试试, 也十分欢迎大家一起来丰富这个小项目, 增加一些有趣的功能, 让大家欣赏, 我会第一时间在 GitHub 上面写上你的大名, 以表感谢.
GitHub 链接: https://github.com/MrLiu1227/WebChat.git
没有基础的同学可以跑一个十分干净的 websocket 示例: https://github.com/MrLiu1227/websocket.git
posted on 2019-05-19 21:57 今天也是阳光正好 阅读 (...) 评论 (...) 编辑 收藏
来源: https://www.cnblogs.com/liuyuan1227/p/10889436.html