java-websocket即时通讯-聊天室

效果预览


有小伙伴需要源码,该文章中的代码年代久远,重新弄了一个seven-im,请移步

java-websocket即时通讯-聊天室_第1张图片

web即时通讯的解决方式


  • 轮询:简单粗暴,过多的请求,服务器表示压力很大

  • 长连接:发送请求到服务器,有消息时才返回,长时间占用资源

  • websocket:基于tcp新的协议,双向通信

    废话少说,上代码(部分关键代码)!

html



交流平台
发送

js

var Chat = {};
Chat.socket = null;
Chat.connect = (function(host){
    if ('WebSocket' in window) {
        Chat.socket = new WebSocket(host);
    } else if ('MozWebSocket' in window) {
        Chat.socket = new MozWebSocket(host);
    } else {
        Console.log('Error: WebSocket is not supported by this browser.');
        return;
    }
    //websocket连接打开时
    Chat.socket.onopen = function () {
        document.getElementById('chat').onkeydown = function(event) {
            if (event.keyCode == 13) {
                Chat.sendMessage();
                event.returnValue = false;
                event.preventDefault();
            }
        };
    };
    //websocket连接关闭时
    Chat.socket.onclose = function () {
        document.getElementById('chat').onkeydown = null;
    };
    //websocket连接有消息时
    Chat.socket.onmessage = function (message) {
        var data = eval('(' + message.data + ')');
        //data即为后台发送的数据,在此根据数据内容进行判断属于Chat.info | Chat.self | Chat.other
    }
    
});
//初始化
Chat.initialize = function() {
    if (window.location.protocol == 'http:') {
        Chat.connect('ws://' + window.location.host + '/websocket/chat');
    } else {
        Chat.connect('wss://' + window.location.host + '/websocket/chat');
    }
};
//发送的方法
Chat.sendMessage = (function() {
    var message = document.getElementById('chat').value;
    if (message != '') {
        var data = {
    		'from':'',
    		'to':'',
    		'groupId':'',
    		'type':'',
    		'message':message
    	}//from,to,type为后期私聊,群里
    	var msg = JSON.stringify(data);
        Chat.socket.send(msg);
        document.getElementById('chat').value = '';
    }
});

