人脸存放的路径
引入依赖
<!--json转换工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.12.0</version>
</dependency>
controller层代码
@ApiOperation("人脸签到")
@RequestMapping(value = "/clockIn", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject clockIn(
@ApiParam(value = "拍照后的图片进行base64加密后的字符串:xxxx")
@RequestParam(value = "faceImgBase64Str") String faceImgBase64Str,
@ApiParam(value = "刷脸的时间:2020-02-21 12:00:00") @RequestParam(value = "date") LocalDateTime date,
@ApiParam(value = "用户编号:01") @RequestParam(value = "userNo") String userNo
){
return attendenceService.clockIn(faceImgBase64Str,date,userNo);
}
package org.nf.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baidu.aip.face.AipFace;
import org.nf.bean.Attendence;
import org.nf.bean.OnTime;
import org.nf.bean.User;
import org.nf.config.exception.CommonJsonException;
import org.nf.mapper.AttendenceMapper;
import org.nf.mapper.OnTimeMapper;
import org.nf.mapper.UserMapper;
import org.nf.service.AttendenceService;
import org.nf.util.CommonUtil;
import org.nf.util.DateTools;
import org.nf.util.FaceRecogUtil;
import org.nf.util.constants.Constants;
import org.nf.util.constants.ErrorEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class AttendenceServiceImpl implements AttendenceService {
@Autowired
AttendenceMapper attendenceMapper;
@Autowired
UserMapper userMapper;
@Autowired
OnTimeMapper onTimeMapper;
@Override
public JSONObject clockIn(String faceImgBase64Str, LocalDateTime date, String userNo) {
// LocalDateTime date=DateTools.toLocalDateTime(date11);
Attendence attendence = new Attendence();
//查出所有的人脸的url
List<User> attendenceList = userMapper.selectAll();
List<String> faceUrlList = attendenceList.stream().map(User::getUserFace).collect(Collectors.toList());
AipFace client = null;
try {
client = new AipFace(Constants.APP_ID, Constants.API_KEY, Constants.SECRET_KEY);
} catch (Exception e) {
throw new CommonJsonException(ErrorEnum.E_3002);
}
//人脸识别
boolean status = FaceRecogUtil.faceRecog(faceUrlList, client, faceImgBase64Str);
if (status == true) { //人脸匹配成功
//查出规定时间
LocalTime ontime = onTimeMapper.selectAll().get(0).getSpecifiedOnDutyTime();
LocalTime offtime = onTimeMapper.selectAll().get(0).getSpecifiedOffDutyTime();
LocalTime time=date.toLocalTime();
if (time.compareTo(ontime) > 0 && time.compareTo(time.parse("12:00")) < 0) {
//迟到了
attendence.setOnDutyTimeStatus(0);
attendence.setOnDutyTime(date);
} else if (date.toLocalTime().compareTo(ontime) < 0 && date.toLocalTime().compareTo(LocalTime.parse("12:00")) < 0) {
//准点上班
attendence.setOnDutyTimeStatus(1);
attendence.setOnDutyTime(date);
} else if (date.toLocalTime().compareTo(offtime) < 0 && date.toLocalTime().compareTo(LocalTime.parse("12:00")) > 0) {
//早退了
attendence.setOffDutyTimeStatus(0);
attendence.setOffDutyTime(date);
} else {
//准点下班
attendence.setOffDutyTimeStatus(1);
attendence.setOffDutyTime(date);
}
attendence.setSpecifiedOnDutyTime(ontime);
attendence.setSpecifiedOffDutyTime(offtime);
attendence.setUserNo(userNo);
attendenceMapper.insert(attendence);
return CommonUtil.successJson();
} else {
return CommonUtil.errorJson(ErrorEnum.E_3001);
}
}
@Override
public JSONObject getcheckInRecords(String userNo) {
Attendence attendence=new Attendence();
attendence.setUserNo(userNo);
return CommonUtil.successJson(attendenceMapper.select(attendence));
}
@Override
public JSONObject getcheckInRecords() {
return CommonUtil.successJson(onTimeMapper.selectAll());
}
@Override
public JSONObject updatecheckInSpecific(OnTime onTime) {
return CommonUtil.successJson(onTimeMapper.updateByPrimaryKey(onTime));
}
//比对时间大小设置类的签到状态
}
人脸识别工具
package org.nf.util;
import com.baidu.aip.face.AipFace;
import com.baidu.aip.face.MatchRequest;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class FaceRecogUtil {
public static boolean faceRecog(List<String> faceUrlList, AipFace client, String srcFace) {
/**
* 前端传入base64加密后的string,后端不作处理
*/
/*try {
srcFace=ImageHandler.getImageStr(srcFace);
} catch (IOException e) {
e.printStackTrace();
}*/
for (String face : faceUrlList) {
try {
String faceBase64 = ImageHandler.getImageStr(face);
MatchRequest srcReq = new MatchRequest(srcFace, "BASE64");
MatchRequest storeReq = new MatchRequest(faceBase64, "BASE64");
ArrayList<MatchRequest> requests = new ArrayList<MatchRequest>();
requests.add(srcReq);
requests.add(storeReq);
JSONObject result = client.match(requests);
// System.out.println(face+"---------------------");
// System.out.println(result);
// System.out.println(" ");
Double bb=0.00;
JSONObject o=null;
try {
o= (JSONObject) result.get("result");
bb=(Double) o.get("score");
}catch (Exception e){
if(o!=null&&(Integer)o.get("score")==100) {
//return false;
bb = 100.0;
}
}
//System.out.println(bb);
if(bb>70) return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
}
Constants :百度api密钥
package org.nf.util.constants;
/**
* @author: hxy
* @description: 通用常量类, 单个业务的常量请单开一个类, 方便常量的分类管理
* @date: 2017/10/24 10:15
*/
public class Constants {
public static final String SUCCESS_CODE = "100";
public static final String SUCCESS_MSG = "请求成功";
public static final String PERMISSION_CODE = "300";
public static final String PERMISSION_MSG = "权限不足";
public static final String HANDLE_CODE = "400";
public static final String HANDLE_MSG = "处理异常";
public static final String SERVER_CODE = "500";
public static final String SERVER_MSG = "服务器异常";
/**
* session中存放用户信息的key值
*/
public static final String SESSION_USER_INFO = "userInfo";
public static final String SESSION_USER_PERMISSION = "userPermission";
/**
* api文档
* http://ai.baidu.com/ai-doc/FACE/8k37c1rqz#%E4%BA%BA%E8%84%B8%E5%AF%B9%E6%AF%94
*
* 百度人脸识别api
*/
//设置APPID/AK/SK
public static final String APP_ID = "18093919";
public static final String API_KEY = "SDE0UZSXaS6n9iLFMm7YM0EC";
public static final String SECRET_KEY = "Ifr4ecYX9MkaiwZm45nqiDwIFS8HHZ8z";
}
前端界面
<template>
<div id="attend">
<div id="attend-image">
<div>
<video id="video" width="400px" height="400px" autoplay="autoplay"></video>
</div>
<div>
<canvas id="canvas" height="400px" width="400px"></canvas>
</div>
</div>
<div id="attend-button">
<input type="button" value="开启" @click="getMedia">
<input type="button" value="拍照" @click="takePhoto">
</div>
</div>
</template>
<script>
// import { Base64 } from 'js-base64'
import {getNowFormatDate} from '@/common/dateconvent.js'
import {faceAttence} from '@/api/user.js'
export default {
methods: {
getMedia () {
let constraints = {
//参数
video: {width: 400, height: 400},
audio: true
}
//获得video摄像头区域
let video = document.getElementById("video");
//返回的Promise对象
//let promise= MediaDevices.getUserMedia();
let promise = navigator.mediaDevices.getUserMedia(constraints);
// let promise = navigator.mediaDevices.getUserMedia(constraints);
//then()异步,调用MediaStream对象作为参数
promise.then(function (MediaStream) {
video.srcObject = MediaStream;
video.play();
});
},
takePhoto () {
//获得Canvas对象
let video = document.getElementById("video");
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext('2d');
//绘图
ctx.drawImage(video, 0, 0, 400, 400);
canvas.toBlob(function (blob) {
let fileReader = new FileReader()
fileReader.readAsDataURL(blob)
fileReader.onload = function () {
let code = this.result
let codeP= code.substring(22,code.length);
let parameter={
faceImgBase64Str:codeP,
date: getNowFormatDate(),
userNo:JSON.parse(window.localStorage.getItem('USER_INFO')).userNo
}
faceAttence(parameter).then((data) => {
alert("返回数据")
console.log(data)
})
//console.log(parameter)
}
}, 'image/png')
}
}
};
</script>
<style scoped>
#attend {
height: 100%;
width: 100%;
box-sizing: border-box;
}
#attend-image {
display: grid;
grid-template-columns: 1fr 1fr;
height: 400px;
width: 800px;
}
#attend-button {
margin-top: 20px;
}
#video {
border: 1px solid green;
}
</style>