WebSocket实现聊天室

原著地址:https://blog.csdn.net/qq_36899469/article/details/78477217

最近小编又犯愁了,项目需求做一个实时的在线客服,小编又是上网各处找办法,最后锁定了一项技术WebSocket,但是对于小编来说这项技术只是听说过,从来没使用过,网上找的各种代码不是只有前端就是只有后端,简直要把我弄疯了,时隔三日我找到了如上链接里的代码,属实帮助到了我~关于WebSocket的定义我就不说了,网上百度一堆堆的,直接整代码吧~

1.首先来个登录页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>跳转人工客服</title>
        <script type="text/javascript" src="js/jquery.js"></script>
    </head>
    <body>
        <form name="ff" action="login" method="post" >
	    用户名:<input name="username" /><br/>
	    <input type="submit" value="登录"/>
	    </form>
    </body>
</html>

2.来个登录方法(我这里用的springMVC框架,原著用的是servlet,如果用的是servlet技术的童鞋请参照原著)

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ZjrgznController {
    //首页跳转,判断浏览器跳转对应页面
    @RequestMapping(value="")
    public String getindex(){
        return "/login";
    }
    
    //登录人工客服
    @RequestMapping(value="/login")
    public String login(String username,HttpServletRequest request){
    	request.getSession().setAttribute("username", username);
    	return "/chat";
    }
}

3.来个聊天界面(我是刚刚使用就到这里贴代码了,前端样式根据需要自己自行修改)

注:var url = "ws://localhost:8080/chatSocket?username=${sessionScope.username}",此处路径根据你的项目实际情况写,不要完全粘贴,否则聊天功能不好使

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
	<script type="text/javascript" src="js/jquery.js"></script>
	<script type="text/javascript">
  	    var ws;
	    var userName = ${sessionScope.username};
	    //通过URL请求服务端(chat为项目名称)
	    var url = "ws://localhost:8080/chatSocket?username=${sessionScope.username}";
	    //进入聊天页面就是一个通信管道
	    window.onload = function() {
	       	if ('WebSocket' in window) {
	            ws = new WebSocket(url);
	       	} else if ('MozWebSocket' in window) {
	            ws = new MozWebSocket(url);
	        } else {
		    alert('WebSocket is not supported by this browser.');
		    return;
	        }
	
	    //监听服务器发送过来的所有信息
            ws.onmessage = function(event) {
	        eval("var result=" + event.data);
		//如果后台发过来的alert不为空就显示出来
		if (result.alert != undefined) {
		    $("#content").append(result.alert + "<br/>");
		}
		//如果用户列表不为空就显示
		if (result.names != undefined) {
		    //刷新用户列表之前清空一下列表,免得会重复,因为后台只是单纯的添加
		    $("#userList").html("");
		    $(result.names).each(function(){
		        $("#userList").append("<input type=checkbox value='"+this+"'/>"+ this + "<br/>");
		    });
		}
		
                //将用户名字和当前时间以及发送的信息显示在页面上
	        if (result.from != undefined) {
	            $("#content").append(result.from + " " + result.date + " 说:<br/>"+ result.sendMsg + "<br/>");
                }
	    };
	    };
	
	    	//将消息发送给后台服务器
	    	function send() {
		        //拿到需要单聊的用户名
		        //alert("当前登录用户为"+userName);
		        var ss = $("#userList :checked");
		        //alert("群聊还是私聊"+ss.size());
		        var to = $('#userList :checked').val();
		        if (to == userName) {
		            alert("你不能给自己发送消息啊");
		            return;
		        }
		        //根据勾选的人数确定是群聊还是单聊
		        var value = $("#msg").val();
		        //alert("消息内容为"+value);
		        var object = null;
		        if (ss.size() == 0) {
		            object = {
		                msg : value,
		                type : 1, //1 广播 2单聊    
		            };
		        } else {
		            object = {
		                to : to,
		                msg : value,
		                type : 2, //1 广播 2单聊    
		            };
		        }
		        //将object转成json字符串发送给服务端
		        var json = JSON.stringify(object);
		        //alert("str="+json);
		        ws.send(json);
		        //消息发送后将消息栏清空
		        $("#msg").val("");
	    	}
		</script>
    </head>
    <body>
        <h3>欢迎 ${sessionScope.username}使用本聊天系统!</h3>
	<div id="content" style="border: 1px solid black; width: 400px; height: 300px; float: left; color: #7f3f00;"></div>
	<div id="userList" style="border: 1px solid black; width: 120px; height: 300px; float: left; color: #00ff00;"></div>
	<div style="clear: both;" style="color:#00ff00">
	    <input id="msg" />
	    <button onclick="send();">发送消息</button>
	</div>
    </body>
</html>

4.启动类(个人感觉这个类要不要都可以,看个人实际需要)

package util;

import java.util.Set;

import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;

