Spring Boot——整合websocket构建在线聊天室(群聊 / 私聊)

    1.引入依赖


            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-websocket
        

2.注入对象ServerEndpointExporter

/*
 *
 *编写一个WebSocketConfig配置类,注入对象ServerEndpointExporter,
 *      这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
 */

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

3.WebSocket 具体实现类

package com.example.springbootwebsocket.mysocket;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 *  
 * 虽然@Component默认是单例模式的,但是spring boot 还是会为每个websocket连接初始化一个bean,所以这里使用一个静态的set保存spring boot
 * 
 * 创建的bean--MyWebSocket.
 **/
@ServerEndpoint(value="/websocket/{nickname}")// websocket连接点映射.
@Component
public class MyWebSocket {
	
	//用来存储每个客户端对应的MyWebSocket对象.
	private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();
	//用来记录sessionId和该session之间的绑定关系.
	private static Map map = new HashMap();
	
	private Session session;//当前会话的session.
	private String nickname;//昵称.
	
	/**
	 * 成功建立连接调用的方法.
	 */
	@OnOpen
	public void onOpen(Session session,@PathParam("nickname") String nickname){
		this.session = session;
		this.nickname = nickname;
		map.put(session.getId(), session);
		webSocketSet.add(this);//加入set中.
		this.session.getAsyncRemote().sendText(nickname+"上线了,(我的id号是"+session.getId()+")");
	}
	
	/**
	 * 连接关闭调用的方法.
	 */
	@OnClose
	public void onClose(Session session){
		webSocketSet.remove(this);//从set中移除.
		map.remove(session.getId());
	}
	
	/**
	 * 收到客户端消息后调用的方法.
	 */
	@OnMessage
	public void onMessage(String message,Session session,@PathParam("nickname") String nickname){
		
		//message 不是普通的string ,而是我们定义的SocketMsg json字符串.
		try {
			SocketMsg socketMsg = new ObjectMapper().readValue(message, SocketMsg.class);
			

			//单聊.
			if(socketMsg.getType() == 1){
				
				//单聊:需要找到发送者和接受者即可.
				socketMsg.setFromUser(session.getId());//发送者.
				//socketMsg.setToUser(toUser);//这个是由客户端进行设置.
				Session fromSession = map.get(socketMsg.getFromUser());
				Session toSession = map.get(socketMsg.getToUser());
				if(toSession != null){
					//发送消息.
					fromSession.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
					toSession.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
				}else{
					fromSession.getAsyncRemote().sendText("系统消息:对方不在线或者您输入的id号有误");
				}
			}else {
				//群发给每个客户端.
				broadcast(socketMsg,nickname);
			}
			
		} catch (JsonParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 发生错误时调用.
	 */
	public void onError(Session session,Throwable error){
		System.out.println("发生错误");
		error.printStackTrace();
	}
	
	/**
	 * 群发的方法.
	 * @param 
	 */
	private void broadcast(SocketMsg socketMsg ,String nickname){
		for(MyWebSocket item:webSocketSet){
			//发送消息.
			item.session.getAsyncRemote().sendText(nickname+":"+socketMsg.getMsg());
		}
	}
	
}

4.创建消息对象SocketMsg

package com.example.springbootwebsocket.mysocket;

public class SocketMsg {
	private int type;//聊天类型,0:群聊;1:单聊;
	private String fromUser;//发送者.
	private String toUser;//接受者. session.getId();
	private String msg;//消息.
	public int getType() {
		return type;
	}
	public void setType(int type) {
		this.type = type;
	}
	public String getFromUser() {
		return fromUser;
	}
	public void setFromUser(String fromUser) {
		this.fromUser = fromUser;
	}
	public String getToUser() {
		return toUser;
	}
	public void setToUser(String toUser) {
		this.toUser = toUser;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
}

5.static目录下创建客户端 webSocketTest.html




    
    聊天室
    




昵称:




消息: id号

测试,打开多个登录窗口,输入http://127.0.0.1:8080/webSocketTest.html ,输入昵称点击连接即可登录成功,群聊直接发送消息即可,私聊输入完消息后,选择对应那个人的id号码就行,快去试试吧:

Spring Boot——整合websocket构建在线聊天室(群聊 / 私聊)_第1张图片

总结:了解了websocket底层是怎么实现的,websocket协议稍微麻烦,其实我们完全可以用它的子协议STOMP来实现本文所有的功能,因已封装的很好,用起来非常简单,实例:SpringBoot+STOMP 实现聊天室(单聊+多聊)及群发消息详解。

参考:https://www.iteye.com/blog/412887952-qq-com-2405514

你可能感兴趣的:(Spring,Boot)