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 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 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 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 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; } }