qzy 8 ヶ月 前
コミット
1142f5c337

+ 17 - 0
config.xml

@@ -22,6 +22,23 @@
         <fileRootPath>D:\\file</fileRootPath>
     </channelSetting>
     <!--设备相关设置-->
+    <faceConfig>
+        <enable>true</enable>
+        <face>
+            <channelCode>01</channelCode>
+            <ip>192.168.1.1</ip>
+            <port>8000</port>
+            <uname>admin</uname>
+            <pwd>ABCabc124</pwd>
+        </face>
+        <face>
+            <channelCode>02</channelCode>
+            <ip>192.168.1.1</ip>
+            <port>8000</port>
+            <uname>admin</uname>
+            <pwd>ABCabc124</pwd>
+        </face>
+    </faceConfig>
     <sysConfig>
         <caputreSetting>
             <enable>true</enable>

+ 67 - 17
src/main/java/com/gzlh/api/OpenApi.java

@@ -10,10 +10,15 @@ import com.gzlh.bus.SysConfig;
 import com.gzlh.config.ModuleEnum;
 import com.gzlh.bus.EventBus;
 import com.gzlh.config.SystemObject;
+import com.gzlh.config.dto.FaceDTO;
 import com.gzlh.config.dto.SerialSetting;
+import com.gzlh.constans.AjaxJson;
+import com.gzlh.device.face.FaceService;
+import com.gzlh.device.face.UserManage;
 import com.gzlh.device.rfid.job.ElectronReadJob;
 import com.gzlh.device.led.event.LedDefaultEvent;
 import com.gzlh.device.led.utils.LedOptions;
+import com.gzlh.entity.AddFaceBO;
 import com.gzlh.entity.ReqBO;
 import com.gzlh.utils.ResultJson;
 import com.gzlh.device.weighbridge.event.WeighbridgeEvent;
