package org.springblade.common.handler;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.corundumstudio.socketio.*;
|
import com.corundumstudio.socketio.annotation.OnConnect;
|
import com.corundumstudio.socketio.annotation.OnDisconnect;
|
import com.corundumstudio.socketio.annotation.OnEvent;
|
import com.corundumstudio.socketio.protocol.Packet;
|
import org.springblade.core.mp.support.Condition;
|
import org.springblade.core.tool.api.R;
|
import org.springblade.modules.modules.entity.FunctionEntity;
|
import org.springblade.modules.modules.entity.ModulesEntity;
|
import org.springblade.modules.modules.service.IFunctionService;
|
import org.springblade.modules.modules.service.IModulesService;
|
import org.springblade.modules.modules.vo.FunctionVO;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.boot.CommandLineRunner;
|
import org.springframework.core.annotation.Order;
|
import org.springframework.stereotype.Component;
|
import com.corundumstudio.socketio.SocketIOServer;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.PostConstruct;
|
import javax.annotation.PreDestroy;
|
import java.net.ServerSocket;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.function.BiConsumer;
|
|
|
/**
|
* SocketIo启动类
|
*/
|
@Component
|
@Order(value = 1)
|
public class SocketIOService {
|
|
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
|
// 用来存已连接的客户端
|
private static Map<String, SocketIOClient> viewMap = new ConcurrentHashMap<>();
|
|
// 用来存已连接的客户端
|
private static Map<String, SocketIOClient> controllerMap = new ConcurrentHashMap<>();
|
|
// // 用来存已连接的视图客户端
|
// private List<Map<String, SocketIOClient>> view = new ArrayList<>();
|
//
|
// // 用来存已连接的控制客户端
|
// private List<Map<String, SocketIOClient>> controller = new ArrayList<>();
|
|
@Autowired
|
private SocketIOServer socketIOServer;
|
|
@Autowired
|
private IFunctionService functionService;
|
|
@Autowired
|
private IModulesService modulesService;
|
|
/**
|
* Spring IoC容器创建之后,在加载SocketIOConfiguration Bean之后启动
|
*
|
* @throws Exception
|
*/
|
@PostConstruct
|
private void autoStartup() throws Exception {
|
start();
|
}
|
|
/**
|
* Spring IoC容器在销毁SocketIOConfiguration Bean之前关闭,避免重启项目服务端口占用问题
|
*
|
* @throws Exception
|
*/
|
@PreDestroy
|
private void autoStop() throws Exception {
|
stop();
|
}
|
|
public void start() {
|
socketIOServer.start();
|
log.info("socket.io初始化服务完成");
|
}
|
|
/**
|
* 连接时
|
*
|
* @param client
|
*/
|
@OnConnect
|
public void onConnect(SocketIOClient client) {
|
FunctionVO functionEntity = getFuncVo(client);
|
|
//判断页面和控制器是否已经连接过了
|
if (functionEntity.getIsView()) {
|
for (int i = 0; i < viewMap.size(); i++) {
|
if (viewMap.containsKey(functionEntity.getModulesId())) {
|
client.sendEvent("connectError", R.fail("已连接"));
|
return;
|
}
|
}
|
} else {
|
for (int i = 0; i < controllerMap.size(); i++) {
|
if (controllerMap.containsKey(functionEntity.getModulesId())) {
|
client.sendEvent("connectError", R.fail("已连接"));
|
return;
|
}
|
}
|
}
|
|
List<FunctionEntity> all = functionService.getAll(functionEntity);
|
if (all.size() > 0) {
|
if (functionEntity.getIsView()) {
|
log.info("预览页{}", client.getSessionId().toString());
|
viewMap.put(functionEntity.getModulesId(), client);
|
|
} else {
|
log.info("控制页{}", client.getSessionId().toString());
|
controllerMap.put(functionEntity.getModulesId(), client);
|
}
|
client.sendEvent("connectOk", R.data(all));
|
} else {
|
client.sendEvent("connectError", R.fail("连接失败"));
|
}
|
}
|
|
/**
|
* 监听前端订阅相同事件发送过来的信息
|
*
|
* @param client
|
* @param ackRequest
|
* @param data
|
*/
|
@OnEvent(value = "msg")
|
public void OnEvent(SocketIOClient client, AckRequest ackRequest, String data) {
|
log.info("发来消息:" + data);
|
}
|
|
/**
|
* 图册上下页控制
|
*/
|
@OnEvent(value = "changeImgPage")
|
public void OnEventImgChange(SocketIOClient client, AckRequest ackRequest, String data) {
|
log.info("图册变更:" + data);
|
FunctionVO funcVo = getFuncVo(client);
|
|
|
viewMap.forEach((e,socketIO)->{
|
if (data.equals("previous")){
|
if (e.equals(funcVo.getModulesId())){
|
socketIO.sendEvent("previousPage","previous");
|
}
|
}else if (data.equals("next")){
|
if (e.equals(funcVo.getModulesId())){
|
socketIO.sendEvent("nextPage","next");
|
}
|
}
|
});
|
}
|
|
/**
|
* 菜单控制
|
*/
|
@OnEvent(value = "menuChange")
|
public void OnEventMenuChange(SocketIOClient client, AckRequest ackRequest, String data) {
|
log.info("菜单变更:" + data);
|
FunctionVO funcVo = getFuncVo(client);
|
viewMap.forEach((e,socketIOClient)->{
|
if (e.equals(funcVo.getModulesId())){
|
log.info("目标客户端:{}", socketIOClient.getSessionId().toString());
|
socketIOClient.sendEvent("menuChange", data);
|
}
|
});
|
}
|
|
/**
|
* 断开连接时
|
*
|
* @param client
|
*/
|
@OnDisconnect()
|
public void OnEvent(SocketIOClient client) {
|
FunctionVO funcVo = getFuncVo(client);
|
if (funcVo.getIsView()) {
|
viewMap.forEach((e,socketIOClient)->{
|
if (e.equals(funcVo.getModulesId())){
|
viewMap.remove(e);
|
log.info("预览页:{}断开连接", socketIOClient.getSessionId());
|
}
|
});
|
} else {
|
controllerMap.forEach((e,socketIOClient)->{
|
if (e.equals(funcVo.getModulesId())){
|
controllerMap.remove(e);
|
log.info("控制页:{}断开连接", socketIOClient.getSessionId());
|
}
|
});
|
}
|
}
|
|
public void stop() {
|
if (socketIOServer != null) {
|
socketIOServer.stop();
|
socketIOServer = null;
|
}
|
log.info("socket.io服务已关闭");
|
}
|
|
/**
|
* 此方法为获取client连接中的参数,可根据需求更改
|
*
|
* @param client
|
* @return
|
*/
|
private String getParamsByClient(SocketIOClient client) {
|
// 从请求的连接中拿出参数(这里的sid必须是唯一标识)
|
Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
|
List<String> list = params.get("UID");
|
if (list != null && list.size() > 0) {
|
return list.get(0);
|
}
|
return null;
|
}
|
|
/**
|
* 获取连接的客户端ip地址
|
*
|
* @param client: 客户端
|
* @return: java.lang.String
|
*/
|
private String getIpByClient(SocketIOClient client) {
|
String sa = client.getRemoteAddress().toString();
|
return sa.substring(1, sa.indexOf(":"));
|
}
|
|
private FunctionVO getFuncVo(SocketIOClient client) {
|
String connectInfo = client.getHandshakeData().getSingleUrlParam("connectInfo");
|
return JSON.parseObject(connectInfo, FunctionVO.class);
|
}
|
|
|
}
|