Compare commits

10 Commits

Author SHA1 Message Date
447aa73ae9 Merge branch 'dyf-device' 2025-08-14 14:22:43 +08:00
bc165f5d60 分享管理 2025-08-09 17:09:26 +08:00
af64984623 修改分享功能 2025-08-09 08:49:37 +08:00
0c932c686d 修改分享查看 2025-08-08 16:32:40 +08:00
47dbd33d56 修改在线上报状态 2025-08-08 15:09:59 +08:00
41c6cb935d Merge branch 'dyf-device' 2025-08-07 18:08:12 +08:00
efed6f3683 修改包名 2025-08-07 15:56:12 +08:00
f67e848256 晶全6710 2025-08-07 15:41:57 +08:00
825e9b329c Merge remote-tracking branch 'origin/main' 2025-08-06 10:39:01 +08:00
67764a733e 设备列表电量显示问题,打印日志优化 2025-08-06 10:38:21 +08:00
27 changed files with 1636 additions and 729 deletions

View File

@ -1,31 +1,20 @@
package com.fuyuanshen.app.controller;
import cn.hutool.json.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.app.domain.dto.APPReNameDTO;
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo;
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
import com.fuyuanshen.app.service.AppDeviceBizService;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
/**
* APP设备信息管理
@ -83,95 +72,4 @@ public class AppDeviceController extends BaseController {
appDeviceService.reName(reNameDTO);
return R.ok("重命名成功!!!");
}
/**
* 获取设备详细信息
*
* @param id 主键
*/
@GetMapping("/{id}")
public R<AppDeviceDetailVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(appDeviceService.getInfo(id));
}
/**
* 人员信息登记
*/
@PostMapping(value = "/registerPersonInfo")
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
return toAjax(appDeviceService.registerPersonInfo(bo));
}
/**
* 发送信息
*/
@PostMapping(value = "/sendMessage")
public R<Void> sendMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendMessage(bo));
}
/**
* 发送报警信息
*/
@PostMapping(value = "/sendAlarmMessage")
public R<Void> sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendAlarmMessage(bo));
}
/**
* 上传设备logo图片
*/
@PostMapping("/uploadLogo")
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
MultipartFile file = bo.getFile();
if(file.getSize()>1024*1024*2){
return R.warn("图片不能大于2M");
}
appDeviceService.uploadDeviceLogo(bo);
return R.ok();
}
/**
* 灯光模式
* 0关灯1强光模式2弱光模式, 3爆闪模式, 4泛光模式
*/
@PostMapping("/lightModeSettings")
public R<Void> lightModeSettings(@RequestBody DeviceInstructDto params) {
// params 转 JSONObject
appDeviceService.lightModeSettings(params);
return R.ok();
}
/**
* 灯光亮度设置
*
*/
@PostMapping("/lightBrightnessSettings")
public R<Void> lightBrightnessSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.lightBrightnessSettings(params);
return R.ok();
}
/**
* 激光模式设置
*
*/
@PostMapping("/laserModeSettings")
public R<Void> laserModeSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.laserModeSettings(params);
return R.ok();
}
/**
* 地图逆解析
*
*/
@PostMapping("/mapReverseGeocoding")
public R<Void> mapReverseGeocoding(@RequestBody DeviceInstructDto params) {
String mapJson = appDeviceService.mapReverseGeocoding(params);
return R.ok(mapJson);
}
}

View File

@ -52,7 +52,7 @@ public class AppDeviceShareController extends BaseController {
*/
@GetMapping("/deviceShareList")
public TableDataInfo<AppDeviceShareVo> list(AppDeviceShareBo bo, PageQuery pageQuery) {
return deviceShareService.queryPageList(bo, pageQuery);
return appDeviceShareService.queryPageList(bo, pageQuery);
}
/**
@ -60,7 +60,7 @@ public class AppDeviceShareController extends BaseController {
*/
@GetMapping("/otherDeviceShareList")
public TableDataInfo<AppDeviceShareVo> otherDeviceShareList(AppDeviceShareBo bo, PageQuery pageQuery) {
return deviceShareService.otherDeviceShareList(bo, pageQuery);
return appDeviceShareService.otherDeviceShareList(bo, pageQuery);
}
/**

View File

@ -0,0 +1,119 @@
package com.fuyuanshen.app.controller.device;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
import com.fuyuanshen.app.service.device.AppDeviceBJQBizService;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* BJQ6170设备控制类
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/bjq/device")
public class AppDeviceBJQController extends BaseController {
private final AppDeviceBJQBizService appDeviceService;
/**
* 获取设备详细信息
*
* @param id 主键
*/
@GetMapping("/{id}")
public R<AppDeviceDetailVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(appDeviceService.getInfo(id));
}
/**
* 人员信息登记
*/
@PostMapping(value = "/registerPersonInfo")
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
return toAjax(appDeviceService.registerPersonInfo(bo));
}
/**
* 发送信息
*/
@PostMapping(value = "/sendMessage")
public R<Void> sendMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendMessage(bo));
}
/**
* 发送报警信息
*/
@PostMapping(value = "/sendAlarmMessage")
public R<Void> sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendAlarmMessage(bo));
}
/**
* 上传设备logo图片
*/
@PostMapping("/uploadLogo")
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
MultipartFile file = bo.getFile();
if(file.getSize()>1024*1024*2){
return R.warn("图片不能大于2M");
}
appDeviceService.uploadDeviceLogo(bo);
return R.ok();
}
/**
* 灯光模式
* 0关灯1强光模式2弱光模式, 3爆闪模式, 4泛光模式
*/
@PostMapping("/lightModeSettings")
public R<Void> lightModeSettings(@RequestBody DeviceInstructDto params) {
// params 转 JSONObject
appDeviceService.lightModeSettings(params);
return R.ok();
}
/**
* 灯光亮度设置
*
*/
@PostMapping("/lightBrightnessSettings")
public R<Void> lightBrightnessSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.lightBrightnessSettings(params);
return R.ok();
}
/**
* 激光模式设置
*
*/
@PostMapping("/laserModeSettings")
public R<Void> laserModeSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.laserModeSettings(params);
return R.ok();
}
/**
* 地图逆解析
*
*/
@PostMapping("/mapReverseGeocoding")
public R<Void> mapReverseGeocoding(@RequestBody DeviceInstructDto params) {
String mapJson = appDeviceService.mapReverseGeocoding(params);
return R.ok(mapJson);
}
}

View File

@ -0,0 +1,112 @@
package com.fuyuanshen.app.controller.device;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
import com.fuyuanshen.app.service.AppDeviceBizService;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* HBY210设备控制类
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/hby/device")
public class AppDeviceHBYController extends BaseController {
private final AppDeviceBizService appDeviceService;
/**
* 获取设备详细信息
*
* @param id 主键
*/
@GetMapping("/{id}")
public R<AppDeviceDetailVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(appDeviceService.getInfo(id));
}
/**
* 人员信息登记
*/
@PostMapping(value = "/registerPersonInfo")
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
return toAjax(appDeviceService.registerPersonInfo(bo));
}
/**
* 发送信息
*/
@PostMapping(value = "/sendMessage")
public R<Void> sendMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendMessage(bo));
}
/**
* 上传设备logo图片
*/
@PostMapping("/uploadLogo")
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
MultipartFile file = bo.getFile();
if(file.getSize()>1024*1024*2){
return R.warn("图片不能大于2M");
}
appDeviceService.uploadDeviceLogo(bo);
return R.ok();
}
/**
* 灯光模式
* 0关灯1强光模式2弱光模式, 3爆闪模式, 4泛光模式
*/
@PostMapping("/lightModeSettings")
public R<Void> lightModeSettings(@RequestBody DeviceInstructDto params) {
// params 转 JSONObject
appDeviceService.lightModeSettings(params);
return R.ok();
}
/**
* 灯光亮度设置
*
*/
@PostMapping("/lightBrightnessSettings")
public R<Void> lightBrightnessSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.lightBrightnessSettings(params);
return R.ok();
}
/**
* 激光模式设置
*
*/
@PostMapping("/laserModeSettings")
public R<Void> laserModeSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.laserModeSettings(params);
return R.ok();
}
/**
* 地图逆解析
*
*/
@PostMapping("/mapReverseGeocoding")
public R<Void> mapReverseGeocoding(@RequestBody DeviceInstructDto params) {
String mapJson = appDeviceService.mapReverseGeocoding(params);
return R.ok(mapJson);
}
}

View File

