whyclxw
2025-01-08 a049ec5d9624662eb9807d9501c0ac811cf4249e
人脸识别
28个文件已添加
10个文件已修改
1272 ■■■■■ 已修改文件
pom.xml 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/constant/YamlProperties.java 106 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/controller/FaceController.java 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/controller/LoginController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/dto/Response.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/factory/FaceEngineFactory.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/factory/ThreadPoolExecutorFactory.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/factory/UserThreadFactory.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/mapper/FaceMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/pojo/db_user/UserClient.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/pojo/db_user/UserFace.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/pojo/db_user/UserInf.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/service/FaceService.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/service/UserInfService.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/util/CommonUtil.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/util/FaceIdentifyUtil.java 243 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/application-dev.yml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/application-prod-ssl.yml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/application-prod.yml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/8611-11H3-Z13R-7HL1.dat 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/LINUX64/libarcsoft_face.so 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/LINUX64/libarcsoft_face_engine.so 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/LINUX64/libarcsoft_face_engine_jni.so 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/LINUX64PRO/libarcsoft_face.so 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/LINUX64PRO/libarcsoft_face_engine.so 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/LINUX64PRO/libarcsoft_face_engine_jni.so 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/WIN64/libarcsoft_face.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/WIN64/libarcsoft_face_engine.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/WIN64/libarcsoft_face_engine_jni.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/WIN64PRO/libarcsoft_face.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/WIN64PRO/libarcsoft_face_engine.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/WIN64PRO/libarcsoft_face_engine_jni.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/arcsoft-sdk-face-3.0.0.0.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/arcsoft-sdk-face-3.1.1.0.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/jacob.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/tomcat-embed-core-9.0.30.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/tomcat-embed-core-9.0.93.jar 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/FaceMapper.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -151,12 +151,101 @@
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>
        <!--common-codec加密-->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.54</version>
        </dependency>
        <!--commons.lang3  RSA签名验证md5使用-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!--外部引入-人脸识别sdk-->
        <!--免费版 V3.0-->
        <dependency>
            <groupId>com.whyc</groupId>
            <artifactId>face</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${pom.basedir}/src/main/resources/lib/arcsoft-sdk-face-3.0.0.0.jar</systemPath>
        </dependency>
        <!--增值版 V3.1-->
        <!--<dependency>
            <groupId>com.whyc</groupId>
            <artifactId>face</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${pom.basedir}/src/main/resources/lib/arcsoft-sdk-face-3.1.1.0.jar</systemPath>
        </dependency>-->
        <!--<dependency>
            <groupId>org.tensorflow</groupId>
            <artifactId>tensorflow</artifactId>
            <version>1.15.0</version>
        </dependency>-->
        <!-- https://mvnrepository.com/artifact/net.sf.jacob-project/jacob -->
        <dependency>
            <groupId>net.sf.jacob-project</groupId>
            <artifactId>jacob</artifactId>
            <version>1.17-M2</version>
            <scope>system</scope>
            <systemPath>${pom.basedir}/src/main/resources/lib/jacob.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>0.0.0</version>
            <scope>system</scope>
            <systemPath>${pom.basedir}/src/main/resources/lib/tomcat-embed-core-9.0.93.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.8.0</version>
        </dependency>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna-platform</artifactId>
            <version>5.8.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.oshi</groupId>
            <artifactId>oshi-core</artifactId>
            <version>5.6.1</version>
            <exclusions>
                <exclusion>
                    <groupId>net.java.dev.jna</groupId>
                    <artifactId>jna</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>net.java.dev.jna</groupId>
                    <artifactId>jna-platform</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.8</version>
        </dependency>
        <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.15.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
src/main/java/com/whyc/constant/YamlProperties.java
@@ -22,32 +22,20 @@
    public static Integer systemType;
    /**人脸识别对比阈值*/
    //public static Float faceThreshold;
    public static Float faceThreshold;
    /**告警短信开关*/
   /* public static String messageSwitch;
    public static String messageSecretId;
    public static String messageSecretKey;
    public static String messageRegion;
    public static String messageSdkAppId;
    public static String messageSignName;
    public static String messageTemplateId;*/
   /* public static String appId4Win;
    public static String sdkKey4Win;
    public static String appId4Linux;
    public static String sdkKey4Linux;*/
    /**告警工单开关*/
    //public static String alarmTaskSwitch;
    /**系统运行模式*/
    public static Integer runModel;
    /**FTP信息*/
    /*public static String ftpIp;
    public static Integer ftpPort;
    public static String ftpUserName;
    public static String ftpPassword;*/
    public static String appId4Win;
    public static String sdkKey4Win;
    public static String appId4Linux;
    public static String sdkKey4Linux;
    public static String activeKey;
    public static Integer faceType;
    /*====== 自定义信息 ======*/
@@ -80,55 +68,25 @@
    public void setSystemType(Integer systemType) {
        YamlProperties.systemType = systemType;
    }
/*
    @Value("${custom.face.threshold}")
    private void setFaceThreshold(Float faceThreshold) {
        YamlProperties.faceThreshold = faceThreshold;
    }*/
/*
    @Value("${custom.message.switch}")
    private void setMessageSwitch(String messageSwitch) {
        YamlProperties.messageSwitch = messageSwitch;
    }*/
