博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java WebSocket实现网络聊天室(群聊+私聊)
阅读量:3732 次
发布时间:2019-05-22

本文共 11565 字,大约阅读时间需要 38 分钟。

1、简单说明

在网上看到一份比较nice的基于webSocket网页聊天项目,准备看看学习学习,如是有了这篇文章!原博主博客:

谢谢博主的文章和项目,我是抱着学习的态度,若有理解错的地方,请指正。

2、项目内容

项目的功能说明去原博主博客看吧,项目上改进的地方,我具体做以下说明。

(1)webSocket服务

对于webSocket服务代码,我进行一部分的封装和优化,主要是消息内容的封装、用户信息封装。

页面显示用户的昵称,指定用户昵称进行消息发送。

ChatServer.java

 

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
onlineUserMap = new ConcurrentHashMap
(); //在线用户 /** * 连接成功调用的方法 */ @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; }}

 

 

 

OnlineUser.java

 

public class OnlineUser {    private String userid;    private String nickname;    private Session session;}

 

 

 

Message.java

 

package com.ccq.webSocket;import net.sf.json.JSONArray;import net.sf.json.JSONObject;import org.apache.commons.collections.CollectionUtils;import org.apache.log4j.Logger;import javax.websocket.Session;import java.io.IOException;import java.util.ArrayList;import java.util.Collection;import java.util.List;/** * @author ccq * @Description 消息类 * @date 2017/12/16 19:08 */public class Message {    private static Logger logger = Logger.getLogger(Message.class);    /**     * 消息类型     */    public static String NOTICE = "notice";     //通知    public static String MESSAGE = "message";   //消息    /**     * 组装信息返回给前台     * @param message  交互信息     * @param type     信息类型     * @param userList 在线列表     * @return     *     * "massage" : {     *              "from" : "xxx",     *              "to" : "xxx",     *              "content" : "xxx",     *              "time" : "xxxx.xx.xx"     *          },     * "type" : {notice|message},     * "list" : {[xx],[xx],[xx]}     */    public static String getMessage(String message,String type,Collection
userList){ JSONObject msg = new JSONObject(); msg.put("message",message); msg.put("type", type); if(CollectionUtils.isNotEmpty(userList)){ List
propertys = new ArrayList
(); propertys.add("session"); JSONArray userListArray = JSONArray.fromObject(userList,JsonConfigUtils.getJsonConfig(propertys)); msg.put("list", userListArray); } return msg.toString(); } /** * 消息内容 * @param fromUser * @param to * @param content * @param time * @return * { * "from" : "xxx", * "to" : "xxx", * "content" : "xxx", * "time" : "xxxx.xx.xx" * } */ public static String getContent(OnlineUser fromUser,String to,String content,String time){ JSONObject contentJson = new JSONObject(); // 转化为json串时去掉session,用户session不能被序列化 List
propertys = new ArrayList
(); propertys.add("session"); contentJson.put("from",JSONObject.fromObject(fromUser,JsonConfigUtils.getJsonConfig(propertys))); contentJson.put("to",to); contentJson.put("content",content); contentJson.put("time",time); return contentJson.toString(); } /** * 广播消息 * @param message 消息 * @param onlineUsers 在线用户 */ public static void broadcast(String message,Collection
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()); } }}

(2)用户头像上传

 

在网上找了一个amazeui的图片上传,可以对图片进行裁剪,地址:

确实比较好用,贴一下主要代码

 

@RequestMapping(value = "{userid}/upload", method = RequestMethod.POST,produces = "application/json; charset=utf-8")    @ResponseBody    public String updateUserPassword(@PathVariable("userid") String userid,String image,HttpServletRequest request){        JSONObject responseJson = new JSONObject();        String filePath = "I:\\IDEA2017-02\\img\\";        String PicName= UUID.randomUUID().toString()+".png";        String header ="data:image";        String[] imageArr=image.split(",");        if(imageArr[0].contains(header)) {//是img的            // 去掉头部            image=imageArr[1];            // 修改图片            BASE64Decoder decoder = new BASE64Decoder();            try {                byte[] decodedBytes = decoder.decodeBuffer(image); // 将字符串格式的image转为二进制流(biye[])的decodedBytes                String imgFilePath = filePath + PicName;           //指定图片要存放的位                File targetFile = new File(filePath);                if(!targetFile.exists()){                    targetFile.mkdirs();                }                FileOutputStream out = new FileOutputStream(imgFilePath);//新建一个文件输出器,并为它指定输出位置imgFilePath                out.write(decodedBytes); //利用文件输出器将二进制格式decodedBytes输出                out.close();                // 修改图片                User user = userService.getUserById(userid);                user.setProfilehead(PicName);                int flag = userService.updateUser(user);                if(flag > 0){                    Log log = LogUtil.setLog(userid, CommonDate.getTime24(), WordDefined.LOG_TYPE_UPDATE,WordDefined.LOG_DETAIL_UPDATE_PROFILEHEAD, NetUtil.getIpAddress(request));                    logService.insertLog(log);                }else{                    responseJson.put("result","error");                    responseJson.put("msg","上传失败!");                }            } catch (IOException e) {                e.printStackTrace();            }        }        responseJson.put("result","ok");        responseJson.put("msg","上传成功!");        responseJson.put("fileUrl","/pic/" + PicName);        return responseJson.toString();    }

 

 

 

 

 

 

 

3、改进的图片

 

4、源码地址(2017-12-17晚更新)

由于小弟刚学会使用github,所以现在才把修改的代码地址放出来。

源码github地址:

说明一下:

1、github是一个好东西,有时间学习一下如何使用git版本管理工具还是蛮有用的;

2、使用maven+idea开发项目确实很带劲;

3、老老实实学习,快快乐乐进步。

你可能感兴趣的文章
Qt Http通信: TLS initialization failed 解决方法
查看>>
QT QMessageBox 弹出两次的可能原因
查看>>
Java 无法运行Java虚拟机 | cmd下输入java -version报错 .Error: Could not create the Java Virtual Machine.
查看>>
在C++里调用Java可执行jar包
查看>>
QT 设置QLabel文字竖直居中
查看>>
Java中调用ImageJ,与直接使用ImageJ软件处理所得图片黑白颠倒的问题
查看>>
解决使用ployfit拟合曲线得到折线图(不够光滑)的问题
查看>>
ImageDataGenerator读取的数据集转Numpy array
查看>>
Python查看函数源码
查看>>
保存Shap生成的神经网络解释图(shap.image_plot)
查看>>
iOS底层代码探索003-类的底层探索
查看>>
iOS底层代码探索003-类的底层探索后续
查看>>
关于Java中JVM,JRE,JDK之间的关系
查看>>
数据类型
查看>>
使用 IDEA编辑器 创建 serlvet 项目的完整流程
查看>>
配置servlet的xml时报错:URL is not registered(Settings | Languages & Frameworks | Schemas aand DTDs)
查看>>
maven插件打包项目jar包时出错
查看>>
汇编语言 内部中断
查看>>
汇编语言 标志位
查看>>
汇编语言 ADC指令和SBB指令
查看>>