websocket可以吧他理解成java下的socket连接,他客户端和服务端你可以相互长连接发送消息,下面介绍如何在前端和后台建立一个websocket连接
一、java后台,首先可以吧websocket理解成一个servlet,这样就需要一个servlet类:
package main.java.test.websocket;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.websocket.WebSocketServlet;
public class WebSocketInitServlet extends WebSocketServlet {
private static final long serialVersionUID = -7302427588920888589L;
/**
* websocket建立连接
*/
@Override
public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(
HttpServletRequest request, String arg1) {
return new WebSocket();
}
}
这个类只有一个覆盖方法,就是建立连接则返回一个websocket实例,websocket实例的代码:
package main.java.test.websocket;
import java.util.List;
import net.sf.json.JSONObject;
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
import com.sun.istack.internal.logging.Logger;
public class WebSocket implements OnTextMessage {
private static final Logger log = Logger.getLogger(WebSocket.class);
/**
* websocket连接
*/
private Connection conn = null;
/**
* websocket关闭事件触发
*/
@Override
public void onClose(int arg0, String arg1) {
log.info("onClose begin. arg0:"+arg0+" arg1:"+arg1+" conn:"+conn);
List<WebSocketService> services = WebSocketServiceManager.getInstance().getServiesByWS(this);
for(WebSocketService service:services){
service.stopService();
}
removeSocket(this);
removeSocketServices(this);
log.info("onClose end. arg0:"+arg0+" arg1:"+arg1+" conn:"+conn);
}
/**
* websocket连接建立触发
*/
@Override
public void onOpen(Connection conn) {
// 如果客户端在这个MaxIdleTime中都没有活动,则它会自动结束
log.info("WebSocket onOpen. conn:"+conn.toString()+""+ conn.getMaxIdleTime()+" class:"+conn.getClass());
conn.setMaxIdleTime(Integer.MAX_VALUE);
this.conn = conn;
addSocket(this);
System.out.println("服务端websocket连接建立");
}
/**
* websocket收到消息触发
*/
@Override
public void onMessage(String data) {
log.info("onMessage. receive a Messag:" + data);
JSONObject jsonObject = JSONObject.fromObject(data);
System.out.println("name="+jsonObject.getString("name")+" age="+jsonObject.getString("age"));
/*WebSocketMessage webSocketMessage = (WebSocketMessage)JSONObject.toBean(jsonObject, WebSocketMessage.class);
OnMessageThread onMessageThread =new OnMessageThread(this,webSocketMessage);
new Thread(onMessageThread).start();*/
String jsonMsg = JSONObject.fromObject(jsonObject).toString();
sendMessage(jsonMsg) ;
}
class OnMessageThread implements Runnable{
private WebSocket ws = null;
private WebSocketMessage wsMessage = null;
public OnMessageThread(WebSocket ws,WebSocketMessage webSocketMessage) {
this.ws = ws;
this.wsMessage = webSocketMessage;
}
public void run(){
//打印websocket信息
log.info("OnMessageThread begin to run. WebSocket:"+ws);
int msgType = wsMessage.getType();
switch (msgType) {
case WebSocketConstants.START://打开业务页面,开始推送
log.info("OnMessageThread run. START:"+wsMessage.getBizName());
//获取对应的service实例,一般而言,该实例是单例的.但是在这里是多利的,单例会有问题
WebSocketService webSocketService = WebSocketServiceFactory.getInstance().buildWebSocketService(wsMessage.getBizName());
//这里用的是set方法,业务实现必须保证set方法的效果是:一个服务能够将其加入到自己要通知的目标客户端的列表当中去
webSocketService.setWebSocket(ws);
//与上面的方法有同样的要求:一个业务可以同时推送给多个不同的客户端,同时,不同客户端的参数可以是不同的
webSocketService.setWebSocketMessage(wsMessage);
//加入到manager管理的service列表中
log.info("OnMessageThread run. add service to manager. BizName:"+wsMessage.getBizName()+" webSocketService[hashcode]:"+webSocketService.hashCode()+" webSocketService[className]:"+webSocketService.getClass().getName());
addService(wsMessage.getBizName(), webSocketService);
log.info("OnMessageThread run. notifyService the service. webSocketService[hashcode]:"+webSocketService.hashCode());
webSocketService.notifyService();
break;
case WebSocketConstants.STOP://关闭页面,停止推送
log.info("OnMessageThread run. STOP:"+wsMessage.getBizName());
WebSocketService service = removeService(wsMessage.getBizName(),ws);
if(service != null){
service.stopService();
}
break;
default:
log.warning("----------onMessage type error-------------");
}
log.info("OnMessageThread end to run. WebSocket:"+ws);
}
};
/**
* websocket发送消息接口
* @param message
*/
public void sendMessage(String message){
try{
log.info("sendMessage. message:"+message);
conn.sendMessage(message);
}catch(Exception e){
log.warning("sendMessage error,close the conn and clear the resource. msg:"+e.getMessage(),e);
removeSocket(this);
removeSocketServices(this);
closeConnection();
}
}
/**
* 关闭连接
*/
private void closeConnection(){
conn.close();
}
/**
* 添加socket
* @param webSocket
*/
private void addSocket(WebSocket webSocket){
log.info("addSocket webSocket:"+webSocket);
new WebSocketManager().getWebSocketList().add(webSocket);
}
/**
* 删除socket
* @param webSocket
*/
private void removeSocket(WebSocket webSocket){
new WebSocketManager().getWebSocketList().remove(webSocket);
}
/**
*这种方式太绕,应该是ws->biz->service的方式来处理。当一个ws 关闭时,直接清除对应的map就可以
* 添加服務对象
* @param bizName
* @param webSocketService
*/
private void addService(String bizName,WebSocketService webSocketService){
WebSocketServiceManager.getInstance().addService(bizName, webSocketService);
}
private void addService(WebSocket ws,String bizName,WebSocketService webSocketService){
WebSocketServiceManager.getInstance().addService(bizName, webSocketService);
}
/**
* 删除服务对象
* @param bizName
* @param webSocket
* @return
*/
private WebSocketService removeService(String bizName,WebSocket webSocket){
WebSocketService service = WebSocketServiceManager.getInstance().removeService(bizName, webSocket);
return service;
}
/**
* 刪除socket关联的所有服務
* @param webSocket
*/
private void removeSocketServices(WebSocket webSocket){
WebSocketServiceManager.getInstance().removeServices(webSocket);
}
}
这里面只需要注意一些关于连接的一些覆盖方法,当触发是会自动进入那一个方法,
后台的代码就完了,但是既然是servlet就必须在web中配置。
<servlet> <servlet-name>websocket</servlet-name> <servlet-class>main.java.test.websocket.WebSocketInitServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>websocket</servlet-name> <url-pattern>/websocket.ws</url-pattern> </servlet-mapping>
二、JavaScript实现
一般都是java后台为服务器,前端为客户端,
var Webchannel = {
wso: "",
wsUrl: "ws://" + window.location.host + "/websocket.ws",
busiTypes: {},
initWebsocket: function () {
if ("WebSocket" in window) {
wso = new WebSocket(Webchannel.wsUrl);
} else if ("MozWebSocket" in window) {
wso = new MozWebSocket(Webchannel.wsUrl);
} else {
console.log("The browser don't support the WebSocket");
}
wso.onopen = function () {
console.log("connect success");
alert("客户端websocket建立");
debugger
var json ={};
json.name="dengwei";
json.age="23";
var jsonData= JSON.stringify(json);
wso.send(jsonData);
};
wso.onclose = function () {
try{
wso = new WebSocket(Webchannel.wsUrl);
}catch(e){
console.log("disconnect error"+e);
}
console.log("disconnect success");
};
wso.onerror = function () {
console.log("sorry,it get error");
};
wso.onmessage = function (receiveMsg) {
/*var jsonObject = eval('(' + receiveMsg.data + ')')
var callback = Webchannel.busiTypes[jsonObject.bizName];
callback( .data);*/
alert(receiveMsg.data.name);
}
},
sendMsg:function(data){
var jsonData= JSON.stringify(data);
wso.send(jsonData);
},
startPush: function (bizName, data) {
var json = {};
json.bizName = bizName;
json.data = data;
json.type = "1";
var jsonData = JSON.stringify(json);
var flag = 0;
var istrue = true;
if (1 == wso.readyState) {
wso.send(jsonData);
} else {
function isOpen() {
if (!istrue) {
window.clearInterval(servalStart);
} else {
if (1 == wso.readyState) {
wso.send(jsonData);
istrue = false;
} else {
flag = flag + 1;
if (flag > 29) {
if(Webchannel.wso != "" && Webchannel.wso != undefined){
Webchannel.closeWebSocket();
Webchannel.initWebsocket();
istrue = false;
}
}
}
}
}
servalStart = window.setInterval(isOpen, 1000);
}
},
stopPush: function (bizName) {
var json = {};
json.bizName = bizName;
json.data = "";
json.type = "2";
var jsonData = JSON.stringify(json);
var flag = 0;
var istrue = true;
if (1 == wso.readyState) {
wso.send(jsonData);
} else {
function isOpen() {
if (!istrue) {
window.clearInterval(servalFinish);
} else {
if (1 == wso.readyState) {
wso.send(jsonData);
istrue = false;
} else {
flag = flag + 1;
if (flag > 9) {
istrue = false;
}
}
}
}
servalFinish = window.setInterval(isOpen, 1000);
}
},
closeWebSocket: function () {
if (1 == wso.readyState) {
wso.close();
wso = "";
}
},
regBusitype: function (busiType, backFunction) {
Webchannel.busiTypes[busiType] = backFunction;
}
};
Webchannel.initWebsocket()
这段代码就是连接服务器的websocket并进行通信,代码很简单就不解释了