Java WebSocket實現網絡聊天室(羣聊+私聊)

一、簡單說明

在網上看到一份比較nice的基於webSocket網頁聊天項目,準備看看學習學習,如是有了這篇文章!原博主博客:http://blog.csdn.net/Amayadream/article/details/50551617java

謝謝博主的文章和項目,我是抱着學習的態度,如有理解錯的地方,請指正。jquery

二、項目內容

項目的功能說明去原博主博客看吧,項目上改進的地方,我具體作如下說明。git

(1)webSocket服務github

對於webSocket服務代碼,我進行一部分的封裝和優化,主要是消息內容的封裝、用戶信息封裝。web

頁面顯示用戶的暱稱,指定用戶暱稱進行消息發送。apache

ChatServer.javajson

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;
    }
}

OnlineUser.javawebsocket

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

  Message.javasession

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<OnlineUser> userList){
        JSONObject msg = new JSONObject();
        msg.put("message",message);
        msg.put("type", type);
 
        if(CollectionUtils.isNotEmpty(userList)){
            List<String> propertys = new ArrayList<String>();
            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<String> propertys = new ArrayList<String>();
        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<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());
        }
    }
}

(2)用戶頭像上傳app

 

在網上找了一個amazeui的圖片上傳,能夠對圖片進行裁剪,地址:http://www.jq22.com/jquery-info13022

確實比較好用,貼一下主要代碼

 

@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();
    }

三、改進的圖片

 

 

 

四、源碼地址(2017-12-17晚更新)

因爲小弟剛學會使用github,因此如今才把修改的代碼地址放出來。

源碼github地址:https://github.com/chengchuanqiang/WebChat

說明一下:

一、github是一個好東西,有時間學習一下如何使用git版本管理工具仍是蠻有用的,有須要的視頻的我能夠免費發給你;

二、使用maven+idea開發項目確實很帶勁;

三、老老實實學習,快快樂樂進步。

相關文章
相關標籤/搜索