@ -54,6 +54,7 @@ import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_K
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.buildArr;
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.generateFixedBitmapData;
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
@Slf4j
@ -101,14 +102,14 @@ public class AppDeviceBizService {
// String backgroundImagePath = "D:\\background.png"; // 替换为实际背景图片路径
byte[] largeData = ImageWithTextGenerate.generate160x80ImageWithText2(bo.getSendMsg(), inputStream, 25600);
int[] ints = convertHexToDecimal(largeData);
RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+"app_send_message_data:" + device.getDeviceImei(), Arrays.toString(ints), Duration.ofSeconds(30 * 60L));
RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_SEND_MESSAGE_KEY_PREFIX , Arrays.toString(ints), Duration.ofSeconds(30 * 60L));
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+"app_send_message_data:" + device.getDeviceImei());
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_SEND_MESSAGE_KEY_PREFIX);
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512);
System.out.println("第0块数据大小: " + specificChunk.length + " 字节");
System.out.println("第0块数据: " + Arrays.toString(specificChunk));
log.info("发送信息第0块数据大小: {} 字节",specificChunk.length);
// log.info("第0块数据: {}", Arrays.toString(specificChunk));
ArrayList<Integer> intData = new ArrayList<>();
intData.add(6);
@ -121,7 +122,7 @@ public class AppDeviceBizService {
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
log.info("发送信息点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", deviceId)
@ -129,7 +130,7 @@ public class AppDeviceBizService {
.set("send_msg", bo.getSendMsg());
deviceMapper.update(updateWrapper);
} catch (Exception e) {
log.info("设备发送信息失败:{}" ,deviceId);
log.info("发送信息设备发送信息失败:{}" ,deviceId);
}
}
@ -149,14 +150,14 @@ public class AppDeviceBizService {
if(item.getCommunicationMode()!=null && item.getCommunicationMode() == 0){
//设备在线状态
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX + item.getDeviceImei());
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
if(StringUtils.isNotBlank(onlineStatus)){
item.setOnlineStatus(1);
}else{
item.setOnlineStatus(0);
}
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX + item.getDeviceImei());
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
// 获取电量
if(StringUtils.isNotBlank(deviceStatus)){
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
@ -165,14 +166,16 @@ public class AppDeviceBizService {
item.setBattery("0");
}
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX + item.getDeviceImei());
// 获取电量
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_LOCATION_KEY_PREFIX);
if(StringUtils.isNotBlank(location)){
JSONObject jsonObject = JSONObject.parseObject(location);
item.setLatitude(jsonObject.getString("latitude"));
item.setLongitude(jsonObject.getString("longitude"));
}else{
item.setBattery("0");
}
String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_ALARM_KEY_PREFIX);
if(StringUtils.isNotBlank(alarmStatus)){
item.setAlarmStatus(alarmStatus);
}
}
});
@ -336,13 +339,13 @@ public class AppDeviceBizService {
vo.setPersonnelInfo(personnelInfoVo);
}
//设备在线状态
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX + device.getDeviceImei());
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
if(StringUtils.isNotBlank(onlineStatus)){
vo.setOnlineStatus(1);
}else{
vo.setOnlineStatus(0);
}
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX + device.getDeviceImei());
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
// 获取电量
if(StringUtils.isNotBlank(deviceStatus)){
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
@ -356,7 +359,7 @@ public class AppDeviceBizService {
}
// 获取经度纬度
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX + device.getDeviceImei();
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX;
String locationInfo = RedisUtils.getCacheObject(locationKey);
if(StringUtils.isNotBlank(locationInfo)){
JSONObject jsonObject = JSONObject.parseObject(locationInfo);
@ -433,19 +436,19 @@ public class AppDeviceBizService {
MultipartFile file = bo.getFile();
byte[] largeData = ImageToCArrayConverter.convertImageToCArray(file.getInputStream(), 160, 80, 25600);
System.out.println("长度:" + largeData.length);
log.info("长度:" + largeData.length);
System.out.println("原始数据大小: " + largeData.length + " 字节");
log.info("原始数据大小: {} 字节", largeData.length);
int[] ints = convertHexToDecimal(largeData);
RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+"app_logo_data:" + device.getDeviceImei(), Arrays.toString(ints), Duration.ofSeconds(30 * 60L));
RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX, Arrays.toString(ints), Duration.ofSeconds(30 * 60L));
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+"app_logo_data:" + device.getDeviceImei());
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX);
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512);
System.out.println("第0块数据大小: " + specificChunk.length + " 字节");
System.out.println("第0块数据: " + Arrays.toString(specificChunk));
log.info("第0块数据大小: {} 字节", specificChunk.length);
// log.info("第0块数据: {}", Arrays.toString(specificChunk));
ArrayList<Integer> intData = new ArrayList<>();
intData.add(3);

View File