public class ServerConfig implements ServerApplicationConfig {
    //扫描src下所有类@ServerEndPoint注解的类
    @Override
    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
        System.out.println("扫描到"+scan.size()+"个服务端程序"); 
	return scan;
    }
	
    //获取所有以接口方式配置的webSocket类
    @Override
    public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> point) {
        System.out.println("实现EndPoint接口的类数量:"+point.size());
	return null;
    }
}

5.搞个实体类(用来显示在线人数,也可以弄个数据库把人员名单和信息存储起来以便以后用,小编这里先没用数据库)

public class ContentVo {
	
	private String to;
	private String msg;
	private Integer type;
	
	public String getTo() {
		return to;
	}
	public void setTo(String to) {
		this.to = to;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public Integer getType() {
		return type;
	}
	public void setType(Integer type) {
		this.type = type;
	}
	
}
import java.util.List;

public class Message {
	
	private String alert;
	private List<String> names;
	private String sendMsg;
	private String from;
	private String date;
	
	public String getAlert() {
		return alert;
	}
	public void setAlert(String alert) {
		this.alert = alert;
	}
	public List<String> getNames() {
		return names;
	}
	public void setNames(List<String> names) {
		this.names = names;
	}
	public String getSendMsg() {
		return sendMsg;
	}
	public void setSendMsg(String sendMsg) {
		this.sendMsg = sendMsg;
	}
	public String getFrom() {
		return from;
	}
	public void setFrom(String from) {
		this.from = from;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	
	public Message() {
        super();
    }
	
}

6.接下来就要实现服务端程序逻辑啦

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.google.gson.Gson;
import ContentVo;
import Message;

@ServerEndpoint("/chatSocket")
public class ChatSocket {
    //定义一个全局变量集合sockets,用户存放每个登录用户的通信管道
    private static Set<ChatSocket> sockets=new HashSet<ChatSocket>();
    //定义一个全局变量Session,用于存放登录用户的用户名
    private Session session;
    //定义一个全局变量map,key为用户名,该用户对应的session为value
    private static Map<String, Session> map=new HashMap<String, Session>();
    //定义一个数组,用于存放所有的登录用户,显示在聊天页面的用户列表栏中
    private static List<String>names=new ArrayList<String>();
    private String username;
    private Gson gson=new Gson();
	
    @OnOpen
    public void open(Session session){
        this.session = session;
	//将当前连接上的用户session信息全部存到scokets中
	sockets.add(this);
	//拿到URL路径后面所有的参数信息
	String queryString = session.getQueryString();
	System.out.println();
	//截取=后面的参数信息(用户名),将参数信息赋值给全局的用户名
	this.username = queryString.substring(queryString.indexOf("=")+1);
	//每登录一个用户,就将该用户名存入到names数组中,用于刷新好友列表
	names.add(this.username);
	//将当前登录用户以及对应的session存入到map中
	this.map.put(this.username, this.session);
	System.out.println("用户"+this.username+"进入聊天室");
	Message message = new Message();
	message.setAlert("用户"+this.username+"进入聊天室");
	//将当前所有登录用户存入到message中,用于广播发送到聊天页面
	message.setNames(names);
	//将聊天信息广播给所有通信管道(sockets)
	broadcast(sockets, gson.toJson(message) );
    }
	
    @OnClose
    public void close(Session session){
	//移除退出登录用户的通信管道
	sockets.remove(this);
	//将用户名从names中剔除,用于刷新好友列表
	names.remove(this.username);
	Message message = new Message();
	System.out.println("用户"+this.username+"退出聊天室");
	message.setAlert(this.username+"退出当前聊天室!!!");
	//刷新好友列表
	message.setNames(names);
	broadcast(sockets, gson.toJson(message));
    }
	
    @OnMessage
    public void receive(Session session,String msg) throws IOException{
	//将客户端消息转成json对象
	ContentVo vo = gson.fromJson(msg, ContentVo.class);
	//如果是群聊,就像消息广播给所有人
	if(vo.getType()==1){
	    Message message = new Message();
	    message.setDate(new Date().toLocaleString());
	    message.setFrom(this.username);
	    message.setSendMsg(vo.getMsg());
	    broadcast(sockets, gson.toJson(message));
	}else{
	    Message message = new Message();
	    message.setDate(new Date().toLocaleString());
	    message.setFrom(this.username);
	    message.setAlert(vo.getMsg());
	    message.setSendMsg("<font color=red>正在私聊你:</font>"+vo.getMsg());
	    String to = vo.getTo();
	    //根据单聊对象的名称拿到要单聊对象的Session
	    Session to_session = this.map.get(to);
	    //如果是单聊,就将消息发送给对方
	    to_session.getBasicRemote().sendText(gson.toJson(message));
	} 
    }
	
    public void broadcast(Set<ChatSocket>sockets ,String msg){
        //遍历当前所有的连接管道,将通知信息发送给每一个管道
	for(ChatSocket socket : sockets){
	    try {
	        //通过session发送信息
		socket.session.getBasicRemote().sendText(msg);
	    } catch (IOException e) {
		e.printStackTrace(); 
	    } 
	} 
    }
}

效果图就不上了,各位把代码运行起来效果自然出现~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值