Merge branch 'master' of http://47.109.37.87:3000/by2025/SmartParks
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package org.dromara.sis.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "zlm")
|
||||
public class ZLMediaKitConfig {
|
||||
|
||||
private String ip;
|
||||
|
||||
private String apiSecret;
|
||||
|
||||
private Short rtspPort;
|
||||
|
||||
private Short rtmpPort;
|
||||
|
||||
private Short httpPort;
|
||||
|
||||
private String vhost;
|
||||
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
package org.dromara.sis.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.sis.domain.vo.SisElevatorFloorRefVo;
|
||||
import org.dromara.sis.domain.bo.SisElevatorFloorRefBo;
|
||||
import org.dromara.sis.service.ISisElevatorFloorRefService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联
|
||||
* 前端访问路由地址为:/sis/elevatorFloorRef
|
||||
*
|
||||
* @author lsm
|
||||
* @since 2025-07-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/elevatorFloorRef")
|
||||
public class SisElevatorFloorRefController extends BaseController {
|
||||
|
||||
private final ISisElevatorFloorRefService sisElevatorFloorRefService;
|
||||
|
||||
/**
|
||||
* 查询电梯⇄楼层关联列表
|
||||
*/
|
||||
@SaCheckPermission("sis:elevatorFloorRef:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<SisElevatorFloorRefVo> list(SisElevatorFloorRefBo bo, PageQuery pageQuery) {
|
||||
return sisElevatorFloorRefService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出电梯⇄楼层关联列表
|
||||
*/
|
||||
@SaCheckPermission("sis:elevatorFloorRef:export")
|
||||
@Log(title = "电梯⇄楼层关联", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(SisElevatorFloorRefBo bo, HttpServletResponse response) {
|
||||
List<SisElevatorFloorRefVo> list = sisElevatorFloorRefService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "电梯⇄楼层关联", SisElevatorFloorRefVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取电梯⇄楼层关联详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("sis:elevatorFloorRef:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<SisElevatorFloorRefVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable("id") Long id) {
|
||||
return R.ok(sisElevatorFloorRefService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增电梯⇄楼层关联
|
||||
*/
|
||||
@SaCheckPermission("sis:elevatorFloorRef:add")
|
||||
@Log(title = "电梯⇄楼层关联", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody SisElevatorFloorRefBo bo) {
|
||||
return toAjax(sisElevatorFloorRefService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改电梯⇄楼层关联
|
||||
*/
|
||||
@SaCheckPermission("sis:elevatorFloorRef:edit")
|
||||
@Log(title = "电梯⇄楼层关联", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SisElevatorFloorRefBo bo) {
|
||||
return toAjax(sisElevatorFloorRefService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除电梯⇄楼层关联
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("sis:elevatorFloorRef:remove")
|
||||
@Log(title = "电梯⇄楼层关联", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable("ids") Long[] ids) {
|
||||
return toAjax(sisElevatorFloorRefService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
package org.dromara.sis.controller.zkmedia;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.sis.sdk.zkmedia.MediaServerUtils;
|
||||
import org.dromara.sis.sdk.zkmedia.ZLMediaKitService;
|
||||
import org.dromara.sis.sdk.zkmedia.model.AddStreamProxy;
|
||||
import org.dromara.sis.sdk.zkmedia.model.AddStreamProxyResp;
|
||||
import org.dromara.sis.sdk.zkmedia.model.StartStreamProxy;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* ZKLmedia 流媒体服务
|
||||
*
|
||||
* @author lxj
|
||||
* @since 2025-07-15
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/stream")
|
||||
public class ZKLmediaController {
|
||||
|
||||
@Resource
|
||||
private ZLMediaKitService zlMediaKitService;
|
||||
|
||||
|
||||
private static final String HIK_REALTIME_RTSP_TEMPLATE = "rtsp://%s:%s@%s:%s/Streaming/Channels/%s";
|
||||
private static final String DAHUA_REALTIME_RTSP_TEMPLATE = "rtsp://%s:%s@%s:%s/cam/realmonitor?channel=%s&subtype=0";
|
||||
|
||||
private static final String HIK_HISTORY_RTSP_TEMPLATE = "rtsp://%s:%s@%s:%s/Streaming/tracks/%s?starttime=%s&endtime=%s";
|
||||
private static final String DAHUA_HISTORY_RTSP_TEMPLATE = "rtsp://%s:%s@%s:%s/cam/playback?channel=%s&subtype=0&starttime=%s&endtime=%s";
|
||||
|
||||
/**
|
||||
* 创建拉流任务,返回null代表创建拉流任务失败
|
||||
*
|
||||
* @param data 创建拉流设备信息(如果外网不建议使用这种方式)
|
||||
* @return 返回拉流任务信息
|
||||
*/
|
||||
@PostMapping("/realtime/add")
|
||||
public R<AddStreamProxyResp> alarm(@RequestBody @Validated AddStreamProxy data) {
|
||||
StartStreamProxy proxy = new StartStreamProxy();
|
||||
proxy.setApp("realtime");
|
||||
String s = IdUtil.fastSimpleUUID();
|
||||
proxy.setStream(s);
|
||||
if ("DS1010".equals(data.getFactoryNo())) {
|
||||
proxy.setUrl(String.format(HIK_REALTIME_RTSP_TEMPLATE, data.getAccount(), data.getPwd(), data.getVideoIp(), data.getVideoPort(), data.getChannelId()));
|
||||
} else if ("DS1014".equals(data.getFactoryNo())) {
|
||||
proxy.setUrl(String.format(DAHUA_REALTIME_RTSP_TEMPLATE, data.getAccount(), data.getPwd(), data.getVideoIp(), data.getVideoPort(), data.getChannelId()));
|
||||
} else {
|
||||
throw new RuntimeException("未知的设备类型!");
|
||||
}
|
||||
AddStreamProxyResp addStreamProxyResp = zlMediaKitService.addStreamProxy(proxy);
|
||||
if (addStreamProxyResp != null) {
|
||||
return R.ok(addStreamProxyResp);
|
||||
}
|
||||
return R.fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建历史回放拉流任务,返回null代表创建拉流任务失败
|
||||
*
|
||||
* @param data 创建拉流设备信息(如果外网不建议使用这种方式)
|
||||
* @return 返回拉流任务信息
|
||||
*/
|
||||
@PostMapping("/history/add")
|
||||
public R<AddStreamProxyResp> history(@RequestBody @Validated AddStreamProxy data) throws InterruptedException {
|
||||
StartStreamProxy proxy = new StartStreamProxy();
|
||||
proxy.setApp("history");
|
||||
String s = IdUtil.fastSimpleUUID();
|
||||
proxy.setStream(s);
|
||||
if ("DS1010".equals(data.getFactoryNo())) {
|
||||
String pattern = "yyyyMMdd'T'HHmmss'Z'";
|
||||
String startTime = MediaServerUtils.formatTimestamp(data.getStartTime(), "yyyyMMdd'T'HHmmss'Z'");
|
||||
String endTime = MediaServerUtils.formatTimestamp(data.getEndTime(), "yyyyMMdd'T'HHmmss'Z'");
|
||||
proxy.setUrl(String.format(HIK_HISTORY_RTSP_TEMPLATE, data.getAccount(), data.getPwd(), data.getVideoIp(), data.getVideoPort(), data.getChannelId(), startTime, endTime));
|
||||
} else if ("DS1014".equals(data.getFactoryNo())) {
|
||||
String startTime = MediaServerUtils.formatTimestamp(data.getStartTime(), "yyyy_MM_dd_HH_mm_ss");
|
||||
String endTime = MediaServerUtils.formatTimestamp(data.getEndTime(), "yyyy_MM_dd_HH_mm_ss");
|
||||
proxy.setUrl(String.format(DAHUA_HISTORY_RTSP_TEMPLATE, data.getAccount(), data.getPwd(), data.getVideoIp(), data.getVideoPort(), data.getChannelId(), startTime, endTime));
|
||||
} else {
|
||||
throw new RuntimeException("未知的设备类型!");
|
||||
}
|
||||
AddStreamProxyResp addStreamProxyResp = zlMediaKitService.addStreamProxy(proxy);
|
||||
if (addStreamProxyResp != null) {
|
||||
return R.ok(addStreamProxyResp);
|
||||
}
|
||||
return R.fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备的信息
|
||||
*
|
||||
* @param data 设备ip
|
||||
* @return
|
||||
*/
|
||||
/*@PostMapping("/queryMediaInfo")
|
||||
public R<TpEqpAcquisitionDTO> queryMediaInfo(@RequestBody VideoConfigTreeDTO data) {
|
||||
if (StringUtils.isEmpty(data.getVideoIp())) {
|
||||
throw new BizException(ErrorType.VIDEOIP_FAIL, "视频IP不能为空");
|
||||
}
|
||||
logger.info("查询视频信息,参数:{}", JSONObject.toJSON(data.getVideoIp()));
|
||||
TpEqpAcquisitionDTO result = tpEqpAcquisitionService.queryConfigByEqpNo(data.getVideoIp());
|
||||
logger.info("查询视频信息,返回信息:{}", JSONObject.toJSON(result));
|
||||
return BizResultVO.success(result);
|
||||
}
|
||||
|
||||
@PostMapping("/history/delete/{stream}")
|
||||
public BizResultVO<String> delete(@PathVariable("stream") String stream) throws InterruptedException {
|
||||
StartStreamProxy proxy = new StartStreamProxy();
|
||||
proxy.setApp("history");
|
||||
proxy.setStream(stream);
|
||||
String ss = zlMediaKitService.delStreamProxy(proxy);
|
||||
if (ss != null) {
|
||||
return BizResultVO.success(ss);
|
||||
}
|
||||
return BizResultVO.fail(ErrorType.ADD_STREAMPROXY_FAIL, null);
|
||||
}*/
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package org.dromara.sis.domain;
|
||||
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联对象 sis_elevator_floor_ref
|
||||
*
|
||||
* @author lsm
|
||||
* @since 2025-07-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sis_elevator_floor_ref")
|
||||
public class SisElevatorFloorRef extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 电梯id
|
||||
*/
|
||||
private Long elevatorId;
|
||||
|
||||
/**
|
||||
* 楼层层数
|
||||
*/
|
||||
private Long layerNum;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package org.dromara.sis.domain.bo;
|
||||
|
||||
import org.dromara.sis.domain.SisElevatorFloorRef;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联业务对象 sis_elevator_floor_ref
|
||||
*
|
||||
* @author lsm
|
||||
* @since 2025-07-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = SisElevatorFloorRef.class, reverseConvertGenerate = false)
|
||||
public class SisElevatorFloorRefBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@NotNull(message = "主键id不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 电梯id
|
||||
*/
|
||||
@NotNull(message = "电梯id不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long elevatorId;
|
||||
|
||||
/**
|
||||
* 楼层层数
|
||||
*/
|
||||
@NotNull(message = "楼层层数不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long layerNum;
|
||||
|
||||
|
||||
}
|
@@ -105,6 +105,12 @@ public class SisAccessControlVo implements Serializable {
|
||||
@ExcelProperty(value = "外部编码")
|
||||
private String outCode;
|
||||
|
||||
/**
|
||||
* 外部门编码
|
||||
*/
|
||||
@ExcelProperty(value = "外部编码")
|
||||
private String outDoorCode;
|
||||
|
||||
private String bindDeviceId;
|
||||
|
||||
private String bindDeviceIp;
|
||||
|
@@ -42,7 +42,7 @@ public class SisAuthRecordVo implements Serializable {
|
||||
* 设备id(门禁/电梯)
|
||||
*/
|
||||
@ExcelProperty(value = "设备id", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "门=禁/电梯")
|
||||
@ExcelDictFormat(readConverterExp = "门禁/电梯")
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,50 @@
|
||||
package org.dromara.sis.domain.vo;
|
||||
|
||||
import org.dromara.sis.domain.SisElevatorFloorRef;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联视图对象 sis_elevator_floor_ref
|
||||
*
|
||||
* @author lsm
|
||||
* @since 2025-07-15
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = SisElevatorFloorRef.class)
|
||||
public class SisElevatorFloorRefVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@ExcelProperty(value = "主键id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 电梯id
|
||||
*/
|
||||
@ExcelProperty(value = "电梯id")
|
||||
private Long elevatorId;
|
||||
|
||||
/**
|
||||
* 楼层层数
|
||||
*/
|
||||
@ExcelProperty(value = "楼层层数")
|
||||
private Long layerNum;
|
||||
|
||||
|
||||
}
|
@@ -4,6 +4,8 @@ import org.dromara.sis.domain.SisAuthRecord;
|
||||
import org.dromara.sis.domain.vo.SisAuthRecordVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 授权记录Mapper接口
|
||||
*
|
||||
@@ -11,5 +13,5 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
* @since 2025-07-14
|
||||
*/
|
||||
public interface SisAuthRecordMapper extends BaseMapperPlus<SisAuthRecord, SisAuthRecordVo> {
|
||||
|
||||
List<SisAuthRecordVo> checkAuth(Long personId);
|
||||
}
|
||||
|
@@ -0,0 +1,15 @@
|
||||
package org.dromara.sis.mapper;
|
||||
|
||||
import org.dromara.sis.domain.SisElevatorFloorRef;
|
||||
import org.dromara.sis.domain.vo.SisElevatorFloorRefVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联Mapper接口
|
||||
*
|
||||
* @author lsm
|
||||
* @date 2025-07-15
|
||||
*/
|
||||
public interface SisElevatorFloorRefMapper extends BaseMapperPlus<SisElevatorFloorRef, SisElevatorFloorRefVo> {
|
||||
|
||||
}
|
@@ -4,25 +4,29 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.sis.domain.bo.SisDeviceManageBo;
|
||||
import org.dromara.sis.domain.vo.SisDeviceManageVo;
|
||||
import org.dromara.sis.domain.vo.SisElevatorInfoVo;
|
||||
import org.dromara.sis.sdk.hik.HikApiService;
|
||||
import org.dromara.sis.sdk.hik.calback.HikAlarmCallBack;
|
||||
import org.dromara.sis.service.ISisDeviceManageService;
|
||||
import org.dromara.sis.service.ISisElevatorInfoService;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class HikDeviceApplicationRunner implements ApplicationRunner {
|
||||
|
||||
private final ISisElevatorInfoService elevatorInfoService;
|
||||
private final HikAlarmCallBack hikAlarmCallBack;
|
||||
private final ISisDeviceManageService deviceManageService;
|
||||
private final ISisElevatorInfoService elevatorInfoService;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
@@ -38,35 +42,73 @@ public class HikDeviceApplicationRunner implements ApplicationRunner {
|
||||
|
||||
@Async
|
||||
public void hikElevatorInfoLogin() {
|
||||
/*List<SisElevatorInfoVo> sisElevatorInfoVos = elevatorInfoService.queryAll();
|
||||
List<SisElevatorInfoVo> sisElevatorInfoVos = elevatorInfoService.queryAll();
|
||||
if (CollUtil.isNotEmpty(sisElevatorInfoVos)) {
|
||||
sisElevatorInfoVos.forEach(item -> {
|
||||
// 执行设备登录操作
|
||||
HikApiService.getInstance().login(item.getControlIp(), item.getControlPort().shortValue(), item.getControlAccount(), item.getControlPwd());
|
||||
// 根据建筑ID获取楼层信息
|
||||
// SisFloorInfoVo floorInfo = floorInfoService.queryByBuildingId(item.getBuildingId());
|
||||
// 获取楼层数组
|
||||
// List<Integer> layerArray = generateFloorArray(floorInfo.getMinLayer().intValue(), floorInfo.getMaxLayer().intValue());
|
||||
// 下发权限
|
||||
// for (int i = 0; i < layerArray.size(); i++) {
|
||||
// HikApiService.getInstance().controlGateway(item.getControlIp(), (i + 1), layerArray.get(i));
|
||||
// }
|
||||
});
|
||||
}*/
|
||||
String ip = "192.168.24.188";
|
||||
short port = 8000;
|
||||
String account = "admin";
|
||||
String pwd = "qweasd123";
|
||||
HikApiService.getInstance().login(ip, port, account, pwd);
|
||||
List<Integer> arrs = Arrays.asList(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2);
|
||||
for (int i = 0; i < arrs.size(); i++) {
|
||||
HikApiService.getInstance().controlGateway(ip, (i + 1), arrs.get(i));
|
||||
}
|
||||
// String ip = "192.168.24.188";
|
||||
// short port = 8000;
|
||||
// String account = "admin";
|
||||
// String pwd = "qweasd123";
|
||||
// HikApiService.getInstance().login(ip, port, account, pwd);
|
||||
// List<Integer> arrs = Arrays.asList(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2);
|
||||
// for (int i = 0; i < arrs.size(); i++) {
|
||||
// HikApiService.getInstance().controlGateway(ip, (i + 1), arrs.get(i));
|
||||
// }
|
||||
}
|
||||
|
||||
//输入最低层,最高层,返回楼层数组
|
||||
public List<Integer> generateFloorArray(int minLayer, int maxLayer) {
|
||||
// 验证输入范围
|
||||
if (minLayer > maxLayer) {
|
||||
throw new IllegalArgumentException("最低层不能大于最高层");
|
||||
}
|
||||
|
||||
// 使用List动态收集楼层
|
||||
List<Integer> layerList = new ArrayList<>();
|
||||
|
||||
// 遍历所有楼层,跳过0层
|
||||
for (int layer = minLayer; layer <= maxLayer; layer++) {
|
||||
if (layer != 0) {
|
||||
// 初始数组赋值为3,不下发权限
|
||||
layerList.add(3);
|
||||
}
|
||||
}
|
||||
|
||||
return layerList;
|
||||
}
|
||||
|
||||
@Async
|
||||
public void hikNetCameraLogin() {
|
||||
String ip = "192.168.24.19";
|
||||
short port = 8000;
|
||||
String account = "admin";
|
||||
String pwd = "xzf13579";
|
||||
int handler = HikApiService.getInstance().login(ip, port, account, pwd);
|
||||
if(handler != -1){
|
||||
HikApiService.getInstance().setAlarmChan(handler);
|
||||
List<SisDeviceManageVo> deviceList = deviceManageService.queryList(new SisDeviceManageBo());
|
||||
|
||||
if (CollUtil.isEmpty(deviceList)) {
|
||||
log.info("没有查询到摄像设备信息,不执行登录");
|
||||
return;
|
||||
}
|
||||
|
||||
deviceList.forEach(item -> {
|
||||
int handler = HikApiService.getInstance().login(item.getDeviceIp(), item.getDevicePort().shortValue(), item.getDeviceAccount(), item.getDevicePwd());
|
||||
if (handler != -1) {
|
||||
HikApiService.getInstance().setAlarmChan(handler);
|
||||
}
|
||||
});
|
||||
// String ip = "192.168.24.19";
|
||||
// short port = 8000;
|
||||
// String account = "admin";
|
||||
// String pwd = "xzf13579";
|
||||
// int handler = HikApiService.getInstance().login(ip, port, account, pwd);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,16 +1,22 @@
|
||||
package org.dromara.sis.sdk.hik.calback;
|
||||
|
||||
import cn.hutool.core.codec.Base64Encoder;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.sun.jna.Pointer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sis.domain.vo.*;
|
||||
import org.dromara.sis.sdk.e8.AccessControlService;
|
||||
import org.dromara.sis.sdk.e8.domain.accessControl.req.RemoteOpenDoorReq;
|
||||
import org.dromara.sis.sdk.hik.HCNetSDK;
|
||||
import org.dromara.sis.sdk.hik.HikApiService;
|
||||
import org.dromara.sis.sdk.huawei.HuaWeiBoxApi;
|
||||
import org.dromara.sis.service.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@@ -19,6 +25,13 @@ import java.util.List;
|
||||
public class HikAlarmCallBack implements HCNetSDK.FMSGCallBack_V31 {
|
||||
|
||||
private final HuaWeiBoxApi huaWeiBoxApi;
|
||||
private final ISisAuthRecordService authRecordService;
|
||||
private final ISisElevatorInfoService elevatorInfoService;
|
||||
private final ISisDeviceBindRefService deviceBindRefService;
|
||||
private final ISisAccessControlService accessControlService;
|
||||
private final ISisElevatorFloorRefService elevatorFloorRefService;
|
||||
|
||||
private final AccessControlService e8AccessControlService;
|
||||
|
||||
private static final int COMM_UPLOAD_FACESNAP_RESULT = 0x1112;
|
||||
|
||||
@@ -32,47 +45,133 @@ public class HikAlarmCallBack implements HCNetSDK.FMSGCallBack_V31 {
|
||||
Pointer pItsPlateInfo = result.getPointer();
|
||||
pItsPlateInfo.write(0, pAlarmInfo.getByteArray(0, result.size()), 0, result.size());
|
||||
result.read();
|
||||
|
||||
// 读取人脸小图
|
||||
ByteBuffer buffers = result.pBuffer1.getByteBuffer(0, result.dwFacePicLen);
|
||||
byte[] smallImg = new byte[result.dwFacePicLen];
|
||||
buffers.rewind();
|
||||
buffers.get(smallImg);
|
||||
String dir = "";
|
||||
|
||||
// 读取人脸大图
|
||||
// ByteBuffer buffers1 = result.pBuffer2.getByteBuffer(0, result.dwBackgroundPicLen);
|
||||
// byte[] bigImg = new byte[result.dwBackgroundPicLen];
|
||||
// buffers1.rewind();
|
||||
// buffers1.get(bigImg);
|
||||
/*ByteBuffer buffers1 = result.pBuffer2.getByteBuffer(0, result.dwBackgroundPicLen);
|
||||
byte[] bigImg = new byte[result.dwBackgroundPicLen];
|
||||
buffers1.rewind();
|
||||
buffers1.get(bigImg);*/
|
||||
|
||||
//设备ip
|
||||
String sAlarmInfo = new String(pAlarmer.sDeviceIP).trim();
|
||||
// 设备绑定关系
|
||||
List<SisDeviceBindRefVo> bindRefList = deviceBindRefService.queryByDeviceIp(sAlarmInfo);
|
||||
if (CollUtil.isEmpty(bindRefList)) {
|
||||
log.info("当前报警设备未绑定门禁/梯控,不做处理!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// todo 进行人脸比对
|
||||
String smallImgBase64Str = Base64Encoder.encode(smallImg);
|
||||
|
||||
long s1 = System.currentTimeMillis();
|
||||
Long person = huaWeiBoxApi.findPerson(smallImgBase64Str);
|
||||
log.info("人脸比对执行完成,耗时:{}", System.currentTimeMillis() - s1);
|
||||
if (person == null) {
|
||||
log.info("未命中人脸数据,暂不处理。");
|
||||
log.info("权限下发执行完成,耗时:{}", System.currentTimeMillis() - s);
|
||||
return true;
|
||||
}
|
||||
log.info("人脸比对完成,personId={}", person);
|
||||
|
||||
// 授权记录
|
||||
List<SisAuthRecordVo> authVoList = authRecordService.checkAuth(person);
|
||||
// 获取门禁id
|
||||
Collection<Long> acIds = authVoList.stream().filter(vo -> vo.getDeviceType() == 1).map(SisAuthRecordVo::getDeviceId).toList();
|
||||
if (CollUtil.isNotEmpty(acIds)) {
|
||||
acIds.forEach(id -> {
|
||||
Long deviceId = bindRefList.stream().filter(vo -> vo.getBindId().equals(id)).findFirst().map(SisDeviceBindRefVo::getDeviceId).orElse(null);
|
||||
SisAccessControlVo ac = accessControlService.queryById(deviceId);
|
||||
if (ac != null) {
|
||||
log.info("调用门禁服务远程开门");
|
||||
RemoteOpenDoorReq req = new RemoteOpenDoorReq();
|
||||
req.setType(0);
|
||||
RemoteOpenDoorReq.ControlData data = new RemoteOpenDoorReq.ControlData();
|
||||
data.setDeviceId(Long.parseLong(ac.getOutCode()));
|
||||
data.setDoorId(Long.parseLong(ac.getOutCode()));
|
||||
req.setControlList(List.of(data));
|
||||
Boolean flag = e8AccessControlService.remoteOpenDoor(req);
|
||||
log.info("远程开门结果,result={}", flag);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 获取电梯ids
|
||||
// Collection<Long> eleIds = authVoList.stream().filter(vo -> vo.getDeviceType() == 2).map(SisAuthRecordVo::getDeviceId).toList();
|
||||
// if (CollUtil.isNotEmpty(eleIds)) {
|
||||
// eleIds.forEach(id -> {
|
||||
// Long deviceId = bindRefList.stream().filter(vo -> vo.getBindId().equals(id)).findFirst().map(SisDeviceBindRefVo::getDeviceId).orElse(null);
|
||||
// SisElevatorInfoVo ele = elevatorInfoService.queryById(deviceId);
|
||||
// if (ele != null) {
|
||||
// log.info("下发电梯权限");
|
||||
// // 根据建筑ID获取楼层信息
|
||||
// SisFloorInfoVo floorInfo = floorInfoService.queryByBuildingId(ele.getBuildingId());
|
||||
// // 获取电梯⇄楼层关联信息
|
||||
// List<SisElevatorFloorRefVo> floorRefList = elevatorFloorRefService.queryByElevatorId(deviceId);
|
||||
// // 获取楼层数组
|
||||
// List<Integer> layerArray = generateFloorArray(floorInfo.getMinLayer().intValue(), floorInfo.getMaxLayer().intValue());
|
||||
//
|
||||
//
|
||||
// layerArray.forEach(layer -> {
|
||||
// SisElevatorFloorRefVo floorRef = floorRefList.stream()
|
||||
// .filter(vo -> vo.getLayerNum().intValue() == layer) // 直接使用 layer
|
||||
// .findFirst()
|
||||
// .orElse(null);
|
||||
//
|
||||
// if (floorRef == null) {
|
||||
// HikApiService.getInstance().controlGateway(ele.getControlIp(), layer, 3);
|
||||
// } else {
|
||||
// HikApiService.getInstance().controlGateway(ele.getControlIp(), layer, 2);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// });
|
||||
// }
|
||||
|
||||
// List<Integer> arrs = Arrays.asList(2, 2, 2, 3, 3, 3 ,3, 3, 3, 3, 3, 3, 3, 3, 3, 3);
|
||||
List<Integer> arrs = Arrays.asList(3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2);
|
||||
for (int i = 0; i < arrs.size(); i++) {
|
||||
HikApiService.getInstance().controlGateway("192.168.24.188", (i + 1), arrs.get(i));
|
||||
}
|
||||
log.info("权限下发执行完成,耗时:{}", System.currentTimeMillis() - s);
|
||||
try {
|
||||
Thread.sleep(10000L);
|
||||
List<Integer> ass = Arrays.asList(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3);
|
||||
for (int i = 0; i < arrs.size(); i++) {
|
||||
HikApiService.getInstance().controlGateway("192.168.24.188", (i + 1), arrs.get(i));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// List<Integer> arrs = Arrays.asList(3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2);
|
||||
// for (int i = 0; i < arrs.size(); i++) {
|
||||
// HikApiService.getInstance().controlGateway("192.168.24.188", (i + 1), arrs.get(i));
|
||||
// }
|
||||
// log.info("权限下发执行完成,耗时:{}", System.currentTimeMillis() - s);
|
||||
// try {
|
||||
// Thread.sleep(10000L);
|
||||
// List<Integer> ass = Arrays.asList(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3);
|
||||
// for (int i = 0; i < arrs.size(); i++) {
|
||||
// HikApiService.getInstance().controlGateway("192.168.24.188", (i + 1), arrs.get(i));
|
||||
// }
|
||||
// } catch (InterruptedException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
|
||||
} else {
|
||||
log.info("未知报警类型,lCommand={}", lCommand);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//输入最低层,最高层,返回楼层数组
|
||||
public List<Integer> generateFloorArray(int minLayer, int maxLayer) {
|
||||
|
||||
// 验证输入范围
|
||||
if (minLayer > maxLayer) {
|
||||
throw new IllegalArgumentException("最低层不能大于最高层");
|
||||
}
|
||||
// 使用List动态收集楼层
|
||||
List<Integer> layerList = new ArrayList<>();
|
||||
// 遍历所有楼层,跳过0层
|
||||
for (int layer = minLayer; layer <= maxLayer; layer++) {
|
||||
if (layer != 0) {
|
||||
layerList.add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
return layerList;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,94 @@
|
||||
package org.dromara.sis.sdk.zkmedia;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.dromara.sis.sdk.zkmedia.model.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class HttpClientUtil {
|
||||
|
||||
public static <T> T get(String url, Map<String, Object> params, TypeReference<T> reference) {
|
||||
String s = get(url, params);
|
||||
return JSONObject.parseObject(s, reference);
|
||||
}
|
||||
|
||||
public static <T> R<T> get(String url, Map<String, Object> params, Class<T> cls) {
|
||||
String s = get(url, params);
|
||||
return JSONObject.parseObject(s, new TypeReference<R<T>>(cls) {
|
||||
});
|
||||
}
|
||||
|
||||
public static String get(String url, Map<String, Object> params) {
|
||||
if (params != null && !params.isEmpty()) {
|
||||
List<String> ls = new ArrayList<>(params.size());
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
ls.add(entry.getKey() + "=" + entry.getValue());
|
||||
}
|
||||
url = url + "?" + CollectionUtil.join(ls, "&");
|
||||
}
|
||||
|
||||
CloseableHttpResponse response;
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
response = httpClient.execute(httpGet);
|
||||
log.info("ZLM请求成功,url={}, code={}", url, response.getStatusLine().getStatusCode());
|
||||
HttpEntity entity = response.getEntity();
|
||||
String res = EntityUtils.toString(entity);
|
||||
log.info("ZLM请求成功,result={}", res);
|
||||
return res;
|
||||
} catch (Exception e) {
|
||||
log.info("ZLM发起请求失败,msg={}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T post(String url, Map<String, Object> header, Map<String, Object> body, TypeReference<T> reference) {
|
||||
String res = post(url, header, body);
|
||||
return JSONObject.parseObject(res, reference);
|
||||
}
|
||||
|
||||
public static <T> R<T> post(String url, Map<String, Object> header, Map<String, Object> body, Class<T> cls) {
|
||||
String res = post(url, header, body);
|
||||
return JSONObject.parseObject(res, new TypeReference<R<T>>(cls) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static String post(String url, Map<String, Object> header, Map<String, Object> body) {
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-Type", "application/json");
|
||||
if (header != null && !header.isEmpty()) {
|
||||
for (Map.Entry<String, Object> entry : header.entrySet()) {
|
||||
httpPost.setHeader(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}
|
||||
}
|
||||
if (body != null && !body.isEmpty()) {
|
||||
httpPost.setEntity(new StringEntity(JSONObject.toJSONString(body)));
|
||||
}
|
||||
CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||
HttpEntity entity = response.getEntity();
|
||||
return EntityUtils.toString(entity);
|
||||
} catch (Exception e) {
|
||||
log.info("ZLM发起请求失败,msg={}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package org.dromara.sis.sdk.zkmedia;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MediaServerUtils {
|
||||
public static Map<String, String> urlParamToMap(String params) {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
if (ObjectUtils.isEmpty(params)) {
|
||||
return map;
|
||||
}
|
||||
String[] paramsArray = params.split("&");
|
||||
if (paramsArray.length == 0) {
|
||||
return map;
|
||||
}
|
||||
for (String param : paramsArray) {
|
||||
String[] paramArray = param.split("=");
|
||||
if (paramArray.length == 2) {
|
||||
map.put(paramArray[0], paramArray[1]);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
public static String formatTimestamp(String timestamp, String pattern) {
|
||||
Date date = new Date(Long.parseLong(timestamp));
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,159 @@
|
||||
package org.dromara.sis.sdk.zkmedia;
|
||||
|
||||
|
||||
import org.dromara.sis.sdk.zkmedia.model.AddStreamProxyResp;
|
||||
import org.dromara.sis.sdk.zkmedia.model.R;
|
||||
import org.dromara.sis.sdk.zkmedia.model.StartStreamProxy;
|
||||
import org.dromara.sis.sdk.zkmedia.model.ThreadsLoadDelay;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ZLMediaKitService {
|
||||
|
||||
/**
|
||||
* 获取各后台 epoll(或 select)线程负载以及延时
|
||||
*/
|
||||
R<List<ThreadsLoadDelay>> getWorkThreadsLoad();
|
||||
|
||||
/**
|
||||
* 获取ZLMediaKit服务器配置信息
|
||||
*/
|
||||
Object getServerConfig();
|
||||
|
||||
/**
|
||||
* 设置服务器配置
|
||||
*/
|
||||
Object setServerConfig();
|
||||
|
||||
/**
|
||||
* 重启服务器,只有 Daemon 方式才能重启,否则是直接关闭!
|
||||
*/
|
||||
Object restartServer();
|
||||
|
||||
/**
|
||||
* 获取流列表,可选筛选参数
|
||||
*/
|
||||
Object getMediaList();
|
||||
|
||||
/**
|
||||
* 关闭流(目前所有类型的流都支持关闭)
|
||||
*/
|
||||
Object closeStreams();
|
||||
|
||||
/**
|
||||
* 获取所有 TcpSession 列表(获取所有 tcp 客户端相关信息)
|
||||
*/
|
||||
Object getAllSession();
|
||||
|
||||
/**
|
||||
* 断开 tcp 连接,比如说可以断开 rtsp、rtmp 播放器等
|
||||
*/
|
||||
Object kickSession();
|
||||
|
||||
/**
|
||||
* 断开 tcp 连接,比如说可以断开 rtsp、rtmp 播放器等
|
||||
*/
|
||||
Object kickSessions();
|
||||
|
||||
/**
|
||||
* 动态添加 rtsp/rtmp/hls/http-ts/http-flv 拉流代理(只支持 H264/H265/aac/G711/opus 负载)
|
||||
*/
|
||||
AddStreamProxyResp addStreamProxy(StartStreamProxy startStreamProxy);
|
||||
|
||||
/**
|
||||
* (流注册成功后,也可以使用close_streams接口替代)
|
||||
* 关闭拉流代理
|
||||
*/
|
||||
String delStreamProxy(StartStreamProxy startStreamProxy);
|
||||
|
||||
/**
|
||||
* 通过 fork FFmpeg 进程的方式拉流代理,支持任意协议
|
||||
*/
|
||||
Object addFFmpegSource();
|
||||
|
||||
/**
|
||||
* 流注册成功后,也可以使用close_streams接口替代
|
||||
*/
|
||||
Object delFFmpegSource();
|
||||
|
||||
/**
|
||||
* 获取 rtp 代理时的某路 ssrc rtp 信息
|
||||
*/
|
||||
Object getRtpInfo();
|
||||
|
||||
/**
|
||||
* 搜索文件系统,获取流对应的录像文件列表或日期文件夹列表
|
||||
*/
|
||||
Object getMp4RecordFile();
|
||||
|
||||
/**
|
||||
* 开始录制 hls 或 MP4
|
||||
*/
|
||||
Object startRecord();
|
||||
|
||||
/**
|
||||
* 停止录制流
|
||||
*/
|
||||
Object stopRecord();
|
||||
|
||||
/**
|
||||
* 获取流录制状态
|
||||
*/
|
||||
Object isRecording();
|
||||
|
||||
/**
|
||||
* 获取截图或生成实时截图并返回
|
||||
*/
|
||||
Object getSnap();
|
||||
|
||||
/**
|
||||
* 创建 GB28181 RTP 接收端口,如果该端口接收数据超时,则会自动被回收(不用调用 closeRtpServer 接口)
|
||||
*/
|
||||
Object openRtpServer();
|
||||
|
||||
/**
|
||||
* 关闭 GB28181 RTP 接收端口
|
||||
*/
|
||||
Object closeRtpServer();
|
||||
|
||||
/**
|
||||
* 获取 openRtpServer 接口创建的所有 RTP 服务器
|
||||
*/
|
||||
Object listRtpServer();
|
||||
|
||||
/**
|
||||
* 作为 GB28181 客户端,启动 ps-rtp 推流,支持 rtp/udp 方式;该接口支持 rtsp/rtmp 等协议转 ps-rtp 推流。第一次推流失败会直接返回错误,成功一次后,后续失败也将无限重试。
|
||||
*/
|
||||
Object startSendRtp();
|
||||
|
||||
/**
|
||||
* 停止 GB28181 ps-rtp 推流
|
||||
*/
|
||||
Object stopSendRtp();
|
||||
|
||||
/**
|
||||
* 获取主要对象个数统计,主要用于分析内存性能
|
||||
*/
|
||||
Object getStatistic();
|
||||
|
||||
/**
|
||||
* 添加 rtsp/rtmp 主动推流(把本服务器的直播流推送到其他服务器去)
|
||||
*/
|
||||
Object addStreamPusherProxy();
|
||||
|
||||
/**
|
||||
* 关闭推流,可以使用close_streams接口关闭源直播流也可以停止推流)
|
||||
*/
|
||||
Object delStreamPusherProxy();
|
||||
|
||||
/**
|
||||
* 获取版本信息,如分支,commit id, 编译时间
|
||||
*/
|
||||
Object getVersion();
|
||||
|
||||
/**
|
||||
* 获取某个流观看者列表
|
||||
*/
|
||||
Object getMediaPlayerList();
|
||||
|
||||
}
|
@@ -0,0 +1,248 @@
|
||||
package org.dromara.sis.sdk.zkmedia;
|
||||
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sis.config.ZLMediaKitConfig;
|
||||
import org.dromara.sis.sdk.zkmedia.model.AddStreamProxyResp;
|
||||
import org.dromara.sis.sdk.zkmedia.model.R;
|
||||
import org.dromara.sis.sdk.zkmedia.model.StartStreamProxy;
|
||||
import org.dromara.sis.sdk.zkmedia.model.ThreadsLoadDelay;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service("com.parkclouds.media.service.ZLMediaKitServiceImpl")
|
||||
public class ZLMediaKitServiceImpl implements ZLMediaKitService {
|
||||
|
||||
@Resource
|
||||
private ZLMediaKitConfig zlmConfig;
|
||||
private static volatile String ZLM_REQUEST_PREFIX = null;
|
||||
|
||||
public String getRequestUrl(String uri) {
|
||||
if (ZLM_REQUEST_PREFIX == null) {
|
||||
synchronized (ZLMediaKitServiceImpl.class) {
|
||||
if (ZLM_REQUEST_PREFIX == null) {
|
||||
ZLM_REQUEST_PREFIX = String.format("http://%s:%d/index/api/", zlmConfig.getIp(), zlmConfig.getHttpPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ZLM_REQUEST_PREFIX + uri;
|
||||
}
|
||||
|
||||
public Map<String, Object> getCommonParams() {
|
||||
Map<String, Object> params = new HashMap<>(16);
|
||||
params.put("secret", zlmConfig.getApiSecret());
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<ThreadsLoadDelay>> getWorkThreadsLoad() {
|
||||
String url = getRequestUrl("getThreadsLoad");
|
||||
Map<String, Object> commonParams = getCommonParams();
|
||||
return HttpClientUtil.get(url, commonParams, new TypeReference<R<List<ThreadsLoadDelay>>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getServerConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setServerConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object restartServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMediaList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object closeStreams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAllSession() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object kickSession() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object kickSessions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拉流地址
|
||||
*/
|
||||
private AddStreamProxyResp setPlayerUrl(String app, String streamId, AddStreamProxyResp resp) {
|
||||
if (resp == null) {
|
||||
resp = new AddStreamProxyResp();
|
||||
}
|
||||
// RTMP 播放地址
|
||||
resp.setRtmp(String.format("rtmp://%s:%d/%s/%s", zlmConfig.getIp(), zlmConfig.getRtmpPort(), app, streamId));
|
||||
// RTSP 播放地址
|
||||
resp.setRtsp(String.format("rtsp://%s:%d/%s/%s", zlmConfig.getIp(), zlmConfig.getRtspPort(), app, streamId));
|
||||
// HTTP-FLV 播放地址
|
||||
resp.setFlv(String.format("http://%s:%d/%s/%s.live.flv", zlmConfig.getIp(), zlmConfig.getHttpPort(), app, streamId));
|
||||
resp.setWsFlv(String.format("ws://%s:%d/%s/%s.live.flv", zlmConfig.getIp(), zlmConfig.getHttpPort(), app, streamId));
|
||||
// HLS 播放地址
|
||||
resp.setHls(String.format("http://%s:%d/%s/%s/hls.m3u8", zlmConfig.getIp(), zlmConfig.getHttpPort(), app, streamId));
|
||||
// MP4 播放地址
|
||||
resp.setMp4(String.format("http://%s:%d/%s/%s.live.mp4", zlmConfig.getIp(), zlmConfig.getHttpPort(), app, streamId));
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AddStreamProxyResp addStreamProxy(StartStreamProxy startStreamProxy) {
|
||||
Map<String, Object> commonParams = getCommonParams();
|
||||
commonParams.put("vhost", zlmConfig.getVhost());
|
||||
commonParams.put("app", startStreamProxy.getApp());
|
||||
commonParams.put("stream", startStreamProxy.getStream());
|
||||
commonParams.put("url", startStreamProxy.getUrl());
|
||||
commonParams.put("rtp_type", startStreamProxy.getRtpType());
|
||||
R<AddStreamProxyResp> result = HttpClientUtil.get(getRequestUrl("addStreamProxy"), commonParams, AddStreamProxyResp.class);
|
||||
if (result != null) {
|
||||
if (result.getCode() == 0) {
|
||||
log.info("创建拉流任务成功.");
|
||||
}
|
||||
// 此处代表拉流任务已存在
|
||||
if (result.getCode() == -1) {
|
||||
log.info("拉流任务已存在,返回播放地址。");
|
||||
}
|
||||
return setPlayerUrl(startStreamProxy.getApp(), startStreamProxy.getStream(), result.getData());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String delStreamProxy(StartStreamProxy startStreamProxy) {
|
||||
Map<String, Object> commonParams = getCommonParams();
|
||||
commonParams.put("schema", "rtsp");
|
||||
commonParams.put("vhost", zlmConfig.getVhost());
|
||||
commonParams.put("app", startStreamProxy.getApp());
|
||||
commonParams.put("stream", startStreamProxy.getStream());
|
||||
commonParams.put("force", 1);
|
||||
R<AddStreamProxyResp> result = HttpClientUtil.get(getRequestUrl("close_streams"), commonParams, AddStreamProxyResp.class);
|
||||
if (result != null) {
|
||||
String s =null;
|
||||
if (result.getCode() == 0) {
|
||||
s = "关闭流成功";
|
||||
}
|
||||
// 此处代表拉流任务已存在
|
||||
if (result.getCode() == -1) {
|
||||
s = "关闭流失败";
|
||||
}
|
||||
log.info("{},关闭流数量:{}",s,result.getData());
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addFFmpegSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object delFFmpegSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRtpInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMp4RecordFile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object startRecord() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object stopRecord() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object isRecording() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSnap() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object openRtpServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object closeRtpServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object listRtpServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object startSendRtp() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object stopSendRtp() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getStatistic() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addStreamPusherProxy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object delStreamPusherProxy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getVersion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMediaPlayerList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
public class AddStreamProxy {
|
||||
|
||||
@NotBlank
|
||||
private String videoIp;
|
||||
|
||||
@NotNull
|
||||
private Integer videoPort;
|
||||
|
||||
@NotBlank
|
||||
private String factoryNo;
|
||||
|
||||
@NotBlank
|
||||
private String account;
|
||||
|
||||
@NotBlank
|
||||
private String pwd;
|
||||
|
||||
@NotNull
|
||||
private String channelId;
|
||||
|
||||
|
||||
private String startTime;
|
||||
|
||||
private String endTime;
|
||||
|
||||
private String stream;
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class AddStreamProxyResp implements Serializable {
|
||||
|
||||
private String key;
|
||||
|
||||
private String rtsp;
|
||||
|
||||
private String rtmp;
|
||||
|
||||
private String flv;
|
||||
private String wsFlv;
|
||||
|
||||
private String mp4;
|
||||
|
||||
private String hls;
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* zlm hook事件的参数
|
||||
* @author lin
|
||||
*/
|
||||
@Data
|
||||
public class HookParam {
|
||||
|
||||
private String mediaServerId;
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class HookResult {
|
||||
|
||||
private int code;
|
||||
private String msg;
|
||||
|
||||
// 此字段在部分返回结果中用到
|
||||
private Boolean close;
|
||||
|
||||
|
||||
public HookResult() {
|
||||
}
|
||||
|
||||
public HookResult(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public static HookResult SUCCESS() {
|
||||
return new HookResult(0, "success");
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class HookResultForOnPublish extends HookResult {
|
||||
|
||||
private boolean enable_audio;
|
||||
private boolean enable_mp4;
|
||||
private int mp4_max_second;
|
||||
private String mp4_save_path;
|
||||
private String stream_replace;
|
||||
private Integer modify_stamp;
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* zlm hook事件中的on_play事件的参数
|
||||
*
|
||||
* @author lin
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OnPlayHookParam extends HookParam {
|
||||
private String id;
|
||||
private String app;
|
||||
private String stream;
|
||||
private String ip;
|
||||
private String params;
|
||||
private int port;
|
||||
private String schema;
|
||||
private String vhost;
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OnPushParam extends HookParam{
|
||||
|
||||
private String app;
|
||||
|
||||
private String id;
|
||||
|
||||
private String ip;
|
||||
|
||||
private String params;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private String schema;
|
||||
|
||||
private String stream;
|
||||
|
||||
private String vhost;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* zlm hook事件中的on_play事件的参数
|
||||
*
|
||||
* @author lin
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OnServerKeepaliveHookParam extends HookParam {
|
||||
|
||||
private Object data;
|
||||
|
||||
private Integer hook_index;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,203 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lin
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OnStreamChangedHookParam extends HookParam {
|
||||
|
||||
/**
|
||||
* 注册/注销
|
||||
*/
|
||||
private boolean regist;
|
||||
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* 流id
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 推流鉴权Id
|
||||
*/
|
||||
private String callId;
|
||||
|
||||
/**
|
||||
* 观看总人数,包括hls/rtsp/rtmp/http-flv/ws-flv
|
||||
*/
|
||||
private int totalReaderCount;
|
||||
|
||||
/**
|
||||
* 协议 包括hls/rtsp/rtmp/http-flv/ws-flv
|
||||
*/
|
||||
private String schema;
|
||||
|
||||
|
||||
/**
|
||||
* 产生源类型,
|
||||
* unknown = 0,
|
||||
* rtmp_push=1,
|
||||
* rtsp_push=2,
|
||||
* rtp_push=3,
|
||||
* pull=4,
|
||||
* ffmpeg_pull=5,
|
||||
* mp4_vod=6,
|
||||
* device_chn=7
|
||||
*/
|
||||
private int originType;
|
||||
|
||||
/**
|
||||
* 客户端和服务器网络信息,可能为null类型
|
||||
*/
|
||||
private OriginSock originSock;
|
||||
|
||||
/**
|
||||
* 产生源类型的字符串描述
|
||||
*/
|
||||
private String originTypeStr;
|
||||
|
||||
/**
|
||||
* 产生源的url
|
||||
*/
|
||||
private String originUrl;
|
||||
|
||||
/**
|
||||
* 服务器id
|
||||
*/
|
||||
private String severId;
|
||||
|
||||
/**
|
||||
* GMT unix系统时间戳,单位秒
|
||||
*/
|
||||
private Long createStamp;
|
||||
|
||||
/**
|
||||
* 存活时间,单位秒
|
||||
*/
|
||||
private Long aliveSecond;
|
||||
|
||||
/**
|
||||
* 数据产生速度,单位byte/s
|
||||
*/
|
||||
private Long bytesSpeed;
|
||||
|
||||
/**
|
||||
* 音视频轨道
|
||||
*/
|
||||
private List<MediaTrack> tracks;
|
||||
|
||||
/**
|
||||
* 音视频轨道
|
||||
*/
|
||||
private String vhost;
|
||||
|
||||
/**
|
||||
* 额外的参数字符串
|
||||
*/
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 额外的参数
|
||||
*/
|
||||
private Map<String, String> paramMap;
|
||||
|
||||
|
||||
@Data
|
||||
public static class MediaTrack {
|
||||
/**
|
||||
* 音频通道数
|
||||
*/
|
||||
private int channels;
|
||||
|
||||
/**
|
||||
* H264 = 0, H265 = 1, AAC = 2, G711A = 3, G711U = 4
|
||||
*/
|
||||
private int codec_id;
|
||||
|
||||
/**
|
||||
* 编码类型名称 CodecAAC CodecH264
|
||||
*/
|
||||
private String codec_id_name;
|
||||
|
||||
/**
|
||||
* Video = 0, Audio = 1
|
||||
*/
|
||||
private int codec_type;
|
||||
|
||||
/**
|
||||
* 轨道是否准备就绪
|
||||
*/
|
||||
private boolean ready;
|
||||
|
||||
/**
|
||||
* 音频采样位数
|
||||
*/
|
||||
private int sample_bit;
|
||||
|
||||
/**
|
||||
* 音频采样率
|
||||
*/
|
||||
private int sample_rate;
|
||||
|
||||
/**
|
||||
* 视频fps
|
||||
*/
|
||||
private float fps;
|
||||
|
||||
/**
|
||||
* 视频高
|
||||
*/
|
||||
private int height;
|
||||
|
||||
/**
|
||||
* 视频宽
|
||||
*/
|
||||
private int width;
|
||||
|
||||
/**
|
||||
* 帧数
|
||||
*/
|
||||
private int frames;
|
||||
|
||||
/**
|
||||
* 关键帧数
|
||||
*/
|
||||
private int key_frames;
|
||||
|
||||
/**
|
||||
* GOP大小
|
||||
*/
|
||||
private int gop_size;
|
||||
|
||||
/**
|
||||
* GOP间隔时长(ms)
|
||||
*/
|
||||
private int gop_interval_ms;
|
||||
|
||||
/**
|
||||
* 丢帧率
|
||||
*/
|
||||
private float loss;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class OriginSock {
|
||||
private String identifier;
|
||||
private String local_ip;
|
||||
private int local_port;
|
||||
private String peer_ip;
|
||||
private int peer_port;
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class OnStreamNoneReaderHookParam extends HookParam{
|
||||
|
||||
private String schema;
|
||||
private String app;
|
||||
private String stream;
|
||||
private String vhost;
|
||||
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* zlm hook事件中的on_stream_not_found事件的参数
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OnStreamNotFoundHookParam extends HookParam {
|
||||
private String id;
|
||||
private String app;
|
||||
private String stream;
|
||||
private String ip;
|
||||
private String params;
|
||||
private int port;
|
||||
private String schema;
|
||||
private String vhost;
|
||||
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class R<T> {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private T data;
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ServerKeepaliveData {
|
||||
|
||||
private Integer Buffer;
|
||||
private String BufferLikeString;
|
||||
private Integer BufferList;
|
||||
private Integer BufferRaw;
|
||||
private Integer Frame;
|
||||
private Integer FrameImp;
|
||||
private Integer MediaSource;
|
||||
private Integer MultiMediaSourceMuxer;
|
||||
private Integer RtmpPacket;
|
||||
private Integer RtpPacket;
|
||||
private Integer Socket;
|
||||
private Integer TcpClient;
|
||||
private Integer TcpServer;
|
||||
private Integer TcpSession;
|
||||
private Integer UdpServer;
|
||||
private Integer UdpSession;
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class StartStreamProxy implements Serializable {
|
||||
|
||||
private String app = "live";
|
||||
|
||||
private String stream;
|
||||
|
||||
private String url;
|
||||
|
||||
private Integer rtpType = 1;
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package org.dromara.sis.sdk.zkmedia.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThreadsLoadDelay {
|
||||
|
||||
/**
|
||||
* 该线程延时
|
||||
*/
|
||||
private Integer delay;
|
||||
|
||||
/**
|
||||
* 该线程负载,0 ~ 100
|
||||
*/
|
||||
private Integer load;
|
||||
|
||||
}
|
@@ -89,4 +89,11 @@ public interface ISisAuthRecordService {
|
||||
* @return List<TreeNode<Long>>
|
||||
*/
|
||||
List<TreeNode<Long>> authDeviceTree();
|
||||
|
||||
/**
|
||||
* 根据人脸比对ID,返回授权记录
|
||||
*
|
||||
* @param personId 人脸比对ID
|
||||
*/
|
||||
List<SisAuthRecordVo> checkAuth(Long personId);
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ public interface ISisDeviceBindRefService {
|
||||
* @param ipcAddr 设备ip
|
||||
* @return 返回关联关系表
|
||||
*/
|
||||
SisDeviceBindRef queryByDeviceIp(String ipcAddr);
|
||||
List<SisDeviceBindRefVo> queryByDeviceIp(String ipcAddr);
|
||||
|
||||
/**
|
||||
* 批量写入设备绑定关系
|
||||
|
@@ -0,0 +1,75 @@
|
||||
package org.dromara.sis.service;
|
||||
|
||||
import org.dromara.sis.domain.vo.SisElevatorFloorRefVo;
|
||||
import org.dromara.sis.domain.bo.SisElevatorFloorRefBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联Service接口
|
||||
*
|
||||
* @author lsm
|
||||
* @since 2025-07-15
|
||||
*/
|
||||
public interface ISisElevatorFloorRefService {
|
||||
|
||||
/**
|
||||
* 查询电梯⇄楼层关联
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 电梯⇄楼层关联
|
||||
*/
|
||||
SisElevatorFloorRefVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询电梯⇄楼层关联列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 电梯⇄楼层关联分页列表
|
||||
*/
|
||||
TableDataInfo<SisElevatorFloorRefVo> queryPageList(SisElevatorFloorRefBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的电梯⇄楼层关联列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 电梯⇄楼层关联列表
|
||||
*/
|
||||
List<SisElevatorFloorRefVo> queryList(SisElevatorFloorRefBo bo);
|
||||
|
||||
/**
|
||||
* 新增电梯⇄楼层关联
|
||||
*
|
||||
* @param bo 电梯⇄楼层关联
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(SisElevatorFloorRefBo bo);
|
||||
|
||||
/**
|
||||
* 修改电梯⇄楼层关联
|
||||
*
|
||||
* @param bo 电梯⇄楼层关联
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(SisElevatorFloorRefBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除电梯⇄楼层关联信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据电梯id,获取电梯⇄楼层关联信息
|
||||
*
|
||||
* @param elevatorId 电梯id
|
||||
*/
|
||||
List<SisElevatorFloorRefVo> queryByElevatorId(Long elevatorId);
|
||||
}
|
@@ -199,7 +199,7 @@ public class SisAuthRecordServiceImpl implements ISisAuthRecordService {
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteByLibId(Long libId){
|
||||
public Boolean deleteByLibId(Long libId) {
|
||||
LambdaQueryWrapper<SisAuthRecord> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(SisAuthRecord::getLibId, libId);
|
||||
return baseMapper.delete(lqw) > 0;
|
||||
@@ -208,10 +208,10 @@ public class SisAuthRecordServiceImpl implements ISisAuthRecordService {
|
||||
/**
|
||||
* 查询所有可授权设备树
|
||||
*
|
||||
* @return List<TreeNode<Long>>
|
||||
* @return List<TreeNode < Long>>
|
||||
*/
|
||||
@Override
|
||||
public List<TreeNode<Long>> authDeviceTree(){
|
||||
public List<TreeNode<Long>> authDeviceTree() {
|
||||
// 暂时将所有数据放入写死的根节点中
|
||||
TreeNode<Long> root = new TreeNode<>();
|
||||
root.setLevel(0);
|
||||
@@ -238,7 +238,6 @@ public class SisAuthRecordServiceImpl implements ISisAuthRecordService {
|
||||
List<SisElevatorInfoVo> eleVoList = elevatorInfoService.queryList(new SisElevatorInfoBo());
|
||||
|
||||
|
||||
|
||||
List<TreeNode<Long>> acChildrenList = acVoList.stream().map(item -> {
|
||||
TreeNode<Long> node = new TreeNode<>();
|
||||
node.setLevel(2);
|
||||
@@ -265,4 +264,14 @@ public class SisAuthRecordServiceImpl implements ISisAuthRecordService {
|
||||
root.setChildren(List.of(accessNode, elevatorNode));
|
||||
return List.of(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据人脸比对ID,返回授权记录
|
||||
*
|
||||
* @param personId 人脸比对ID
|
||||
*/
|
||||
@Override
|
||||
public List<SisAuthRecordVo> checkAuth(Long personId) {
|
||||
return baseMapper.checkAuth(personId);
|
||||
}
|
||||
}
|
||||
|
@@ -138,10 +138,10 @@ public class SisDeviceBindRefServiceImpl implements ISisDeviceBindRefService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SisDeviceBindRef queryByDeviceIp(String ipcAddr) {
|
||||
public List<SisDeviceBindRefVo> queryByDeviceIp(String ipcAddr) {
|
||||
LambdaQueryWrapper<SisDeviceBindRef> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(SisDeviceBindRef::getDeviceIp, ipcAddr);
|
||||
return baseMapper.selectOne(lqw);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,145 @@
|
||||
package org.dromara.sis.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.sis.domain.bo.SisElevatorFloorRefBo;
|
||||
import org.dromara.sis.domain.vo.SisElevatorFloorRefVo;
|
||||
import org.dromara.sis.domain.SisElevatorFloorRef;
|
||||
import org.dromara.sis.mapper.SisElevatorFloorRefMapper;
|
||||
import org.dromara.sis.service.ISisElevatorFloorRefService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 电梯⇄楼层关联Service业务层处理
|
||||
*
|
||||
* @author lsm
|
||||
* @date 2025-07-15
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class SisElevatorFloorRefServiceImpl implements ISisElevatorFloorRefService {
|
||||
|
||||
private final SisElevatorFloorRefMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询电梯⇄楼层关联
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 电梯⇄楼层关联
|
||||
*/
|
||||
@Override
|
||||
public SisElevatorFloorRefVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询电梯⇄楼层关联列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 电梯⇄楼层关联分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<SisElevatorFloorRefVo> queryPageList(SisElevatorFloorRefBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<SisElevatorFloorRef> lqw = buildQueryWrapper(bo);
|
||||
Page<SisElevatorFloorRefVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的电梯⇄楼层关联列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 电梯⇄楼层关联列表
|
||||
*/
|
||||
@Override
|
||||
public List<SisElevatorFloorRefVo> queryList(SisElevatorFloorRefBo bo) {
|
||||
LambdaQueryWrapper<SisElevatorFloorRef> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<SisElevatorFloorRef> buildQueryWrapper(SisElevatorFloorRefBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<SisElevatorFloorRef> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(SisElevatorFloorRef::getId);
|
||||
lqw.eq(bo.getElevatorId() != null, SisElevatorFloorRef::getElevatorId, bo.getElevatorId());
|
||||
lqw.eq(bo.getLayerNum() != null, SisElevatorFloorRef::getLayerNum, bo.getLayerNum());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增电梯⇄楼层关联
|
||||
*
|
||||
* @param bo 电梯⇄楼层关联
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(SisElevatorFloorRefBo bo) {
|
||||
SisElevatorFloorRef add = MapstructUtils.convert(bo, SisElevatorFloorRef.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改电梯⇄楼层关联
|
||||
*
|
||||
* @param bo 电梯⇄楼层关联
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(SisElevatorFloorRefBo bo) {
|
||||
SisElevatorFloorRef update = MapstructUtils.convert(bo, SisElevatorFloorRef.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(SisElevatorFloorRef entity) {
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除电梯⇄楼层关联信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据电梯id,获取电梯⇄楼层关联信息
|
||||
*
|
||||
* @param elevatorId 电梯id
|
||||
*/
|
||||
@Override
|
||||
public List<SisElevatorFloorRefVo> queryByElevatorId(Long elevatorId) {
|
||||
LambdaQueryWrapper<SisElevatorFloorRef> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(SisElevatorFloorRef::getElevatorId, elevatorId);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
}
|
@@ -5,10 +5,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<mapper namespace="org.dromara.sis.mapper.SisAuthRecordMapper">
|
||||
|
||||
<select id="checkAuth" resultType="org.dromara.sis.domain.vo.SisAuthRecordVo">
|
||||
SELECT a.*
|
||||
FROM sis_auth_record a
|
||||
LEFT JOIN sis_lib_device_img_ref b ON a.lib_id = b.lib_id AND a.img_id = b.img_id
|
||||
WHERE a.ac_id = #{accessControlId}
|
||||
AND b.eqp_lib_img_id = #{personId}
|
||||
SELECT
|
||||
device_type,
|
||||
device_id
|
||||
FROM sis_auth_record sar
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM sis_person_lib_img a
|
||||
INNER JOIN sis_lib_img_ref b ON a.id = b.img_id
|
||||
WHERE a.remote_img_id = #{personId}
|
||||
AND b.lib_id = sar.lib_id -- 关联主表
|
||||
)
|
||||
</select>
|
||||
</mapper>
|
||||
|
Reference in New Issue
Block a user