package com.ard.device.camera.service.impl;
|
|
import com.ard.common.annotation.DataScope;
|
import com.ard.common.constant.CacheConstants;
|
import com.ard.common.constant.DeviceConstants;
|
import com.ard.common.core.domain.entity.SysUser;
|
import com.ard.common.core.redis.RedisCache;
|
import com.ard.common.exception.ServiceException;
|
import com.ard.common.utils.DateUtils;
|
import com.ard.common.utils.SecurityUtils;
|
import com.ard.common.utils.StringUtils;
|
import com.ard.common.utils.bean.BeanValidators;
|
import com.ard.common.utils.spring.SpringUtils;
|
import com.ard.common.utils.uuid.IdUtils;
|
import com.ard.device.camera.domain.ArdCamera;
|
import com.ard.device.camera.domain.CameraCmd;
|
import com.ard.device.camera.mapper.ArdCameraMapper;
|
import com.ard.device.camera.service.IArdCameraService;
|
import com.ard.device.channel.domain.ArdChannel;
|
import com.ard.device.channel.service.IArdChannelService;
|
import com.ard.device.component.sdk.common.GlobalVariable;
|
import com.ard.device.component.sdk.event.LoginEvent;
|
import com.ard.device.component.sdk.service.CameraSDKService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.ObjectUtils;
|
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationRunner;
|
import org.springframework.context.event.EventListener;
|
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.Resource;
|
import javax.validation.Validator;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* 相机设备Service业务层处理
|
*
|
* @author 刘苏义
|
* @date 2023-02-11
|
*/
|
@Service
|
@Slf4j
|
public class ArdCameraServiceImpl implements IArdCameraService, ApplicationRunner {
|
@Resource
|
private ArdCameraMapper ardCameraMapper;
|
|
@Resource
|
private CameraSDKService cameraSDKService;
|
|
@Resource
|
private RedisCache redisService;
|
|
@Resource
|
private IArdChannelService ardChannelService;
|
|
@Resource
|
protected Validator validator;
|
|
|
@Override
|
public void run(ApplicationArguments args) {
|
initCamera();
|
}
|
|
public void initCamera() {
|
//清空相机缓存
|
redisService.deleteObject(redisService.keys(getCacheKey("*")));
|
//重新加载相机到缓存
|
ardCameraMapper.selectArdCameraList(new ArdCamera()).forEach(ardCamera -> {
|
ardCameraMapper.resetCameraLoginId(ardCamera);
|
redisService.setCacheObject(getCacheKey(ardCamera.getId()), ardCamera);
|
cameraSDKService.login(ardCamera);
|
});
|
}
|
|
/**
|
* 设置cache key
|
*
|
* @param configKey 参数键
|
* @return 缓存键key
|
*/
|
private String getCacheKey(String configKey) {
|
return CacheConstants.CAMERA_LIST_KEY + configKey;
|
}
|
|
|
/**
|
* 查询相机设备
|
*
|
* @param id 相机设备主键
|
* @return 相机设备
|
*/
|
@Override
|
public ArdCamera selectArdCameraById(String id) {
|
return ardCameraMapper.selectArdCameraById(id);
|
}
|
|
/**
|
* 查询相机设备
|
*
|
* @param name 相机设备名称
|
* @return 相机设备
|
*/
|
@Override
|
public ArdCamera selectArdCameraByName(String name) {
|
return ardCameraMapper.selectArdCameraByName(name);
|
}
|
|
/**
|
* 查询相机设备列表
|
*
|
* @param ardCamera 相机设备
|
* @return 相机设备
|
*/
|
@Override
|
@DataScope(deptAlias = "d", userAlias = "u")
|
public List<ArdCamera> selectArdCameraList(ArdCamera ardCamera) {
|
return ardCameraMapper.selectArdCameraList(ardCamera);
|
}
|
|
/**
|
* 查询所有相机
|
*
|
* @param ardCamera 相机设备
|
* @return 相机设备
|
*/
|
@Override
|
public List<ArdCamera> selectArdCameraListAll(ArdCamera ardCamera) {
|
return ardCameraMapper.selectArdCameraList(ardCamera);
|
}
|
|
/**
|
* 新增相机设备
|
*
|
* @param ardCamera 相机设备
|
* @return 结果
|
*/
|
@Override
|
public int insertArdCamera(ArdCamera ardCamera) {
|
ardCamera.setId(IdUtils.simpleUUID());
|
ardCamera.setCreateBy(SecurityUtils.getUsername());
|
ardCamera.setCreateTime(DateUtils.getNowDate());
|
ardCamera.setUserId(SecurityUtils.getUserId());
|
int res = ardCameraMapper.insertArdCamera(ardCamera);
|
if (res > 0) {
|
cameraSDKService.login(ardCamera);//sdk登录获取通道信息
|
}
|
return res;
|
}
|
|
/**
|
* 修改相机设备
|
*
|
* @param ardCamera 相机设备
|
* @return 结果
|
*/
|
@Override
|
public int updateArdCamera(ArdCamera ardCamera) {
|
ardCamera.setUpdateTime(DateUtils.getNowDate());
|
ardCamera.setUpdateBy(SecurityUtils.getUsername());
|
int res = ardCameraMapper.updateArdCamera(ardCamera);
|
if (res > 0) {
|
cameraSDKService.logout(ardCamera.getId());//sdk注销
|
cameraSDKService.login(ardCamera);//sdk登录获取通道信息
|
}
|
return res;
|
}
|
|
|
/**
|
* 批量删除相机设备
|
*
|
* @param ids 需要删除的相机设备主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteArdCameraByIds(String[] ids) {
|
for (String id : ids) {
|
ArdCamera camera = ardCameraMapper.selectArdCameraById(id);
|
if (camera != null) {
|
//redis中删除
|
redisService.deleteObject(getCacheKey(id));
|
//删除当前相机的所有通道
|
ardChannelService.deleteArdChannelByDeviceId(id);
|
//sdk注销
|
cameraSDKService.logout(id);
|
}
|
}
|
return ardCameraMapper.deleteArdCameraByIds(ids);
|
}
|
|
/**
|
* 删除相机设备信息
|
*
|
* @param id 相机设备主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteArdCameraById(String id) {
|
int i = ardCameraMapper.deleteArdCameraById(id);
|
if (i > 0) {
|
//redis中删除
|
redisService.deleteObject(getCacheKey(id));
|
//删除当前相机的所有通道
|
ardChannelService.deleteArdChannelByDeviceId(id);
|
//sdk注销
|
cameraSDKService.logout(id);
|
}
|
return i;
|
}
|
|
@Override
|
public String importCamera(List<ArdCamera> ardCameraList, Boolean isUpdateSupport, String operatorName) {
|
if (StringUtils.isNull(ardCameraList) || ardCameraList.isEmpty()) {
|
throw new ServiceException("导入相机数据不能为空!");
|
}
|
int successNum = 0;
|
int failureNum = 0;
|
StringBuilder successMsg = new StringBuilder();
|
StringBuilder failureMsg = new StringBuilder();
|
for (ArdCamera camera : ardCameraList) {
|
try {
|
//获取当前登录用户id
|
Long userId = SecurityUtils.getUserId();
|
camera.setUserId(userId);
|
// 验证是否存在这个用户
|
ArdCamera u = ardCameraMapper.selectArdCameraById(camera.getId());
|
if (StringUtils.isNull(u)) {
|
BeanValidators.validateWithException(validator, camera);
|
camera.setCreateBy(operatorName);
|
this.insertArdCamera(camera);
|
successNum++;
|
successMsg.append("<br/>" + successNum + "、相机ID " + camera.getId() + " 导入成功");
|
} else if (isUpdateSupport) {
|
BeanValidators.validateWithException(validator, camera);
|
checkCameraDataScope(camera.getUserId());
|
camera.setUpdateBy(operatorName);
|
this.updateArdCamera(camera);
|
successNum++;
|
successMsg.append("<br/>" + successNum + "、相机ID " + camera.getId() + " 更新成功");
|
} else {
|
failureNum++;
|
failureMsg.append("<br/>" + failureNum + "、相机ID " + camera.getId() + " 已存在");
|
}
|
} catch (Exception e) {
|
failureNum++;
|
String msg = "<br/>" + failureNum + "、相机ID " + camera.getId() + " 导入失败:";
|
failureMsg.append(msg + e.getMessage());
|
log.error(msg, e);
|
}
|
}
|
if (failureNum > 0) {
|
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
throw new ServiceException(failureMsg.toString());
|
} else {
|
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
}
|
return successMsg.toString();
|
}
|
|
/**
|
* 校验用户是否有数据权限
|
*
|
* @param userId 用户id
|
*/
|
@Override
|
public void checkCameraDataScope(Long userId) {
|
if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
|
ArdCamera camera = new ArdCamera();
|
camera.setUserId(userId);
|
List<ArdCamera> cameras = SpringUtils.getAopProxy(this).selectArdCameraList(camera);
|
if (StringUtils.isEmpty(cameras)) {
|
throw new ServiceException("没有权限访问井数据!");
|
}
|
}
|
}
|
|
/**
|
* 校验相机是否唯一
|
*
|
* @param camera 相机
|
* @return 结果
|
*/
|
@Override
|
public String checkCameraIpAndPortUnique(ArdCamera camera) {
|
String id = camera.getId();
|
String ip = camera.getIp();
|
Integer port = camera.getPort();
|
ArdCamera info = ardCameraMapper.checkCameraIpAndPortUnique(ip, port);
|
if (StringUtils.isNotNull(info) && !info.getId().equals(id)) {
|
return DeviceConstants.NOT_UNIQUE;
|
}
|
return DeviceConstants.UNIQUE;
|
}
|
|
/**
|
* 校验机场是否已关联相机
|
*
|
* @param camera 相机
|
* @return 结果
|
*/
|
@Override
|
public ArdCamera checkAirportHasCamera(ArdCamera camera) {
|
ArdCamera info = ardCameraMapper.checkAirportHasCamera(camera);
|
if (StringUtils.isNotNull(info)&& !info.getId().equals(camera.getId())) {
|
return info;
|
}
|
return null;
|
}
|
|
/**
|
* 同步通道
|
*
|
* @param oldArrayList 旧通道列表(库中)
|
* @param newArrayList 新通道列表(sdk)
|
* @author 刘苏义
|
* @date 2024/8/23 16:28
|
*/
|
@Override
|
public void asyncChannel(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList) {
|
// 将列表转换为映射以提高性能
|
Map<Integer, ArdChannel> oldMap = oldArrayList.stream()
|
.collect(Collectors.toMap(ArdChannel::getChanNo, channel -> channel));
|
Map<Integer, ArdChannel> newMap = newArrayList.stream()
|
.collect(Collectors.toMap(ArdChannel::getChanNo, channel -> channel));
|
|
// 需要更新的数据
|
newArrayList.stream()
|
.filter(channel -> {
|
ArdChannel oldChannel = oldMap.get(channel.getChanNo());
|
return oldChannel != null && (!Objects.equals(channel.getName(), oldChannel.getName()) || !Objects.equals(channel.getVideoCode(), oldChannel.getVideoCode()));
|
})
|
.forEach(channel -> {
|
ArdChannel oldChannel = oldMap.get(channel.getChanNo());
|
channel.setId(oldChannel.getId());
|
ardChannelService.updateArdChannel(channel);
|
});
|
|
// 需要删除的数据
|
oldArrayList.stream()
|
.filter(channel -> !newMap.containsKey(channel.getChanNo()))
|
.forEach(channel -> {
|
ardChannelService.deleteArdChannelById(channel.getId());
|
|
});
|
|
// 需要新增的数据
|
newArrayList.stream()
|
.filter(channel -> !oldMap.containsKey(channel.getChanNo()))
|
.forEach(channel -> {
|
if (ardChannelService.checkArdChannelUnique(channel)) {
|
ardChannelService.insertArdChannel(channel);
|
}
|
});
|
}
|
|
/**
|
* 监听登录事件
|
*
|
* @param loginEvent 登录事件
|
* @author 刘苏义
|
* @date 2024/8/23 15:42
|
*/
|
@Async
|
@EventListener(LoginEvent.class)
|
public void LoginEventListener(LoginEvent loginEvent) {
|
ArdCamera camera = loginEvent.getCamera();
|
ardCameraMapper.updateArdCamera(camera);
|
// SDK 登录成功后写入 Redis
|
redisService.setCacheObject(getCacheKey(camera.getId()), camera);
|
}
|
|
/**
|
* 同步设备通道与本地通道库信息
|
*
|
* @author 刘苏义
|
* @date 2024/8/22 14:37
|
*/
|
@Scheduled(fixedDelay = 5000)
|
public void syncChannel() {
|
try {
|
log.debug("定时执行同步通道任务");
|
List<ArdCamera> ardCameraList = this.selectArdCameraList(new ArdCamera());
|
if (!ardCameraList.isEmpty()) {
|
ardCameraList
|
.forEach(ardCamera -> {
|
//SDK获取实际通道
|
List<ArdChannel> ardChannelListSDK = cameraSDKService.getChannels(ardCamera);
|
//数据库获取通道
|
ArdChannel ardChannel = new ArdChannel();
|
ardChannel.setDeviceId(ardCamera.getId());
|
List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel);
|
//同步通道
|
asyncChannel(ardChannelListDb, ardChannelListSDK);
|
});
|
}
|
} catch (Exception ex) {
|
log.error("定时执行同步通道任务异常:{}", ex.getMessage());
|
}
|
}
|
|
/**
|
* 定时执行登录失败相机重新登录
|
*
|
* @author 刘苏义
|
* @date 2024/8/22 14:37
|
*/
|
@Scheduled(fixedDelay = 30000)
|
public void failedReconnect() {
|
try {
|
log.debug("定时执行失败相机重连任务");
|
List<Object> ardCameras = redisService.getListKey(CacheConstants.CAMERA_LIST_KEY);
|
ardCameras.stream()
|
.map(object -> (ArdCamera) object) // 将Object转换为ArdCameras
|
.filter(camera -> !GlobalVariable.loginMap.containsKey(camera.getId()))
|
.forEach(camera -> cameraSDKService.login(camera));
|
} catch (Exception ex) {
|
log.error("定时执行失败相机重连任务异常:{}", ex.getMessage());
|
}
|
}
|
|
/**
|
* 同步相机在线状态
|
* 刘苏义
|
* 2023/10/8 14:54:41
|
*/
|
@Scheduled(fixedDelay = 5000)
|
public void cameraState() {
|
try {
|
log.debug("定时执行同步相机在线状态任务");
|
//调用查询方法
|
List<ArdCamera> ardCameraList = selectArdCameraList(new ArdCamera());
|
ardCameraList
|
.forEach(camera -> {
|
CameraCmd cmd = new CameraCmd();
|
cmd.setCameraId(camera.getId());
|
boolean onLineNew = cameraSDKService.isOnLine(cmd);
|
boolean onLineOld = "1".equals(camera.getState());
|
if (onLineNew != onLineOld) {
|
if (onLineNew) {
|
camera.setState("1");
|
} else {
|
camera.setState("0");
|
}
|
camera.setUpdateTime(DateUtils.getNowDate());
|
ardCameraMapper.updateArdCamera(camera);
|
}
|
});
|
} catch (Exception ex) {
|
log.error("同步相机在线状态异常:{}", ex.getMessage());
|
}
|
}
|
}
|