/*
    @Value("${custom.message.secret_id}")
    private void setMessageSecretId(String messageSecretId) {
        YamlProperties.messageSecretId = messageSecretId;
    }
*/
    /*@Value("${custom.message.secret_key}")
    private void setMessageSecretKey(String messageSecretKey) {
        YamlProperties.messageSecretKey = messageSecretKey;
    @Value("${configFile.type}")
    public void setRunModel(Integer runModel) {
        YamlProperties.runModel = runModel;
    }
    @Value("${custom.message.region}")
    private void setMessageRegion(String messageRegion) {
        YamlProperties.messageRegion = messageRegion;
    @Value("${custom.face.activeKey}")
    private void setActiveKey(String activeKey) {
        YamlProperties.activeKey = activeKey;
    }
    @Value("${custom.message.smsSdkAppId}")
    private void setMessageSdkAppId(String messageSdkAppId) {
        YamlProperties.messageSdkAppId = messageSdkAppId;
    @Value("${custom.face.type}")
    public void setFaceType(Integer faceType) {
        YamlProperties.faceType = faceType;
    }
    @Value("${custom.message.signName}")
    private void setMessageSignName(String messageSignName) {
        YamlProperties.messageSignName = messageSignName;
    }
    @Value("${custom.message.templateId}")
    private void setMessageTemplateId(String messageTemplateId) {
        YamlProperties.messageTemplateId = messageTemplateId;
    }*/
   /* @Value("${custom.alarm.task.switch}")
    private void setAlarmTaskSwitch(String alarmTaskSwitch) {
        YamlProperties.alarmTaskSwitch = alarmTaskSwitch;
    }
*/
    /*@Value("${custom.face.appId4Win}")
    @Value("${custom.face.appId4Win}")
    private void setAppId4Win(String appId4Win) {
        YamlProperties.appId4Win = appId4Win;
    }
@@ -146,32 +104,10 @@
    @Value("${custom.face.sdkKey4Linux}")
    private void setSdkKey4Linux(String sdkKey4Linux) {
        YamlProperties.sdkKey4Linux = sdkKey4Linux;
    }*/
    @Value("${configFile.type}")
    public void setRunModel(Integer runModel) {
        YamlProperties.runModel = runModel;
    }
    /*@Value("${ftpInforMation.ftpIp}")
    public void setFtpIp(String ftpIp){
        YamlProperties.ftpIp=ftpIp;
    @Value("${custom.face.threshold}")
    private void setFaceThreshold(Float faceThreshold) {
        YamlProperties.faceThreshold = faceThreshold;
    }
    @Value("${ftpInforMation.ftpPort}")
    public void setFtpPort(Integer ftpPort){
        YamlProperties.ftpPort=ftpPort;
    }
    @Value("${ftpInforMation.ftpUserName}")
    public void setFtpUserName(String ftpUserName){
        YamlProperties.ftpUserName=ftpUserName;
    }
    @Value("${ftpInforMation.ftpPassword}")
    public void setFtpPassword(String ftpPassword){
        YamlProperties.ftpPassword=ftpPassword;
    }*/
}
src/main/java/com/whyc/controller/FaceController.java
New file
@@ -0,0 +1,411 @@
package com.whyc.controller;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.whyc.constant.YamlProperties;
import com.whyc.dto.Response;
import com.whyc.factory.FaceEngineFactory;
import com.whyc.pojo.db_user.UserInf;
import com.whyc.service.FaceService;
import com.whyc.service.UserInfService;
import com.whyc.util.ActionUtil;
import com.whyc.util.CommonUtil;
import com.whyc.util.FaceIdentifyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Decoder;
import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * 人脸识别
 */
