海康考勤机数据对接,有两种方式,一是让考勤机自己推送给我们,二是我们自己调用它的sdk获取数据,我都亲测可行了。
第一种比较简单,海康的机器本身有后台管理系统,并且支持配置数据http推送,我们只需要定义一个controller方法,把我们定义的方法的地址配进去就行了,大致如下:
但是靠机器推送我们就比较被动,也不够灵活,第二种方法:
一、准备工作:(我是eclipse开发的boot项目)
1、去海康官网或找技术支持要一份开发文档,如下图:
根据文档一步一步的开发就行了,以下是我踩过坑之后的开发步骤
2、把1中的部分文件添加到项目中,结构如下:
3、yml中配置:
注意,dllPath就是2步骤中hikvision文件夹的地址,需要根据部署环境的不同而改变
4、找厂家要机器的相关信息,也就是ip端口登录人啥的:
二、获取数据,代码如下:
传参:机器信息、查询开始时间、结束时间,调用XXXService中的getUserSignRecord方法就可以获取数据了:
XXXService代码如下:
@Service
public class XXXService {
static HCNetSDK hCNetSDK = null;
static int lUserID = -1;// 用户句柄
static int iCharEncodeType = 0;// 设备字符集
private @Autowired HikvisionProperties hikvisionProperties;// 3步骤中yml中配置信息的映射类
private @Autowired EventSearch eventSearch;// 数据查询类
/**
* 获取机器数据
*/
public List<EventLog> getUserSignRecord(OfficeTecoMachine teco, Date stratDate, Date endDate) throws Exception {
// 登录设备
this.init(teco);
// 查询数据
List<EventLog> eventLogList = this.eventSearch.searchAllEvent(lUserID, teco.getTecoNumber(), stratDate, endDate);
// 注销设备
this.logout();
return eventLogList;
}
/**
* 初始化SDK并登录设备
*/
public void init(OfficeTecoMachine teco) throws InterruptedException {
if (hCNetSDK == null && !createSDKInstance()) {
HikvisionLogUtils.HIKVISION_LOG.error("加载sdk失败,请检查海康dll文件的路径是否配置正确");
return;
}
//SDK初始化,和进程保持同步,仅需要调用一次
hCNetSDK.NET_DVR_Init();
//开启SDK日志打印
hCNetSDK.NET_DVR_SetLogToFile(hikvisionProperties.getSdkLogLev(), hikvisionProperties.getSdkLogPath(), false);
//设备登录
lUserID=loginDevice(teco.getHost(),
(short)teco.getPort(),
teco.getLoginUser(),
teco.getLoginPassWord());
// 增加sleep时间,保证程序一直运行
Thread.sleep(1000);
}
/**
* 初始化SDK
*/
private boolean createSDKInstance() {
if (hCNetSDK == null) {
synchronized (HCNetSDK.class) {
try {
hCNetSDK = (HCNetSDK) Native.loadLibrary(hikvisionProperties.getDllPath() + File.separator + "HCNetSDK.dll", HCNetSDK.class);
} catch (Throwable t) {
HikvisionLogUtils.HIKVISION_LOG.error("海康考勤机loadLibrary:{},出错", hikvisionProperties.getDllPath(), t);
return false;
}
}
}
return true;
}
/**
* 登录设备,支持 V40 和 V30 版本,功能一致。
*
* @param ip 设备IP地址
* @param port SDK端口,默认为设备的8000端口
* @param user 设备用户名
* @param psw 设备密码
* @return 登录成功返回用户ID,失败返回-1
*/
public static int loginDevice(String ip, short port, String user, String psw) {
// 创建设备登录信息和设备信息对象
HCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
HCNetSDK.NET_DVR_DEVICEINFO_V40 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
// 设置设备IP地址
byte[] deviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
byte[] ipBytes = ip.getBytes();
System.arraycopy(ipBytes, 0, deviceAddress, 0, Math.min(ipBytes.length, deviceAddress.length));
loginInfo.sDeviceAddress = deviceAddress;
// 设置用户名和密码
byte[] userName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
byte[] password = psw.getBytes();
System.arraycopy(user.getBytes(), 0, userName, 0, Math.min(user.length(), userName.length));
System.arraycopy(password, 0, loginInfo.sPassword, 0, Math.min(password.length, loginInfo.sPassword.length));
loginInfo.sUserName = userName;
// 设置端口和登录模式
loginInfo.wPort = port;
loginInfo.bUseAsynLogin = false; // 同步登录
loginInfo.byLoginMode = 0; // 使用SDK私有协议
// 执行登录操作
int userID = hCNetSDK.NET_DVR_Login_V40(loginInfo, deviceInfo);
if (userID == -1) {
HikvisionLogUtils.HIKVISION_LOG.error("登录失败,错误码为: " + hCNetSDK.NET_DVR_GetLastError());
} else {
HikvisionLogUtils.HIKVISION_LOG.info(ip + " 设备登录成功!");
}
// 返回登录结果
return userID;
}
/**
* 登出操作
*/
public void logout(){
/**登出和清理,释放SDK资源*/
if (lUserID>=0) {
if (!hCNetSDK.NET_DVR_Logout(lUserID)) {
HikvisionLogUtils.HIKVISION_LOG.error("设备注销失败,错误码:" + hCNetSDK.NET_DVR_GetLastError());
return;
}
HikvisionLogUtils.HIKVISION_LOG.info("设备注销成功!!!");
}
}
}
EventSearch 类代码如下:
@Service
public class EventSearch {
/**
* 门禁事件查询,基于起止时间,事件类型进行查询
* @param lUserID
* @param tecoNumber
* @param stratDate
* @param endDate
* @return
* @throws UnsupportedEncodingException
* @throws InterruptedException
*/
public List<EventLog> searchAllEvent(int lUserID, String tecoNumber, Date stratDate, Date endDate) throws UnsupportedEncodingException, InterruptedException {
EventLog eventLog = null;
HCNetSDK.NET_DVR_ACS_EVENT_COND struAcsEventCond = new HCNetSDK.NET_DVR_ACS_EVENT_COND();
struAcsEventCond.read();
struAcsEventCond.dwSize = struAcsEventCond.size();
HikvisionLogUtils.HIKVISION_LOG.error(tecoNumber+"主机数据:"+struAcsEventCond.dwSize);
//查询全部主次类型的报警
struAcsEventCond.dwMajor = 0; // 主次事件类型设为0,代表查询所有事件
struAcsEventCond.dwMinor = 0; //
//开始时间
struAcsEventCond.struStartTime.dwYear = JodaTimeUtils.getYear(stratDate);
struAcsEventCond.struStartTime.dwMonth = JodaTimeUtils.getMonth(stratDate);
struAcsEventCond.struStartTime.dwDay = JodaTimeUtils.getDayOfMonth(stratDate);
struAcsEventCond.struStartTime.dwHour = 0;
struAcsEventCond.struStartTime.dwMinute = 0;
struAcsEventCond.struStartTime.dwSecond = 0;
//结束时间
struAcsEventCond.struEndTime.dwYear = JodaTimeUtils.getYear(endDate);
struAcsEventCond.struEndTime.dwMonth = JodaTimeUtils.getMonth(endDate);
struAcsEventCond.struEndTime.dwDay = JodaTimeUtils.getDayOfMonth(endDate);
struAcsEventCond.struEndTime.dwHour = 23;
struAcsEventCond.struEndTime.dwMinute = 59;
struAcsEventCond.struEndTime.dwSecond = 59;
struAcsEventCond.wInductiveEventType = 1;
struAcsEventCond.byPicEnable = 0; //是否带图片,0-不带图片,1-带图片
struAcsEventCond.write();
Pointer ptrStruEventCond = struAcsEventCond.getPointer();
int m_lSearchEventHandle = XXXService.hCNetSDK.NET_DVR_StartRemoteConfig(lUserID, HCNetSDK.NET_DVR_GET_ACS_EVENT, ptrStruEventCond, struAcsEventCond.size(), null, null);
if (m_lSearchEventHandle<=-1) {
HikvisionLogUtils.HIKVISION_LOG.error("NET_DVR_StartRemoteConfig调用失败,错误码:" + XXXService.hCNetSDK.NET_DVR_GetLastError());
}
HCNetSDK.NET_DVR_ACS_EVENT_CFG struAcsEventCfg = new HCNetSDK.NET_DVR_ACS_EVENT_CFG();
struAcsEventCfg.read();
struAcsEventCfg.dwSize = struAcsEventCfg.size();
struAcsEventCfg.write();
Pointer ptrStruEventCfg = struAcsEventCfg.getPointer();
List<EventLog> eventLogList = new ArrayList<EventLog>();
HikvisionLogUtils.HIKVISION_LOG.info("=========dwSize="+struAcsEventCond.dwSize);
while (true) {
int dwEventSearch = XXXService.hCNetSDK.NET_DVR_GetNextRemoteConfig(m_lSearchEventHandle, ptrStruEventCfg, struAcsEventCfg.size());
if (dwEventSearch <= -1) {
HikvisionLogUtils.HIKVISION_LOG.error("NET_DVR_GetNextRemoteConfig接口调用失败,错误码:" + XXXService.hCNetSDK.NET_DVR_GetLastError());
break;
}
if (dwEventSearch == HCNetSDK.NET_SDK_GET_NEXT_STATUS_NEED_WAIT) {
HikvisionLogUtils.HIKVISION_LOG.info("配置等待....");
Thread.sleep(10);
continue;
} else if (dwEventSearch == HCNetSDK.NET_SDK_NEXT_STATUS__FINISH) {
HikvisionLogUtils.HIKVISION_LOG.info("获取事件完成");
break;
} else if (dwEventSearch == HCNetSDK.NET_SDK_GET_NEXT_STATUS_FAILED) {
HikvisionLogUtils.HIKVISION_LOG.info("获取事件出现异常");
break;
} else if (dwEventSearch == HCNetSDK.NET_SDK_GET_NEXT_STATUS_SUCCESS) {
struAcsEventCfg.read();
// 只获取考勤签到事件
if(struAcsEventCfg.dwMajor != 5 || struAcsEventCfg.dwMinor != 75){
continue;
}
eventLog = new EventLog();
eventLog.setAccessControllerEvent(new AccessControllerEvent());
eventLog.setDateTime(struAcsEventCfg.struTime.dwYear+"-"+struAcsEventCfg.struTime.dwMonth+"-"+struAcsEventCfg.struTime.dwDay+
" "+struAcsEventCfg.struTime.dwHour+":"+struAcsEventCfg.struTime.dwMinute+":"+struAcsEventCfg.struTime.dwSecond);
eventLog.getAccessControllerEvent().setEmployeeNoString(new String(struAcsEventCfg.struAcsEventInfo.byEmployeeNo).trim());
eventLog.getAccessControllerEvent().setAttendanceStatus(String.valueOf(struAcsEventCfg.struAcsEventInfo.byAttendanceStatus));
eventLog.getAccessControllerEvent().setCurrentProcessVerifyMode(String.valueOf(struAcsEventCfg.struAcsEventInfo.byCurrentVerifyMode));
eventLog.getAccessControllerEvent().setDeviceName(tecoNumber);
eventLogList.add(eventLog);
continue;
}
}
if (!XXXService.hCNetSDK.NET_DVR_StopRemoteConfig(m_lSearchEventHandle)) {
HikvisionLogUtils.HIKVISION_LOG.error("NET_DVR_StopRemoteConfig接口调用失败,错误码:" + XXXService.hCNetSDK.NET_DVR_GetLastError());
} else {
HikvisionLogUtils.HIKVISION_LOG.info("NET_DVR_StopRemoteConfig接口成功");
}
return eventLogList;
}
}