实现web端的推送目前有几种方式:
* 轮询
客户端定时向服务器发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接。
优点:后端程序编写简单
缺点:请求中有大多是无用的,浪费带宽和服务器资源。
示例:适用于小型应用
* websocket
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
优点:节省服务器资源和带宽,实时进行通信
缺点:少部分浏览器不支持,且不同浏览器支持的程度和方式有区别
那么接下来说明一下自己写的一个超简单的demo,关于接收消息的一些逻辑控制未写入代码,此处只做简单的推送功能展示。
1、服务端
* 引入jar包:
敲重点:注意scope作用域, provided--在编译和测试的过程有效,最后生成war包时不会加入
<!-- 引入websocket -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
* 消息处理类(注意前后端websocket对象是同一个)
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
@ServerEndpoint("/websocket/endpoint")
public class WebsocketHandler {
private static Map<String, WebsocketHandler> clients = new ConcurrentHashMap<String, WebsocketHandler>();
@OnOpen
public void onOpen(Session session) throws IOException {
//如果有用户信息,可以将用户编码之类的唯一标识作为clients的key,这样可以保证一个用户只有一个websocket client有效(此处的“1”仅仅作为demo的测试例子)
//如果同一个用户可以拥有多个websocket client,可以将session.getId()作为key,根据实际业务需求来设置即可
clients.put("1", this);
System.out.println("已连接");
}
@OnMessage
public void onMessage(String message) {
//以下代码省略...
System.out.println(message);
for (WebsocketHandler client : clients.values()) {
client.session.getBasicRemote().sendText(message);
}
}
@OnError
public void onError(Throwable t) {
//以下代码省略...
t.printStackTrace();
}
@OnClose
public void onClose(Session session, CloseReason reason) {
//以下代码省略...
System.out.println(String.format("Session %s closed because of %s", session.getId(), reason));
System.out.println("已关闭连接");
}
public static void pushMsg(String message){
// “1”只是测试用的key
WebsocketHandler client = clients.get("1");
try {
if(client != null){
client.session.getBasicRemote().sendText(message);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
* 后端对外消息推送接口
@ResponseBody
@RequestMapping(value="/sendMessage", method = RequestMethod.GET)
public void sendMessage() throws IOException {
WebsocketHandler.pushMsg("这是我需要发送的消息,记得给我传达,后面可以做成通用的接口");
}
2、客户端
<!-- html -->
<button onclick="sendMessage()">发送消息</button>
<button onclick="closeWebSocket()">关闭</button>
<div>这是显示结果的地方:
<p id="message" style="color:red;"></p>
</div>
<!-- javascript -->
<script type="text/javascript" src="../js/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
var websocket = null;
var url = "ws://localhost:8081/websocket-demo/websocket/endpoint";
$(document).ready(function(){
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
alert("浏览器支持Websocket")
websocket = new WebSocket(url);
} else {
alert('当前浏览器 Not support websocket');
}
if(websocket != null){
//连接发生错误的回调方法
websocket.onerror = function() {
alert("WebSocket连接发生错误")
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function() {
alert("WebSocket连接成功")
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
alert("接收到消息的回调方法")
alert("这是后台推送的消息:"+event.data);
// websocket.close();
// alert("webSocket已关闭!")
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket连接关闭");
}
}
});
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
closeWebSocket();
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
$("#message").text(innerHTML);
}
</script>