改造socket

This commit is contained in:
zzc 2024-11-16 23:44:48 +08:00
parent 7420a2040e
commit 4a7f767638
12 changed files with 371 additions and 8 deletions

View File

@ -0,0 +1,19 @@
package org.dromara.web.config;
import lombok.Data;
import org.dromara.web.domain.bo.EqAppHomeBo;
import java.io.Serializable;
/**
* @ClassName : WebSocketParamDto
* @Author : ZZC
* @Date : 2024/11/16 21:58
* @Description :
**/
@Data
public class LastWebSocketParamDto implements Serializable {
private String method;
private EqAppHomeBo bo;
}

View File

@ -9,12 +9,15 @@ import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.common.websocket.dto.WebSocketMessageDto; import org.dromara.common.websocket.dto.WebSocketMessageDto;
@ -23,11 +26,13 @@ import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDictTypeService; import org.dromara.system.service.ISysDictTypeService;
import org.dromara.system.service.ISysUserService; import org.dromara.system.service.ISysUserService;
import org.dromara.web.config.LastWebSocketParamDto;
import org.dromara.web.device.iot.DeviceByDeviceName; import org.dromara.web.device.iot.DeviceByDeviceName;
import org.dromara.web.device.iot.DeviceDto; import org.dromara.web.device.iot.DeviceDto;
import org.dromara.web.domain.bo.*; import org.dromara.web.domain.bo.*;
import org.dromara.web.domain.vo.*; import org.dromara.web.domain.vo.*;
import org.dromara.web.service.*; import org.dromara.web.service.*;
import org.dromara.web.utils.WebSocketBusinessHandler;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -360,5 +365,6 @@ public class EqDeviceController extends BaseController {
} }
} }

View File