@ -1,7 +1,11 @@
package com.fuyuanshen.app.service;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.app.domain.AppDeviceShare;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import com.fuyuanshen.app.domain.bo.AppDeviceShareBo;
@ -16,12 +20,15 @@ import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.exception.user.CaptchaExpireException;
import com.fuyuanshen.common.core.utils.MessageUtils;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -30,6 +37,9 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
@RequiredArgsConstructor
@Slf4j
@ -44,10 +54,51 @@ public class AppDeviceShareService {
private final AppPersonnelInfoMapper appPersonnelInfoMapper;
public TableDataInfo<AppDeviceShareVo> queryPageList(AppDeviceShareBo bo, PageQuery pageQuery) {
Long userId = AppLoginHelper.getUserId();
bo.setCreateBy(userId);
Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
Page<AppDeviceShareVo> result = appDeviceShareMapper.selectAppDeviceShareList(bo, page);
List<AppDeviceShareVo> records = result.getRecords();
records.forEach(AppDeviceShareService::buildDeviceStatus);
return TableDataInfo.build(result);
}
private static void buildDeviceStatus(AppDeviceShareVo item) {
//设备在线状态
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
if(StringUtils.isNotBlank(onlineStatus)){
item.setOnlineStatus(1);
}else{
item.setOnlineStatus(0);
}
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
// 获取电量
if(StringUtils.isNotBlank(deviceStatus)){
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
item.setBattery(jsonObject.getString("batteryPercentage"));
}else{
item.setBattery("0");
}
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_LOCATION_KEY_PREFIX);
if(StringUtils.isNotBlank(location)){
JSONObject jsonObject = JSONObject.parseObject(location);
item.setLatitude(jsonObject.getString("latitude"));
item.setLongitude(jsonObject.getString("longitude"));
}
String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_ALARM_KEY_PREFIX);
if(StringUtils.isNotBlank(alarmStatus)){
item.setAlarmStatus(alarmStatus);
}
}
public AppDeviceShareDetailVo getInfo(Long id) {
LambdaQueryWrapper<AppDeviceShare> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AppDeviceShare::getDeviceId, id);
queryWrapper.eq(AppDeviceShare::getId, id);
List<AppDeviceShareVo> appDeviceShareVos = appDeviceShareMapper.selectVoList(queryWrapper);
if(appDeviceShareVos==null || appDeviceShareVos.isEmpty()){
return null;
@ -81,7 +132,35 @@ public class AppDeviceShareService {
if(appPersonnelInfoVos!=null && !appPersonnelInfoVos.isEmpty()){
shareDetailVo.setPersonnelInfo(appPersonnelInfoVos.get(0));
}
//设备在线状态
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei()+ DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
if(StringUtils.isNotBlank(onlineStatus)){
shareDetailVo.setOnlineStatus(1);
}else{
shareDetailVo.setOnlineStatus(0);
}
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX);
// 获取电量
if(StringUtils.isNotBlank(deviceStatus)){
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
shareDetailVo.setMainLightMode(jsonObject.getString("mainLightMode"));
shareDetailVo.setLaserLightMode(jsonObject.getString("laserLightMode"));
shareDetailVo.setBatteryPercentage(jsonObject.getString("batteryPercentage"));
shareDetailVo.setChargeState(jsonObject.getString("chargeState"));
shareDetailVo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime"));
}else{
shareDetailVo.setBatteryPercentage("0");
}
// 获取经度纬度
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
String locationInfo = RedisUtils.getCacheObject(locationKey);
if(StringUtils.isNotBlank(locationInfo)){
JSONObject jsonObject = JSONObject.parseObject(locationInfo);
shareDetailVo.setLongitude(jsonObject.get("longitude").toString());
shareDetailVo.setLatitude(jsonObject.get("latitude").toString());
shareDetailVo.setAddress((String)jsonObject.get("address"));
}
return shareDetailVo;
}
/**
@ -132,4 +211,17 @@ public class AppDeviceShareService {
public int remove(Long[] ids) {
return appDeviceShareMapper.deleteByIds(Arrays.asList(ids));
}
public TableDataInfo<AppDeviceShareVo> otherDeviceShareList(AppDeviceShareBo bo, PageQuery pageQuery) {
String username = AppLoginHelper.getUsername();
bo.setPhonenumber(username);
Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
IPage<AppDeviceShareVo> result = appDeviceShareMapper.otherDeviceShareList(bo, page);
List<AppDeviceShareVo> records = result.getRecords();
records.forEach(AppDeviceShareService::buildDeviceStatus);
return TableDataInfo.build(result);
}
}

View File

@ -0,0 +1,388 @@
package com.fuyuanshen.app.service.device;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.*;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
import com.fuyuanshen.global.mqtt.config.MqttGateway;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.time.Duration;
import java.util.*;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.buildArr;
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.generateFixedBitmapData;
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_BOOT_LOGO_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
@Slf4j
@Service
@RequiredArgsConstructor
public class AppDeviceBJQBizService {
private final DeviceMapper deviceMapper;
private final AppPersonnelInfoMapper appPersonnelInfoMapper;
private final DeviceTypeMapper deviceTypeMapper;
private final MqttGateway mqttGateway;
public int sendMessage(AppDeviceSendMsgBo bo) {
List<Long> deviceIds = bo.getDeviceIds();
if (deviceIds == null || deviceIds.isEmpty()) {
throw new ServiceException("请选择设备");
}
for (Long deviceId : deviceIds) {
Device device = deviceMapper.selectById(deviceId);
if (device == null) {
throw new ServiceException("设备不存在" + deviceId);
}
try {
ClassPathResource resource = new ClassPathResource("image/background.png");
InputStream inputStream = resource.getInputStream();
// String backgroundImagePath = "D:\\background.png"; // 替换为实际背景图片路径
byte[] largeData = ImageWithTextGenerate.generate160x80ImageWithText2(bo.getSendMsg(), inputStream, 25600);
int[] ints = convertHexToDecimal(largeData);
RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data" , Arrays.toString(ints), Duration.ofSeconds(30 * 60L));
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data");
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512);
log.info("发送信息第0块数据大小: {} 字节",specificChunk.length);
// log.info("第0块数据: {}", Arrays.toString(specificChunk));
ArrayList<Integer> intData = new ArrayList<>();
intData.add(6);
intData.add(1);
ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk),intData);
intData.add(0);
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送信息点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", deviceId)
.eq("binding_user_id", AppLoginHelper.getUserId())
.set("send_msg", bo.getSendMsg());
deviceMapper.update(updateWrapper);
} catch (Exception e) {
log.info("发送信息设备发送信息失败:{}" ,deviceId);
}
}
return 1;
}
public AppDeviceDetailVo getInfo(Long id) {
Device device = deviceMapper.selectById(id);
if (device == null) {
throw new RuntimeException("请先将设备入库!!!");
}
AppDeviceDetailVo vo = new AppDeviceDetailVo();
vo.setDeviceId(device.getId());
vo.setDeviceName(device.getDeviceName());
vo.setDevicePic(device.getDevicePic());
vo.setDeviceImei(device.getDeviceImei());
vo.setDeviceMac(device.getDeviceMac());
vo.setDeviceStatus(device.getDeviceStatus());
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
if (deviceType != null) {
vo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode()));
vo.setTypeName(deviceType.getTypeName());
}
vo.setBluetoothName(device.getBluetoothName());
vo.setSendMsg(device.getSendMsg());
QueryWrapper<AppPersonnelInfo> qw = new QueryWrapper<AppPersonnelInfo>()
.eq("device_id", device.getId());
AppPersonnelInfo appPersonnelInfo = appPersonnelInfoMapper.selectOne(qw);
if (appPersonnelInfo != null) {
AppPersonnelInfoVo personnelInfoVo = MapstructUtils.convert(appPersonnelInfo, AppPersonnelInfoVo.class);
vo.setPersonnelInfo(personnelInfoVo);
}
//设备在线状态
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei()+ DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
if(StringUtils.isNotBlank(onlineStatus)){
vo.setOnlineStatus(1);
}else{
vo.setOnlineStatus(0);
}
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX);
// 获取电量
if(StringUtils.isNotBlank(deviceStatus)){
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
vo.setMainLightMode(jsonObject.getString("mainLightMode"));
vo.setLaserLightMode(jsonObject.getString("laserLightMode"));
vo.setBatteryPercentage(jsonObject.getString("batteryPercentage"));
vo.setChargeState(jsonObject.getString("chargeState"));
vo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime"));
}else{
vo.setBatteryPercentage("0");
}
// 获取经度纬度
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
String locationInfo = RedisUtils.getCacheObject(locationKey);
if(StringUtils.isNotBlank(locationInfo)){
JSONObject jsonObject = JSONObject.parseObject(locationInfo);
vo.setLongitude(jsonObject.get("longitude").toString());
vo.setLatitude(jsonObject.get("latitude").toString());
vo.setAddress((String)jsonObject.get("address"));
}
return vo;
}
public boolean registerPersonInfo(AppPersonnelInfoBo bo) {
Long deviceId = bo.getDeviceId();
Device deviceObj = deviceMapper.selectById(deviceId);
if (deviceObj == null) {
throw new RuntimeException("请先将设备入库!!!");
}
QueryWrapper<AppPersonnelInfo> qw = new QueryWrapper<AppPersonnelInfo>()
.eq("device_id", deviceId);
List<AppPersonnelInfoVo> appPersonnelInfoVos = appPersonnelInfoMapper.selectVoList(qw);
// unitName,position,name,id
byte[] unitName = generateFixedBitmapData(bo.getUnitName(), 120);
byte[] position = generateFixedBitmapData(bo.getPosition(), 120);
byte[] name = generateFixedBitmapData(bo.getName(), 120);
byte[] id = generateFixedBitmapData(bo.getCode(), 120);
ArrayList<Integer> intData = new ArrayList<>();
intData.add(2);
buildArr(convertHexToDecimal(unitName), intData);
buildArr(convertHexToDecimal(position), intData);
buildArr(convertHexToDecimal(name), intData);
buildArr(convertHexToDecimal(id), intData);
intData.add(0);
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), 1, JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), bo);
if (ObjectUtils.length(appPersonnelInfoVos) == 0) {
AppPersonnelInfo appPersonnelInfo = MapstructUtils.convert(bo, AppPersonnelInfo.class);
return appPersonnelInfoMapper.insertOrUpdate(appPersonnelInfo);
} else {
UpdateWrapper<AppPersonnelInfo> uw = new UpdateWrapper<>();
uw.eq("device_id", deviceId)
.set("name", bo.getName())
.set("position", bo.getPosition())
.set("unit_name", bo.getUnitName())
.set("code", bo.getCode());
return appPersonnelInfoMapper.update(null, uw) > 0;
}
}
public void uploadDeviceLogo(AppDeviceLogoUploadDto bo) {
try {
Device device = deviceMapper.selectById(bo.getDeviceId());
if (device == null) {
throw new ServiceException("设备不存在");
}
MultipartFile file = bo.getFile();
byte[] largeData = ImageToCArrayConverter.convertImageToCArray(file.getInputStream(), 160, 80, 25600);
log.info("长度:" + largeData.length);
log.info("原始数据大小: {} 字节", largeData.length);
int[] ints = convertHexToDecimal(largeData);
RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() +DEVICE_BOOT_LOGO_KEY_PREFIX, Arrays.toString(ints), Duration.ofSeconds(30 * 60L));
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX);
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512);
log.info("第0块数据大小: {} 字节", specificChunk.length);
// log.info("第0块数据: {}", Arrays.toString(specificChunk));
ArrayList<Integer> intData = new ArrayList<>();
intData.add(3);
intData.add(1);
ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk),intData);
intData.add(0);
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 灯光模式
* 0关灯1强光模式2弱光模式, 3爆闪模式, 4泛光模式
*/
public void lightModeSettings(DeviceInstructDto params) {
try {
Long deviceId = params.getDeviceId();
Device device = deviceMapper.selectById(deviceId);
if(device == null){
throw new ServiceException("设备不存在");
}
Integer instructValue = Integer.parseInt(params.getInstructValue());
ArrayList<Integer> intData = new ArrayList<>();
intData.add(1);
intData.add(instructValue);
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
} catch (Exception e){
e.printStackTrace();
}
}
//灯光亮度设置
public void lightBrightnessSettings(DeviceInstructDto params) {
try {
Long deviceId = params.getDeviceId();
Device device = deviceMapper.selectById(deviceId);
if(device == null){
throw new ServiceException("设备不存在");
}
String instructValue = params.getInstructValue();
ArrayList<Integer> intData = new ArrayList<>();
intData.add(5);
String[] values = instructValue.split("\\.");
String value1 = values[0];
String value2 = values[1];
if(StringUtils.isNoneBlank(value1)){
intData.add(Integer.parseInt(value1));
}
if(StringUtils.isNoneBlank(value2)){
intData.add(Integer.parseInt(value2));
}
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
} catch (Exception e){
e.printStackTrace();
}
}
//激光模式设置
public void laserModeSettings(DeviceInstructDto params) {
try {
Long deviceId = params.getDeviceId();
Device device = deviceMapper.selectById(deviceId);
if(device == null){
throw new ServiceException("设备不存在");
}
Integer instructValue = Integer.parseInt(params.getInstructValue());
ArrayList<Integer> intData = new ArrayList<>();
intData.add(4);
intData.add(instructValue);
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
} catch (Exception e){
e.printStackTrace();
}
}
public String mapReverseGeocoding(DeviceInstructDto params) {
QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("device_imei", params.getDeviceImei());
List<Device> devices = deviceMapper.selectList(queryWrapper);
if(ObjectUtils.length( devices) ==0){
throw new ServiceException("设备不存在");
}
return RedisUtils.getCacheObject("device:location:" + devices.get(0).getDeviceImei());
}
public int sendAlarmMessage(AppDeviceSendMsgBo bo) {
try {
List<Long> deviceIds = bo.getDeviceIds();
if (deviceIds == null || deviceIds.isEmpty()) {
throw new ServiceException("请选择设备");
}
for (Long deviceId : deviceIds) {
Device device = deviceMapper.selectById(deviceId);
if (device == null) {
throw new ServiceException("设备不存在" + deviceId);
}
try {
ArrayList<Integer> intData = new ArrayList<>();
intData.add(7);
intData.add(Integer.parseInt(bo.getInstructValue()));
intData.add(0);
intData.add(0);
intData.add(0);
intData.add(0);
Map<String, Object> map = new HashMap<>();
map.put("instruct", intData);
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map));
log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map));
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", deviceId)
.eq("binding_user_id", AppLoginHelper.getUserId())
.set("send_msg", bo.getSendMsg());
deviceMapper.update(updateWrapper);
} catch (Exception e) {
log.info("设备发送信息失败:{}" ,deviceId);
}
}
} catch (Exception e){
e.printStackTrace();
}
return 1;
}
}