@RequestMapping("face")
@RestController
@Api(tags = "用户管理-人脸识别")
public class FaceController {
    @Resource
    private FaceService service;
    @Resource
    private UserInfService userService;
    //@Resource
    //private MapOutlineService mapOutlineService;
    @GetMapping("activeOnline")
    @ApiOperation(value = "在线激活人脸识别引擎",notes = "只需要刚开始时调用一次,会导致appId与硬件设备绑定,必须有外部网络,否则激活会失败!" +
            "后续使用无需再调用激活,可以离线使用")
    public Response activeOnline(){
        boolean b = FaceIdentifyUtil.active(1);
        if(b){
            return new Response().set(1,true,"引擎激活成功");
        }else{
            return new Response().set(1,false,"引擎激活失败,请检查网络是否为外网并确认appId和key是否正确!");
        }
    }
    @GetMapping("activeOffline")
    @ApiOperation(value = "离线激活人脸识别引擎,增值版使用")
    public Response activeOffline(){
        boolean b = FaceIdentifyUtil.active(2);
        if(b){
            return new Response().set(1,true,"引擎激活成功");
        }else{
            return new Response().set(1,false,"引擎激活失败,请检查网络是否为外网并确认appId和key是否正确!");
        }
    }
    @PostMapping
    @ApiOperation(value = "添加",notes = "添加到人脸库")
    public Response add(@RequestBody Map<String,Object> paramMap ){
        String fileData = (String) paramMap.get("fileData");
        String uName  = (String) paramMap.get("uName");
        //过滤 uName的特殊字符,避免路径遍历攻击
        uName = ActionUtil.filterFileName(uName);
        Integer uId  = Integer.parseInt((String)paramMap.get("uId"));
        //传参 uId,uName,fileData--文件流
        fileData = fileData.replaceAll(" ", "+");
        //由于图片字符串是由base64编码的,解码成字节数组
        //data:image/jpeg;base64,
        // fileData = fileData.replaceAll("data:image/jpeg;base64,","");
        fileData = fileData.split(",")[1];
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] dataBytes = new byte[0];
        try {
            dataBytes = decoder.decodeBuffer(fileData);
            /*for (int i = 0; i < dataBytes.length; ++i) {
                if (dataBytes[i] < 0) {// 调整异常数据
                    dataBytes[i] += 256;
                }
            }*/
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*=========检查图片是否有效=======*/
        //检验图片是否有效
        ImageInfo imageInfo = ImageFactory.getRGBData(dataBytes);
        //初始化引擎
//        FaceEngine faceEngine = FaceIdentifyUtil.init();
        FaceEngine faceEngine = FaceEngineFactory.getInstance();
        if (faceEngine==null){
            return new Response().set(1,false,"初始化引擎失败");
        }else {
            //检查角度是否端正,检查人脸像素大小是否>50×50
            Response checkRes1 = FaceIdentifyUtil.orientAndPxDetect(faceEngine,imageInfo);
            if((boolean)checkRes1.getData()){
                /*=========图片保存===========*/
                ApplicationHome applicationHome = new ApplicationHome(getClass());
                File jarFile = applicationHome.getDir();
                //存储人脸图片的文件夹
                String fileDirName;
                if(YamlProperties.runModel == 1) {
                    fileDirName = jarFile.getParentFile().toString() + File.separator + "fg_photo";
                }else{
                    fileDirName = jarFile.toString() + File.separator + "fg_photo";
                }
                File file = new File(fileDirName);
                //不存在则创建该文件夹
                if (!file.exists()) {
                    file.mkdirs();
                }
                //文件全路径
                String fileName = fileDirName + File.separator + uName + ".jpg";
                FileOutputStream fot=null;
                try {
                    fot = new FileOutputStream(fileName);
                    fot.write(dataBytes);
                    fot.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if(fot!=null){
                        try {
                            fot.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                /*=========数据库表更新===========*/
                // model = service.add(uId, uName, projectName);
                service.add(uId, uName, fileName);
                return new Response().set(1,true,"新增成功");
            }
            return checkRes1;
        }
    }
    /**
     * 人脸库管理: 更新
     * @return
     */
    @PostMapping("update")
    @ApiOperation(value = "更新")
    public Response update(@RequestBody String fileData,@RequestParam String uName){
        //传参,uName,fileData--文件流
        //过滤 uName的特殊字符,避免路径遍历攻击
        uName = ActionUtil.filterFileName(uName);
        //由于图片字符串是由base64编码的,解码成字节数组
        fileData = fileData.replaceAll(" ", "+");
        fileData = fileData.split(",")[1];
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] dataBytes = new byte[0];
        try {
            dataBytes = decoder.decodeBuffer(fileData);
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*=========检查图片是否有效=======*/
        //检验图片是否有效
        //获取图像信息
        ImageInfo imageInfo = ImageFactory.getRGBData(dataBytes);
        //初始化引擎
//        FaceEngine faceEngine = FaceIdentifyUtil.init();
        FaceEngine faceEngine = FaceEngineFactory.getInstance();
        if (faceEngine==null){
            return new Response().set(1,false,"初始化引擎失败");
        }else {
            //检测图片
            Response checkRes1 = FaceIdentifyUtil.orientAndPxDetect(faceEngine, imageInfo);
            if ((boolean)checkRes1.getData()) {
                /*=========图片保存===========*/
                ApplicationHome applicationHome = new ApplicationHome(getClass());
                File jarFile = applicationHome.getDir();
                //存储人脸图片的文件夹
                String fileDirName;
                if(YamlProperties.runModel == 1) {
                    fileDirName = jarFile.getParentFile().toString() + File.separator + "fg_photo";
                }else{
                    fileDirName = jarFile.toString() + File.separator + "fg_photo";
                }
                File file = new File(fileDirName);
                //不存在则创建该文件夹
                if (!file.exists()) {
                    file.mkdirs();
                }
                //文件全路径
                String fileName = fileDirName + File.separator + uName + ".jpg";
                FileOutputStream fot =null;
                try {
                    fot = new FileOutputStream(fileName);
                    fot.write(dataBytes);
                    fot.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if(fot!=null){
                        try {
                            fot.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                return new Response().set(1,"更新成功");
            }
            return checkRes1;
        }
    }
    /**
     * 人脸库管理: 删除
     * @return
     */
    @PostMapping("delete")
    @ApiOperation(value = "删除")
    @Transactional
    public Response delete(@RequestParam Integer uId,@RequestParam Integer faceId,
                         @RequestParam String uName,HttpServletRequest request){
        //过滤 uName的特殊字符,避免路径遍历攻击
        uName = ActionUtil.filterFileName(uName);
        //更新user_inf和face表
        service.update(uId,faceId);
        //删除图片
        //获取到图片所在文件夹的全路径
        String fileName = findFileDirPath(request);
        //获取图片的全路径
        File file = new File(fileName+File.separator+uName+".jpg");
        if(file.exists()){
            file.delete();
        }
        return new Response().set(1,"删除成功");
    }
    /**获取图片文件夹全路径
     * @param request*/
    private String findFileDirPath(HttpServletRequest request) {
        ApplicationHome applicationHome = new ApplicationHome(getClass());
        File jarFile = applicationHome.getDir();
        //在jar包所在目录下生成一个upload文件夹用来存储上传的图片
        return jarFile.getParentFile().toString()+File.separator+"fg_photo";
    }
    /**获取图片的http加载url*/
    private String findWebPhotoUrl(String uName){
        HttpServletRequest request = ActionUtil.getRequest();
        //获取项目名称
        String realPath = ActionUtil.getApplication().getRealPath("/");
        //String[] split = realPath.split("/");
        String[] split = realPath.split(File.separator);
        String projectName = split[split.length - 1];
        //图片保存路径,采取ip+port访问形式而非硬盘形式,方便图片加载
        String url = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/"+projectName+"_photo/"+uName+".jpg";
        return url;
    }
    /**
     * 人脸库管理: 查询分页列表
     * 现在逻辑是当前用户查询自己的人脸信息
     * @return
     */
    @GetMapping("info")
    @ApiOperation(value = "查询人脸信息")
    public Response getInfo(HttpServletRequest request){
        //传入pageNum,pageSize
        UserInf userInf = (UserInf) request.getSession().getAttribute("user");
        UserInf user = service.getInfo(userInf.getUid());
        return new Response().set(1,user);
    }
    /**
     * 人脸识别: 活体检验,相似度对比,1比N
     */
    @PostMapping("faceCompare2N")
    @ApiOperation(value = "人脸识别对比")
    public Response faceCompare2N(@RequestBody String fileData,@RequestParam String uKeyId,HttpServletRequest request){
        Response res = new Response();
        //先验证uKeyId对应的用户
        UserInf userByUKeyId = userService.getUserByUKeyId(uKeyId);
        if (userByUKeyId == null){
            return res.set(1,false,"Ukey没有绑定用户");
        }
        /*====获取图片并校验活体,角度,像素大小====*/
        //由于图片字符串是由base64编码的,解码成字节数组
        fileData = fileData.replaceAll(" ", "+");
        fileData = fileData.split(",")[1];
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] dataBytes = new byte[0];
        try {
            dataBytes = decoder.decodeBuffer(fileData);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ImageInfo imageInfo = ImageFactory.getRGBData(dataBytes);
        FaceEngine faceEngine = FaceEngineFactory.getInstance();
        if(faceEngine!=null) {
            res = FaceIdentifyUtil.liveDetect(faceEngine, imageInfo);
            //活体校验通过
            if (res.getCode() == 1) {
                res = FaceIdentifyUtil.orientAndPxDetect(faceEngine, imageInfo);
                //人像角度,大小校验通过
                if((boolean) res.getData()) {
                    //重置标识
                    res.setData(null);
                    res.setMsg(null);
                    //获取数据库中所有的人脸图片
                    List<UserInf> userInfList = service.findAllFaceUrl();
                    if(userInfList.size()==0){
                        res.setCode(0);
                        res.setMsg("人脸库暂无任何数据");
                    }else{
                        boolean urlExist = false;
                        for (UserInf temp:userInfList){
                            String filePath = temp.getFace().getUrl();
                            File file = new File(filePath);
                            //不存在则不继续执行
                            if(!file.exists()){
                                continue;
                            }else{
                                urlExist = true;
                            }
                            ImageInfo imageInfo2 = ImageFactory.getRGBData(file);
                            res = FaceIdentifyUtil.faceCompare(faceEngine, imageInfo, imageInfo2);
                            //对比成功,记录用户登录信息
                            if((boolean) res.getData()){
                                //Ukey对应用户和人脸对应用户验证
                                if(!(temp.getUid()==userByUKeyId.getUid())){
                                    return res.set(1,false,"UKey对应用户和当前人脸对应用户不匹配");
                                }
                                List<Object> dataList = new ArrayList<>();
                                dataList.add(temp);
                                // 将登陆成功的用户存入session
                                ServletContext servletContext = request.getServletContext();
                                servletContext.setAttribute(temp.getUname(), request.getSession().getId());
                                ActionUtil.getSession().setAttribute("user", temp);
                                //设置session不活动时间为30分
                                ActionUtil.getSession().setMaxInactiveInterval(60 * 30);
                                ActionUtil.getSession().setAttribute("ip", ActionUtil.getRequest().getRemoteAddr());
                               /* List<PermitGroup> permitList = permitGroupUserService.getPermitByUser(temp.getUId());
                                if (permitList!=null && permitList.size()!=0) {
                                    dataList.add(permitList.get(0).getPermitGroupId());
                                    ActionUtil.getSession().setAttribute("permits", permitList);
                                } else {
                                    res.setCode(1);
                                    res.setData(false);
                                    res.setMsg("还未分配权限");
                                }
*/
                                //查询用户对应的班组标识
                                //dataList.add(baoJiGroupUserService.getGroupFlag(temp.getUId().intValue()));
                                //查询激活的地图
                                //String mapName = mapOutlineService.selectMapName();
                               //dataList.add(mapName);
                                //CommonUtil.record(temp.getUId(), UserOperation.TYPE_LOGIN.getType(), UserOperation.TYPE_LOGIN.getTypeName(), UserOperation.TYPE_LOGIN.getTypeNameEn());
                                res.setData2(dataList);
                                //将新登录的用户存入application
                                userService.setApplication(temp);
                            }
                        }
                        if(!urlExist){
                            res.set(1,false,"ukey对应的人脸库路径不存在");
                        }
                    }
                }
            }
        }else{
            res.setCode(0);
            res.setMsg("初始化引擎失败");
        }
        return res;
    }
}
src/main/java/com/whyc/controller/LoginController.java
@@ -47,4 +47,10 @@
        return new Response().set(1, true);
    }
    @ApiOperation(value = "test测试平台正确性")
    @GetMapping("test")
    public Response test() {
        return new Response().set(1, true);
    }
}
src/main/java/com/whyc/dto/Response.java
@@ -14,6 +14,16 @@
    private T data4;
    private T data5;
    private String msg;
    public Response<T> setCode(Integer code) {
        this.code = code;
        return this;
    }
    public Response<T> setData(T data) {
        this.data = data;
        return this;
    }
    public Response<T> set(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
src/main/java/com/whyc/factory/FaceEngineFactory.java
New file
@@ -0,0 +1,16 @@
package com.whyc.factory;
import com.arcsoft.face.FaceEngine;
import com.whyc.util.FaceIdentifyUtil;
/**
 * 单例工厂,获取FaceEngine:
 * 采取恶汉模式
 */
public class FaceEngineFactory {
    private static FaceEngine faceEngine = FaceIdentifyUtil.init();
    public static FaceEngine getInstance(){
        return faceEngine;
    }
}
src/main/java/com/whyc/factory/ThreadPoolExecutorFactory.java
New file
@@ -0,0 +1,23 @@
package com.whyc.factory;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorFactory {
    private static ThreadPoolExecutor poolExecutor = init();
    private static ThreadPoolExecutor init() {
        //线程池初始化
        UserThreadFactory userThreadFactory = new UserThreadFactory("fg");
        ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 48, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(16), userThreadFactory,new ThreadPoolExecutor.CallerRunsPolicy());
        poolExecutor = pool;
        return pool;
    }
    public static ThreadPoolExecutor getPoolExecutor() {
        return poolExecutor;
    }
}
src/main/java/com/whyc/factory/UserThreadFactory.java
New file
@@ -0,0 +1,23 @@
package com.whyc.factory;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class UserThreadFactory implements ThreadFactory {
    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);
    // 定义线程组名称,在 jstack 问题排查时,非常有帮助
    public UserThreadFactory(String whatFeaturOfGroup) {
        namePrefix = "From UserThreadFactory's " + whatFeaturOfGroup + "-Worker-";
    }
    @Override
    public Thread newThread(Runnable task) {
        String name = namePrefix + nextId.getAndIncrement();
        return new Thread(task, name);
    }
    public static boolean flag = true;
}
src/main/java/com/whyc/mapper/FaceMapper.java
New file
@@ -0,0 +1,14 @@
package com.whyc.mapper;
import com.whyc.pojo.db_user.UserInf;
import java.util.List;
public interface FaceMapper<UserFace> extends CustomMapper<UserFace> {
    UserInf getInfo(int uId);
    List<UserInf> findAllFaceUrl();
}
src/main/java/com/whyc/pojo/db_user/UserClient.java
New file
@@ -0,0 +1,51 @@
package com.whyc.pojo.db_user;
public class UserClient {
    /**客户端ip地址 */
    public String ip;
    /** 客户端用户信息*/
    public UserInf user;
    /** 客户端登录时间的毫秒数*/
    public Long login_times;
    public UserClient() {
    }
    public UserClient(String ip, UserInf user) {
        super();
        this.ip = ip;
        this.user = user;
    }
    public UserClient(String ip, UserInf user, Long login_times) {
        super();
        this.ip = ip;
        this.user = user;
        this.login_times = login_times;
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public UserInf getUser() {
        return user;
    }
    public void setUser(UserInf user) {
        this.user = user;
    }
    public Long getLogin_times() {
        return login_times;
    }
    public void setLogin_times(Long login_times) {
        this.login_times = login_times;
    }
}
src/main/java/com/whyc/pojo/db_user/UserFace.java
New file
@@ -0,0 +1,48 @@
package com.whyc.pojo.db_user;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.ToString;
/**
 * 人脸识别
 */
@Data
@ToString
@TableName(schema = "db_user",value = "tb_user_face")
@ApiModel(value="UserFace对象", description="")
public class UserFace {
    @TableId
    private Integer id;
    /**人脸图片路径,http*/
    private String url;
    public UserFace() {
    }
    public UserFace(String url) {
        this.url = url;
    }
    public UserFace(Integer id, String url) {
        this.id = id;
        this.url = url;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
}
src/main/java/com/whyc/pojo/db_user/UserInf.java
@@ -58,12 +58,18 @@
    @ApiModelProperty(value = "地址")
    private String address;
    @ApiModelProperty(value = "人脸库id")
    private Integer faceId;
    @TableField(exist = false)
    private List<AreaInf> ainfList;
    @TableField(exist = false)
    private List<Integer> idList;
    @TableField(exist = false)
    private UserFace face;
    public UserInf(int uid, String uname) {
        this.uid = uid;
src/main/java/com/whyc/service/FaceService.java
New file
@@ -0,0 +1,74 @@
package com.whyc.service;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.whyc.mapper.FaceMapper;
import com.whyc.mapper.UserInfMapper;
import com.whyc.pojo.db_user.UserFace;
import com.whyc.pojo.db_user.UserInf;
import com.whyc.util.ActionUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
public class FaceService {
    @Resource
    private FaceMapper mapper;
    @Resource
    private UserInfMapper userMapper;
    /**
     * 两种分页:mybatis-plus自带和PageHelper的自定义
     * @param
     * @param uId
     * @return
     */
    /*public List<UserFace> getPage(PageInfo page, int uId) {
        PageInfo<Face> pageInfo = mapper.findAll(page,uId);
        model.setCode(1);
        model.setData(pageInfo);
        return model;
    }*/
    @Transactional
    public boolean add(int uId, String uName, String fileName) {
        //人脸表新增记录
        UserFace userFace = new UserFace(fileName);
        mapper.insert(userFace);
        //用户表关联新增的人脸表记录id
        UpdateWrapper<UserInf> wrapper = Wrappers.update();
        wrapper.set("face_id",userFace.getId()).eq("uid",uId);
        userMapper.update((UserInf) ActionUtil.objeNull,wrapper);
        return true;
    }
    /**TODO 待错误测试*/
    /**逻辑删除,取消用户与图片的关系*/
    public boolean update(int uId,int faceId) {
        //人脸表删除记录
        mapper.deleteById(faceId);
        //用户表关联新增的人脸表记录id
        UpdateWrapper<UserInf> wrapper = Wrappers.update();
        wrapper.set("face_id",null).eq("uId",uId);
        userMapper.update((UserInf) ActionUtil.objeNull,wrapper);
        return true;
    }
    public UserInf getInfo(int uId) {
        return mapper.getInfo(uId);
    }
    public List<UserInf> findAllFaceUrl() {
        return mapper.findAllFaceUrl();
    }
}
src/main/java/com/whyc/service/UserInfService.java
@@ -8,10 +8,10 @@
import com.whyc.dto.Response;
import com.whyc.mapper.*;
import com.whyc.pojo.db_area.*;
import com.whyc.pojo.db_user.UserClient;
import com.whyc.pojo.db_user.UserInf;
import com.whyc.util.ActionUtil;
import com.whyc.util.MD5Util;
import com.whyc.util.PageInfoUtils;
import com.whyc.util.RSAUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UnknownAccountException;
@@ -20,14 +20,11 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -373,4 +370,31 @@
        }
        return new Response().set(1,true,"编辑用户信息成功");
    }
    public UserInf getUserByUKeyId(String uKeyId){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("uKey_ID",uKeyId);
        UserInf userInf = mapper.selectOne(queryWrapper);
        return userInf;
    }
    // 将所有登陆的用户的信息存到application中
    public void setApplication(UserInf user) {
        ServletContext application = ActionUtil.getApplication();
        //查看全局中存储的users的Map的key-value集合
        Map<String, UserClient> map = (Map) application.getAttribute("users");
        if (map == ActionUtil.objeNull) {
            map = new HashMap<String, UserClient>();
        } else {
            //如果集合中有值,则获取当前用户对应的用户信息,key为用户名username,Value为用户名,存储的时间
            UserClient client = map.get(user.getUname());
            if (client != ActionUtil.objeNull) { //已存在
                map.remove(user.getUname());
            }
        }
        Long login_time = new Date().getTime();
        ActionUtil.getSession().setAttribute("login_time", login_time);
        map.put(user.getUname(), new UserClient(ActionUtil.getRequest().getRemoteAddr(),user,login_time));
        application.setAttribute("users", map);
    }
}
src/main/java/com/whyc/util/CommonUtil.java
@@ -1,7 +1,13 @@
package com.whyc.util;
import com.whyc.constant.YamlProperties;
import com.whyc.pojo.db_user.UserInf;
import com.whyc.service.OperationLogService;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
/**
 * 通用工具列
@@ -31,6 +37,48 @@
        service.record(type1, type2, msg, msgDetail);
    }
    /**获取当前Session中的属性user*/
    public static UserInf getUser(HttpServletRequest request) {
        return (UserInf) request.getSession().getAttribute("user");
    }
    public static String classesPath(){
        ApplicationHome applicationHome = new ApplicationHome(CommonUtil.class);
        File jarFile = applicationHome.getDir();
        return jarFile.toString();
    }
    public static String getRootFile(){
        ApplicationHome applicationHome = new ApplicationHome(CommonUtil.class);
        File jarFile = applicationHome.getDir();
        String baseDirPath;
        if(YamlProperties.runModel == 1) {
            //开发路径
            baseDirPath = jarFile.getParentFile().toString()+File.separator+"fg_file"+File.separator;
        }else {
            //打包路径
            baseDirPath = jarFile.toString()+File.separator+"fg_file"+File.separator;
        }
        return baseDirPath;
    }
    /**
     * 获取项目所在文件夹路径
     * @return 获取项目所在文件夹路径
     */
    public static String getProjectDir(){
        ApplicationHome applicationHome = new ApplicationHome(CommonUtil.class);
        File jarFile = applicationHome.getDir();
        String baseDirPath;
        if (YamlProperties.runModel == 1) {
            //开发路径
            baseDirPath = jarFile.getParentFile().toString();
        } else {
            //打包路径
            baseDirPath = jarFile.toString();
        }
        return baseDirPath;
    }
src/main/java/com/whyc/util/FaceIdentifyUtil.java
New file
@@ -0,0 +1,243 @@
package com.whyc.util;
import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.toolkit.ImageInfo;
import com.whyc.constant.YamlProperties;
import com.whyc.dto.Response;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
 * @Description : 虹软人脸识别工具类
 * @date 2020/10/28
 **/
public class FaceIdentifyUtil {
    //外网激活
    public static boolean active(int activeType){
        boolean res = false;
        String appId="";
        String sdkKey="";
        String activeKey = YamlProperties.activeKey;
        Integer faceType = YamlProperties.faceType;
        FaceEngine faceEngine =null;
        /*//从官网我的应用中获取
        String appId4Win = "AafPX5afzycEnTqH3v79gY3VozNVTSNqT8kzSmP7b48q";
        String sdkKey4Win = "GsYwWhxzuQEE1WE34J3Fo8d2QppjkqYGojyc4625JhKb";
        //Linux系统appId和sdkKey及文件加载
        String appId4Linux ="AafPX5afzycEnTqH3v79gY3VozNVTSNqT8kzSmP7b48q";
        String sdkKey4Linux ="GsYwWhxzuQEE1WE34J3Fo8d2GiFdddqH81ghetQQTGmv";*/
        //从官网我的应用中获取
        String appId4Win = YamlProperties.appId4Win;
        String sdkKey4Win = YamlProperties.sdkKey4Win;
        //Linux系统appId和sdkKey及文件加载
        String appId4Linux =YamlProperties.appId4Linux;
        String sdkKey4Linux =YamlProperties.sdkKey4Linux;
        //String realPath = ActionUtil.getApplication().getRealPath("/");
        String realPath = CommonUtil.classesPath();
        System.out.println("========realPath=========:"+realPath);
        System.out.println("========faceEngine dll 路径=========:"+realPath+ File.separator+"lib"+File.separator+"WIN64");
        //FaceEngine获取,判断是什么系统和什么版本
        if(System.getProperty("os.name").toLowerCase().contains("window")){
            appId = appId4Win;
            sdkKey = sdkKey4Win;
            if(faceType == 1 //免费版
            ) {
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "WIN64");
            }else{ //付费版永久
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "WIN64PRO");
            }
        }else{
            appId=appId4Linux;
            sdkKey=sdkKey4Linux;
            if(faceType == 1 //免费版
            ) {
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "LINUX64");
            }else{ //付费版永久
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "LINUX64PRO");
            }
        }
        //激活引擎,只需一次就行,后续无需再激活
        int errorCode = 666;
        /**========需要免费版的依赖包才能调用 Start========*/
        errorCode = faceEngine.activeOnline(appId, sdkKey);
        /**========需要免费版的依赖包才能调用 End========*/
        /**========需要增值版的依赖包才能调用 Start========*/
        /*if(activeType == 1){ //在线激活
            errorCode = faceEngine.activeOnline(appId,sdkKey,activeKey);
        }else if(activeType == 2){ //离线激活
            //先服务器生成离线授权文件,离线.dat文件放在 lib下即可
            errorCode = faceEngine.activeOffline(realPath + File.separator + "lib" + File.separator + activeKey+".dat");
        }*/
        /**========需要增值版的依赖包才能调用 End========*/
        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            //激活失败
        }else{
            res=true;
        }
        return res;
    }
    /**初始化*/
    public static FaceEngine init(){
        FaceEngine faceEngine=null;
        String realPath = CommonUtil.classesPath();
        if(System.getProperty("os.name").toLowerCase().contains("window")) {
            if(YamlProperties.faceType == 1 //免费版
            ) {
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "WIN64");
            }else{ //付费版永久
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "WIN64PRO");
            }
        }else{
            if(YamlProperties.faceType == 1 //免费版
            ) {
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "LINUX64");
            }else{ //付费版永久
                faceEngine = new FaceEngine(realPath + File.separator + "lib" + File.separator + "LINUX64PRO");
            }
        }
        //引擎配置
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
        //对特定场景推荐单一角度而非全角度,那样精度更高
        engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
        //最多支持的人脸数量
        // engineConfiguration.setDetectFaceMaxNum(10);
        engineConfiguration.setDetectFaceMaxNum(1);
        engineConfiguration.setDetectFaceScaleVal(16);
        //功能配置
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        // functionConfiguration.setSupportAge(true);
        functionConfiguration.setSupportFace3dAngle(true);
        functionConfiguration.setSupportFaceDetect(true);
        functionConfiguration.setSupportFaceRecognition(true);
        // functionConfiguration.setSupportGender(true);
        functionConfiguration.setSupportLiveness(true);
        // functionConfiguration.setSupportIRLiveness(true);
        engineConfiguration.setFunctionConfiguration(functionConfiguration);
        //初始化引擎
        int errorCode = faceEngine.init(engineConfiguration);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            String errorCodeStr = ErrorInfo.getValidEnum(errorCode).name();
            System.out.println("初始化引擎失败,错误码:"+errorCode+",错误码解释:"+errorCodeStr);
            return null;
        }
        System.out.println("初始化faceEngine引擎成功");
        return faceEngine;
    }
    public static Response orientAndPxDetect(FaceEngine faceEngine, ImageInfo imageInfo) {
        //检查角度是否端正,检查人脸像素大小是否>50×50
        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
        faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
        if (faceInfoList.size()<1){
            return new Response().set(1,false,"无效的人脸信息");
        }else {
            FaceInfo faceInfo = faceInfoList.get(0);
            Rect rect = faceInfo.getRect();
            if (faceInfo.getOrient() != 1) {
                return new Response().set(1,false,"人像姿势不端正");
            } else if ((rect.bottom - rect.top) < 50 || (rect.right - rect.left) < 50) {
                return new Response().set(1,false,"人像面部像素太低");
            }
        }
        return new Response().set(1,true,"校验通过");
    }
    public static Response liveDetect(FaceEngine faceEngine, ImageInfo imageInfo) {
        Response res = new Response();
        int errorCode=0;
        List<FaceInfo> faceInfoList = new ArrayList<>();
        List<LivenessInfo> livenessInfoList = new ArrayList<>();
        errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
        //设置活体测试
        //活体取值范围为[0~1],推荐阈值如下,高于此阈值的即可判断为活体。
        // RGB 活体:0.5
        // IR 活体:0.7
        errorCode = faceEngine.setLivenessParam(0.5f, 0.7f);
        //人脸属性检测
        FunctionConfiguration configuration = new FunctionConfiguration();
//        configuration.setSupportAge(true);
        configuration.setSupportFace3dAngle(true);
//        configuration.setSupportGender(true);
        configuration.setSupportLiveness(true);
        errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
        faceEngine.getLiveness(livenessInfoList);
        if(livenessInfoList.size()<1 || livenessInfoList.get(0).getLiveness()!=1){
            res.setCode(0);
            res.setMsg("无效的脸部信息");
        }else{
            res.setCode(1);
        }
        return res;
    }
    public static Response faceCompare(FaceEngine faceEngine, ImageInfo imageInfo, ImageInfo imageInfo2) {
        Response res = new Response();
        int errorCode=0;
        //人脸检测
        List<FaceInfo> faceInfoList = new ArrayList<>();
        errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
        //特征提取
        FaceFeature faceFeature = new FaceFeature();
        errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
        //人脸检测2
        List<FaceInfo> faceInfoList2 = new ArrayList<>();
        errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(),imageInfo2.getImageFormat(), faceInfoList2);
        //特征提取2
        FaceFeature faceFeature2 = new FaceFeature();
        errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2.get(0), faceFeature2);
        //特征比对
        FaceFeature targetFaceFeature = new FaceFeature();
        targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
        FaceFeature sourceFaceFeature = new FaceFeature();
        sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
        FaceSimilar faceSimilar = new FaceSimilar();
        errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
        //官方建议:
        //人脸比对取值范围为[0~1],推荐阈值如下,高于此阈值的即可判断为同一人。
        // 用于生活照之间的特征比对,推荐阈值0.80
        // 用于证件照或生活照与证件照之间的特征比对,推荐阈值0.82
        float faceThreshold = YamlProperties.faceThreshold;
        if(faceSimilar.getScore()<faceThreshold){
            res.setCode(1);
            res.setData(false);
            res.setMsg("人脸不匹配");
        }else{
            res.setCode(1);
            res.setData(true);
            res.setMsg("匹配成功");
        }
        return res;
    }
}
src/main/resources/config/application-dev.yml
@@ -62,6 +62,16 @@
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
custom:
  #人脸
  face:
    #type=1 免费版,type=2 增值版永久
    type: 1
    threshold: 0.8
    appId4Win: 9yyDc1NXJsSQBdareYkBHA8Z4XDvSNkKAibxSmiYhA39
    sdkKey4Win: GHmUteeWmeLCRZstetQfXgJTB29wenDazF3UrH85K9hw
    appId4Linux: AafPX5afzycEnTqH3v79gY3VozNVTSNqT8kzSmP7b48q
    sdkKey4Linux: GsYwWhxzuQEE1WE34J3Fo8d2GiFdddqH81ghetQQTGmv
    activeKey: 8611-11H3-Z13R-7HL1
  #告警工单
  alarm:
    task.switch: off
