1. 程式人生 > >netty-socketio即時聊天包括文字、emoji表情、檔案處理

netty-socketio即時聊天包括文字、emoji表情、檔案處理

netty-socketio是一個開源的Socket.io伺服器端的一個java的實現,它基於Netty框架。專案地址為:https://github.com/mrniko/netty-socketio

最主要:服務端的主要工作,就是新增各種事件的監聽,然後在監聽中,做出相應的處理。

程式碼說明:
1.本程式碼不能完全copy然後執行,只是放出了關鍵程式碼,需要對socketio有一定的理解;
2.有聊天emoji表情的處理功能;
3.有檔案的上傳功能:我這裡把檔案分為圖片和非圖片檔案,因為圖片檔案要實時展示出來的。

引入maven依賴:

<dependency>
<groupId>com.corundumstudio.socketio</groupId> <artifactId>netty-socketio</artifactId> <version>1.7.11</version> </dependency>

新建ServerRunner類實現ApplicationListener確保伺服器在spring啟動完成後啟動,新增@Service標籤確保spring可以掃描到。

@Service("ServerRunner")
public class
ServerRunner implements ApplicationListener<ContextRefreshedEvent>{ private static final Logger logger = LoggerFactory.getLogger(ServerRunner.class); @Value("${server.host}") private String host ; @Value("${server.port}") private Integer port; @Value("${fileUrl}") private String fileUrl;
private EmojiConverter emojiConverter = EmojiConverter.getInstance(); //會話集合 private static final ConcurrentSkipListMap<String, ClientInfo> webSocketMap = new ConcurrentSkipListMap<>(); //靜態變數,用來記錄當前線上連線數。(原子類、執行緒安全) private static AtomicInteger onlineCount = new AtomicInteger(0); private SocketIOServer server; @Override public void onApplicationEvent(ContextRefreshedEvent event) { //埠 int WSS_PORT=port; //伺服器ip String WSS_HOST=host; System.out.println("WSS_PORT"+WSS_PORT+"**************************"+WSS_HOST); //避免重複啟動 if( server== null){ Configuration config = new Configuration(); //伺服器ip config.setHostname(WSS_HOST); config.setPort(WSS_PORT); config.setMaxFramePayloadLength(1024 * 1024);//防止上傳檔案超過預設值報錯 config.setMaxHttpContentLength(1024 * 1024); //該處進行身份驗證 config.setAuthorizationListener(handshakeData -> {return true;}); //異常 config.setExceptionListener(new ExceptionListenerAdapter(){ @Override public boolean exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { logger.debug("錯誤:"+e.getMessage()); ctx.close(); return true; } }); server = new SocketIOServer(config); //新增連結事件監聽 server.addConnectListener(new ConnectListener() { @Override public void onConnect(SocketIOClient client) { logger.debug("socket 建立新連線"); ... } }); //新增銷燬連結事件監聽 server.addDisconnectListener(new DisconnectListener() { @Override public void onDisconnect(SocketIOClient client) { logger.debug("socket 斷開連線"); ... } }); //添加發送訊息事件監聽 server.addEventListener("messageEvent", Message.class, new DataListener<Message>(){ @Override public void onData(SocketIOClient client, Message data, AckRequest ackSender) { SendData sendData = new SendData();//傳送的訊息 try{ Message chat = new Message();//存入資料庫 Integer userId = data.getUserId(); String filePath = "/"+userId+"/"; String fileRandomName = null; String format =null; ClientInfo si = webSocketMap.get(userId); if (si != null) { String result = null; byte[] fileByte = data.getFileByte();//接收客戶端傳來的檔案位元組陣列 String fileName = data.getFileName();//接收客戶的傳來的檔名稱 Integer msgType = data.getMsgType();//接收客戶的傳來的檔案型別 Integer materialId = null; if(msgType==1){//1文字 result = emojiConverter.toAlias(data.getMsgContent());//對emoji表情進行轉入,否則存入mysql資料庫將報錯 }else if(msgType==2||msgType==3){//2圖片和3檔案 if(fileByte!=null){ //這裡儲存檔案 } } chat.setCreater(userId); chat.setMsgContent(result); chat.setMsgType(msgType); chat.setMaterialId(materialId); //這裡儲存聊天記錄 Integer sendStatus = 2;//傳送留言的狀態,2未傳送 SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String msgDate = simpleDateFormat.format(new Date()); sendData.setCreateDate(new Date()); sendData.setMsgContent(result); sendData.setCreater(userId); sendData.setMsgType(msgType); if(fileByte!=null){ sendData.setFormat(format); sendData.setFileName(fileName); sendData.setFileByte(fileByte); sendData.setFilePath(filePath+fileRandomName); } List<Integer> userIds = data.getUserIds();//客戶端傳來的要轉發給其他的使用者的Id if(userIds!=null){ for(Integer targetClientId : userIds){ if(targetClientId!=userId){ ClientInfo clientInfo = webSocketMap.get(targetClientId); if (clientInfo != null && clientInfo.isOnline()){//當前線上 UUID target = new UUID(clientInfo.getMostSignificantBits(), clientInfo.getLeastSignificantBits()); // 向目標會話傳送資訊 if(server.getClient(target)!=null){ server.getClient(target).sendEvent("messageEvent", sendData); } sendStatus=1;//傳送留言成功 }else{//不線上 sendStatus=2;//未傳送 } //對留言傳送成功或失敗的處理 } } } } }catch(Exception e){ e.printStackTrace(); logger.debug("傳送留言異常:"+e.getMessage()); sendData.setSuccess(false); sendData.setMsgContent("傳送留言異常"); } // 向當前會話傳送資訊 client.sendEvent("messageEvent", sendData); } }); } } }
public class Message {

    private List<Integer> userIds;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createDate;

    private Integer msgType;

    private Integer materialId;

    private String msgContent;
    
    private String createrFullname;
    
    private String filePath;
    
    private Integer userId;//在接收聊天訊息時用到,等於creater欄位
    
    private byte[] fileByte;
    
    private String fileName;
    
    private String format;
    //getter and setter
}
public class SendData extends Message {
	private Boolean success;
	private String msgDate;
	private String message;
	//getter and setter
}

emoji表情報錯參考:https://blog.csdn.net/qq_23888451/article/details/84638365

另外,該功能是在這篇文章上,做了些改進。