View File

@ -4,12 +4,6 @@ import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
/**
* @Author: HarryLin
* @Date: 2025/3/20 17:06
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {
public abstract void sendMsgToMqtt(@Header(value = MqttHeaders.TOPIC) String topic, String payload);

View File

@ -1,12 +1,50 @@
package com.fuyuanshen.global.mqtt.constants;
public class DeviceRedisKeyConstants {
// 将设备上报状态
public static final String DEVICE_STATUS_KEY_PREFIX = "device:status:";
public static final String DEVICE_KEY_PREFIX = "device:";
// 设备上报状态
public static final String DEVICE_STATUS_KEY_PREFIX = ":status";
// 在线状态
public static final String DEVICE_ONLINE_STATUS_KEY_PREFIX = "device:onlineStatus:";
// 设备状态信息存储到Redis中
public static final String DEVICE_LOCATION_KEY_PREFIX = "device:location:";
public static final String DEVICE_ONLINE_STATUS_KEY_PREFIX = ":onlineStatus";
// 设备状态信息存储到Redis中
public static final String DEVICE_LOCATION_KEY_PREFIX = ":location";
// 存储到一个列表中,保留历史位置信息
public static final String DEVICE_LOCATION_HISTORY_KEY_PREFIX = "device:location:history:";
public static final String DEVICE_LOCATION_HISTORY_KEY_PREFIX = ":location:history";
// 存储设备活跃上报信息
public static final String DEVICE_ACTIVE_REPORTING_KEY_PREFIX = ":activeReporting";
// 存储设备人员信息
public static final String DEVICE_PERSONNEL_INFO_KEY_PREFIX = ":personnelInfo";
// 存储设备发送消息
public static final String DEVICE_SEND_MESSAGE_KEY_PREFIX = ":sendMessage";
// 存储设备启动logo
public static final String DEVICE_BOOT_LOGO_KEY_PREFIX = ":bootLogo";
/**
* 灯模式
*/
public static final String DEVICE_LIGHT_MODE_KEY_PREFIX = ":lightMode";
/**
* 亮度模式
*/
public static final String DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX = ":lightBrightness";
/**
* 激光模式
*/
public static final String DEVICE_LASER_MODE_KEY_PREFIX = ":laserMode";
/**
* 地图逆地理编码
*/
public static final String DEVICE_MAP_REVERSE_GEOCODING_KEY_PREFIX = ":mapReverseGeocoding";
/**
* 告警
*/
public static final String DEVICE_ALARM_KEY_PREFIX = ":alarm";
}

View File

@ -6,12 +6,7 @@ import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;
/**
* @Author: HarryLin
* @Date: 2025/3/20 16:16
* @Company: 北京红山信息科技研究院有限公司
* @Email: linyun@***.com.cn
**/
@Service
public class MqttMessageSender {
@Autowired

View File

@ -20,6 +20,8 @@ import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.Objects;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
@Service
@Slf4j
public class ReceiverMessageHandler implements MessageHandler {
@ -46,7 +48,7 @@ public class ReceiverMessageHandler implements MessageHandler {
String deviceImei = subStr[1];
if(StringUtils.isNotBlank(deviceImei)){
//在线状态
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX + deviceImei;
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(60*15));
}

View File

@ -1,22 +1,22 @@
package com.fuyuanshen.global.mqtt.rule;
package com.fuyuanshen.global.mqtt.rule.bjq;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.json.utils.JsonUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
import com.fuyuanshen.global.mqtt.config.MqttGateway;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX;
/**
* 主动上报设备数据命令处理
* "第1位为12表示设备主动上报设备硬件状态第2为表示当时设备主灯档位第3位表示当时激光灯档位第4位电量百分比第5位为充电状态0没有充电1正在充电2为已充满
@ -25,10 +25,7 @@ import java.util.concurrent.CompletableFuture;
@Component
@RequiredArgsConstructor
@Slf4j
public class ActiveReportingDeviceDataRule implements MqttMessageRule {
private final MqttGateway mqttGateway;
public class BjqActiveReportingDeviceDataRule implements MqttMessageRule {
@Override
public String getCommandType() {
@ -80,10 +77,10 @@ public class ActiveReportingDeviceDataRule implements MqttMessageRule {
deviceInfo.put("timestamp", System.currentTimeMillis());
// 将设备状态信息存储到Redis中
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX + deviceImei;
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_STATUS_KEY_PREFIX;
String deviceInfoJson = JsonUtils.toJsonString(deviceInfo);
// 存储到Redis设置过期时间例如24小时
// 存储到Redis
RedisUtils.setCacheObject(deviceRedisKey, deviceInfoJson);
log.info("设备状态信息已异步发送到Redis: device={}, mainLightMode={}, laserLightMode={}, batteryPercentage={}",

View File

@ -0,0 +1,69 @@
package com.fuyuanshen.global.mqtt.rule.bjq;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
/**
* 灯光模式订阅设备回传消息
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class BjqAlarmRule implements MqttMessageRule {
@Override
public String getCommandType() {
return LightingCommandTypeConstants.LIGHT_MODE;
}
@Override
public void execute(MqttRuleContext context) {
try {
Object[] convertArr = context.getConvertArr();
String mainLightMode = convertArr[1].toString();
if(StringUtils.isNotBlank(mainLightMode)){
// 异步发送设备状态和位置信息到Redis
asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode);
}
} catch (Exception e) {
log.error("处理灯光模式命令时出错", e);
}
}
/**
* 异步发送设备状态信息和位置信息到Redis使用CompletableFuture
*
* @param deviceImei 设备IMEI
*/
public void asyncSendDeviceDataToRedisWithFuture(String deviceImei,Object convertValue) {
CompletableFuture.runAsync(() -> {
try {
// 将设备状态信息存储到Redis中
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_ALARM_KEY_PREFIX;
// 存储到Redis
RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString());
} catch (Exception e) {
log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
}
});
}
}

View File

