This commit is contained in:
2025-08-12 17:03:11 +08:00
parent bc165f5d60
commit 61ed9f0154
24 changed files with 742 additions and 19 deletions

View File

@ -1,12 +1,14 @@
package com.fuyuanshen.app.controller;
import com.fuyuanshen.app.domain.dto.APPReNameDTO;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo;
import com.fuyuanshen.app.service.AppDeviceBizService;
import com.fuyuanshen.common.core.domain.R;
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.Device;
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
@ -15,6 +17,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* APP设备信息管理
@ -72,4 +75,19 @@ public class AppDeviceController extends BaseController {
appDeviceService.reName(reNameDTO);
return R.ok("重命名成功!!!");
}
@GetMapping("/realTimeStatus")
public R<Map<String, Object>> getRealTimeStatus(AppRealTimeStatusDto statusDto) {
Map<String, Object> status = appDeviceService.getRealTimeStatus(statusDto);
return R.ok(status);
}
/**
* 根据mac查询设备信息
*/
@GetMapping("/getDeviceInfoByDeviceMac")
public R<Device> getDeviceInfo(String deviceMac) {
return R.ok(appDeviceService.getDeviceInfo(deviceMac));
}
}

View File

@ -7,6 +7,8 @@ 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.ratelimiter.annotation.FunctionAccessAnnotation;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
import jakarta.validation.constraints.NotNull;
@ -41,6 +43,7 @@ public class AppDeviceBJQController extends BaseController {
* 人员信息登记
*/
@PostMapping(value = "/registerPersonInfo")
@FunctionAccessAnnotation("registerPersonInfo")
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
return toAjax(appDeviceService.registerPersonInfo(bo));
}
@ -49,6 +52,7 @@ public class AppDeviceBJQController extends BaseController {
* 发送信息
*/
@PostMapping(value = "/sendMessage")
@FunctionAccessBatcAnnotation("sendMessage")
public R<Void> sendMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendMessage(bo));
}
@ -57,6 +61,7 @@ public class AppDeviceBJQController extends BaseController {
* 发送报警信息
*/
@PostMapping(value = "/sendAlarmMessage")
@FunctionAccessBatcAnnotation("sendAlarmMessage")
public R<Void> sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) {
return toAjax(appDeviceService.sendAlarmMessage(bo));
}
@ -65,6 +70,7 @@ public class AppDeviceBJQController extends BaseController {
* 上传设备logo图片
*/
@PostMapping("/uploadLogo")
@FunctionAccessAnnotation("uploadLogo")
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
MultipartFile file = bo.getFile();
@ -80,6 +86,7 @@ public class AppDeviceBJQController extends BaseController {
* 灯光模式
* 0关灯1强光模式2弱光模式, 3爆闪模式, 4泛光模式
*/
@FunctionAccessAnnotation("lightModeSettings")
@PostMapping("/lightModeSettings")
public R<Void> lightModeSettings(@RequestBody DeviceInstructDto params) {
// params 转 JSONObject
@ -91,6 +98,7 @@ public class AppDeviceBJQController extends BaseController {
* 灯光亮度设置
*
*/
@FunctionAccessAnnotation("lightBrightnessSettings")
@PostMapping("/lightBrightnessSettings")
public R<Void> lightBrightnessSettings(@RequestBody DeviceInstructDto params) {
appDeviceService.lightBrightnessSettings(params);
@ -102,18 +110,10 @@ public class AppDeviceBJQController extends BaseController {
*
*/
@PostMapping("/laserModeSettings")
@FunctionAccessAnnotation("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

@ -8,6 +8,7 @@ public class AppDeviceLogoUploadDto {
private Long deviceId;
private String deviceImei;
/**
* 文件
*/

View File

@ -0,0 +1,30 @@
package com.fuyuanshen.app.domain.dto;
import lombok.Data;
/**
* 设备实时状态
*/
@Data
public class AppRealTimeStatusDto {
/**
* 设备IMEI
*/
private String deviceImei;
/**
* 设备类型
*/
private String typeName;
/**
* 功能类型
*/
private String functionMode;
/**
* 批次号
*/
private String batchId;
}

View File

@ -11,6 +11,7 @@ import com.fuyuanshen.app.domain.AppPersonnelInfo;
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.AppRealTimeStatusDto;
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo;
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
@ -18,6 +19,8 @@ import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.RealTimeStatusEngine;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.*;
@ -35,7 +38,7 @@ import com.fuyuanshen.equipment.enums.BindingStatusEnum;
import com.fuyuanshen.equipment.enums.CommunicationModeEnum;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
import com.fuyuanshen.equipment.utils.c.ReliableTextToBitmap;
import com.fuyuanshen.equipment.service.DeviceService;
import com.fuyuanshen.global.mqtt.config.MqttGateway;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
@ -68,6 +71,9 @@ public class AppDeviceBizService {
private final DeviceTypeMapper deviceTypeMapper;
private final MqttGateway mqttGateway;
private final AppDeviceBindRecordMapper appDeviceBindRecordMapper;
private final RealTimeStatusEngine realTimeStatusEngine;
private final DeviceService deviceService;
public List<APPDeviceTypeVo> getTypeList() {
@ -602,4 +608,28 @@ public class AppDeviceBizService {
}
return 1;
}
public Map<String, Object> getRealTimeStatus(AppRealTimeStatusDto statusDto) {
try {
String commandType = statusDto.getTypeName()+"_" + statusDto.getFunctionMode();
DeviceStatusRule rule = realTimeStatusEngine.getDeviceStatusRule(commandType);
if(rule == null){
throw new ServiceException("未匹配到处理命令");
}
return rule.getStatus(statusDto);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
public Device getDeviceInfo(String deviceMac) {
QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("device_mac", deviceMac);
List<Device> devices = deviceMapper.selectList(queryWrapper);
if(ObjectUtils.length(devices) ==0){
return null;
}
return devices.get(0);
}
}

View File

@ -14,6 +14,7 @@ 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.ratelimiter.annotation.FunctionAccessAnnotation;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.equipment.domain.Device;
@ -62,12 +63,10 @@ public class AppDeviceBJQBizService {
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));
@ -77,7 +76,6 @@ public class AppDeviceBJQBizService {
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);
@ -167,6 +165,7 @@ public class AppDeviceBJQBizService {
}
public boolean registerPersonInfo(AppPersonnelInfoBo bo) {
Long deviceId = bo.getDeviceId();
Device deviceObj = deviceMapper.selectById(deviceId);
@ -212,6 +211,7 @@ public class AppDeviceBJQBizService {
}
@FunctionAccessAnnotation("uploadDeviceLogo")
public void uploadDeviceLogo(AppDeviceLogoUploadDto bo) {
try {
Device device = deviceMapper.selectById(bo.getDeviceId());
@ -256,6 +256,7 @@ public class AppDeviceBJQBizService {
* 灯光模式
* 0关灯1强光模式2弱光模式, 3爆闪模式, 4泛光模式
*/
public void lightModeSettings(DeviceInstructDto params) {
try {
Long deviceId = params.getDeviceId();
@ -280,6 +281,7 @@ public class AppDeviceBJQBizService {
}
//灯光亮度设置
@FunctionAccessAnnotation("lightBrightnessSettings")
public void lightBrightnessSettings(DeviceInstructDto params) {
try {
Long deviceId = params.getDeviceId();
@ -312,6 +314,7 @@ public class AppDeviceBJQBizService {
}
//激光模式设置
@FunctionAccessAnnotation("laserModeSettings")
public void laserModeSettings(DeviceInstructDto params) {
try {
Long deviceId = params.getDeviceId();

View File

@ -0,0 +1,20 @@
package com.fuyuanshen.app.service.device.status;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.equipment.domain.Device;
import java.util.Map;
// 规则接口
public interface DeviceStatusRule {
/**
* 获取命令类型
* @return 命令类型
*/
String getCommandType();
boolean supports(String deviceType);
Map<String, Object> getStatus(AppRealTimeStatusDto statusDto);
}

View File

@ -0,0 +1,6 @@
package com.fuyuanshen.app.service.device.status.constants;
public class DeviceTypeConstants {
public static final String TYPE_BJQ6170 = "BJQ6170";
}

View File

@ -0,0 +1,50 @@
package com.fuyuanshen.app.service.device.status.jbq;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.constants.DeviceTypeConstants;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Component
public class AlarmStatusRule implements DeviceStatusRule {
@Override
public String getCommandType() {
return DeviceTypeConstants.TYPE_BJQ6170+"_5";
}
@Override
public boolean supports(String deviceType) {
return true; // 适用于所有设备类型
}
@Override
public Map<String, Object> getStatus(AppRealTimeStatusDto dto) {
Map<String, Object> status = new HashMap<>();
String functionAccess = RedisUtils.getCacheObject(
FUNCTION_ACCESS_KEY + dto.getDeviceImei());
if(functionAccess==null){
status.put("functionAccess", "OK");
}else{
status.put("functionAccess", "ACTIVE");
}
//
// String alarmStatus = RedisUtils.getCacheObject(
// GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + dto.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
//
// if (StringUtils.isNotBlank(alarmStatus)) {
// status.put("alarmStatus", alarmStatus);
// }
return status;
}
}

View File

@ -0,0 +1,49 @@
package com.fuyuanshen.app.service.device.status.jbq;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.constants.DeviceTypeConstants;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
// 上传开机图片
@Slf4j
@Component
public class BootLogoStatusRule implements DeviceStatusRule {
@Override
public String getCommandType() {
return DeviceTypeConstants.TYPE_BJQ6170+"_3";
}
@Override
public boolean supports(String deviceType) {
return true; // 适用于所有设备类型
}
@Override
public Map<String, Object> getStatus(AppRealTimeStatusDto dto) {
Map<String, Object> status = new HashMap<>();
String functionAccess = RedisUtils.getCacheObject(
FUNCTION_ACCESS_KEY + dto.getDeviceImei());
if(functionAccess==null){
status.put("functionAccess", "OK");
}else{
status.put("functionAccess", "ACTIVE");
}
// String location = RedisUtils.getCacheObject(
// GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + dto.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX);
//
// if (StringUtils.isNotBlank(location)) {
// JSONObject jsonObject = JSONObject.parseObject(location);
// status.put("latitude", jsonObject.getString("latitude"));
// status.put("longitude", jsonObject.getString("longitude"));
// }
return status;
}
}

View File

@ -0,0 +1,48 @@
package com.fuyuanshen.app.service.device.status.jbq;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.constants.DeviceTypeConstants;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
// 激光模式设置
@Slf4j
@Component
public class LaserModeSettingsStatusRule implements DeviceStatusRule {
@Override
public String getCommandType() {
return DeviceTypeConstants.TYPE_BJQ6170+"_2";
}
@Override
public boolean supports(String deviceType) {
return true; // 适用于所有设备类型
}
/**
* @param dto
* @return
*/
@Override
public Map<String, Object> getStatus(AppRealTimeStatusDto dto) {
Map<String, Object> status = new HashMap<>();
String functionAccess = RedisUtils.getCacheObject(
FUNCTION_ACCESS_KEY + dto.getDeviceImei());
if(functionAccess==null){
status.put("functionAccess", "OK");
}else{
status.put("functionAccess", "ACTIVE");
}
// String onlineStatus = RedisUtils.getCacheObject(
// GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + dto.getDeviceImei() + DEVICE_ONLINE_STATUS_KEY_PREFIX);
// status.put("onlineStatus", StringUtils.isNotBlank(onlineStatus) ? 1 : 0);
return status;
}
}

View File

@ -0,0 +1,47 @@
package com.fuyuanshen.app.service.device.status.jbq;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.constants.DeviceTypeConstants;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
// 灯光状态
@Slf4j
@Component
public class ModeStatusRule implements DeviceStatusRule {
@Override
public String getCommandType() {
return DeviceTypeConstants.TYPE_BJQ6170+"_1";
}
@Override
public boolean supports(String deviceType) {
return true; // 适用于所有设备类型
}
@Override
public Map<String, Object> getStatus(AppRealTimeStatusDto dto) {
Map<String, Object> status = new HashMap<>();
String functionAccess = RedisUtils.getCacheObject(
FUNCTION_ACCESS_KEY + dto.getDeviceImei());
status.put("functionAccess", functionAccess);
// String deviceStatus = RedisUtils.getCacheObject(
// GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + dto.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
//
// if (StringUtils.isNotBlank(deviceStatus)) {
// JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
// status.put("battery", jsonObject.getString("batteryPercentage"));
// } else {
// status.put("battery", "0");
// }
return status;
}
}

View File

@ -0,0 +1,47 @@
package com.fuyuanshen.app.service.device.status.jbq;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.constants.DeviceTypeConstants;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Component
public class RegisterPersonInfoStatusRule implements DeviceStatusRule {
@Override
public String getCommandType() {
return DeviceTypeConstants.TYPE_BJQ6170+"_4";
}
@Override
public boolean supports(String deviceType) {
return true; // 适用于所有设备类型
}
@Override
public Map<String, Object> getStatus(AppRealTimeStatusDto dto) {
Map<String, Object> status = new HashMap<>();
String functionAccess = RedisUtils.getCacheObject(
FUNCTION_ACCESS_KEY + dto.getDeviceImei());
if(functionAccess==null){
status.put("functionAccess", "OK");
}else{
status.put("functionAccess", "ACTIVE");
}
// String alarmStatus = RedisUtils.getCacheObject(
// GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + dto.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
//
// if (StringUtils.isNotBlank(alarmStatus)) {
// status.put("alarmStatus", alarmStatus);
// }
return status;
}
}

View File

@ -0,0 +1,48 @@
package com.fuyuanshen.app.service.device.status.jbq;
import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto;
import com.fuyuanshen.app.service.device.status.DeviceStatusRule;
import com.fuyuanshen.app.service.device.status.constants.DeviceTypeConstants;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Component
public class SendMessageStatusRule implements DeviceStatusRule {
@Override
public String getCommandType() {
return DeviceTypeConstants.TYPE_BJQ6170+"_6";
}
@Override
public boolean supports(String deviceType) {
return true; // 适用于所有设备类型
}
@Override
public Map<String, Object> getStatus(AppRealTimeStatusDto dto) {
Map<String, Object> status = new HashMap<>();
List<String> functionAccess = RedisUtils.getCacheObject(
FUNCTION_ACCESS_KEY + dto.getBatchId());
if(functionAccess==null){
status.put("functionAccess", "OK");
}else{
status.put("functionAccess", "ACTIVE");
}
// String alarmStatus = RedisUtils.getCacheObject(
// GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + dto.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
//
// if (StringUtils.isNotBlank(alarmStatus)) {
// status.put("alarmStatus", alarmStatus);
// }
return status;
}
}

View File

@ -23,7 +23,7 @@ import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVIC
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
/**
* 人员信息命令处理
* 上传开机图片命令处理
*/
@Component
@RequiredArgsConstructor

View File

@ -14,6 +14,7 @@ import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX;
@ -47,6 +48,10 @@ public class BjqModeRule implements MqttMessageRule {
} catch (Exception e) {
log.error("处理灯光模式命令时出错", e);
}finally {
log.info("处理灯光模式命令完成");
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
RedisUtils.deleteObject(functionAccess);
}
}

View File

@ -36,4 +36,7 @@ public interface GlobalConstants {
* 三方认证 redis key
*/
String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
String FUNCTION_ACCESS_KEY = GLOBAL_REDIS_KEY + "device:function_access:";
}

View File

@ -0,0 +1,11 @@
package com.fuyuanshen.common.ratelimiter.annotation;// DeviceRedisKeyAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionAccessAnnotation {
String value() default "";
}

View File

@ -0,0 +1,11 @@
package com.fuyuanshen.common.ratelimiter.annotation;// DeviceRedisKeyAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionAccessBatcAnnotation {
String value() default "";
}

View File

@ -0,0 +1,103 @@
package com.fuyuanshen.common.ratelimiter.aspectj;// DeviceRedisKeyAspect.java
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.time.Duration;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Aspect
@Component
public class FunctionAccessAspect {
// 定义切点拦截带有DeviceRedisKeyAnnotation注解的方法
@Around("@annotation(functionAccessAnnotation)")
public Object addDeviceRedisKey(ProceedingJoinPoint joinPoint, FunctionAccessAnnotation functionAccessAnnotation) throws Throwable {
Object result;
String deviceImei = null;
// 获取方法参数查找设备ID
Object[] args = joinPoint.getArgs();
deviceImei = extractDeviceImei(args);
if (StringUtils.isNotBlank(deviceImei)) {
// 生成全局Redis key
String redisKey = generateDeviceRedisKey(deviceImei);
String cacheKey = RedisUtils.getCacheObject(redisKey);
if(StringUtils.isNotBlank(cacheKey) && "ACTIVE".equals(cacheKey)){
throw new ServiceException("设备已存在访问限制,请稍后再试", 500);
}
// 存储到Redis中设置过期时间
RedisUtils.setCacheObject(redisKey, "ACTIVE", Duration.ofMinutes(30));
log.info("设备Redis key已添加: {}", redisKey);
}
// 执行原方法
result = joinPoint.proceed();
return result;
}
/**
* 从方法参数中提取设备ID
*/
private String extractDeviceImei(Object[] args) {
if (args == null || args.length == 0) {
return null;
}
for (Object arg : args) {
if (arg == null) continue;
// 如果参数本身就是设备ID (Long类型)
if (arg instanceof Long) {
return arg.toString();
}
// 如果参数是对象尝试获取deviceId字段
try {
// 使用反射获取deviceId字段
java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if ("deviceImei".equalsIgnoreCase(field.getName()) ||
"device_imei".equalsIgnoreCase(field.getName())) {
field.setAccessible(true);
Object value = field.get(arg);
if (value != null) {
return value.toString();
}
}
}
// 尝试获取getId方法
try {
java.lang.reflect.Method getIdMethod = arg.getClass().getMethod("getDeviceImei");
Object value = getIdMethod.invoke(arg);
if (value != null) {
return value.toString();
}
} catch (Exception ignored) {}
} catch (Exception e) {
log.debug("从参数中提取设备ID时出错: {}", e.getMessage());
}
}
return null;
}
/**
* 生成设备的全局Redis key
*/
private String generateDeviceRedisKey(String deviceImei) {
return FUNCTION_ACCESS_KEY + deviceImei;
}
}

View File

@ -0,0 +1,184 @@
package com.fuyuanshen.common.ratelimiter.aspectj;// DeviceRedisKeyAspect.java
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fuyuanshen.common.core.exception.ServiceException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
@Slf4j
@Aspect
@Component
public class FunctionAccessBatchAspect {
// 定义切点拦截带有DeviceRedisKeyAnnotation注解的方法
@Around("@annotation(functionAccessBatchAspect)")
public Object addDeviceRedisKey(ProceedingJoinPoint joinPoint, FunctionAccessBatcAnnotation functionAccessBatchAspect) throws Throwable {
Object result;
String batchId = null;
List<String> deviceImeiList = null;
// 获取方法参数查找设备ID
Object[] args = joinPoint.getArgs();
batchId = extractDeviceBatchId(args);
deviceImeiList = extractDeviceImeiList(args);
if (StringUtils.isNotBlank(batchId)) {
// 生成全局Redis key
String redisKey = generateDeviceRedisKey(batchId);
String cacheKey = RedisUtils.getCacheObject(redisKey);
if(StringUtils.isNotBlank(cacheKey) && "ACTIVE".equals(cacheKey)){
throw new ServiceException("设备已存在访问限制,请稍后再试", 500);
}
// 存储到Redis中设置过期时间
RedisUtils.setCacheObject(redisKey, JSONUtil.toJsonStr(deviceImeiList), Duration.ofMinutes(30));
log.info("设备Redis key已添加: {}", redisKey);
}
// 执行原方法
result = joinPoint.proceed();
return result;
}
/**
* 从方法参数中提取设备IMEI列表
*/
private List<String> extractDeviceImeiList(Object[] args) {
if (args == null || args.length == 0) {
return null;
}
for (Object arg : args) {
if (arg == null) continue;
// 如果参数本身就是List<String>类型
if (arg instanceof List) {
List<?> list = (List<?>) arg;
if (!list.isEmpty() && list.get(0) instanceof String) {
// 检查是否为deviceImeiList
return (List<String>) list;
}
}
// 如果参数是对象尝试获取deviceImeiList字段
try {
// 使用反射获取deviceImeiList字段
java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if ("deviceImeiList".equalsIgnoreCase(field.getName()) ||
"device_imei_list".equalsIgnoreCase(field.getName()) ||
"deviceImeis".equalsIgnoreCase(field.getName()) ||
"device_imeis".equalsIgnoreCase(field.getName())) {
field.setAccessible(true);
Object value = field.get(arg);
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!list.isEmpty() && list.get(0) instanceof String) {
return (List<String>) list;
}
}
}
}
// 尝试获取getDeviceImeiList方法
try {
java.lang.reflect.Method getDeviceImeiListMethod = arg.getClass().getMethod("getDeviceImeiList");
Object value = getDeviceImeiListMethod.invoke(arg);
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!list.isEmpty() && list.get(0) instanceof String) {
return (List<String>) list;
}
}
} catch (Exception ignored) {}
// 尝试获取getDeviceImeis方法
try {
java.lang.reflect.Method getDeviceImeisMethod = arg.getClass().getMethod("getDeviceImeis");
Object value = getDeviceImeisMethod.invoke(arg);
if (value instanceof List) {
List<?> list = (List<?>) value;
if (!list.isEmpty() && list.get(0) instanceof String) {
return (List<String>) list;
}
}
} catch (Exception ignored) {}
} catch (Exception e) {
log.debug("从参数中提取设备IMEI列表时出错: {}", e.getMessage());
}
}
return null;
}
/**
* 从方法参数中提取设备ID
*/
private String extractDeviceBatchId(Object[] args) {
if (args == null || args.length == 0) {
return null;
}
for (Object arg : args) {
if (arg == null) continue;
// 如果参数本身就是设备ID (Long类型)
if (arg instanceof Long) {
return arg.toString();
}
// 如果参数是对象尝试获取deviceId字段
try {
// 使用反射获取deviceId字段
java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if ("batchId".equalsIgnoreCase(field.getName()) ||
"batch_id".equalsIgnoreCase(field.getName())) {
field.setAccessible(true);
Object value = field.get(arg);
if (value != null) {
return value.toString();
}
}
}
// 尝试获取getId方法
try {
java.lang.reflect.Method getIdMethod = arg.getClass().getMethod("batchId");
Object value = getIdMethod.invoke(arg);
if (value != null) {
return value.toString();
}
} catch (Exception ignored) {}
} catch (Exception e) {
log.debug("从参数中提取批次号时出错: {}", e.getMessage());
}
}
return null;
}
/**
* 生成设备的全局Redis key
*/
private String generateDeviceRedisKey(String batchId) {
return FUNCTION_ACCESS_KEY + batchId;
}
}

View File

@ -25,6 +25,11 @@ public class AppPersonnelInfoBo extends BaseEntity {
*/
private Long id;
/**
* 设备IMEI
*/
private String deviceImei;
/**
* 设备id
*/

View File

@ -5,8 +5,7 @@ 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 d.device_name, d.device_name,
d.device_name,
select d.device_name,
d.device_mac,
d.device_sn,
d.device_imei,
@ -25,8 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
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,
select d.device_name,
d.device_mac,
d.device_sn,
d.device_imei,
@ -42,7 +40,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
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}

View File

@ -14,9 +14,16 @@ public class AppDeviceSendMsgBo {
private List<Long> deviceIds;
private List<String> deviceImeiList;
/**
* 下发指令
*/
private String instructValue;
/**
* 批次号
*/
private String batchId;
}