@@ -23,11 +28,16 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @RestController
-@RequestMapping("open")
+@RequestMapping("api")
 public class OpenApi {
-
+    @Resource
+    private FaceService faceService;
+    @Resource
+    private UserManage userManage;
 
 
     @Resource
@@ -37,38 +47,78 @@ public class OpenApi {
     private BackgroundClientNetty backgroundClientNetty;
 
     @RequestMapping("test")
-    public ResultJson test(String msg,String line,String showType,String color){
-        eventBus.startEvent(ModuleEnum.LED_MODULE.getModuleEn()+"."+ LedDefaultEvent.READ);
-        eventBus.startEvent(ModuleEnum.WEIGHBRIDGE_MODULE.getModuleEn()+"."+ WeighbridgeEvent.READ);
+    public ResultJson test(String msg, String line, String showType, String color) {
+        eventBus.startEvent(ModuleEnum.LED_MODULE.getModuleEn() + "." + LedDefaultEvent.READ);
+        eventBus.startEvent(ModuleEnum.WEIGHBRIDGE_MODULE.getModuleEn() + "." + WeighbridgeEvent.READ);
         System.out.println();
-        SerialSetting.LedDTO ledDTO= SysConfig.serialSetting.getLed();
-        LedOptions ledOptions=new LedOptions();
+        SerialSetting.LedDTO ledDTO = SysConfig.serialSetting.getLed();
+        LedOptions ledOptions = new LedOptions();
         ledOptions.setLine(line).setShowType(showType).setColor(color);
-        SystemObject.ledFactory.handler(ledDTO.getBrand()).sendMsg(msg,ledOptions);
+        SystemObject.ledFactory.handler(ledDTO.getBrand()).sendMsg(msg, ledOptions);
 
         return ResultJson.success();
     }
+
     @RequestMapping("electron")
-    public ResultJson test(String msg){
-        ElectronReadJob job=   new ElectronReadJob();
+    public ResultJson test(String msg) {
+        ElectronReadJob job = new ElectronReadJob();
         ThreadUtil.execute(job);
         return ResultJson.success();
     }
 
     @RequestMapping("trunk")
-    public ResultJson trunk(@RequestBody ReqBO reqBO){
+    public ResultJson trunk(@RequestBody ReqBO reqBO) {
         Arrays.stream(ReflectUtil.getFields(ReqBO.class)).forEach(field -> {
-            String name=field.getName();
-            Object value=ReflectUtil.getFieldValue(reqBO,field.getName());
-            EventDataManager.cacheData(name,value);
+            String name = field.getName();
+            Object value = ReflectUtil.getFieldValue(reqBO, field.getName());
+            EventDataManager.cacheData(name, value);
         });
-        StaticLog.info("data:{}",JSONUtil.toJsonStr(EventDataManager.getCacheData()));
-        eventBus.startEvent(ModuleEnum.WEIGHBRIDGE_MODULE.getModuleEn()+"."+ WeighbridgeEvent.READ);
+        StaticLog.info("data:{}", JSONUtil.toJsonStr(EventDataManager.getCacheData()));
+        eventBus.startEvent(ModuleEnum.WEIGHBRIDGE_MODULE.getModuleEn() + "." + WeighbridgeEvent.READ);
         return ResultJson.success();
     }
+
     @RequestMapping("shutdown")
-    public ResultJson shutdown(){
+    public ResultJson shutdown() {
         return ResultJson.success();
     }
 
+    @RequestMapping("face/add")
+    public AjaxJson addFace(@RequestBody AddFaceBO faceBO) throws Exception {
+        List<FaceDTO> faceDTOList = SysConfig.faceDTO.getFace()
+                .stream().filter(dto -> dto.getChannelCode().equals(faceBO.getChannelCode()))
+                .collect(Collectors.toList());
+        for (FaceDTO faceDTO : faceDTOList) {
+            userManage.AddUserInfo(faceDTO.getUserId(), faceBO.getNo(), faceBO.getName());
+            faceService.AddFaceByBinary(faceDTO.getUserId(), faceBO.getNo(), faceBO.getBase64());
+        }
+
+        return AjaxJson.getSuccess();
+    }
+
+    @RequestMapping("face/del")
+    public AjaxJson delFace(@RequestBody AddFaceBO faceBO) {
+        List<FaceDTO> faceDTOList = SysConfig.faceDTO.getFace()
+                .stream().filter(dto -> dto.getChannelCode().equals(faceBO.getChannelCode()))
+                .collect(Collectors.toList());
+        for (FaceDTO faceDTO : faceDTOList) {
+            userManage.deleteUserInfo(faceDTO.getUserId(), faceBO.getNo());
+        }
+        return AjaxJson.getSuccess();
+    }
+
+    /**
+     * 远程控门
+     *
+     * @param userID
+     */
+    public AjaxJson RemoteControlGate(@RequestBody AddFaceBO faceBO) {
+        List<FaceDTO> faceDTOList = SysConfig.faceDTO.getFace()
+                .stream().filter(dto -> dto.getChannelCode().equals(faceBO.getChannelCode()))
+                .collect(Collectors.toList());
+        for (FaceDTO faceDTO : faceDTOList) {
+            faceService.RemoteControlGate(faceDTO.getUserId(), faceBO.getCommand());
+        }
+        return AjaxJson.getSuccess();
+    }
 }

+ 3 - 0
src/main/java/com/gzlh/bus/SysConfig.java

@@ -20,6 +20,7 @@ public class SysConfig {
     public static CaputreSetting caputreSetting;
     public static ChannelSetting channelSetting;
     public static ManagerSetting managerSetting;
+    public static FaceListDTO faceDTO;
 
     public static void initConfig() {
         Properties properties = System.getProperties();
@@ -39,6 +40,8 @@ public class SysConfig {
         caputreSetting=configDTO.getConfig().getSysConfig().getCaputreSetting();
         channelSetting=configDTO.getConfig().getChannelSetting();
         managerSetting=configDTO.getConfig().getManagerSetting();
+       faceDTO= configDTO.getConfig().getFaceConfig();
         DeviceCache.deviceStatusInit();
     }
+
 }

+ 7 - 0
src/main/java/com/gzlh/config/dto/ApplicationConfigDTO.java

@@ -23,8 +23,13 @@ public class ApplicationConfigDTO implements Serializable {
         private ChannelSetting channelSetting;
         @JsonProperty("configList")
         private ConfigListDTO sysConfig;
+
         @JsonProperty("eventList")
         private EventListDTO eventList;
+
+        @JsonProperty("faceConfig")
+        private FaceListDTO faceConfig;
+
         @NoArgsConstructor
         @Data
         public static class EventListDTO {
@@ -32,6 +37,8 @@ public class ApplicationConfigDTO implements Serializable {
             private List<EventDTO> event;
         }
 
+
+
         @Data
         @NoArgsConstructor
         public static class ConfigListDTO{

+ 22 - 0
src/main/java/com/gzlh/config/dto/FaceConfig.java

@@ -0,0 +1,22 @@
+package com.gzlh.config.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+public class FaceConfig {
+    @JsonProperty("enable")
+    private Boolean enable;
+    @JsonProperty("actionList")
+    private ActionListDTO actionList;
+
+    @NoArgsConstructor
+    @Data
+    public static class ActionListDTO {
+        @JsonProperty("action")
+        private List<String> action;
+    }
+}

+ 23 - 0
src/main/java/com/gzlh/config/dto/FaceDTO.java

@@ -0,0 +1,23 @@
+package com.gzlh.config.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * 人脸机子
+ */
+@Data
+@AllArgsConstructor
+public class FaceDTO {
+    private String channelCode;
+    private String ip;
+    private short port;
+    @JsonIgnore
+    private  String uname;
+    @JsonIgnore
+    private  String pwd;
+    private Integer userId;
+    private boolean online;
+
+}

+ 16 - 0
src/main/java/com/gzlh/config/dto/FaceListDTO.java

@@ -0,0 +1,16 @@
+package com.gzlh.config.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+@NoArgsConstructor
+@Data
+public class FaceListDTO {
+    @JsonProperty("enable")
+    private Boolean enable;
+
+    @JsonProperty("face")
+    private List<FaceDTO> face;
+}

+ 16 - 0
src/main/java/com/gzlh/config/properties/ExternalProperties.java

@@ -0,0 +1,16 @@
+package com.gzlh.config.properties;
+
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@ConfigurationProperties(prefix = "external")
+@Data
+@Component
+public class ExternalProperties {
+    private String faceStatusCallbackPath;
+
+    private String faceOpenGatePath;
+
+}

+ 46 - 0
src/main/java/com/gzlh/device/face/CheckFaceGateOnlineTask.java

@@ -0,0 +1,46 @@
+package com.gzlh.device.face;
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
+
+import com.gzlh.config.dto.FaceDTO;
+import com.gzlh.config.hksdk.HCNetSDK;
+import com.gzlh.config.hksdk.HkUtils;
+import com.gzlh.config.properties.ExternalProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.env.Environment;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class CheckFaceGateOnlineTask implements Runnable {
+
+
+    @Override
+    public void run() {
+        HkUtils hkUtils = SpringUtil.getBean(HkUtils.class);
+        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+        List<FaceDTO> faceDTOList = Collections.emptyList();
+        if (faceDTOList.isEmpty()) {
+            return;
+        }
+        HCNetSDK hcNetSDK = SpringUtil.getBean(HCNetSDK.class);
+        Runnable task = () -> {
+            for (FaceDTO faceDTO : faceDTOList) {
+                faceDTO.setOnline(hkUtils.getStatus(hcNetSDK, faceDTO.getUserId()));
+            }
+        };
+        // 初始延迟1秒后开始执行,每隔20秒执行一次
+        executor.scheduleAtFixedRate(task, 1, 30, TimeUnit.SECONDS);
+        ExternalProperties externalProperties = SpringUtil.getBean(ExternalProperties.class);
+        String url = externalProperties.getFaceStatusCallbackPath();
+        System.out.println(url);
+        String resp = HttpUtil.createPost(url).body(JSONUtil.toJsonStr(faceDTOList)).execute().body();
+        log.info("上报状态:{},{}", resp, JSONUtil.toJsonStr(faceDTOList));
+    }
+}

+ 333 - 0
src/main/java/com/gzlh/device/face/FaceService.java

@@ -0,0 +1,333 @@
+package com.gzlh.device.face;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONException;
+import cn.hutool.json.JSONObject;
+
+import com.gzlh.config.dto.FaceDTO;
+import com.gzlh.config.hksdk.HCNetSDK;
+import com.gzlh.config.properties.ExternalProperties;
+import com.gzlh.constans.AjaxError;
+import com.gzlh.utils.FileUtils;
+import com.sun.jna.Pointer;
+import com.sun.jna.ptr.IntByReference;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+@Service
+@Slf4j
+public class FaceService {
+    @Resource
+    private HCNetSDK hcNetSDK;
+
+   @Resource
+   private ExternalProperties externalProperties;
+
+    /**
+     * 功能:按照二进制方式下发人脸图片
+     *
+     * @param userID     用户注册ID
+     * @param employeeNo 人员工号
+     * @throws JSONException
+     * @throws InterruptedException
+     */
+    public void AddFaceByBinary(int userID, String employeeNo, String baseImg) throws JSONException, InterruptedException {
+        HCNetSDK.BYTE_ARRAY ptrByteArray = new HCNetSDK.BYTE_ARRAY(1024);    //数组
+        String strInBuffer = "PUT /ISAPI/Intelligent/FDLib/FDSetUp?format=json";
+        System.arraycopy(strInBuffer.getBytes(), 0, ptrByteArray.byValue, 0, strInBuffer.length());//字符串拷贝到数组中
+        ptrByteArray.write();
+
+        int lHandler = hcNetSDK.NET_DVR_StartRemoteConfig(userID, HCNetSDK.NET_DVR_FACE_DATA_RECORD, ptrByteArray.getPointer(), strInBuffer.length(), null, null);
+        if (lHandler < 0) {
+            System.out.println("Addface NET_DVR_StartRemoteConfig 失败,错误码为" + hcNetSDK.NET_DVR_GetLastError());
+            return;
+        } else {
+            System.out.println("Addface NET_DVR_StartRemoteConfig 成功!");
+
+            HCNetSDK.NET_DVR_JSON_DATA_CFG struAddFaceDataCfg = new HCNetSDK.NET_DVR_JSON_DATA_CFG();
+            struAddFaceDataCfg.read();
+
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("faceLibType", "blackFD");
+            jsonObject.put("FDID", "1");
+            jsonObject.put("FPID", employeeNo);//人脸下发关联的工号
+
+            String strJsonData = jsonObject.toString();
+            System.arraycopy(strJsonData.getBytes(), 0, ptrByteArray.byValue, 0, strJsonData.length());//字符串拷贝到数组中
+            ptrByteArray.write();
+            struAddFaceDataCfg.dwSize = struAddFaceDataCfg.size();
+            struAddFaceDataCfg.lpJsonData = ptrByteArray.getPointer();
+            struAddFaceDataCfg.dwJsonDataSize = strJsonData.length();
+
+            /*****************************************
+             * 从本地文件里面读取JPEG图片二进制数据
+             *****************************************/
+            FileInputStream picfile = null;
+            int picdataLength = 0;
+            try {
+
+                picfile = FileUtils.convertBase64ToFileInputStream(baseImg);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            try {
+                picdataLength = picfile.available();
+            } catch (IOException e1) {
+                e1.printStackTrace();
+            }
+            if (picdataLength < 0) {
+                System.out.println("input file dataSize < 0");
+                return;
+            }
+
+            HCNetSDK.BYTE_ARRAY ptrpicByte = new HCNetSDK.BYTE_ARRAY(picdataLength);
+            try {
+                picfile.read(ptrpicByte.byValue);
+            } catch (IOException e2) {
+                e2.printStackTrace();
+            }
+            ptrpicByte.write();
+            struAddFaceDataCfg.dwPicDataSize = picdataLength;
+            struAddFaceDataCfg.lpPicData = ptrpicByte.getPointer();
+            struAddFaceDataCfg.write();
+
+            HCNetSDK.BYTE_ARRAY ptrOutuff = new HCNetSDK.BYTE_ARRAY(1024);
+
+            IntByReference pInt = new IntByReference(0);
+
+            while (true) {
+                int dwState = hcNetSDK.NET_DVR_SendWithRecvRemoteConfig(lHandler, struAddFaceDataCfg.getPointer(), struAddFaceDataCfg.dwSize, ptrOutuff.getPointer(), 1024, pInt);
+                //读取返回的json并解析
+                ptrOutuff.read();
+                String strResult = new String(ptrOutuff.byValue).trim();
+                System.out.println("dwState:" + dwState + ",strResult:" + strResult);
+
+                JSONObject jsonResult = new JSONObject(strResult);
+                int statusCode = jsonResult.getInt("statusCode");
+                String statusString = jsonResult.getStr("statusString");
+
+
+                if (dwState == -1) {
+                    System.out.println("NET_DVR_SendWithRecvRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_NEED_WAIT) {
+                    System.out.println("配置等待");
+                    Thread.sleep(10);
+                    continue;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FAILED) {
+                    System.out.println("下发人脸失败, json retun:" + jsonResult.toString());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_EXCEPTION) {
+                    System.out.println("下发人脸异常, json retun:" + jsonResult.toString());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_SUCCESS) {//返回NET_SDK_CONFIG_STATUS_SUCCESS代表流程走通了,但并不代表下发成功,比如人脸图片不符合设备规范等原因,所以需要解析Json报文
+                    if (statusCode != 1) {
+                        System.out.println("下发人脸成功,但是有异常情况:" + jsonResult.toString());
+                    } else {
+                        System.out.println("下发人脸成功,  json retun:" + jsonResult.toString());
+                    }
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FINISH) {
+                    //下发人脸时:dwState其实不会走到这里,因为设备不知道我们会下发多少个人,所以长连接需要我们主动关闭
+                    System.out.println("下发人脸完成");
+                    break;
+                }
+            }
+            if (!hcNetSDK.NET_DVR_StopRemoteConfig(lHandler)) {
+                System.out.println("NET_DVR_StopRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+            } else {
+                System.out.println("NET_DVR_StopRemoteConfig接口成功");
+            }
+        }
+
+    }
+
+    /**
+     * 按URL方式下发人脸图片
+     *
+     * @param userID     用户注销ID
+     * @param employeeNo 人员工号
+     * @throws JSONException
+     */
+    public void AddFaceByUrl(int userID, String employeeNo, String imgUrl) throws JSONException {
+        HCNetSDK.BYTE_ARRAY ptrByteArray = new HCNetSDK.BYTE_ARRAY(1024);    //数组
+        String strInBuffer = "PUT /ISAPI/Intelligent/FDLib/FDSetUp?format=json";
+        System.arraycopy(strInBuffer.getBytes(), 0, ptrByteArray.byValue, 0, strInBuffer.length());//字符串拷贝到数组中
+        ptrByteArray.write();
+
+        int lHandler = hcNetSDK.NET_DVR_StartRemoteConfig(userID, HCNetSDK.NET_DVR_FACE_DATA_RECORD, ptrByteArray.getPointer(), strInBuffer.length(), null, null);
+        if (lHandler < 0) {
+            System.out.println("Addface NET_DVR_StartRemoteConfig 失败,错误码为" + hcNetSDK.NET_DVR_GetLastError());
+            return;
+        } else {
+            System.out.println("Addface NET_DVR_StartRemoteConfig 成功!");
+
+            HCNetSDK.NET_DVR_JSON_DATA_CFG struAddFaceDataCfg = new HCNetSDK.NET_DVR_JSON_DATA_CFG();
+            struAddFaceDataCfg.read();
+
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.set("faceURL", imgUrl); //人脸图片URL
+            jsonObject.set("faceLibType", "blackFD");
+            jsonObject.set("FDID", "1");
+            jsonObject.set("FPID", employeeNo);//人脸下发关联的工号
+
+            String strJsonData = jsonObject.toString();
+            System.arraycopy(strJsonData.getBytes(), 0, ptrByteArray.byValue, 0, strJsonData.length());//字符串拷贝到数组中
+            ptrByteArray.write();
+            struAddFaceDataCfg.dwSize = struAddFaceDataCfg.size();
+            struAddFaceDataCfg.lpJsonData = ptrByteArray.getPointer();
+            struAddFaceDataCfg.dwJsonDataSize = strJsonData.length();
+            struAddFaceDataCfg.lpPicData = null;
+            struAddFaceDataCfg.dwPicDataSize = 0;
+            struAddFaceDataCfg.write();
+            HCNetSDK.BYTE_ARRAY ptrOutuff = new HCNetSDK.BYTE_ARRAY(1024);
+
+            IntByReference pInt = new IntByReference(0);
+
+            while (true) {
+                int dwState = hcNetSDK.NET_DVR_SendWithRecvRemoteConfig(lHandler, struAddFaceDataCfg.getPointer(), struAddFaceDataCfg.dwSize, ptrOutuff.getPointer(), 1024, pInt);
+                //读取返回的json并解析
+                ptrOutuff.read();
+                String strResult = new String(ptrOutuff.byValue).trim();
+                System.out.println("dwState:" + dwState + ",strResult:" + strResult);
+                if (dwState == 1004) {
+                    hcNetSDK.NET_DVR_StopRemoteConfig(lHandler);
+                    break;
+                }
+                JSONObject jsonResult = new JSONObject(strResult);
+                int statusCode = jsonResult.getInt("statusCode");
+                String statusString = jsonResult.getStr("statusString");
+
+
+                if (dwState == -1) {
+                    System.out.println("NET_DVR_SendWithRecvRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_NEED_WAIT) {
+                    System.out.println("配置等待");
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    continue;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FAILED) {
+                    System.out.println("下发人脸失败, json retun:" + jsonResult.toString());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_EXCEPTION) {
+                    System.out.println("下发人脸异常, json retun:" + jsonResult.toString());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_SUCCESS) {//返回NET_SDK_CONFIG_STATUS_SUCCESS代表流程走通了,但并不代表下发成功,比如人脸图片不符合设备规范等原因,所以需要解析Json报文
+                    if (statusCode != 1) {
+                        System.out.println("下发人脸成功,但是有异常情况:" + jsonResult.toString());
+                    } else {
+                        System.out.println("下发人脸成功,  json retun:" + jsonResult.toString());
+                    }
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FINISH) {
+                    //下发人脸时:dwState其实不会走到这里,因为设备不知道我们会下发多少个人,所以长连接需要我们主动关闭
+                    System.out.println("下发人脸完成");
+                    break;
+                }
+            }
+            if (!hcNetSDK.NET_DVR_StopRemoteConfig(lHandler)) {
+                System.out.println("NET_DVR_StopRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+            } else {
+                System.out.println("NET_DVR_StopRemoteConfig接口成功");
+            }
+        }
+    }
+
+    /**
+     * 人脸删除,支持批量删除,json中添加多个工号
+     *
+     * @param userID
+     * @param employeeNo
+     */
+
+    public void DeleteFaceInfo(int userID, String employeeNo) {
+        String deleteFaceUrl = "PUT /ISAPI/Intelligent/FDLib/FDSearch/Delete?format=json&FDID=1&faceLibType=blackFD";
+        String deleteFaceJson = "{\n" +
+                "    \"FPID\": [{\n" +
+                "        \"value\": \"" + employeeNo + "\"\n" +
+                "    }]\n" +
+                "}";
+        String result = transIsapi.put_isapi(userID, deleteFaceUrl, deleteFaceJson, hcNetSDK);
+        log.info("删除人员结果:" + result);
+    }
+
+    public boolean RemoteControlGate(int userID, int command) {
+        /**第二个参数lGatewayIndex
+         [in] 门禁序号(楼层编号、锁ID),从1开始,-1表示对所有门(或者梯控的所有楼层)进行操作
+         第三个参数dwStaic
+         [in] 命令值:0- 关闭(对于梯控,表示受控),1- 打开(对于梯控,表示开门),2- 常开(对于梯控,表示自由、通道状态),3- 常关(对于梯控,表示禁用),4- 恢复(梯控,普通状态),5- 访客呼梯(梯控),6- 住户呼梯(梯控)*/
+        boolean b_gate = hcNetSDK.NET_DVR_ControlGateway(userID, 1, command);
+        if (!b_gate) {
+            log.error("远程控门失败,err=" + hcNetSDK.NET_DVR_GetLastError());
+            throw new AjaxError("开门失败");
+        }
+        return b_gate;
+    }
+
+    public void handlerFaceOpenGate(HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo) {
+        String[] sIP = new String[2];
+        sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
+        //报警设备ip
+        String ip = sIP[0];
+        FaceDTO faceDTO = null;
+        if (faceDTO == null) {
+            log.error("未找到ip为{}的faceDTO", ip);
+            return;
+        }
+        String employeeId = null;
+        HCNetSDK.NET_DVR_ACS_ALARM_INFO strACSInfo = new HCNetSDK.NET_DVR_ACS_ALARM_INFO();
+        strACSInfo.write();
+        Pointer pACSInfo = strACSInfo.getPointer();
+        pACSInfo.write(0, pAlarmInfo.getByteArray(0, strACSInfo.size()), 0, strACSInfo.size());
+        strACSInfo.read();
+        //主类型 5 事件上报
+        if (strACSInfo.dwMajor != 5) {
+            return;
+        }
+        //以人为中心设备
+        if (strACSInfo.byAcsEventInfoExtend == 1) {
+            HCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND test = new HCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND();
+            test.write();
+            Pointer pAcsEventInfoExtend = test.getPointer();
+            pAcsEventInfoExtend.write(0, strACSInfo.pAcsEventInfoExtend.getByteArray(0, test.size()), 0, test.size());
+            test.read();
+            employeeId = new String(test.byEmployeeNo).trim();
+        }
+        log.info("员工employeeId=" + employeeId);
+        String eventTime = DateUtil.now();
+        log.info("刷卡时间eventTime=" + eventTime);
+        //刷脸成功
+        if (strACSInfo.dwMinor == 75) {
+            log.info("刷脸成功============dwMinor============" + strACSInfo.dwMinor);
+        }
+        //刷脸失败
+        else if (strACSInfo.dwMinor == 76) {
+            log.info("刷脸失败============dwMinor============" + strACSInfo.dwMinor);
+        }
+        //门锁打开
+        else if (strACSInfo.dwMinor == 21) {
+            log.info("门锁打开============dwMinor============" + strACSInfo.dwMinor);
+        }
+        String uploadFaceGateUrl=externalProperties.getFaceOpenGatePath();
+        JSONObject params = new JSONObject();
+        params.set("employeeNo", employeeId)
+                .set("ip", ip)
+                .set("time", DateUtil.now())
+                .set("channelCode", faceDTO.getChannelCode());
+        String resp = HttpUtil.createPost(uploadFaceGateUrl).body(params.toJSONString(0)).execute().body();
+        log.info("上报开门事件:{},{},{}", uploadFaceGateUrl, params.toJSONString(0), resp);
+
+    }
+
+}

+ 38 - 0
src/main/java/com/gzlh/device/face/LoginFaceGate.java

@@ -0,0 +1,38 @@
+package com.gzlh.device.face;
+
+import cn.hutool.extra.spring.SpringUtil;
+
+import com.gzlh.config.hksdk.HCNetSDK;
+import com.gzlh.config.hksdk.HkUtils;
+import com.gzlh.config.dto.FaceDTO;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class LoginFaceGate implements Runnable{
+    private FaceDTO faceDTO;
+
+    public LoginFaceGate(FaceDTO faceDTO) {
+        this.faceDTO = faceDTO;
+    }
+
+    @Override
+    public void run() {
+        log.info("Connecting face gate :{}",faceDTO.getIp());
+        HkUtils hkUtils = SpringUtil.getBean(HkUtils.class);
+        HCNetSDK hcNetSDK = SpringUtil.getBean(HCNetSDK.class);
+        String ip = faceDTO.getIp();
+        short port = faceDTO.getPort();
+        String uname = faceDTO.getUname();
+        String pwd = faceDTO.getPwd();
+        int userId = hkUtils.Login_V40(ip, port, uname, pwd, hcNetSDK);
+        if (userId != -1) {
+            log.info("登录海康人脸机成功,已布防:{},{}", ip, userId);
+            hkUtils.SetAlarm(hcNetSDK, userId);
+            faceDTO.setUserId(userId);
+//            ThreadUtil.execute(new CheckCarNoCaptureOnlineTask(carNoCaptureDTO));
+        } else {
+            int errorCode = hcNetSDK.NET_DVR_GetLastError();
+            log.info("登录海康人脸机失败:{},{}", errorCode, userId);
+        }
+    }
+}

+ 347 - 0
src/main/java/com/gzlh/device/face/UserManage.java

@@ -0,0 +1,347 @@
+package com.gzlh.device.face;
+
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONException;
+import cn.hutool.json.JSONObject;
+
+import com.gzlh.config.hksdk.HCNetSDK;
+import com.gzlh.constans.AjaxError;
+import com.sun.jna.Pointer;
+import com.sun.jna.ptr.IntByReference;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 功能:人脸下发、查询、删除、人员计划模板配置
+ */
+@Service
+@Slf4j
+public class UserManage {
+    @Resource
+    private HCNetSDK hcNetSDK;
+
+    /**
+     * 添加人员
+     *
+     * @param lUserID    登录句柄
+     * @param employeeNo 工号
+     * @throws UnsupportedEncodingException
+     * @throws InterruptedException
+     * @throws JSONException
+     */
+    public void AddUserInfo(int lUserID, String employeeNo, String name) throws UnsupportedEncodingException, InterruptedException, JSONException {
+        HCNetSDK.BYTE_ARRAY ptrByteArray = new HCNetSDK.BYTE_ARRAY(1024);    //数组
+        //"POST /ISAPI/AccessControl/UserInfo/Record?format=json" 此URL也是下发人员
+        String strInBuffer = "PUT /ISAPI/AccessControl/UserInfo/SetUp?format=json";
+        System.arraycopy(strInBuffer.getBytes(), 0, ptrByteArray.byValue, 0, strInBuffer.length());//字符串拷贝到数组中
+        ptrByteArray.write();
+
+        int lHandler = hcNetSDK.NET_DVR_StartRemoteConfig(lUserID, HCNetSDK.NET_DVR_JSON_CONFIG, ptrByteArray.getPointer(), strInBuffer.length(), null, null);
+        if (lHandler < 0) {
+            log.error("AddUserInfo NET_DVR_StartRemoteConfig 失败,错误码为" + hcNetSDK.NET_DVR_GetLastError());
+            throw new AjaxError("添加失败");
+        } else {
+            byte[] Name = name.getBytes(StandardCharsets.UTF_8); //根据iCharEncodeType判断,如果iCharEncodeType返回6,则是UTF-8编码。
+            //如果是0或者1或者2,则是GBK编码
+            //将中文字符编码之后用数组拷贝的方式,避免因为编码导致的长度问题
+            String strInBuffer1 = "{\"UserInfo\":{\"Valid\":{\"beginTime\":\"2024-08-01T17:30:08\",\"enable\":true,\"endTime\":" +
+                    "\"2030-08-01T17:30:08\"}," +
+                    "\"checkUser\":false,\"belongGroup \":\"1\",\"doorRight\":\"1\",\"RightPlan\":[{\"doorNo\": 1,\"planTemplateNo\": \"1,3,5\"}]," +
+                    "\"employeeNo\":\"" + employeeNo + "\",\"floorNumber\":2,\"maxOpenDoorTime\":0,\"name\":\"";
+            String strInBuffer2 = "\",\"openDelayEnabled\":false,\"password\":\"123456\",\"roomNumber\":4,\"userType\":\"normal\"}}";
+            int iStringSize = Name.length + strInBuffer1.length() + strInBuffer2.length();
+
+            HCNetSDK.BYTE_ARRAY ptrByte = new HCNetSDK.BYTE_ARRAY(iStringSize);
+            System.arraycopy(strInBuffer1.getBytes(), 0, ptrByte.byValue, 0, strInBuffer1.length());
+            System.arraycopy(Name, 0, ptrByte.byValue, strInBuffer1.length(), Name.length);
+            System.arraycopy(strInBuffer2.getBytes(), 0, ptrByte.byValue, strInBuffer1.length() + Name.length, strInBuffer2.length());
+            ptrByte.write();
+
+            log.info(new String(ptrByte.byValue));
+
+            HCNetSDK.BYTE_ARRAY ptrOutuff = new HCNetSDK.BYTE_ARRAY(1024);
+
+            IntByReference pInt = new IntByReference(0);
+            while (true) {
+                int dwState = hcNetSDK.NET_DVR_SendWithRecvRemoteConfig(lHandler, ptrByte.getPointer(), iStringSize, ptrOutuff.getPointer(), 1024, pInt);
+                //读取返回的json并解析
+                ptrOutuff.read();
+                String strResult = new String(ptrOutuff.byValue).trim();
+                log.info("dwState:" + dwState + ",strResult:" + strResult);
+                JSONObject jsonResult = new JSONObject(strResult);
+                int statusCode = jsonResult.getInt("statusCode");
+                String statusString = jsonResult.getStr("statusString");
+                if (statusString.equals("OK")) {
+                    break;
+                }
+                if (dwState == -1) {
+                    log.info("NET_DVR_SendWithRecvRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_NEED_WAIT) {
+                    log.info("配置等待");
+                    Thread.sleep(10);
+                    continue;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FAILED) {
+                    log.info("下发人员失败, json retun:" + jsonResult.toString());
+                    throw new AjaxError("下发人员"+employeeNo+"失败");
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_EXCEPTION) {
+                    log.info("下发人员异常, json retun:" + jsonResult.toString());
+                    throw new AjaxError("下发人员"+employeeNo+"失败");
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_SUCCESS) {//返回NET_SDK_CONFIG_STATUS_SUCCESS代表流程走通了,但并不代表下发成功,比如有些设备可能因为人员已存在等原因下发失败,所以需要解析Json报文
+                    if (statusCode != 1) {
+                        log.info("下发人员成功,但是有异常情况:" + jsonResult.toString());
+                        throw new AjaxError("下发人员"+employeeNo+"失败");
+                    } else {
+                        log.info("下发人员成功: json retun:" + jsonResult.toString());
+                    }
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FINISH) {
+                    //下发人员时:dwState其实不会走到这里,因为设备不知道我们会下发多少个人,所以长连接需要我们主动关闭
+                    log.info("下发人员完成");
+                    break;
+                }
+            }
+            if (!hcNetSDK.NET_DVR_StopRemoteConfig(lHandler)) {
+                log.info("NET_DVR_StopRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+            } else {
+                log.info("NET_DVR_StopRemoteConfig接口成功");
+            }
+        }
+    }
+
+
+    public void SearchUserInfo(int userID, String employeeNo) throws JSONException {
+        HCNetSDK.BYTE_ARRAY ptrByteArray = new HCNetSDK.BYTE_ARRAY(1024);    //数组
+        String strInBuffer = "POST /ISAPI/AccessControl/UserInfo/Search?format=json";
+        System.arraycopy(strInBuffer.getBytes(), 0, ptrByteArray.byValue, 0, strInBuffer.length());//字符串拷贝到数组中
+        ptrByteArray.write();
+
+        int lHandler = hcNetSDK.NET_DVR_StartRemoteConfig(userID, HCNetSDK.NET_DVR_JSON_CONFIG, ptrByteArray.getPointer(), strInBuffer.length(), null, null);
+        if (lHandler < 0) {
+            log.info("SearchUserInfo NET_DVR_StartRemoteConfig 失败,错误码为" + hcNetSDK.NET_DVR_GetLastError());
+            return;
+        } else {
+            //组装查询的JSON报文,这边查询的是所有的人员
+            JSONObject jsonObject = new JSONObject();
+            JSONObject jsonSearchCond = new JSONObject();
+
+            //如果需要查询指定的工号人员信息,把下面注释的内容去除掉即可
+            JSONArray EmployeeNoList = new JSONArray();
+            JSONObject employeeNo1 = new JSONObject();
+            employeeNo1.set("employeeNo", employeeNo);
+            EmployeeNoList.put(employeeNo1);
+            jsonSearchCond.set("EmployeeNoList", EmployeeNoList);
+
+            jsonSearchCond.set("searchID", RandomUtil.randomNumbers(12));
+            jsonSearchCond.set("searchResultPosition", 0);
+            jsonSearchCond.set("maxResults", 50);
+            jsonObject.set("UserInfoSearchCond", jsonSearchCond);
+
+            String strInbuff = jsonObject.toString();
+            log.info("查询的json报文:{},{}", employeeNo, strInbuff);
+
+            //把string传递到Byte数组中,后续用.getPointer()方法传入指针地址中。
+            HCNetSDK.BYTE_ARRAY ptrInbuff = new HCNetSDK.BYTE_ARRAY(strInbuff.length());
+            System.arraycopy(strInbuff.getBytes(), 0, ptrInbuff.byValue, 0, strInbuff.length());
+            ptrInbuff.write();
+
+            //定义接收结果的结构体
+            HCNetSDK.BYTE_ARRAY ptrOutuff = new HCNetSDK.BYTE_ARRAY(10 * 1024);
+
+            IntByReference pInt = new IntByReference(0);
+
+            while (true) {
+                int dwState = hcNetSDK.NET_DVR_SendWithRecvRemoteConfig(lHandler, ptrInbuff.getPointer(), strInbuff.length(), ptrOutuff.getPointer(), 10 * 1024, pInt);
+                if (dwState == -1) {
+                    log.info("NET_DVR_SendWithRecvRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_NEED_WAIT) {
+                    log.info("配置等待");
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    }
+                    continue;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FAILED) {
+                    log.info("查询人员失败");
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_EXCEPTION) {
+                    log.info("查询人员异常");
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_SUCCESS) {
+                    ptrOutuff.read();
+                    log.info("查询人员成功, json:" + new String(ptrOutuff.byValue).trim());
+                    break;
+                } else if (dwState == HCNetSDK.NET_SDK_CONFIG_STATUS_FINISH) {
+                    log.info("获取人员完成");
+                    break;
+                }
+            }
+
+            if (!hcNetSDK.NET_DVR_StopRemoteConfig(lHandler)) {
+                log.info("NET_DVR_StopRemoteConfig接口调用失败,错误码:" + hcNetSDK.NET_DVR_GetLastError());
+            } else {
+                log.info("NET_DVR_StopRemoteConfig接口成功");
+                lHandler = -1;
+            }
+        }
+
+
+    }
+
+    public boolean deleteUserInfo(int userID, String employeeNo) throws JSONException {
+        //删除单个人员
+        String deleteUserjson = "{\n" +
+                "\t\"UserInfoDetail\": {\t\n" +
+                "\t\t\"mode\":  \"byEmployeeNo\",\t\n" +
+                "\t\t\"EmployeeNoList\": [\t\n" +
+                "\t\t\t{\n" +
+                "\t\t\t\t\"employeeNo\":  \"" + employeeNo + "\"\t\n" +
+                "\t\t\t}\n" +
+                "\t\t]\n" +
+                "\n" +
+                "\t}\n" +
+                "}";
+        //删除所有人员
+//        String deleteUserjson = "{\n" +
+//                "\t\"UserInfoDetail\": {\t\n" +
+//                "\t\t\"mode\":  \"all\",\t\n" +
+//                "\t\t\"EmployeeNoList\": [\t\n" +
+//                "\t\t]\n" +
+//                "\n" +
+//                "\t}\n" +
+//                "}";
+        String deleteUserUrl = "PUT /ISAPI/AccessControl/UserInfoDetail/Delete?format=json";
+        String result = transIsapi.put_isapi(userID, deleteUserUrl, deleteUserjson, hcNetSDK);
+        log.info(result);
+        //获取删除进度
+        while (true) {
+            String getDeleteProcessUrl = "GET /ISAPI/AccessControl/UserInfoDetail/DeleteProcess?format=json";
+            String deleteResult = transIsapi.get_isapi(userID, getDeleteProcessUrl, hcNetSDK);
+            JSONObject jsonObject = new JSONObject(deleteResult);
+            JSONObject jsonObject1 = jsonObject.getJSONObject("UserInfoDetailDeleteProcess");
+            String process = jsonObject1.getStr("status");
+            log.info("process =" + process);
+            if (process.equals("processing")) {
+                log.info("正在删除");
+                continue;
+            } else if (process.equals("success")) {
+                log.info("删除成功");
+                break;
+            } else if (process.equals("failed")) {
+                throw new AjaxError("删除" + employeeNo + "失败");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 人员计划模板配置
+     *
+     * @param userID              用户登录句柄
+     * @param iPlanTemplateNumber 计划模板编号,从1开始,最大值从门禁能力集获取
+     */
+    public void SetCardTemplate(int userID, int iPlanTemplateNumber) {
+        //设置卡权限计划模板参数
+        HCNetSDK.NET_DVR_PLAN_TEMPLATE_COND struPlanCond = new HCNetSDK.NET_DVR_PLAN_TEMPLATE_COND();
+        struPlanCond.dwSize = struPlanCond.size();
+        struPlanCond.dwPlanTemplateNumber = iPlanTemplateNumber;//计划模板编号,从1开始,最大值从门禁能力集获取
+        struPlanCond.wLocalControllerID = 0;//就地控制器序号[1,64],0表示门禁主机
+        struPlanCond.write();
+        HCNetSDK.NET_DVR_PLAN_TEMPLATE struPlanTemCfg = new HCNetSDK.NET_DVR_PLAN_TEMPLATE();
+        struPlanTemCfg.dwSize = struPlanTemCfg.size();
+        struPlanTemCfg.byEnable = 1; //是否使能:0- 否,1- 是
+        struPlanTemCfg.dwWeekPlanNo = 2;//周计划编号,0表示无效
+        struPlanTemCfg.dwHolidayGroupNo[0] = 0;//假日组编号,按值表示,采用紧凑型排列,中间遇到0则后续无效
+        byte[] byTemplateName;
+        try {
+            byTemplateName = "CardTemplatePlan_2".getBytes("GBK");
+            //计划模板名称
+            for (int i = 0; i < HCNetSDK.NAME_LEN; i++) {
+                struPlanTemCfg.byTemplateName[i] = 0;
+            }
+            System.arraycopy(byTemplateName, 0, struPlanTemCfg.byTemplateName, 0, byTemplateName.length);
+        } catch (UnsupportedEncodingException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        struPlanTemCfg.write();
+        IntByReference pInt = new IntByReference(0);
+        Pointer lpStatusList = pInt.getPointer();
+        if (false == hcNetSDK.NET_DVR_SetDeviceConfig(userID, HCNetSDK.NET_DVR_SET_CARD_RIGHT_PLAN_TEMPLATE_V50, 1, struPlanCond.getPointer(), struPlanCond.size(), lpStatusList, struPlanTemCfg.getPointer(), struPlanTemCfg.size())) {
+            log.info("NET_DVR_SET_CARD_RIGHT_PLAN_TEMPLATE_V50失败,错误号:" + hcNetSDK.NET_DVR_GetLastError());
+            return;
+        }
+        log.info("NET_DVR_SET_CARD_RIGHT_PLAN_TEMPLATE_V50成功!");
+        //获取卡权限周计划参数
+        HCNetSDK.NET_DVR_WEEK_PLAN_COND struWeekPlanCond = new HCNetSDK.NET_DVR_WEEK_PLAN_COND();
+        struWeekPlanCond.dwSize = struWeekPlanCond.size();
+        struWeekPlanCond.dwWeekPlanNumber = 2;
+        struWeekPlanCond.wLocalControllerID = 0;
+        HCNetSDK.NET_DVR_WEEK_PLAN_CFG struWeekPlanCfg = new HCNetSDK.NET_DVR_WEEK_PLAN_CFG();
+        struWeekPlanCond.write();
+        struWeekPlanCfg.write();
+        Pointer lpCond = struWeekPlanCond.getPointer();
+        Pointer lpInbuferCfg = struWeekPlanCfg.getPointer();
+        if (false == hcNetSDK.NET_DVR_GetDeviceConfig(userID, HCNetSDK.NET_DVR_GET_CARD_RIGHT_WEEK_PLAN_V50, 1, lpCond, struWeekPlanCond.size(), lpStatusList, lpInbuferCfg, struWeekPlanCfg.size())) {
+            log.info("NET_DVR_GET_CARD_RIGHT_WEEK_PLAN_V50失败,错误号:" + hcNetSDK.NET_DVR_GetLastError());
+            return;
+        }
+        struWeekPlanCfg.read();
+        struWeekPlanCfg.byEnable = 1; //是否使能:0- 否,1- 是
+        /**避免时间段交叉,先初始化, 七天八小时*/
+        for (int i = 0; i < 7; i++) {
+            for (int j = 0; j < 8; j++) {
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].byEnable = 0;
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].struTimeSegment.struBeginTime.byHour = 0;
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].struTimeSegment.struBeginTime.byMinute = 0;
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].struTimeSegment.struBeginTime.bySecond = 0;
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].struTimeSegment.struEndTime.byHour = 0;
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].struTimeSegment.struEndTime.byMinute = 0;
+                struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[j].struTimeSegment.struEndTime.bySecond = 0;
+            }
+        }
+        /**一周7天,全天24小时*/
+        for (int i = 0; i < 7; i++) {
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].byEnable = 1;
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struBeginTime.byHour = 21;
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struBeginTime.byMinute = 0;
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struBeginTime.bySecond = 0;
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struEndTime.byHour = 23;
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struEndTime.byMinute = 0;
+            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struEndTime.bySecond = 0;
+        }
+        /**一周7天,每天设置2个时间段*/
+        /*for(int i=0;i<7;i++)
+        {
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].byEnable = 1;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struBeginTime.byHour = 0;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struBeginTime.byMinute = 0;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struBeginTime.bySecond = 0;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struEndTime.byHour = 11;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struEndTime.byMinute = 59;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[0].struTimeSegment.struEndTime.bySecond = 59;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].byEnable = 1;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].struTimeSegment.struBeginTime.byHour = 13;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].struTimeSegment.struBeginTime.byMinute = 30;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].struTimeSegment.struBeginTime.bySecond = 0;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].struTimeSegment.struEndTime.byHour = 19;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].struTimeSegment.struEndTime.byMinute = 59;
+	            struWeekPlanCfg.struPlanCfg[i].struPlanCfgDay[1].struTimeSegment.struEndTime.bySecond = 59;
+	    }*/
+        struWeekPlanCfg.write();
+        //设置卡权限周计划参数
+        if (false == hcNetSDK.NET_DVR_SetDeviceConfig(userID, HCNetSDK.NET_DVR_SET_CARD_RIGHT_WEEK_PLAN_V50, 1, lpCond, struWeekPlanCond.size(), lpStatusList, lpInbuferCfg, struWeekPlanCfg.size())) {
+            log.info("NET_DVR_SET_CARD_RIGHT_WEEK_PLAN_V50失败,错误号:" + hcNetSDK.NET_DVR_GetLastError());
+        } else {
+            log.info("NET_DVR_SET_CARD_RIGHT_WEEK_PLAN_V50成功!");
+        }
+    }
+
+}

+ 100 - 0
src/main/java/com/gzlh/device/face/transIsapi.java

@@ -0,0 +1,100 @@
+package com.gzlh.device.face;
+
+
+import com.gzlh.config.hksdk.HCNetSDK;
+
+/**
+ * @create 2021-04-13-15:23
+ * 功能:透传接口实现,透传ISAPI命令
+ */
+public final class transIsapi {
+    public static String get_isapi(int lUserID, String url,HCNetSDK hcNetSDK) {
+        HCNetSDK.NET_DVR_XML_CONFIG_INPUT struXMLInput = new HCNetSDK.NET_DVR_XML_CONFIG_INPUT();
+        struXMLInput.read();
+        HCNetSDK.BYTE_ARRAY stringRequest = new HCNetSDK.BYTE_ARRAY(1024);
+        stringRequest.read();
+        //输入ISAPI协议命令
+        System.arraycopy(url.getBytes(), 0, stringRequest.byValue, 0, url.length());
+        stringRequest.write();
+        struXMLInput.dwSize = struXMLInput.size();
+        struXMLInput.lpRequestUrl = stringRequest.getPointer();
+        struXMLInput.dwRequestUrlLen = url.length();
+        struXMLInput.lpInBuffer = null;
+        struXMLInput.dwInBufferSize = 0;
+        struXMLInput.write();
+
+        HCNetSDK.BYTE_ARRAY stringXMLOut = new HCNetSDK.BYTE_ARRAY(8 * 1024);
+        stringXMLOut.read();
+        HCNetSDK.BYTE_ARRAY struXMLStatus = new HCNetSDK.BYTE_ARRAY(1024);
+        struXMLStatus.read();
+        HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT struXMLOutput = new HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT();
+        struXMLOutput.read();
+        struXMLOutput.dwSize = struXMLOutput.size();
+        struXMLOutput.lpOutBuffer = stringXMLOut.getPointer();
+        struXMLOutput.dwOutBufferSize = stringXMLOut.size();
+        struXMLOutput.lpStatusBuffer = struXMLStatus.getPointer();
+        struXMLOutput.dwStatusSize = struXMLStatus.size();
+        struXMLOutput.write();
+        if (!hcNetSDK.NET_DVR_STDXMLConfig(lUserID, struXMLInput, struXMLOutput)) {
+            int iErr = hcNetSDK.NET_DVR_GetLastError();
+            System.err.println("NET_DVR_STDXMLConfig失败,错误号" + iErr+"----URL:"+url);
+            return null;
+        } else {
+            stringXMLOut.read();
+            System.out.println("输出文本大小:" + struXMLOutput.dwReturnedXMLSize);
+            //打印输出XML文本
+            String strOutXML = new String(stringXMLOut.byValue).trim();
+            System.out.println(strOutXML);
+            struXMLStatus.read();
+            String strStatus = new String(struXMLStatus.byValue).trim();
+            System.out.println(strStatus);
+            return strOutXML;
+        }
+    }
+
+
+    public static String put_isapi(int lUserID, String url, String inputXml,HCNetSDK hcNetSDK) {
+        HCNetSDK.NET_DVR_XML_CONFIG_INPUT struXMLInput = new HCNetSDK.NET_DVR_XML_CONFIG_INPUT();
+        struXMLInput.read();
+        HCNetSDK.BYTE_ARRAY stringRequest = new HCNetSDK.BYTE_ARRAY(1024);
+        stringRequest.read();
+        //输入ISAPI协议命令
+        System.arraycopy(url.getBytes(), 0, stringRequest.byValue, 0, url.length());
+        stringRequest.write();
+        struXMLInput.dwSize = struXMLInput.size();
+        struXMLInput.lpRequestUrl = stringRequest.getPointer();
+        struXMLInput.dwRequestUrlLen = url.length();
+        HCNetSDK.BYTE_ARRAY ptrInBuffer = new HCNetSDK.BYTE_ARRAY(inputXml.length());
+        ptrInBuffer.read();
+        System.arraycopy(inputXml.getBytes(), 0, ptrInBuffer.byValue, 0, inputXml.length());
+        ptrInBuffer.write();
+        struXMLInput.lpInBuffer = ptrInBuffer.getPointer();
+        struXMLInput.dwInBufferSize = inputXml.length();
+        struXMLInput.write();
+        HCNetSDK.BYTE_ARRAY stringXMLOut = new HCNetSDK.BYTE_ARRAY(8 * 1024);
+        stringXMLOut.read();
+        HCNetSDK.BYTE_ARRAY struXMLStatus = new HCNetSDK.BYTE_ARRAY(1024);
+        struXMLStatus.read();
+        HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT struXMLOutput = new HCNetSDK.NET_DVR_XML_CONFIG_OUTPUT();
+        struXMLOutput.read();
+        struXMLOutput.dwSize = struXMLOutput.size();
+        struXMLOutput.lpOutBuffer = stringXMLOut.getPointer();
+        struXMLOutput.dwOutBufferSize = stringXMLOut.size();
+        struXMLOutput.lpStatusBuffer = struXMLStatus.getPointer();
+        struXMLOutput.dwStatusSize = struXMLStatus.size();
+        struXMLOutput.write();
+        if (!hcNetSDK.NET_DVR_STDXMLConfig(lUserID, struXMLInput, struXMLOutput)){
+            int iErr = hcNetSDK.NET_DVR_GetLastError();
+            System.err.println("NET_DVR_STDXMLConfig失败,错误号" + iErr+"----URL:"+url);
+            return null;
+        } else {
+            stringXMLOut.read();
+            System.out.println("输出文本大小:" + struXMLOutput.dwReturnedXMLSize);
+            //打印输出XML文本
+            String strOutXML = new String(stringXMLOut.byValue).trim();
+            struXMLStatus.read();
+            String strStatus = new String(struXMLStatus.byValue).trim();
+            return strOutXML;
+        }
+    }
+}

+ 13 - 0
src/main/java/com/gzlh/entity/AddFaceBO.java

@@ -0,0 +1,13 @@
+package com.gzlh.entity;
+
+import lombok.Data;
+
+@Data
+public class AddFaceBO {
+    private String ip;
+    private String channelCode;
+    private String no;
+    private String name;
+    private Integer command;
+    private String base64;
+}

+ 14 - 0
src/main/java/com/gzlh/startup/StartupRunner.java

@@ -7,6 +7,8 @@ import com.gzlh.bus.SysConfig;
 import com.gzlh.bus.task.CheckInitTask;
 import com.gzlh.config.SystemObject;
 import com.gzlh.config.dto.CaputreSetting;
+import com.gzlh.config.dto.FaceDTO;
+import com.gzlh.config.dto.FaceListDTO;
 import com.gzlh.config.dto.SerialSetting;
 import com.gzlh.config.ModuleEnum;
 import com.gzlh.bus.EventBus;
@@ -15,6 +17,8 @@ import com.gzlh.config.hksdk.HkUtils;
 import com.gzlh.config.hksdk.bo.HKCacheManager;
 import com.gzlh.config.task.TaskService;
 import com.gzlh.device.capture.brand.CaptureBrandType;
+import com.gzlh.device.face.CheckFaceGateOnlineTask;
+import com.gzlh.device.face.LoginFaceGate;
 import com.gzlh.device.print.client.CheckPrintOnlineTask;
 import com.gzlh.device.rfid.client.ElectronNettyConfig;
 import com.gzlh.device.led.client.LedNettyConfig;
@@ -30,6 +34,7 @@ import org.springframework.boot.CommandLineRunner;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
+import java.util.List;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -115,6 +120,15 @@ public class StartupRunner implements CommandLineRunner {
                 ThreadUtil.execute(new InitHxSDK());
             }
         }
+
+        FaceListDTO faceListDTO = SysConfig.faceDTO;
+        if (faceListDTO.getEnable()) {
+            List<FaceDTO> faceDTOList = faceListDTO.getFace();
+            faceDTOList.forEach(faceDTO -> ThreadUtil.execute(new LoginFaceGate(faceDTO)));
+            ThreadUtil.execute(new CheckFaceGateOnlineTask());
+        }
+
+
     }
 
 

+ 19 - 0
src/main/java/com/gzlh/utils/FileUtils.java

@@ -11,7 +11,26 @@ import java.util.Calendar;
 public class FileUtils {
 
 
+    public static FileInputStream convertBase64ToFileInputStream(String base64String) throws IOException {
+        // 移除 base64 字符串中可能包含的 header(如:"data:image/jpeg;base64,")
+        if (base64String.contains(",")) {
+            base64String = base64String.split(",")[1];
+        }
+
+        // 将 base64 解码为字节数组
+        byte[] imageBytes = Base64.getDecoder().decode(base64String);
+
+        // 创建临时文件
+        File tempFile = File.createTempFile("temp_image", ".tmp");
 
+        // 将字节数组写入临时文件
+        try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) {
+            fileOutputStream.write(imageBytes);
+        }
+
+        // 创建并返回 FileInputStream
+        return new FileInputStream(tempFile);
+    }
 
 
     public static String downLoad(String urlString,String savePath) throws IOException {

+ 8 - 1
src/main/resources/application.yml

@@ -18,4 +18,11 @@ hk:
   lib-home: E:\libs\hklib
   lib-path: ${hk.lib-home}\HCNetSDK.dll
   linux-libcrypto-path: ${hk.lib-home}/libcrypto.so.1.1
-  linux-libssl-path: ${hk.lib-home}/libssl.so.1.1
+  linux-libssl-path: ${hk.lib-home}/libssl.so.1.1
+
+external:
+    base-url: http://external-service.com
+    status-callback-path: ${external.service}/api/barrier/status-callback
+    status-report-interval: 30000
+    face-status-callback-path:  ${external.service}/api/face-status-callback
+    face-open-gate-path:  ${external.service}/api/face-open-callback