@ -1,6 +1,5 @@
package com.fuyuanshen.global.mqtt.rule;
package com.fuyuanshen.global.mqtt.rule.bjq;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.json.utils.JsonUtils;
@ -15,11 +14,13 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_BOOT_LOGO_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
/**
* 人员信息命令处理
@ -27,7 +28,7 @@ import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHex
@Component
@RequiredArgsConstructor
@Slf4j
public class DeviceBootLogoRule implements MqttMessageRule {
public class BjqBootLogoRule implements MqttMessageRule {
private final MqttGateway mqttGateway;
@ -44,14 +45,14 @@ public class DeviceBootLogoRule implements MqttMessageRule {
return;
}
String data = RedisUtils.getCacheObject(GlobalConstants.GLOBAL_REDIS_KEY+"app_logo_data:" + context.getDeviceImei());
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() +DEVICE_BOOT_LOGO_KEY_PREFIX);
if (StringUtils.isEmpty(data)) {
return;
}
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512);
System.out.println("" + val2 + "块数据大小: " + specificChunk.length + " 字节");
log.info("第{}块数据大小: {} 字节", val2, specificChunk.length);
// System.out.println("" + val2 + "块数据: " + Arrays.toString(specificChunk));
ArrayList<Integer> intData = new ArrayList<>();
@ -71,7 +72,7 @@ public class DeviceBootLogoRule implements MqttMessageRule {
MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
JsonUtils.toJsonString(map));
} catch (Exception e) {
log.error("处理人员信息命令时出错", e);
log.error("处理开机LOGO时出错", e);
}
}
}

View File

@ -1,6 +1,5 @@
package com.fuyuanshen.global.mqtt.rule;
package com.fuyuanshen.global.mqtt.rule.bjq;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.StringUtils;
@ -18,20 +17,22 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
/**
* 定位数据命令处理
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class LocationDataRule implements MqttMessageRule {
public class BjqLocationDataRule implements MqttMessageRule {
private final MqttGateway mqttGateway;
@ -113,7 +114,7 @@ public class LocationDataRule implements MqttMessageRule {
String[] latArr = latitude.split("\\.");
String[] lonArr = longitude.split("\\.");
// 将位置信息存储到Redis中
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX + deviceImei;
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DEVICE_LOCATION_KEY_PREFIX;
String redisObj = RedisUtils.getCacheObject(redisKey);
JSONObject jsonOBj = JSONObject.parseObject(redisObj);
if(jsonOBj != null){
@ -169,7 +170,7 @@ public class LocationDataRule implements MqttMessageRule {
*/
public void storeDeviceTrajectoryWithSortedSet(String deviceImei, String locationJson) {
try {
String trajectoryKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX + deviceImei;
String trajectoryKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX;
// String trajectoryKey = "device:trajectory:zset:" + deviceImei;
// String locationJson = JsonUtils.toJsonString(locationInfo);
long timestamp = System.currentTimeMillis();
@ -181,7 +182,7 @@ public class LocationDataRule implements MqttMessageRule {
// RedisUtils.expire(trajectoryKey, Duration.ofDays(30));
// 清理30天前的数据冗余保护
long thirtyDaysAgo = System.currentTimeMillis() - (90L * 24 * 60 * 60 * 1000);
long thirtyDaysAgo = System.currentTimeMillis() - (7L * 24 * 60 * 60 * 1000);
RedisUtils.zRemoveRangeByScore(trajectoryKey, 0, thirtyDaysAgo);
} catch (Exception e) {
log.error("存储设备轨迹到Redis(ZSet)失败: device={}, error={}", deviceImei, e.getMessage(), e);

View File

@ -0,0 +1,75 @@
package com.fuyuanshen.global.mqtt.rule.bjq;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX;
/**
* 灯光模式订阅设备回传消息
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class BjqModeRule implements MqttMessageRule {
@Override
public String getCommandType() {
return LightingCommandTypeConstants.LIGHT_MODE;
}
@Override
public void execute(MqttRuleContext context) {
try {
Object[] convertArr = context.getConvertArr();
String mainLightMode = convertArr[1].toString();
if(StringUtils.isNotBlank(mainLightMode)){
if("0".equals(mainLightMode)){
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ context.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "0", Duration.ofSeconds(60*15));
}
// 异步发送设备状态和位置信息到Redis
asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode);
}
} catch (Exception e) {
log.error("处理灯光模式命令时出错", e);
}
}
/**
* 异步发送设备状态信息和位置信息到Redis使用CompletableFuture
*
* @param deviceImei 设备IMEI
*/
public void asyncSendDeviceDataToRedisWithFuture(String deviceImei,Object convertValue) {
CompletableFuture.runAsync(() -> {
try {
// 将设备状态信息存储到Redis中
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_LIGHT_MODE_KEY_PREFIX;
// 存储到Redis
RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString());
} catch (Exception e) {
log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
}
});
}
}

View File

@ -1,6 +1,5 @@
package com.fuyuanshen.global.mqtt.rule;
package com.fuyuanshen.global.mqtt.rule.bjq;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.json.utils.JsonUtils;
@ -18,7 +17,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
/**
* 人员信息命令处理
@ -26,7 +27,7 @@ import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHex
@Component
@RequiredArgsConstructor
@Slf4j
public class DeviceSendMessageRule implements MqttMessageRule {
public class BjqSendMessageRule implements MqttMessageRule {
private final MqttGateway mqttGateway;
@ -43,14 +44,14 @@ public class DeviceSendMessageRule implements MqttMessageRule {
return;
}
String data = RedisUtils.getCacheObject(GlobalConstants.GLOBAL_REDIS_KEY+"app_send_message_data:" + context.getDeviceImei());
String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + context.getDeviceImei() + ":app_send_message_data");
if (StringUtils.isEmpty(data)) {
return;
}
byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data);
byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512);
System.out.println("" + val2 + "块数据大小: " + specificChunk.length + " 字节");
log.info("第{}块数据大小: {} 字节", val2, specificChunk.length);
// System.out.println("" + val2 + "块数据: " + Arrays.toString(specificChunk));
ArrayList<Integer> intData = new ArrayList<>();
@ -70,7 +71,7 @@ public class DeviceSendMessageRule implements MqttMessageRule {
MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(),
JsonUtils.toJsonString(map));
} catch (Exception e) {
log.error("处理人员信息命令时出错", e);
log.error("处理发送设备信息时出错", e);
}
}
}

View File

@ -1,61 +1,61 @@
package com.fuyuanshen.web.config;
import cn.hutool.core.lang.UUID;
import com.fuyuanshen.global.mqtt.config.MqttPropertiesConfig;
import com.fuyuanshen.web.handler.mqtt.DeviceReceiverMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
/**
* @author: 默苍璃
* @date: 2025-08-0110:46
*/
@Configuration
public class CustomMqttInboundConfiguration {
@Autowired
private MqttPropertiesConfig mqttPropertiesConfig;
@Autowired
private MqttPahoClientFactory mqttPahoClientFactory;
@Autowired
private DeviceReceiverMessageHandler deviceReceiverMessageHandler;
@Bean
public MessageChannel customMqttChannel(){
return new DirectChannel();
}
@Bean
public MessageProducer customMessageProducer(){
String clientId = "custom_client_" + UUID.fastUUID();
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
mqttPropertiesConfig.getUrl(),
clientId,
mqttPahoClientFactory,
"A/#", "B/#" // 直接指定这两个主题
);
adapter.setQos(1);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setOutputChannel(customMqttChannel());
return adapter;
}
@Bean
@ServiceActivator(inputChannel = "customMqttChannel")
public MessageHandler customMessageHandler(){
return deviceReceiverMessageHandler;
}
}
//package com.fuyuanshen.web.config;
//
//import cn.hutool.core.lang.UUID;
//import com.fuyuanshen.global.mqtt.config.MqttPropertiesConfig;
//import com.fuyuanshen.web.handler.mqtt.DeviceReceiverMessageHandler;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.integration.annotation.ServiceActivator;
//import org.springframework.integration.channel.DirectChannel;
//import org.springframework.integration.core.MessageProducer;
//import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
//import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
//import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
//import org.springframework.messaging.MessageChannel;
//import org.springframework.messaging.MessageHandler;
//
///**
// * @author: 默苍璃
// * @date: 2025-08-0110:46
// */
//@Configuration
//public class CustomMqttInboundConfiguration {
//
// @Autowired
// private MqttPropertiesConfig mqttPropertiesConfig;
// @Autowired
// private MqttPahoClientFactory mqttPahoClientFactory;
// @Autowired
// private DeviceReceiverMessageHandler deviceReceiverMessageHandler;
//
//
// @Bean
// public MessageChannel customMqttChannel(){
// return new DirectChannel();
// }
//
//
// @Bean
// public MessageProducer customMessageProducer(){
// String clientId = "custom_client_" + UUID.fastUUID();
// MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
// mqttPropertiesConfig.getUrl(),
// clientId,
// mqttPahoClientFactory,
// "A/#", "B/#" // 直接指定这两个主题
// );
// adapter.setQos(1);
// adapter.setConverter(new DefaultPahoMessageConverter());
// adapter.setOutputChannel(customMqttChannel());
// return adapter;
// }
//
//
// @Bean
// @ServiceActivator(inputChannel = "customMqttChannel")
// public MessageHandler customMessageHandler(){
// return deviceReceiverMessageHandler;
// }
//
//}

View File