src/main/resources/config/application-prod-ssl.yml
@@ -28,7 +28,7 @@
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3382/db_user?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
    url: jdbc:mysql://192.168.10.82:3382/db_user?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
    username: root
    password: Hdw8688139
    maxIdel: 60
@@ -73,6 +73,16 @@
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
custom:
  #人脸
  face:
    #type=1 免费版,type=2 增值版永久
    type: 1
    threshold: 0.8
    appId4Win: 9yyDc1NXJsSQBdareYkBHA8Z4XDvSNkKAibxSmiYhA39
    sdkKey4Win: GHmUteeWmeLCRZstetQfXgJTB29wenDazF3UrH85K9hw
    appId4Linux: AafPX5afzycEnTqH3v79gY3VozNVTSNqT8kzSmP7b48q
    sdkKey4Linux: GsYwWhxzuQEE1WE34J3Fo8d2GiFdddqH81ghetQQTGmv
    activeKey: 8611-11H3-Z13R-7HL1
  #告警工单
  alarm:
    task.switch: off
src/main/resources/config/application-prod.yml
@@ -18,6 +18,7 @@
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3382/db_user?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
#    url: jdbc:mysql://192.168.10.82:3382/db_user?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
    username: root
    password: Hdw8688139
    maxIdel: 60