@ -349,6 +349,24 @@ public class EqHomeController extends BaseController {
return eqEquipmentService.queryPageList(eqEquipmentBo, pageQuery,shared,equipmentIdIds); //在设备表中增加了分布id return eqEquipmentService.queryPageList(eqEquipmentBo, pageQuery,shared,equipmentIdIds); //在设备表中增加了分布id
} }
public TableDataInfo<EqEquipmentVo> listForWebSocket(EqAppHomeBo bo, PageQuery pageQuery,LoginUser loginUser){
//当前用户为家庭主体 切换用户后需要传输用户id
// Long currentUserId = LoginHelper.getUserId();
Long currentUserId = loginUser.getUserId();
boolean shared=true;
List<Long> equipmentIdIds=null;
if (bo.getUserId() == null) {
bo.setUserId(currentUserId);
shared=false;
}
equipmentIdIds =checkUserId(bo.getUserId(), currentUserId);
// 下面返回的状态 会在设备状态变化时更新设备状态 状态更新由iot触发
EqEquipmentBo eqEquipmentBo = new EqEquipmentBo();
eqEquipmentBo.setUserId(bo.getUserId());
eqEquipmentBo.setAreaId(bo.getAreaId());
return eqEquipmentService.queryPageList(eqEquipmentBo, pageQuery,shared,equipmentIdIds); //在设备表中增加了分布id
}
/** /**
* 检查要查询的userId 是否为分享给当前用户的userId * 检查要查询的userId 是否为分享给当前用户的userId
* 如果不是 则抛出异常 * 如果不是 则抛出异常

View File

@ -0,0 +1,169 @@
package org.dromara.web.controller.app;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.system.service.ISysDictTypeService;
import org.dromara.web.config.LastWebSocketParamDto;
import org.dromara.web.device.iot.DeviceByDeviceName;
import org.dromara.web.domain.bo.*;
import org.dromara.web.domain.vo.*;
import org.dromara.web.service.*;
import org.dromara.web.utils.WebSocketBusinessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* app iot设备业务
*
* @author Lion Li
* @date 2024-07-14
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/iot")
public class EqIotDeviceController extends BaseController {
private final ScheduledExecutorService scheduledExecutorService;
private final IEqEquipmentService eqEquipmentService;
private final IotService iotService;
private final IEqShareService shareService;
private final WebSocketBusinessHandler webSocketBusinessHandler;
/**
* 实时发送设备状态信息
* 在设备状态变化的时候会实时推送设备信息到前端
* @param eqEquipmentLogBo
*/
@SaIgnore
@PostMapping("/sendDeviceMsg")
public void sendDeviceMsg(@RequestBody EqEquipmentLogBo eqEquipmentLogBo){
String equipmentName = eqEquipmentLogBo.getEquipmentName();
//设备id查询
DeviceByDeviceName deviceByNameDto = iotService.apiTenantDevicesByName(equipmentName);//无信息会抛异常 无需判断
if (deviceByNameDto==null) throw new RuntimeException("设备不存在");
String equipmentCode = deviceByNameDto.getId().getId();
//查询设备信息
EqEquipmentBo eqEquipmentBo = new EqEquipmentBo();
eqEquipmentBo.setEquipmentCode(equipmentCode);
List<EqEquipmentVo> eqEquipmentVos = eqEquipmentService.queryList(eqEquipmentBo);
if (CollectionUtils.isEmpty(eqEquipmentVos)) return;
EqEquipmentVo eqEquipmentVo = eqEquipmentVos.get(0);
Long userId = eqEquipmentVo.getUserId();
//设备详情查询
EqAppHomeBo bo = new EqAppHomeBo();
bo.setEquipmentId(eqEquipmentVo.getEquipmentId());
bo.setEquipmentCode(eqEquipmentVo.getEquipmentCode());
EqEquipmentDetailVo deviceMsg = eqEquipmentService.getDeviceMsg(bo);
//设备列表
EqEquipmentBo eqEquipmentBo2 = new EqEquipmentBo();
eqEquipmentBo2.setUserId(userId);
List<EqEquipmentVo> list2 = eqEquipmentService.queryList(eqEquipmentBo2);
eqEquipmentService.initEqEquipmentVo(list2);
//查看设备被分享者
EqShareBo shareBo = new EqShareBo();
shareBo.setShareUserId(userId);
List<EqShareVo> eqShareVos = shareService.queryList(shareBo);
List<Long> userIds = new ArrayList<>();
userIds.add(userId);
if (CollUtil.isNotEmpty(eqShareVos)){
for (EqShareVo eqShareVo : eqShareVos) {
userIds.add(eqShareVo.getSharedUserId());
}
}
//数据结构
Map<String, Object> result = new HashMap<>();
result.put("detail", deviceMsg);
result.put("list", list2);
//推送消息
scheduledExecutorService.schedule(() -> {
WebSocketMessageDto dto = new WebSocketMessageDto();
dto.setMessage(JSONObject.toJSONString(result));
// dto.setSessionKeys(List.of(userId));
dto.setSessionKeys(userIds);
WebSocketUtils.publishMessage(dto);
}, 3, TimeUnit.SECONDS);
}
/**
* 实时发送设备状态信息2
* 改动版本v2
* @param eqEquipmentLogBo
*/
@SaIgnore
@PostMapping("/sendDeviceMsg2")
public void sendDeviceMsg2(@RequestBody EqEquipmentLogBo eqEquipmentLogBo){
String equipmentName = eqEquipmentLogBo.getEquipmentName();
//设备id查询
DeviceByDeviceName deviceByNameDto = iotService.apiTenantDevicesByName(equipmentName);//无信息会抛异常 无需判断
if (deviceByNameDto==null) throw new RuntimeException("设备不存在");
String equipmentCode = deviceByNameDto.getId().getId();
//查询设备信息
EqEquipmentBo eqEquipmentBo = new EqEquipmentBo();
eqEquipmentBo.setEquipmentCode(equipmentCode);
List<EqEquipmentVo> eqEquipmentVos = eqEquipmentService.queryList(eqEquipmentBo);
if (CollectionUtils.isEmpty(eqEquipmentVos)) return;
EqEquipmentVo eqEquipmentVo = eqEquipmentVos.get(0);
Long userId = eqEquipmentVo.getUserId();
LoginUser loginUser = new LoginUser();
loginUser.setUserId(userId);
LastWebSocketParamDto dto = RedisUtils.getCacheObject(Constants.WEBSOCKET_METHOD+loginUser.getUserId());
String param = JSONObject.toJSONString(dto.getBo());
if (Constants.METHOD_EQ_DETAIL.equals(dto.getMethod())){
webSocketBusinessHandler.dealWithDetailMsg(loginUser,param);
}else if (Constants.METHOD_EQ_LIST.equals(dto.getMethod())){
webSocketBusinessHandler.dealWithListMsg(loginUser,param);
}else{
System.out.println("无设备信息最新参数");
}
}
}