@ -1,318 +1,318 @@
package com.fuyuanshen.web.handler.mqtt;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceLog;
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
import com.fuyuanshen.equipment.utils.map.LngLonUtil;
import com.fuyuanshen.global.mqtt.constants.TenantsConstant;
import com.fuyuanshen.web.enums.InstructType6170;
import com.fuyuanshen.web.enums.LightModeEnum6170;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Component;
/**
* 定义监听主题消息的处理器
*
* @author: 默苍璃
* @date: 2025-08-0110:19
*/
@Component
@Data
@AllArgsConstructor
@Slf4j
public class DeviceReceiverMessageHandler implements MessageHandler {
private final DeviceMapper deviceMapper;
private final DeviceLogMapper deviceLogMapper;
// 使用Jackson解析JSON
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 处理接收的消息
*
* @param message
* @throws MessagingException
*/
@Override
public void handleMessage(Message<?> message) throws MessagingException {
// System.out.println("接收到的消息:" + message.getPayload());
MessageHeaders headers = message.getHeaders();
String receivedTopicName = (String) headers.get("mqtt_receivedTopic");
System.out.println("消息来自主题:" + receivedTopicName);
// String tenantId = LoginHelper.getTenantId();
String tenantId = TenantsConstant.FU_YUAN_SHENG;
String payload = message.getPayload().toString();
if (receivedTopicName != null) {
// 1. 提取设备ID (从主题中获取)
String deviceImei = extractDeviceId(receivedTopicName);
Device device = deviceMapper.selectOne(new QueryWrapper<Device>()
.eq("tenant_id", tenantId)
.eq("device_imei", deviceImei));
if (device == null) {
log.info("不存在的设备IMEI: {}", deviceImei);
} else {
try {
JsonNode root = objectMapper.readTree(payload);
DeviceLog record = new DeviceLog();
// 手动设置租户ID
record.setTenantId(device.getTenantId()); // 从设备信息中获取租户ID
// 设备ID
record.setDeviceId(device.getId());
// 设备名称
record.setDeviceName(device.getDeviceName());
// 2. 处理instruct消息
if (root.has("instruct")) {
JsonNode instructNode = root.get("instruct");
if (instructNode.isArray()) {
boolean b = receivedTopicName.startsWith("B/");
record = parseInstruct(device, instructNode, b);
// 根据不同主题进行不同处理
if (receivedTopicName.startsWith("A/")) {
// 处理A主题的消息设备上传
record.setDataSource("设备上报");
} else if (receivedTopicName.startsWith("B/")) {
// 处理B主题的消息 (手动上传)
record.setDataSource("客户端操作");
}
}
// 确保在插入前设置tenantId和deviceId
record.setTenantId(device.getTenantId());
record.setDeviceId(device.getId());
deviceLogMapper.insert(record);
}
// 2. 处理 state 消息
if (root.has("state")) {
JsonNode instructNode = root.get("state");
if (instructNode.isArray()) {
boolean b = receivedTopicName.startsWith("B/");
record = parseState(device, instructNode, b);
// 根据不同主题进行不同处理
if (receivedTopicName.startsWith("A/")) {
// 处理A主题的消息设备上传
record.setDataSource("设备上报");
} else if (receivedTopicName.startsWith("B/")) {
// 处理B主题的消息 (手动上传)
record.setDataSource("客户端操作");
}
}
// 确保在插入前设置tenantId和deviceId
record.setTenantId(device.getTenantId());
record.setDeviceId(device.getId());
deviceLogMapper.insert(record);
}
if (root.has("imei")) {
// 设备行为
record.setDeviceAction(InstructType6170.fromCode(0).getDescription());
record.setDataSource("设备上报");
record.setContent("设备启动");
// 确保在插入前设置tenantId和deviceId
record.setTenantId(device.getTenantId());
record.setDeviceId(device.getId());
deviceLogMapper.insert(record);
}
// 3. 处理state消息
// else if (root.has("state")) {
// JsonNode stateNode = root.get("state");
// if (stateNode.isArray()) {
// StateRecord record = parseState(device, stateNode);
// stateRepo.save(record);
// }
// }
} catch (Exception e) {
log.error("消息解析失败: {}", payload, e);
}
}
}
}
/**
* 从主题中提取设备ID(IMEI)
*
* @param topic
* @return
*/
private String extractDeviceId(String topic) {
// 处理 A/# 或 B/# 格式的主题,例如 B/861556078765285 或 A/861556078765285
String[] segments = topic.split("/");
if (segments.length >= 2) {
// 返回第二个段,即 / 后面的部分
return segments[1];
}
// 如果格式不符合预期,返回原主题
return topic;
}
/**
* 解析instruct消息
*
* @param device
* @param array
* @param b
* @return
*/
private DeviceLog parseInstruct(Device device, JsonNode array, boolean b) {
DeviceLog record = new DeviceLog();
record.setDeviceName(device.getDeviceName());
// 设备行为
record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription());
switch (array.get(0).asInt()) {
case 1: // 灯光模式
LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt());
record.setContent(lightModeEnum6170.getDescription());
break;
case 2: // 单位/姓名/职位
byte[] unitBytes = new byte[480];
for (int i = 1; i <= 480; i++) {
unitBytes[i - 1] = (byte) array.get(i).asInt();
}
// record.setUnitData(unitBytes);
break;
case 3: // 开机图片
// record.setImagePage(array.get(1).asInt());
byte[] imageBytes = new byte[512];
for (int i = 2; i <= 513; i++) {
imageBytes[i - 2] = (byte) array.get(i).asInt();
}
// record.setImageData(imageBytes);
break;
case 4: // 激光灯
int anInt = array.get(1).asInt();
if (anInt == 0) {
record.setContent("关闭激光灯");
} else if (anInt == 1) {
record.setContent("开启激光灯");
} else {
record.setContent("未知操作");
}
break;
case 5: // 亮度调节
record.setContent(+array.get(1).asInt() + "%");
break;
case 11: // 定位数据
if (b) {
break;
}
int i1 = array.get(1).asInt();
int i2 = array.get(2).asInt();
int i3 = array.get(3).asInt();
int i4 = array.get(4).asInt();
// 优雅的转换方式 Longitude and latitude
double latitude = i1 + i2 / 10.0;
double Longitude = i3 + i4 / 10.0;
// 84 ==》 高德
double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude);
String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
record.setContent(address);
break;
}
return record;
}
/**
* 解析 state 消息
*
* @param device
* @param array
* @return
*/
private DeviceLog parseState(Device device, JsonNode array, boolean b) {
DeviceLog record = new DeviceLog();
record.setDeviceName(device.getDeviceName());
// 设备行为
record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription());
switch (array.get(0).asInt()) {
case 1: // 灯光模式
LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt());
record.setContent(lightModeEnum6170.getDescription());
break;
case 2: // 单位/姓名/职位
byte[] unitBytes = new byte[480];
for (int i = 1; i <= 480; i++) {
unitBytes[i - 1] = (byte) array.get(i).asInt();
}
// record.setUnitData(unitBytes);
break;
case 3: // 开机图片
// record.setImagePage(array.get(1).asInt());
byte[] imageBytes = new byte[512];
for (int i = 2; i <= 513; i++) {
imageBytes[i - 2] = (byte) array.get(i).asInt();
}
// record.setImageData(imageBytes);
break;
case 4: // 激光灯
int anInt = array.get(1).asInt();
if (anInt == 0) {
record.setContent("关闭激光灯");
} else if (anInt == 1) {
record.setContent("开启激光灯");
} else {
record.setContent("未知操作");
}
break;
case 5: // 亮度调节
record.setContent(+array.get(1).asInt() + "%");
break;
case 11: // 定位数据
if (b) {
break;
}
int i1 = array.get(1).asInt();
int i2 = array.get(2).asInt();
int i3 = array.get(3).asInt();
int i4 = array.get(4).asInt();
// 优雅的转换方式 Longitude and latitude
double latitude = i1 + i2 / 10.0;
double Longitude = i3 + i4 / 10.0;
// 84 ==》 高德
double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude);
String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
record.setContent(address);
break;
}
return record;
}
}
//package com.fuyuanshen.web.handler.mqtt;
//
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
//import com.fasterxml.jackson.databind.JsonNode;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.fuyuanshen.common.satoken.utils.LoginHelper;
//import com.fuyuanshen.equipment.domain.Device;
//import com.fuyuanshen.equipment.domain.DeviceLog;
//import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
//import com.fuyuanshen.equipment.mapper.DeviceMapper;
//import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
//import com.fuyuanshen.equipment.utils.map.LngLonUtil;
//import com.fuyuanshen.global.mqtt.constants.TenantsConstant;
//import com.fuyuanshen.web.enums.InstructType6170;
//import com.fuyuanshen.web.enums.LightModeEnum6170;
//import lombok.AllArgsConstructor;
//import lombok.Data;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.messaging.Message;
//import org.springframework.messaging.MessageHandler;
//import org.springframework.messaging.MessageHeaders;
//import org.springframework.messaging.MessagingException;
//import org.springframework.stereotype.Component;
//
///**
// * 定义监听主题消息的处理器
// *
// * @author: 默苍璃
// * @date: 2025-08-0110:19
// */
//@Component
//@Data
//@AllArgsConstructor
//@Slf4j
//public class DeviceReceiverMessageHandler implements MessageHandler {
//
// private final DeviceMapper deviceMapper;
// private final DeviceLogMapper deviceLogMapper;
//
// // 使用Jackson解析JSON
// private static final ObjectMapper objectMapper = new ObjectMapper();
//
//
// /**
// * 处理接收的消息
// *
// * @param message
// * @throws MessagingException
// */
// @Override
// public void handleMessage(Message<?> message) throws MessagingException {
// // System.out.println("接收到的消息:" + message.getPayload());
// MessageHeaders headers = message.getHeaders();
// String receivedTopicName = (String) headers.get("mqtt_receivedTopic");
// System.out.println("消息来自主题:" + receivedTopicName);
//
// // String tenantId = LoginHelper.getTenantId();
// String tenantId = TenantsConstant.FU_YUAN_SHENG;
// String payload = message.getPayload().toString();
//
// if (receivedTopicName != null) {
// // 1. 提取设备ID (从主题中获取)
// String deviceImei = extractDeviceId(receivedTopicName);
// Device device = deviceMapper.selectOne(new QueryWrapper<Device>()
// .eq("tenant_id", tenantId)
// .eq("device_imei", deviceImei));
// if (device == null) {
// log.info("不存在的设备IMEI: {}", deviceImei);
// } else {
//
// try {
// JsonNode root = objectMapper.readTree(payload);
//
// DeviceLog record = new DeviceLog();
// // 手动设置租户ID
// record.setTenantId(device.getTenantId()); // 从设备信息中获取租户ID
// // 设备ID
// record.setDeviceId(device.getId());
// // 设备名称
// record.setDeviceName(device.getDeviceName());
//
// // 2. 处理instruct消息
// if (root.has("instruct")) {
// JsonNode instructNode = root.get("instruct");
// if (instructNode.isArray()) {
// boolean b = receivedTopicName.startsWith("B/");
// record = parseInstruct(device, instructNode, b);
// // 根据不同主题进行不同处理
// if (receivedTopicName.startsWith("A/")) {
// // 处理A主题的消息设备上传
// record.setDataSource("设备上报");
// } else if (receivedTopicName.startsWith("B/")) {
// // 处理B主题的消息 (手动上传)
// record.setDataSource("客户端操作");
// }
// }
// // 确保在插入前设置tenantId和deviceId
// record.setTenantId(device.getTenantId());
// record.setDeviceId(device.getId());
// deviceLogMapper.insert(record);
// }
//
// // 2. 处理 state 消息
// if (root.has("state")) {
// JsonNode instructNode = root.get("state");
// if (instructNode.isArray()) {
// boolean b = receivedTopicName.startsWith("B/");
// record = parseState(device, instructNode, b);
// // 根据不同主题进行不同处理
// if (receivedTopicName.startsWith("A/")) {
// // 处理A主题的消息设备上传
// record.setDataSource("设备上报");
// } else if (receivedTopicName.startsWith("B/")) {
// // 处理B主题的消息 (手动上传)
// record.setDataSource("客户端操作");
// }
// }
// // 确保在插入前设置tenantId和deviceId
// record.setTenantId(device.getTenantId());
// record.setDeviceId(device.getId());
// deviceLogMapper.insert(record);
// }
//
// if (root.has("imei")) {
// // 设备行为
// record.setDeviceAction(InstructType6170.fromCode(0).getDescription());
// record.setDataSource("设备上报");
// record.setContent("设备启动");
// // 确保在插入前设置tenantId和deviceId
// record.setTenantId(device.getTenantId());
// record.setDeviceId(device.getId());
// deviceLogMapper.insert(record);
// }
//
//
// // 3. 处理state消息
// // else if (root.has("state")) {
// // JsonNode stateNode = root.get("state");
// // if (stateNode.isArray()) {
// // StateRecord record = parseState(device, stateNode);
// // stateRepo.save(record);
// // }
// // }
// } catch (Exception e) {
// log.error("消息解析失败: {}", payload, e);
// }
//
// }
//
// }
// }
//
//
// /**
// * 从主题中提取设备ID(IMEI)
// *
// * @param topic
// * @return
// */
// private String extractDeviceId(String topic) {
// // 处理 A/# 或 B/# 格式的主题,例如 B/861556078765285 或 A/861556078765285
// String[] segments = topic.split("/");
// if (segments.length >= 2) {
// // 返回第二个段,即 / 后面的部分
// return segments[1];
// }
// // 如果格式不符合预期,返回原主题
// return topic;
// }
//
//
// /**
// * 解析instruct消息
// *
// * @param device
// * @param array
// * @param b
// * @return
// */
// private DeviceLog parseInstruct(Device device, JsonNode array, boolean b) {
// DeviceLog record = new DeviceLog();
// record.setDeviceName(device.getDeviceName());
// // 设备行为
// record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription());
//
// switch (array.get(0).asInt()) {
// case 1: // 灯光模式
// LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt());
// record.setContent(lightModeEnum6170.getDescription());
// break;
//
// case 2: // 单位/姓名/职位
// byte[] unitBytes = new byte[480];
// for (int i = 1; i <= 480; i++) {
// unitBytes[i - 1] = (byte) array.get(i).asInt();
// }
// // record.setUnitData(unitBytes);
// break;
//
// case 3: // 开机图片
// // record.setImagePage(array.get(1).asInt());
// byte[] imageBytes = new byte[512];
// for (int i = 2; i <= 513; i++) {
// imageBytes[i - 2] = (byte) array.get(i).asInt();
// }
// // record.setImageData(imageBytes);
// break;
//
// case 4: // 激光灯
// int anInt = array.get(1).asInt();
// if (anInt == 0) {
// record.setContent("关闭激光灯");
// } else if (anInt == 1) {
// record.setContent("开启激光灯");
// } else {
// record.setContent("未知操作");
// }
// break;
//
// case 5: // 亮度调节
// record.setContent(+array.get(1).asInt() + "%");
// break;
//
// case 11: // 定位数据
// if (b) {
// break;
// }
// int i1 = array.get(1).asInt();
// int i2 = array.get(2).asInt();
// int i3 = array.get(3).asInt();
// int i4 = array.get(4).asInt();
//
// // 优雅的转换方式 Longitude and latitude
// double latitude = i1 + i2 / 10.0;
// double Longitude = i3 + i4 / 10.0;
// // 84 ==》 高德
// double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude);
// String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
// record.setContent(address);
// break;
// }
// return record;
// }
//
//
// /**
// * 解析 state 消息
// *
// * @param device
// * @param array
// * @return
// */
// private DeviceLog parseState(Device device, JsonNode array, boolean b) {
// DeviceLog record = new DeviceLog();
// record.setDeviceName(device.getDeviceName());
// // 设备行为
// record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription());
//
// switch (array.get(0).asInt()) {
// case 1: // 灯光模式
// LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt());
// record.setContent(lightModeEnum6170.getDescription());
// break;
//
// case 2: // 单位/姓名/职位
// byte[] unitBytes = new byte[480];
// for (int i = 1; i <= 480; i++) {
// unitBytes[i - 1] = (byte) array.get(i).asInt();
// }
// // record.setUnitData(unitBytes);
// break;
//
// case 3: // 开机图片
// // record.setImagePage(array.get(1).asInt());
// byte[] imageBytes = new byte[512];
// for (int i = 2; i <= 513; i++) {
// imageBytes[i - 2] = (byte) array.get(i).asInt();
// }
// // record.setImageData(imageBytes);
// break;
//
// case 4: // 激光灯
// int anInt = array.get(1).asInt();
// if (anInt == 0) {
// record.setContent("关闭激光灯");
// } else if (anInt == 1) {
// record.setContent("开启激光灯");
// } else {
// record.setContent("未知操作");
// }
// break;
//
// case 5: // 亮度调节
// record.setContent(+array.get(1).asInt() + "%");
// break;
//
// case 11: // 定位数据
// if (b) {
// break;
// }
// int i1 = array.get(1).asInt();
// int i2 = array.get(2).asInt();
// int i3 = array.get(3).asInt();
// int i4 = array.get(4).asInt();
//
// // 优雅的转换方式 Longitude and latitude
// double latitude = i1 + i2 / 10.0;
// double Longitude = i3 + i4 / 10.0;
// // 84 ==》 高德
// double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude);
// String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
// record.setContent(address);
// break;
// }
// return record;
// }
//
//}