@@ -62,11 +63,21 @@
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
custom:
  #人脸
  face:
    #type=1 免费版,type=2 增值版永久
    type: 1
    threshold: 0.8
    appId4Win: 9yyDc1NXJsSQBdareYkBHA8Z4XDvSNkKAibxSmiYhA39
    sdkKey4Win: GHmUteeWmeLCRZstetQfXgJTB29wenDazF3UrH85K9hw
    appId4Linux: AafPX5afzycEnTqH3v79gY3VozNVTSNqT8kzSmP7b48q
    sdkKey4Linux: GsYwWhxzuQEE1WE34J3Fo8d2GiFdddqH81ghetQQTGmv
    activeKey: 8611-11H3-Z13R-7HL1
  #告警工单
  alarm:
    task.switch: off
  #允许跨域的白名单 http://192.168.10.132:8080,http://192.168.10.109:8080
  cors: http://localhost:8098,http://192.168.10.133:8098
  cors: http://192.168.10.86:8001,http://localhost:8001
  rsa:
    #publicKey: ENC(ZCCRYK0TIFYCrdHZprQS0I8hWFD1uXKIRYcfwDkh3V87FjFePAWlWIzi6tJFcswo525c+m5UGmkt+eq/wCIIabjbcbt6l+18hz6ogtGXHTalaEATqjbrjWmbdzc92A6dYmoNI5Rdpi+jqBKciXZhDKWDNPY2M3/WyejcPGDOeo9CWOvR1hdmLX8iTlcuPRS6k7YzybGZwP9cOHfcAyt6QN+GSuNRzapo5pUmQdT7aUwF3P73qcoxHpRO1li6kYF9KVOMgVix8a3h6TyFMMuJdPGboRV8DL9wLK3bnJT6s0Ei35niYv4ePJ7IzHiEa4J1x0wo8pNU0CfdhylySWLsnxgFjzbhMWjmoQhwQjjnTj+DgyvRrZqaE3R0cLpSwxT4x2ceHzKm1KUzF7OhGgnmc3lPN3H8UyVHy+l3GyejGpRnqFtABHqIlbM2nbsTA8lT/sAeN/AVlBORNgd5Rai7upWk43pvd2qG9ykSW+t/++ZiKBXfAZOBgrcWhPseEG94e3bHhM62nwcgHZ5HzFCZ8PEwXn0053vbxdM6LxVIqCAIzrWoOgBWoaRRBqfSUTvJf2tdc5m9NncXRmYEzZOg3f1wOvVGDJeyKC3OuyhlJnD2VWYVwNsorDkI+dT9mPAMMTZaPeqwPGxtkjaaFSgB5RDHcBfeEIMNdAVOqMCA9qOLFX+zr9mHvjV1kpiDKb5JZFhLHlXObROUtqMndTQDRCATBjutLB4QS0/0BCOvSLnDTA39e/nVKBwTHPqnlz4N)
    #privateKey: ENC(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)
