在上一篇博客中,小编简单向大家介绍了一下websocket,在这篇博客中小编将通过一个聊天实例来展示一下websocket是如何使用的。
二、资料准备2.1 环境要求
- JDK版本在1.7以上
注:小编刚开始的时候使用的是JDK 1.6 无法运行,原因是websocket是j2ee7规范引入,只要使用支持其标准的服务器就可以运行,所以要在JDK1.7的环境上运行。
2.2 jar包的准备
我们需要三个jar包:
tomcat7-websocket.jar
websocket-api.jar
gson-2.2.4.jar
简单介绍:前两个jar包是在tomcat7及以上版本的lib目录下获得的。主要是封装了websocket的API方法类以及实现了其中的方法。gson.jar是一个操作json的jar包。我们用他把字段转换成为json字符串。
关于实时聊天的需求是这样的,我们有一个登录的页面,输入用户名后,点击登录就可以跳转到聊天窗口。在聊天窗口上就会显示“欢迎XXX来到聊天室~”以及在线的列表中显示在线的人的人名。用户可以发送消息,可以群发,也可以单聊。
3.1 建立web项目
建立一个名字为chatTest的web项目,把上文提到的jar包导入WEB-INF/lib目录下。
在src下建立名为com.dmsd.config的包,在此包中建立DemoConfig类,实现ServerApplicationConfig 接口。
ServerApplicationConfig 是websocket的核心配置类。会在项目启动的时候,自动执行。
实现ServerApplicationConfig后,会有两个方法getAnnotatedEndpointClasses和getEndpointConfigs。
getAnnotatedEndpointClasses会扫描src下所有带有@ServerEndPoint注解的类。
getEndpointConfigs会获取所有以接口方式配置的websocket类
DemoConfig :
package com.dmsd.config;
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
public class DemoConfig implements ServerApplicationConfig {
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
System.out.println("endPoint扫描到的数量:"+scan.size());
//返回提供了过滤的作用
return scan;
}
public Set<ServerEndpointConfig> getEndpointConfigs(
Set<Class<? extends Endpoint>> arg0) {
return null;
}
}
3.3 用户登录
编写用户登录jsp:
用户登录后,就会提交表单,调用后台的LoginServlet。
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>登录</title>
<script type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
</head>
<body>
<form action="LoginServlet" method="post" name="ff">
name:<input name="username"/><br>
<input type="submit"/>
</form>
</body>
</html>
LoginServlet :
package com.dmsd.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class LoginServlet
*/
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//获取登录提交表单中的用户姓名信息
String username = request.getParameter("username");
//把用户姓名存储到session中
request.getSession().setAttribute("username",username);
//重定向到chat.jsp
response.sendRedirect("chat.jsp");
}
}
3.4 事件操作
当跳转到chat.jsp页面的时候,会加载其中的js文件,js中会开启一个通信管道。页面加载判断是否已经开启了这个通道,如果没有开启,就开启。当管道开启的时候就会触发onopen事件。触发的方法在ChatSocket类中。
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 type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
<script>
var ws; //一个ws对象就是一个通信管道!!,只要不关浏览器,不关闭服务器就一直开着
var target="ws://localhost:8080/chatTest/chatSocket?username=${sessionScope.username}";
$().ready(function connect() {
//页面加载判断是否已经开启了target这个通道,如果没有开启,就开启
if ('WebSocket' in window) {
ws = new WebSocket(target);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
} 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.username} 使用本系统!!</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>
在ChatSocket类中,可以把他理解为一个事件操作类,需要添加@ServerEndpoint的注解,这样当系统跑起来的时候,会监控它,来判断是否有推送消息,退出系统,登录系统的操作等等,这样就达到了一个实时的效果。
在这个类中有以下几种事件:
@OnOpen 开启通道的时候触发
@OnClose 关闭通道的时候触发
@OnMessage 客户端发送数据的时候触发
ChatSocket :
package com.dmsd.socket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
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.dmsd.vo.Message;
import com.google.gson.Gson;
@ServerEndpoint("/chatSocket")
public class ChatSocket {
private static Set<ChatSocket> sockets=new HashSet<ChatSocket>();
private static List<String> nameList=new ArrayList<String>();
private Session session;
private String username;
private Gson gson=new Gson();
//只要有人连接这个服务,就会打开,执行下面的方法。
@OnOpen
public void open(Session session){
//一个session就代表一个通信会话
System.out.println("sessionid:"+session.getId()+"通道开启了。。。。");
//把session添加到容器中
this.session=session;
sockets.add(this);
//getQueryString把url中?后面的所有的串儿都取出来
String QueryString = session.getQueryString();
System.out.println(QueryString);
//获取用户名
this.username = QueryString.substring(QueryString.indexOf("=")+1);
nameList.add(username);
Message message = new Message();
message.setAlert(username+"进入聊天室!!");
message.setNames(nameList) ;
broadcast(sockets, gson.toJson(message) );
}
//退出
@OnClose
public void close(Session session){
//1.清理退出的session
sockets.remove(this);
//2.清理列表用户名
nameList.remove(this.username);
//3.更新消息信息
Message message=new Message();
message.setAlert(this.username+"退出聊天室!!");
message.setNames(nameList);
//4.广播消息信息
broadcast(sockets, gson.toJson(message));
}
//收
@OnMessage
/**
*
* @param session
* @param msg 从客户端接收的消息
*/
public void message(Session session,String msg){
//接收消息
Message message=new Message();
message.setSendMsg(msg);
message.setFrom(this.username);
message.setDate(new Date().toString());
broadcast(sockets, gson.toJson(message));
}
/**
* 广播消息
* @param ss 用户session
* @param msg 广播消息
*/
public void broadcast(Set<ChatSocket> ss ,String msg ){
for (Iterator iterator = ss.iterator(); iterator.hasNext();) {
ChatSocket chatSocket = (ChatSocket) iterator.next();
try {
chatSocket.session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通过这次练习,小编把websocket的四个步骤算是搞明白了,知道了具体处理的流程,操作也比较方便了。以后会更好的了解了websocket的发展,以及数据的传输。