View File

@ -1,163 +1,163 @@
package com.fuyuanshen.web.listener;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.fuyuanshen.common.core.constant.CacheConstants;
import com.fuyuanshen.common.core.constant.Constants;
import com.fuyuanshen.common.core.domain.dto.UserOnlineDTO;
import com.fuyuanshen.common.core.utils.MessageUtils;
import com.fuyuanshen.common.core.utils.ServletUtils;
import com.fuyuanshen.common.core.utils.SpringUtils;
import com.fuyuanshen.common.core.utils.ip.AddressUtils;
import com.fuyuanshen.common.log.event.LogininforEvent;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.common.tenant.helper.TenantHelper;
import com.fuyuanshen.web.service.SysLoginService;
import org.springframework.stereotype.Component;
import java.time.Duration;
/**
* 用户行为 侦听器的实现
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Component
@Slf4j
public class UserActionListener implements SaTokenListener {
private final SysLoginService loginService;
/**
* 每次登录时触发
*/
@Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP();
UserOnlineDTO dto = new UserOnlineDTO();
dto.setIpaddr(ip);
dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
dto.setBrowser(userAgent.getBrowser().getName());
dto.setOs(userAgent.getOs().getName());
dto.setLoginTime(System.currentTimeMillis());
dto.setTokenId(tokenValue);
String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY);
String tenantId = (String) loginParameter.getExtra(LoginHelper.TENANT_KEY);
dto.setUserName(username);
dto.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY));
dto.setDeviceType(loginParameter.getDeviceType());
dto.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY));
TenantHelper.dynamic(tenantId, () -> {
if(loginParameter.getTimeout() == -1) {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
} else {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(loginParameter.getTimeout()));
}
});
// 记录登录日志
LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username);
logininforEvent.setStatus(Constants.LOGIN_SUCCESS);
logininforEvent.setMessage(MessageUtils.message("user.login.success"));
logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent);
// 更新登录信息
loginService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip);
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次注销时触发
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
});
log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次被踢下线时触发
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
});
log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次被顶下线时触发
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
});
log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
}
/**
* 每次被封禁时触发
*/
@Override
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
}
/**
* 每次被解封时触发
*/
@Override
public void doUntieDisable(String loginType, Object loginId, String service) {
}
/**
* 每次打开二级认证时触发
*/
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
}
/**
* 每次创建Session时触发
*/
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
}
/**
* 每次创建Session时触发
*/
@Override
public void doCreateSession(String id) {
}
/**
* 每次注销Session时触发
*/
@Override
public void doLogoutSession(String id) {
}
/**
* 每次Token续期时触发
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
}
}
//package com.fuyuanshen.web.listener;
//
//import cn.dev33.satoken.listener.SaTokenListener;
//import cn.dev33.satoken.stp.StpUtil;
//import cn.dev33.satoken.stp.parameter.SaLoginParameter;
//import cn.hutool.core.convert.Convert;
//import cn.hutool.http.useragent.UserAgent;
//import cn.hutool.http.useragent.UserAgentUtil;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import com.fuyuanshen.common.core.constant.CacheConstants;
//import com.fuyuanshen.common.core.constant.Constants;
//import com.fuyuanshen.common.core.domain.dto.UserOnlineDTO;
//import com.fuyuanshen.common.core.utils.MessageUtils;
//import com.fuyuanshen.common.core.utils.ServletUtils;
//import com.fuyuanshen.common.core.utils.SpringUtils;
//import com.fuyuanshen.common.core.utils.ip.AddressUtils;
//import com.fuyuanshen.common.log.event.LogininforEvent;
//import com.fuyuanshen.common.redis.utils.RedisUtils;
//import com.fuyuanshen.common.satoken.utils.LoginHelper;
//import com.fuyuanshen.common.tenant.helper.TenantHelper;
//import com.fuyuanshen.web.service.SysLoginService;
//import org.springframework.stereotype.Component;
//
//import java.time.Duration;
//
///**
// * 用户行为 侦听器的实现
// *
// * @author Lion Li
// */
//@RequiredArgsConstructor
//@Component
//@Slf4j
//public class UserActionListener implements SaTokenListener {
//
// private final SysLoginService loginService;
//
// /**
// * 每次登录时触发
// */
// @Override
// public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) {
// UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
// String ip = ServletUtils.getClientIP();
// UserOnlineDTO dto = new UserOnlineDTO();
// dto.setIpaddr(ip);
// dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
// dto.setBrowser(userAgent.getBrowser().getName());
// dto.setOs(userAgent.getOs().getName());
// dto.setLoginTime(System.currentTimeMillis());
// dto.setTokenId(tokenValue);
// String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY);
// String tenantId = (String) loginParameter.getExtra(LoginHelper.TENANT_KEY);
// dto.setUserName(username);
// dto.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY));
// dto.setDeviceType(loginParameter.getDeviceType());
// dto.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY));
// TenantHelper.dynamic(tenantId, () -> {
// if(loginParameter.getTimeout() == -1) {
// RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
// } else {
// RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(loginParameter.getTimeout()));
// }
// });
// // 记录登录日志
// LogininforEvent logininforEvent = new LogininforEvent();
// logininforEvent.setTenantId(tenantId);
// logininforEvent.setUsername(username);
// logininforEvent.setStatus(Constants.LOGIN_SUCCESS);
// logininforEvent.setMessage(MessageUtils.message("user.login.success"));
// logininforEvent.setRequest(ServletUtils.getRequest());
// SpringUtils.context().publishEvent(logininforEvent);
// // 更新登录信息
// loginService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip);
// log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
// }
//
// /**
// * 每次注销时触发
// */
// @Override
// public void doLogout(String loginType, Object loginId, String tokenValue) {
// String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
// TenantHelper.dynamic(tenantId, () -> {
// RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
// });
// log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
// }
//
// /**
// * 每次被踢下线时触发
// */
// @Override
// public void doKickout(String loginType, Object loginId, String tokenValue) {
// String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
// TenantHelper.dynamic(tenantId, () -> {
// RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
// });
// log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
// }
//
// /**
// * 每次被顶下线时触发
// */
// @Override
// public void doReplaced(String loginType, Object loginId, String tokenValue) {
// String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
// TenantHelper.dynamic(tenantId, () -> {
// RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
// });
// log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
// }
//
// /**
// * 每次被封禁时触发
// */
// @Override
// public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
// }
//
// /**
// * 每次被解封时触发
// */
// @Override
// public void doUntieDisable(String loginType, Object loginId, String service) {
// }
//
// /**
// * 每次打开二级认证时触发
// */
// @Override
// public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
// }
//
// /**
// * 每次创建Session时触发
// */
// @Override
// public void doCloseSafe(String loginType, String tokenValue, String service) {
// }
//
// /**
// * 每次创建Session时触发
// */
// @Override
// public void doCreateSession(String id) {
// }
//
// /**
// * 每次注销Session时触发
// */
// @Override
// public void doLogoutSession(String id) {
// }
//
// /**
// * 每次Token续期时触发
// */
// @Override
// public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
// }
//}