src/main/resources/lib/8611-11H3-Z13R-7HL1.dat
src/main/resources/lib/LINUX64/libarcsoft_face.so
Binary files differ
src/main/resources/lib/LINUX64/libarcsoft_face_engine.so
Binary files differ
src/main/resources/lib/LINUX64/libarcsoft_face_engine_jni.so
Binary files differ
src/main/resources/lib/LINUX64PRO/libarcsoft_face.so
Binary files differ
src/main/resources/lib/LINUX64PRO/libarcsoft_face_engine.so
Binary files differ
src/main/resources/lib/LINUX64PRO/libarcsoft_face_engine_jni.so
Binary files differ
src/main/resources/lib/WIN64/libarcsoft_face.dll
Binary files differ
src/main/resources/lib/WIN64/libarcsoft_face_engine.dll
Binary files differ
src/main/resources/lib/WIN64/libarcsoft_face_engine_jni.dll
Binary files differ
src/main/resources/lib/WIN64PRO/libarcsoft_face.dll
Binary files differ
src/main/resources/lib/WIN64PRO/libarcsoft_face_engine.dll
Binary files differ
src/main/resources/lib/WIN64PRO/libarcsoft_face_engine_jni.dll
Binary files differ
src/main/resources/lib/arcsoft-sdk-face-3.0.0.0.jar
Binary files differ
src/main/resources/lib/arcsoft-sdk-face-3.1.1.0.jar
Binary files differ
src/main/resources/lib/jacob.jar
Binary files differ
src/main/resources/lib/tomcat-embed-core-9.0.30.jar
Binary files differ
src/main/resources/lib/tomcat-embed-core-9.0.93.jar
Binary files differ
src/main/resources/mapper/FaceMapper.xml
New file
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whyc.mapper.FaceMapper" >
    <resultMap id="Map_UserInf" type="UserInf">
        <id property="uid" column="uid" />
        <result property="uname" column="uname"/>
        <association property="face" javaType="UserFace">
            <id property="id" column="faceId" jdbcType="INTEGER"/>
            <result property="url" column="faceUrl" jdbcType="VARCHAR"/>
        </association>
    </resultMap>
    <resultMap id="Map_UserInf2" type="UserInf">
        <id property="uid" column="uId" />
        <result property="uname" column="uName"/>
        <result property="usnid" column="uSnId"/>
        <result property="urole" column="uRole"/>
        <association property="face" javaType="UserFace">
            <result property="url" column="url" />
        </association>
    </resultMap>
    <update id="initDB">
    </update>
    <select id="getInfo" resultMap="Map_UserInf">
        select inf.uid,inf.uname,face.id faceId,face.url faceUrl from db_user.tb_user_inf inf left join db_user.tb_user_face face
        on inf.face_id=face.id where uId=#{uId} limit 1
    </select>
    <select id="findAllFaceUrl" resultMap="Map_UserInf2">
        select inf.uname,inf.uid,inf.usnid,inf.urole,face.url from db_user.tb_user_inf inf inner join db_user.tb_user_face face
        on inf.face_id=face.id
    </select>
</mapper>