var Console = {};//聊天主窗体
//负责展现系统提示,例如 小明进入
Console.info = (function(message) {
    var h = '
'+ message +'
'; $('#center').append(h); }); //负责展现自己发送的消息,显示在右边 Console.self=(function(data){ var h = ''; //将data解析为html片段 $('#center').append(h); }); //负责展现其他人发送的消息,显示在左边 Console.other=(function(data){ var h = ''; //将data解析为html片段 $('#center').append(h); }); Chat.initialize();

java后台

  • 核心处理类ChatWebSocket.java,负责websocket连接/关闭/收发消息的整个过程
  • 消息类WebSocketMessage.java,发送消息的载体
  • 消息处理类ServerEncoder.java,将消息进行编码转json设置
  • 配置类GetHttpSessionConfigurator.java,获取httpSession

ChatWebSocket.java

websocket连接/关闭/收发消息的整个过程

@ServerEndpoint(value = "/websocket/chat", configurator = GetHttpSessionConfigurator.class, encoders = ServerEncoder.class)
public class ChatWebSocket {
    //存储所有的websocket连接
    private static final Map CONNECTIONS = new LinkedHashMap();
	private User user;
	private Session session;
    
    /**
    * 当websocket握手成功时触发
    * 该方法参数是可选的,session指的是websocket的session,不是httpSession.
    * 获取httpSession需要通过EndpointConfig类,而EndpointConfig类是由@ServerEndpoin()中的configurator进行设置
    */
    @OnOpen
    public void start(Session session, EndpointConfig config){
        this.session = session;            
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        WebSocketMessage webSocketMessage = new WebSocketMessage();
        if(httpSession == null){
			webSocketMessage.setMessage("您未登录系统");
			ChatWebSocket.sendToOne(this,webSocketMessage);
			try {
				this.session.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else{
		    //获取httpSession中登录的用户
		    User user = (User) httpSession.getAttribute("currentUser");
		    if(user == null){
				webSocketMessage.setMessage("登录错误,未知用户");
				ChatWebSocket.sendToOne(this,webSocketMessage);
				try {
					this.session.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}else{
				this.user = user;
				CONNECTIONS.put(this.user.getId(), this);
				webSocketMessage.setUserId(this.user.getId());
				ChatWebSocket.sendToOne(this,webSocketMessage);
				String msg = this.user.getName() + " 进入";
				ChatWebSocket.broadcastOnline(msg);
			}
		}
    }
    
    //当websocket握手关闭时触发
    @OnClose
    public void end(){
        CONNECTIONS.remove(this.user.getId());
		String msg = this.user.getName() + " 离开";
		ChatWebSocket.broadcastOnline(msg);
    }
    
    //当收到消息时
    @OnMessage
    public void incoming(String message){
        WebSocketMessage webSocketMessage = new WebSocketMessage();
		webSocketMessage.setUserId(this.user.getId());
		webSocketMessage.setUserName(this.user.getName());
		webSocketMessage.setMessage(message);
		webSocketMessage.setSendDate(new Date());
		ChatWebSocket.broadcast(webSocketMessage);
    }
    
    //发送至单独用户
    private static void sendToOne(ChatWebSocket chatWebSocket,
			WebSocketMessage webSocketMessage) {
		chatWebSocket.session.getAsyncRemote().sendObject(webSocketMessage);
	}
    
    //广播
    private static void broadcast(WebSocketMessage webSocketMessage) {
        Set keys = CONNECTIONS.keySet();
        for (String key : keys) {
			ChatWebSocket chatWebSocket = CONNECTIONS.get(key);
			synchronized (chatWebSocket) {
				ChatWebSocket.sendToOne(chatWebSocket, webSocketMessage);
			}
		}
    }
    
    //广播在线用户
    private static void broadcastOnline(String msg) {
		Set keys = CONNECTIONS.keySet();
		WebSocketMessage webSocketMessage = new WebSocketMessage();
		webSocketMessage.setType(WebSocketMessage.WEBSOCKETMESSAGE_TYPE_ALL);
		webSocketMessage.setMessage(msg);
		List userList = new ArrayList();
		for (String key : keys) {
			ChatWebSocket chatWebSocket = CONNECTIONS.get(key);
			userList.add(chatWebSocket.user);
		}
		webSocketMessage.getAttributes().put("user", userList);
		for (String key : keys) {
			ChatWebSocket chatWebSocket = CONNECTIONS.get(key);
			synchronized (chatWebSocket) {
				ChatWebSocket.sendToOne(chatWebSocket, webSocketMessage);
			}
		}
	}
    
}

WebSocketMessage.java

发送消息的载体

public class WebSocketMessage {
    private String userId;
	private String userName;
	private string from;
	private string to;
	private string groupId;
	...
	private String message;
	private Date sendDate;
	private String type;
	private Map attributes = new HashMap();
	
	public WebSocketMessage(){
		super();
	}
	
	public WebSocketMessage(String userName,String message,Date sendDate) {
		this.userName = userName;
		this.sendDate = sendDate;
		this.message = message;
	}
	
	//getter and setter ...
}

ServerEncoder.java

将消息进行编码转json设置

public class ServerEncoder implements Encoder.Text {
	@Override
	public void init(EndpointConfig paramEndpointConfig) {
		// TODO Auto-generated method stub
	}
	
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
	}
	
	@Override
	public String encode(WebSocketMessage paramT) throws EncodeException {
	    //将WebSocketMessage转为json
		return JsonMapper.buildNormalMapper().toJson(paramT);
	}
}

GetHttpSessionConfigurator

获取httpSession

public class GetHttpSessionConfigurator extends Configurator {
	@Override
	public void modifyHandshake(ServerEndpointConfig sec,
			HandshakeRequest request, HandshakeResponse response) {
		HttpSession httpSession=(HttpSession) request.getHttpSession();
		if(httpSession!=null){
			sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
		}        
	}
	
}

以上只是部分关键代码,简单的实现了即时通讯,若需要私聊,群聊,分组等功能,则需改造WebSocketMessage.java和前端js中Chat.socket.onmessage()

有小伙伴需要源码,该文章中的代码年代久远,重新弄了一个seven-im,请移步

你可能感兴趣的:(websocket,即时通讯,java,聊天室)