1:websocket的原理?
websocket支持持久连接,http协议不支持持久连接。websocket是基于http协议的。我在公司项目中有个需求:统计管理员名下的在裁判和选手。
一开始考虑的是用session进行统计。 但是http是短连接,如果需要进行实时查看在线情况就需要,在客户端定时访问服务端。但是每一次访问都要重新开启一个http协议,这是十分消耗资源的。
websocket是可以持长连接的,每个用户登录成功后,将用户信息放于redis的list中, 随后使用llen命令将数据使用websock的onmessage就可以将数据推送给管理员。
2:怎么测试连接成功?
前端代码:
function startWebSocket() {
var websocket= new WebSocket("ws://localhost:8080/test/websocket");
websocket.onopen = function (event) {
// websocket.send("前端数据")
console.log(event)
};
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
}
后台代码:
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpSession;
import javax.websocket.EncodeException;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/test/websocket", configurator = GetHttpSessionConfigurator.class, encoders = { DataEncoder.class })
public class WebSocket {
public static Map<Long, Set<IndexWebSocket>> userSocket = new ConcurrentHashMap<>();
private Session session;
private Long userId;
@OnOpen
public void onOpen(Session session, EndpointConfig config) throws IOException{
HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
Long userId = (Long) httpSession.getAttribute("userId");
this.session = session;
this.userId = userId;
if (userSocket.containsKey(this.userId)) {
userSocket.get(this.userId).add(this);
} else {
Set<IndexWebSocket> socketSet = new HashSet<>();
socketSet.add(this);
userSocket.put(this.userId, socketSet);
}
OnlineUserUtil.push(userId);
}
@OnClose
public void onClose() {
if (userSocket.get(this.userId).size() == 1) {
userSocket.remove(this.userId);
} else {
userSocket.get(this.userId).remove(this);
}
}
@OnMessage
public void onMessage(String message, Session session) {
<b>message为接收的前端数据</b>
//在这可以根据接受的数据进行相应的数据处理
Map<String, Object> resMap = new HashMap<>();
resMap.put("msg", "服务器收到你的消息:" + message);
sendMessageToUser(this.userId, resMap);
}
@OnError
public void onError(Session session, Throwable error){
error.printStackTrace();
}
public static Boolean sendMessageToUser(Long userId, Object message) {
if (userSocket.containsKey(userId)) {
for (IndexWebSocket socket : userSocket.get(userId)) {
try {
socket.session.getBasicRemote().sendObject(message);
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (EncodeException e) {
e.printStackTrace();
return false;
}
}
return true;
}
return false;
}
public static void sendMessageToAllUser(Object message) {
for (Long userId: userSocket.keySet()) {
sendMessageToUser(userId, message);
}
}
public Boolean send(Object message) {
try {
this.session.getBasicRemote().sendObject(message);
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (EncodeException e) {
e.printStackTrace();
return false;
}
return true;
}
}
import java.util.HashMap;
import java.util.Map;
public class OnlineUserUtil {
public static void add(Long userId, String sessionId) {
JedisUtil.lpush(Constants.MAT_ONLINE_USER_INFO_MAP + roleName.getValue() + userId , sessionId);
push(userId);
}
public static void push(Long userId) {
String pKey ="redis的角色key1";
String rKey ="redis的角色key2" ;
Long pCount = JedisUtil.llen(pKey );
JedisUtil.expire(userId, 30 * 60);
Long rCount = JedisUtil.llen(rKey);
JedisUtil.expire(userId, 30 * 60);
Map<String, Object> socketParams = new HashMap<>();
socketParams.put("playerCount", pCount == null ? 0 : pCount);
socketParams.put("refereeCount", rCount == null ? 0 : rCount);
WebSocket.sendMessageToUser(userId, socketParams);
}
}
3:怎么进行交互数据?
后台给前端传输数据: 由于每个用户登录后,都会调用push方法,这时客户端会立即接收到后台返回的数据。
前端给服务端传输数据:js中 调用用websocket.send(“传输的数据”),后台WebSocket中的onmessage方法内可以进行,并且其中可以根据数据类型进行不同的数据梳理。