View File

@ -127,7 +127,8 @@ public class EqTextController extends BaseController {
MessageUtils.message("homepage.name9"), MessageUtils.message("homepage.name9"),
MessageUtils.message("homepage.name10"), MessageUtils.message("homepage.name10"),
MessageUtils.message("homepage.name11"), MessageUtils.message("homepage.name11"),
MessageUtils.message("homepage.name12") MessageUtils.message("homepage.name12"),
MessageUtils.message("homepage.name13")
)); ));
//关门提醒warningClose //关门提醒warningClose

View File

@ -0,0 +1,99 @@
package org.dromara.web.utils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.websocket.constant.WebSocketConstants;
import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.handler.PlusWebSocketHandler;
import org.dromara.common.websocket.handler.WebSocketApi;
import org.dromara.common.websocket.holder.WebSocketSessionHolder;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.web.config.LastWebSocketParamDto;
import org.dromara.web.controller.app.EqDeviceController;
import org.dromara.web.controller.app.EqHomeController;
import org.dromara.web.domain.bo.EqAppHomeBo;
import org.dromara.web.domain.vo.EqEquipmentDetailVo;
import org.dromara.web.domain.vo.EqEquipmentVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
/**
* @ClassName : WebSocketHandler
* @Author : ZZC
* @Date : 2024/11/16 18:54
* @Description :
**/
@Service
@Slf4j
public class WebSocketBusinessHandler implements WebSocketApi {
@Autowired
private EqDeviceController controller;
@Autowired
private EqHomeController homeController;
@Override
public void dealWithDetailMsg(LoginUser loginUser, String msg) {
EqAppHomeBo bo = null;
String sendMsg = "";
try {
bo = JSON.parseObject(msg, EqAppHomeBo.class);
LastWebSocketParamDto dto = new LastWebSocketParamDto();
dto.setMethod(Constants.METHOD_EQ_DETAIL);
dto.setBo(bo);
RedisUtils.setCacheObject(Constants.WEBSOCKET_METHOD+loginUser.getUserId(),dto);
} catch (Exception e) {
log.error("参数错误");
sendMsg = "参数错误";
}
R<EqEquipmentDetailVo> deviceMsg = controller.getDeviceMsg(bo);
// EqEquipmentDetailVo data = deviceMsg.getData();
sendMsg = JSON.toJSONString(deviceMsg);
sendMsg(sendMsg,loginUser.getUserId());
}
@Override
public void dealWithListMsg(LoginUser loginUser, String msg) {
EqAppHomeBo bo = null;
String sendMsg = "";
try {
bo = JSON.parseObject(msg, EqAppHomeBo.class);
LastWebSocketParamDto dto = new LastWebSocketParamDto();
dto.setMethod(Constants.METHOD_EQ_LIST);
dto.setBo(bo);
RedisUtils.setCacheObject(Constants.WEBSOCKET_METHOD +loginUser.getUserId(),dto);
} catch (Exception e) {
log.error("参数错误");
sendMsg = "参数错误";
}
PageQuery pageQuery = new PageQuery();
pageQuery.setPageNum(0);
pageQuery.setPageSize(100);
TableDataInfo<EqEquipmentVo> list = homeController.listForWebSocket(bo, pageQuery,loginUser);
sendMsg = JSON.toJSONString(list);
sendMsg(sendMsg,loginUser.getUserId());
}
public void sendMsg(String msg,Long userId){
WebSocketMessageDto dto = new WebSocketMessageDto();
dto.setMessage(msg);
dto.setSessionKeys(List.of(userId));
WebSocketUtils.publishMessage(dto);
}
}

View File

@ -145,6 +145,7 @@ homepage.name9=是否暂停
homepage.name10=请选择 homepage.name10=请选择
homepage.name11=全部 homepage.name11=全部
homepage.name12=暂无数据 homepage.name12=暂无数据
homepage.name13=设备初始化失败
##《关门提醒》warningClose ##《关门提醒》warningClose
warningClose.name0=关门提醒 warningClose.name0=关门提醒
warningClose.name1=设备-deviceName-已开门-num-分钟了,请记得关门 warningClose.name1=设备-deviceName-已开门-num-分钟了,请记得关门