View File

@ -4,7 +4,7 @@ spring.servlet.multipart.location: /fys/server/temp
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: true
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
@ -16,7 +16,7 @@ spring.boot.admin.client:
--- # snail-job 配置
snail-job:
enabled: true
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "fys_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表
@ -52,9 +52,9 @@ spring:
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://localhost:3306/fys_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
url: jdbc:mysql://47.120.79.150:3306/fys-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: Jz_5623_cl1
password: Jq_123456#
# # 从库数据源
# slave:
# lazy: true
@ -101,13 +101,13 @@ spring:
spring.data:
redis:
# 地址
host: localhost
host: 47.120.79.150
# 端口默认为6379
port: 6379
# 数据库索引
database: 1
# redis 密码必须配置
password: re_fs_11520631
password: xhYc_djkl382^#780!
# 连接超时时间
timeout: 10s
# 是否开启ssl
@ -177,11 +177,14 @@ sms:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey
access-key-id: LTAI5tJdDNpZootsPQ5hdELx
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
access-key-secret: mU4WtffcCXpHPz5tLwQpaGtLsJXONt
#模板ID 非必须配置如果使用sendMessage的快速发送需此配置
template-id: SMS_322180518
#模板变量 上述模板的变量
templateName: code
signature: 湖北星汉研创科技
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
@ -280,8 +283,8 @@ mqtt:
password: #YtvpSfCNG
url: tcp://47.120.79.150:2883
subClientId: fys_subClient
subTopic: worker/alert/#,worker/location/#
pubTopic: worker/location
subTopic: A/#,B/#,worker/location/#
pubTopic: B/#
pubClientId: fys_pubClient

View File

@ -99,4 +99,9 @@ public class AppDeviceDetailVo {
// 逆解析地址
private String address;
/**
* 告警状态(0解除告警1告警)
*/
private String alarmStatus;
}

View File

@ -104,4 +104,38 @@ public class AppDeviceShareDetailVo implements Serializable {
* 发送信息
*/
private String sendMsg;
//设备主灯档位
private String mainLightMode;
//激光灯档位
private String laserLightMode;
//电量百分比
private String batteryPercentage;
//充电状态0没有充电1正在充电2为已充满
private String chargeState;
//电池剩余续航时间200分钟
private String batteryRemainingTime;
/**
* 在线状态(0离线1在线)
*/
private Integer onlineStatus;
// 经度
private String longitude;
// 纬度
private String latitude;
// 逆解析地址
private String address;
/**
* 告警状态(0解除告警1告警)
*/
private String alarmStatus;
}

View File

@ -57,6 +57,12 @@ public class AppDeviceShareVo implements Serializable {
@ExcelProperty(value = "手机号")
private String phonenumber;
/**
* 他人分享手机号
*/
@ExcelProperty(value = "手机号")
private String otherPhonenumber;
/**
* 功能权限1灯光模式2激光模式3开机画面4人员信息登记5发送信息6产品信息
以逗号分隔
@ -73,4 +79,29 @@ public class AppDeviceShareVo implements Serializable {
// 设备图片
private String devicePic;
/**
* 在线状态(0离线1在线)
*/
private Integer onlineStatus;
/**
* 电量 百分比
*/
private String battery;
/**
* 纬度
*/
private String latitude;
/**
* 经度
*/
private String longitude;
/**
* 告警状态(0解除告警1告警)
*/
private String alarmStatus;
}

View File

@ -1,5 +1,6 @@
package com.fuyuanshen.app.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.app.domain.AppDeviceShare;
@ -16,4 +17,6 @@ import org.apache.ibatis.annotations.Param;
*/
public interface AppDeviceShareMapper extends BaseMapperPlus<AppDeviceShare, AppDeviceShareVo> {
IPage<AppDeviceShareVo> otherDeviceShareList(@Param("bo") AppDeviceShareBo bo, Page<AppDeviceShareVo> page);
Page<AppDeviceShareVo> selectAppDeviceShareList(@Param("bo") AppDeviceShareBo bo,Page<AppDeviceShareVo> page);
}

View File

@ -5,6 +5,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.fuyuanshen.app.mapper.AppDeviceShareMapper">
<select id="otherDeviceShareList" resultType="com.fuyuanshen.app.domain.vo.AppDeviceShareVo">
SELECT * FROM app_device_share a where a.phonenumber = #{bo.phonenumber}
select d.device_name, d.device_name,
d.device_name,
d.device_mac,
d.device_sn,
d.device_imei,
d.device_pic,
dt.type_name,
dt.communication_mode,
d.bluetooth_name,
c.binding_time,
ad.*,u.user_name otherPhonenumber
from
app_device_share ad
left join device d on ad.device_id = d.id
left join app_user u on ad.create_by = u.user_id
inner join device_type dt on d.device_type = dt.id
inner join app_device_bind_record c on d.id = c.device_id
where ad.phonenumber = #{bo.phonenumber}
</select>
<select id="selectAppDeviceShareList" resultType="com.fuyuanshen.app.domain.vo.AppDeviceShareVo">
select d.device_name, d.device_name,
d.device_name,
d.device_mac,
d.device_sn,
d.device_imei,
d.device_pic,
dt.type_name,
dt.communication_mode,
d.bluetooth_name,
c.binding_time,
ad.*,u.user_name otherPhonenumber
from
app_device_share ad
left join device d on ad.device_id = d.id
left join app_user u on ad.create_by = u.user_id
inner join device_type dt on d.device_type = dt.id
inner join app_device_bind_record c on d.id = c.device_id
where ad.create_by = #{bo.createBy}
<if test="bo.deviceId != null">
and ad.device_id = #{bo.deviceId}
</if>
</select>
</mapper>

View File

@ -76,4 +76,9 @@ public class AppDeviceVo implements Serializable {
* 经度
*/
private String longitude;
/**
* 告警状态(0解除告警1告警)
*/
private String alarmStatus;
}