上个月公司开发APP中用到了实时聊天功能,一开始觉得不可思议,因为完全没有接触过,然后听安卓和ios的说之前的公司都是用第三方sdk的很少看到自己写聊天功能的(南京大公司不多,我想大点的公司自己写还是可以的,因为实现功能和商用还是有点区别的),老板对我们的要求也不高,鼓励我们说先实现功能即可,然后我们就开始入坑了。经过查找资料看教程等一番工作后终于把这个功能实现了。然后下面分享一下,也希望大家可以少踩点坑,大牛可也以指点一下我这个才工作了一年多的菜鸟。
一.首先是一个配置类
使用websocket不用引入外部依赖,因为从tomcat7开始内置了websocket的jar包
创建ChatServerConfigImpl继承ServerApplicationConfi。tomcat容器启动就会自动扫描带有@ServerEndpoint注解的类
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
public class ChatServerConfigImpl implements ServerApplicationConfig {
@Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
System.out.println("endPoint扫描到的数量:"+scan.size());
//返回提供了过滤的作用
return scan;
}
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(
Set<Class<? extends Endpoint>> arg0) {
return null;
}
二.写Socket,这里包含了服务端对客户端所有的响应
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.sf.json.JSONObject;
@ServerEndpoint("/chatSocket")
public class ChatSocket {
static Logger logger = LogManager.getLogger(ChatSocket.class.getName());
private static List<ChatSocket> sockets=new Vector<ChatSocket>();
private static List<String> nameList=new ArrayList<String>();
private Session session;
private String userId;
//只要有人连接这个服务,就会打开,执行下面的方法。
@OnOpen
public void open(Session session) throws UnsupportedEncodingException{
//一个session就代表一个通信会话
System.out.println("sessionid:"+session.getId()+"通道开启了。。。。");
//把session添加到容器中
this.session=session;
sockets.add(this);
//getQueryString把url中?后面的所有的串儿都取出来
String queryString = session.getQueryString();
//获取用户名
this.userId = URLDecoder.decode(queryString.substring(queryString.indexOf("=")+1), "UTF-8");
logger.info("userId:"+userId);
nameList.add(userId);
JSONObject message = new JSONObject();
/* message.put("alert", userId+"进入聊天室!!");
message.put("names", nameList);
broadcast(sockets, message.toString());*/
System.out.println(userId+"进入聊天室!!");
}
//退出
@OnClose
public void close(Session session){
//1.清理退出的session
sockets.remove(this);
//2.清理列表用户名
nameList.remove(this.userId);
//3.更新消息信息
JSONObject message = new JSONObject();
message.put("alert", this.userId+"退出聊天室!!");
message.put("names", nameList);
//4.广播消息信息
// broadcast(sockets, message.toString());
System.out.println(this.userId+"退出聊天室!!");
}
//收
@OnMessage
/**
*
* @param session
* @param msg 从客户端接收的消息
*/
public void message(Session session,String msg){
//接收消息
JSONObject message = new JSONObject();
String[] split = msg.split("#");
message.put("sendMsg", split[1]);
message.put("from", this.userId);
message.put("date", new Date().toString());
broadcast(sockets, message.toString(),split[0]);
}
/**
* 广播消息
* @param ss 用户session
* @param msg 广播消息
*/
public void broadcast(List<ChatSocket> ss ,String msg,String toId){
System.out.println("toId:"+toId);
int index = nameList.indexOf(toId);
ChatSocket chatSocket = ss.get(index);
try {
chatSocket.session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
三.前端的页面也很简单,创建一个简单的chat.jsp测试一下
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>聊天室</title>
<script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script>
<script>
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
var ws; //一个ws对象就是一个通信管道!!,只要不关浏览器,不关闭服务器就一直开着 ${sessionScope.userId}
var target="ws://localhost:8080/ChatTest/chatSocket?userId="+getQueryVariable("userId");
alert(target);
$().ready(function () {
//alert("开始");
//页面加载判断是否已经开启了target这个通道,如果没有开启,就开启
if ('WebSocket' in window) {
ws = new WebSocket(target);
alert(ws);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
alert(ws);
} else {
alert('WebSocket is not supported by this browser.');
return;
}
//接收消息
ws.onmessage = function (event) {
eval("var result="+event.data);
if(result.alert!=undefined){
$("#content").append(result.alert+"<br/>");
}
if(result.names!=undefined){
$("#userList").html("");
$(result.names).each(function(){
$("#userList").append(this+"<br/>");
});
}
if(result.from!=undefined){
$("#content").append(result.from+" "+result.date+
" 说:<br/>"+result.sendMsg+"<br/>");
}
};
});
//点击发送消息触发事件
function send(){
var msg = $("#msg").val();
ws.send(msg);
$("#msg").val("");
}
</script>
</head>
<body>
<h3>欢迎 ${sessionScope.userId} 使用本系统!!</h3>
<div id="content"
style="
border: 1px solid black; width: 400px; height: 300px;
float: left;
"></div>
<div id="userList"
style="
border: 1px solid black; width: 100px; height: 300px;
float:left;
"></div>
<div style="clear: both;">
<input id="msg" />
<button onclick="send();">send</button>
</div>
</body>
</html>
四.注意
访问这个jsp的时候应该在后面加上访问用户的id比如http://localhost:8080/ChatTest/chat.jsp?userId=10,这样js代码里面就会获取你传过来的userId然后发起一个ws://localhost:8080/ChatTest/chatSocket?userId=10的会话,/ChatTest/chatSocket接口就会将为一个以userId为标识建立一个长连接,断开连接时传入userId即可。向指定用户发消息时用toId#sendMsg的格式,toId即要对话的用户id,sendMsg是要发送的消息。好了这样就可以实现简单的两个用户间的对话了。