View File

@ -77,5 +77,11 @@ public interface Constants {
*/ */
Long TOP_PARENT_ID = 0L; Long TOP_PARENT_ID = 0L;
//websocket 相关
String WEBSOCKET_METHOD = "webSocket_method";
String METHOD_EQ_DETAIL = "detail";
String METHOD_EQ_LIST = "list";
} }

View File

@ -41,7 +41,7 @@ public class WebSocketConfig {
// 返回一个WebSocketConfigurer对象用于配置WebSocket // 返回一个WebSocketConfigurer对象用于配置WebSocket
return registry -> registry return registry -> registry
// 添加WebSocket处理程序和拦截器到指定路径设置允许的跨域来源 // 添加WebSocket处理程序和拦截器到指定路径设置允许的跨域来源
.addHandler(webSocketHandler, webSocketProperties.getPath()) .addHandler(webSocketHandler, webSocketProperties.getPath(),webSocketProperties.getPath()+"/list",webSocketProperties.getPath()+"/detail")
.addInterceptors(handshakeInterceptor) .addInterceptors(handshakeInterceptor)
.setAllowedOrigins(webSocketProperties.getAllowedOrigins()); .setAllowedOrigins(webSocketProperties.getAllowedOrigins());
} }

View File

@ -1,12 +1,14 @@
package org.dromara.common.websocket.constant; package org.dromara.common.websocket.constant;
import org.dromara.common.websocket.config.properties.WebSocketProperties;
import org.springframework.beans.factory.annotation.Autowired;
/** /**
* websocket的常量配置 * websocket的常量配置
* *
* @author zendwang * @author zendwang
*/ */
public interface WebSocketConstants { public interface WebSocketConstants {
/** /**
* websocketSession中的参数的key * websocketSession中的参数的key
*/ */
@ -26,4 +28,8 @@ public interface WebSocketConstants {
* 服务端心跳恢复的字符串 * 服务端心跳恢复的字符串
*/ */
String PONG = "pong"; String PONG = "pong";
String detail = "/detail";
String list = "/list";
} }

View File

@ -1,11 +1,15 @@
package org.dromara.common.websocket.handler; package org.dromara.common.websocket.handler;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.websocket.constant.WebSocketConstants;
import org.dromara.common.websocket.dto.WebSocketMessageDto; import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.holder.WebSocketSessionHolder; import org.dromara.common.websocket.holder.WebSocketSessionHolder;
import org.dromara.common.websocket.utils.WebSocketUtils; import org.dromara.common.websocket.utils.WebSocketUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.*; import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler; import org.springframework.web.socket.handler.AbstractWebSocketHandler;
@ -37,6 +41,9 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
} }
@Autowired
WebSocketApi webSocketApi;
/** /**
* 处理接收到的文本消息 * 处理接收到的文本消息
* *
@ -48,12 +55,26 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 从WebSocket会话中获取登录用户信息 // 从WebSocket会话中获取登录用户信息
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
String currentPath = session.getUri().getPath();
String lastPath = WebSocketSessionHolder.getSessions(loginUser.getUserId()).getUri().getPath();
if (!currentPath.equals(lastPath)){
WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
}
String payload = message.getPayload();
if (currentPath.contains(WebSocketConstants.detail)){
webSocketApi.dealWithDetailMsg(loginUser, payload);
} else if (currentPath.contains(WebSocketConstants.list)) {
webSocketApi.dealWithListMsg(loginUser, payload);
} else {
// 创建WebSocket消息DTO对象
WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
webSocketMessageDto.setMessage(payload);
WebSocketUtils.publishMessage(webSocketMessageDto);
}
// 创建WebSocket消息DTO对象
WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
webSocketMessageDto.setMessage(message.getPayload());
WebSocketUtils.publishMessage(webSocketMessageDto);
} }
/** /**

View File

@ -0,0 +1,17 @@
package org.dromara.common.websocket.handler;
import org.dromara.common.core.domain.model.LoginUser;
import org.springframework.stereotype.Service;
/**
* @ClassName : WebSocketApi
* @Author : ZZC
* @Date : 2024/11/16 19:06
* @Description :
**/
@Service
public interface WebSocketApi {
void dealWithDetailMsg(LoginUser loginUser, String msg);
void dealWithListMsg(LoginUser loginUser, String msg);
}