现在写文章都喜欢“手把手”,有一种老爸抱着三岁的儿子在路边撒尿的感觉,所以这篇的题目我也“手把手”一回,费话不说,开始撒尿:
使用到的技术
- websocket
- springmvc
- maven
- fastjson
这里使用到的主要技术是websocket
,后端服务用java来写,其中springmvc
,maven
只是用于写java时的框架和构建工具,fastjson
用于json数据格式的转换。
什么是websocket?
websocket是html5提供的一种在一个(TCP)接口进行全双工通信的技术,所谓全双工通信,简单点说就是通信的双方都可以同时向对方发送数据,类似于打电话时两方可以同时说话。
在没有websocket之前,实现聊天室这种实时的消息响应需求,一般会用长连接
或轮询
的方式,在特定的的时间间隔(如每1秒),由客户端对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端,这种方式有很明显的缺点,客户端需要不断的向服务器发出请求,然而HTTP请求的header是非常长的,而我们需要的有用数据可能只是一个很小的值,这样会占用很多的带宽。而用websocket,浏览器和服务器只需要做一个握手的动作,两者之间就形成了一条快速通道,直接就可以互相传送数据了。
支持websocket的浏览器和服务器
websocket是html5的特性,浏览器至少要支持html5,服务器我这边用tomcat7.0.54(其它较高版本我这边不起作用!?),另外java版本要7以上:
浏览器支持 | 版本 |
---|---|
Chrome | 4+ |
Firefox | 4+ |
Internet | Explorer 10+ |
Opera | 10+ |
Safari | 5+ |
服务器支持 | 版本 |
---|---|
tomcat | 7.0.27+ |
jetty | 7.0.1+ |
Nginx | 1.3.13+ |
resin | 4+ |
开始代码
websocket浏览器实现
浏览器通过javascript向服务器发起websocket请求,获取websocket连接后,浏览器和服务器就可以通过TCP连接直接交换数据了。
首先需要创建一个websocket对象:
var socket = new WebSocket('ws://localhost:8080/chatsocket');
这里的参数指定后台websocket服务的连接地址,不同于http://
,websocket请求地址以ws://
开头,接下来是主机的地址
+端口号
+后台服务名
,这里的chatsocket
是后面java后端所起的服务名字。其实第一次的握手连接,套接字还是以HTTP连接开始的,在HTTP握手之后才升级为TCP套接字,任意一端就都可以发送数据了。如果页面用得是JSP模板,地址和端口可以用JSP的pageContext
获取,而不要直接写死:
- 获取地址:${pageContext.request.serverName}
- 获取端口:${pageContext.request.serverPort}
- 获取上下文路径:${pageContext.request.contextPath}
websocket对象的方法
创建websocket对象后,它有一些相关属性、事件和方法,具体可以查看W3C的websocket API。
比较重要的事件和方法主要有以下几个:
//连接成功建立的回调方法
socket.onopen = function (event) { console.log("连接服务器成功!"); };
//点击发送消息的方法,这里以json格式传送数据
socket.send(JSON.stringify({
content: "这里是消息的内容"
name:"发送人"
}));
//接收到消息的回调方法,一般将返回的数据append到消息页面
socket.onmessage = function (event) {
var message = JSON.parse(event.data);
//dosomething...
//发送人:message.name ,发送时间: message.date,发送内容:message.content
};
websocket服务器实现
第一步:加入信赖
java要使用websocket要加入相关信赖:
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.0.1.RELEASE</version>
</dependency>
注意:
- tomcat的lib目录下有一个包
websocket-api.jar
,用这个包就可以了,所以部署的时候将上述的javax.websocket-api.jar
删除再重新启动,否则两则重复,启动会报错。 spring-websocket-4.0.1.RELEASE.jar
这个包的作用只是需要在websocket后端注入service所用的,否则删除这个包不影响websocket服务运行。- 具体spring对websocket的支持见这里
第二步:开启后端服务
新建一个java类,在这个类上加上ServerEndpoint
注解,它就变成websocket服务了:
@ServerEndpoint(value = "/chatsocket",configurator = SpringConfigurator.class)
public class HudongEndpoint{
}
这里定义了两个参数:
- value:服务的名字,前面js创建websocket时的url的服务名就是这个
- configurator:如果要用spring注入servie,就要加上这个参数
第三步:接收消息的方法
和html5的websocket一样,后端也有相关操作方法,加上相关的注解就可以,比如:
- @OnOpen:连接建立成功时调用的方法
- @OnMessage:收到客户端消息后调用的方法
- @OnClose:连接关闭调用的方法
- @OnError:发生错误时调用的方法
这里主要说明下@OnMessage方法:
@OnMessage
public void getMessage(String message, Session session) {
JSONObject jsonObject= JSONObject.parseObject(message);
jsonObject.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
for (Session openSession : session.getOpenSessions()) {
jsonObject.put("isSelf", openSession.equals(session));
openSession.getAsyncRemote().sendText(jsonObject.toString());
//openSession.getBasicRemote().sendText(message);
}
}
这个方法有两个参数:
- message:前端发送过来的消息,json格式
- session:这个参数可选,为与某个客户端的连接会话,需要通过它给客户端发送数据。如果要将聊天数据保存到数据库中,可以在这个方法中执行相关操作
总结
整个websocket发送消息和接收消息的过程,和http请求在使用上其实没多大区别,后台的一个ServerEndpoint
类似于 springmvc的一个controller,相关的业务操作在对应的方法里就是了。这里只是简单的文本聊天,如果要加上表情和图片,可以使用富文本编辑器(Ueditor,kindeditor等),当然还可以加上计算实时在线人数,上线下线通知等功能。