413 lines
20 KiB
Java
413 lines
20 KiB
Java
package com.ycwl.basic.controller.viid;
|
||
|
||
import cn.hutool.core.collection.CollUtil;
|
||
import cn.hutool.core.util.ObjectUtil;
|
||
import com.alibaba.fastjson.JSON;
|
||
import com.alibaba.fastjson.JSONObject;
|
||
import com.ycwl.basic.annotation.IgnoreLogReq;
|
||
import com.ycwl.basic.annotation.IgnoreToken;
|
||
import com.ycwl.basic.annotation.RequestToFile;
|
||
import com.ycwl.basic.aspectj.HttpSaver;
|
||
import com.ycwl.basic.facebody.FaceBodyFactory;
|
||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||
import com.ycwl.basic.facebody.entity.AddFaceResp;
|
||
import com.ycwl.basic.mapper.DeviceMapper;
|
||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||
import com.ycwl.basic.mapper.SourceMapper;
|
||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
|
||
import com.ycwl.basic.model.viid.entity.FaceListObject;
|
||
import com.ycwl.basic.model.viid.entity.FaceObject;
|
||
import com.ycwl.basic.model.viid.entity.FacePositionObject;
|
||
import com.ycwl.basic.model.viid.entity.ImageListObject;
|
||
import com.ycwl.basic.model.viid.entity.ImageObject;
|
||
import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
|
||
import com.ycwl.basic.model.viid.entity.SubImageInfoObject;
|
||
import com.ycwl.basic.model.viid.entity.SubImageList;
|
||
import com.ycwl.basic.model.viid.entity.SystemTimeObject;
|
||
import com.ycwl.basic.model.viid.req.FaceUploadReq;
|
||
import com.ycwl.basic.model.viid.req.ImageUploadReq;
|
||
import com.ycwl.basic.model.viid.req.KeepaliveReq;
|
||
import com.ycwl.basic.model.viid.req.RegisterReq;
|
||
import com.ycwl.basic.model.viid.req.UnRegisterReq;
|
||
import com.ycwl.basic.model.viid.resp.SystemTimeResp;
|
||
import com.ycwl.basic.model.viid.resp.VIIDBaseResp;
|
||
import com.ycwl.basic.repository.DeviceRepository;
|
||
import com.ycwl.basic.repository.ScenicRepository;
|
||
import com.ycwl.basic.service.pc.ScenicService;
|
||
import com.ycwl.basic.service.task.TaskFaceService;
|
||
import com.ycwl.basic.storage.StorageFactory;
|
||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||
import com.ycwl.basic.task.DynamicTaskGenerator;
|
||
import com.ycwl.basic.utils.ImageUtils;
|
||
import com.ycwl.basic.utils.IpUtils;
|
||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||
import io.swagger.annotations.Api;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.apache.commons.lang3.StringUtils;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RequestMethod;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
|
||
import javax.servlet.http.HttpServletRequest;
|
||
import java.io.IOException;
|
||
import java.text.ParseException;
|
||
import java.text.SimpleDateFormat;
|
||
import java.util.Date;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import java.util.TimeZone;
|
||
import java.util.UUID;
|
||
import java.util.concurrent.ArrayBlockingQueue;
|
||
import java.util.concurrent.ConcurrentHashMap;
|
||
import java.util.concurrent.ThreadPoolExecutor;
|
||
import java.util.concurrent.TimeUnit;
|
||
import java.util.stream.Collectors;
|
||
|
||
import static com.ycwl.basic.constant.StorageConstant.PHOTO_PATH;
|
||
import static com.ycwl.basic.service.task.impl.TaskFaceServiceImpl.generateEntityId;
|
||
|
||
@IgnoreToken
|
||
@RestController
|
||
@Api(tags = "摄像头对接接口")
|
||
@RequestMapping("/VIID")
|
||
@Slf4j
|
||
public class ViidController {
|
||
@Autowired
|
||
private DeviceMapper deviceMapper;
|
||
private static final String serverId = "00000000000000000001";
|
||
@Autowired
|
||
private SourceMapper sourceMapper;
|
||
@Autowired
|
||
private DeviceRepository deviceRepository;
|
||
@Autowired
|
||
private ScenicRepository scenicRepository;
|
||
@Autowired
|
||
private TaskFaceService taskFaceService;
|
||
private final Map<String, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
|
||
@Autowired
|
||
private ScenicService scenicService;
|
||
|
||
private ThreadPoolExecutor getExecutor(String deviceId) {
|
||
ThreadPoolExecutor executor = executors.get(deviceId);
|
||
if (executor == null) {
|
||
executor = new ThreadPoolExecutor(4, 4096, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(4096));
|
||
executors.put(deviceId, executor);
|
||
}
|
||
return executor;
|
||
}
|
||
|
||
// region 注册注销基础接口
|
||
/**
|
||
* 注册接口
|
||
*
|
||
* @param req 注册的信息
|
||
* @param request 请求
|
||
* @return 返回
|
||
*/
|
||
@RequestMapping(value = "/System/Register", method = RequestMethod.POST)
|
||
public VIIDBaseResp register(@RequestBody RegisterReq req, HttpServletRequest request) {
|
||
DeviceIdObject deviceIdObject = req.getRegisterObject();
|
||
log.info("注册的设备信息:{}", deviceIdObject);
|
||
// 保存设备注册时间
|
||
String deviceId = deviceIdObject.getDeviceId();
|
||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
|
||
if (device == null) {
|
||
device = new DeviceEntity();
|
||
device.setName("未配置设备");
|
||
device.setNo(deviceId);
|
||
device.setOnline(1);
|
||
}
|
||
device.setKeepaliveAt(new Date());
|
||
device.setIpAddr(IpUtils.getIpAddr(request));
|
||
if (device.getId() != null) {
|
||
deviceMapper.updateEntity(device);
|
||
} else {
|
||
device.setId(SnowFlakeUtil.getLongId());
|
||
deviceMapper.addEntity(device);
|
||
deviceRepository.clearDeviceCache(deviceId);
|
||
}
|
||
return new VIIDBaseResp(
|
||
new ResponseStatusObject(serverId, "/VIID/System/Register", "0", "注册成功", sdfTime.format(new Date()))
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 保活接口
|
||
*
|
||
* @param req 保活的设备信息
|
||
* @param request 请求
|
||
* @return 返回
|
||
*/
|
||
@IgnoreLogReq
|
||
@RequestMapping(value = "/System/Keepalive", method = RequestMethod.POST)
|
||
public VIIDBaseResp keepalive(@RequestBody KeepaliveReq req, HttpServletRequest request) {
|
||
DeviceIdObject keepaliveObject = req.getKeepaliveObject();
|
||
// log.info("对方发送的心跳的信息:{}", keepaliveObject);
|
||
|
||
String deviceId = keepaliveObject.getDeviceId();
|
||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
|
||
|
||
// 判断设备状态
|
||
if (device == null) {
|
||
// 不存在设备就注册
|
||
device = new DeviceEntity();
|
||
device.setName("未配置设备");
|
||
device.setNo(deviceId);
|
||
device.setOnline(1);
|
||
device.setKeepaliveAt(new Date());
|
||
device.setIpAddr(IpUtils.getIpAddr(request));
|
||
device.setId(SnowFlakeUtil.getLongId());
|
||
deviceMapper.addEntity(device);
|
||
deviceRepository.clearDeviceCache(deviceId);
|
||
} else {
|
||
deviceRepository.updateOnlineStatus(device.getId(), IpUtils.getIpAddr(request), 1, new Date());
|
||
}
|
||
// log.info("已经解析过的心跳信息:{}", keepaliveObject);
|
||
|
||
return new VIIDBaseResp(
|
||
new ResponseStatusObject(deviceId, "/VIID/System/Keepalive", "0", "保活", sdfTime.format(new Date()))
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 注销设备
|
||
*
|
||
* @param req 参数
|
||
* @return 返回
|
||
*/
|
||
@RequestMapping(value = "/System/UnRegister", method = RequestMethod.POST)
|
||
public VIIDBaseResp unRegister(@RequestBody UnRegisterReq req, HttpServletRequest request) {
|
||
// 获取设备id
|
||
DeviceIdObject unRegisterObject = req.getUnRegisterObject();
|
||
String deviceId = unRegisterObject.getDeviceId();
|
||
log.info("获取的注销的请求参数:{}", unRegisterObject);
|
||
|
||
// 首先查询该设备是否存在
|
||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
|
||
// 判断
|
||
if (device != null) {
|
||
deviceRepository.updateOnlineStatus(device.getId(), IpUtils.getIpAddr(request), 0, new Date());
|
||
}
|
||
return new VIIDBaseResp(
|
||
new ResponseStatusObject(deviceId, "/VIID/System/UnRegister", "0", "注销成功", sdfTime.format(new Date()))
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 校时接口
|
||
*
|
||
* @return 返回
|
||
*/
|
||
@RequestMapping(value = "/System/Time", method = RequestMethod.GET)
|
||
public SystemTimeResp time() {
|
||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
|
||
return new SystemTimeResp(
|
||
new SystemTimeObject(serverId, "2", sdf.format(new Date()), TimeZone.getTimeZone("Asia/Shanghai").toString())
|
||
);
|
||
}
|
||
|
||
// endregion
|
||
|
||
@Autowired
|
||
private FaceSampleMapper faceSampleMapper;
|
||
|
||
private final SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
|
||
|
||
|
||
/**
|
||
* 批量新增人脸
|
||
*/
|
||
@RequestMapping(value = "/Faces", method = RequestMethod.POST)
|
||
@IgnoreLogReq
|
||
public VIIDBaseResp faces(@RequestBody FaceUploadReq req) {
|
||
FaceListObject faceListObject = req.getFaceListObject();
|
||
List<FaceObject> faceObject = faceListObject.getFaceObject();
|
||
String faceId = null;
|
||
// 遍历人脸列表
|
||
for (FaceObject face : faceObject) {
|
||
// 设置FaceId
|
||
faceId = face.getFaceID();
|
||
// 获取图片信息
|
||
SubImageList subImageList = face.getSubImageList();
|
||
// 判断人脸对象中的列表是否为空
|
||
String deviceID = face.getDeviceID();
|
||
DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceID);
|
||
if (device == null) {
|
||
continue;
|
||
}
|
||
DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(device.getId());
|
||
int viidMode = 0;
|
||
if (deviceConfig != null && deviceConfig.getViidType() != null) {
|
||
viidMode = deviceConfig.getViidType();
|
||
}
|
||
Date shotTime = null;
|
||
if (StringUtils.isNotBlank(face.getShotTime())) {
|
||
try {
|
||
shotTime = sdfTime.parse(face.getShotTime());
|
||
} catch (ParseException e) {
|
||
log.warn("拍摄时间时间转换失败,使用当前时间。错误entity:{}", face);
|
||
}
|
||
}
|
||
if (shotTime == null) {
|
||
if (StringUtils.isNotBlank(face.getFaceAppearTime())) {
|
||
try {
|
||
shotTime = sdfTime.parse(face.getFaceAppearTime());
|
||
} catch (ParseException e) {
|
||
log.warn("拍摄时间时间转换失败,使用当前时间。错误entity:{}", face);
|
||
}
|
||
}
|
||
}
|
||
if (shotTime == null) {
|
||
shotTime = new Date();
|
||
} else if (Math.abs(shotTime.getTime() - System.currentTimeMillis()) > + 24 * 60 * 60 * 1000) {
|
||
shotTime = new Date();
|
||
}
|
||
Long scenicId = device.getScenicId();
|
||
if (scenicId == null) {
|
||
continue;
|
||
}
|
||
IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId);
|
||
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
|
||
FacePositionObject facePosition = new FacePositionObject();
|
||
facePosition.setLtY(face.getLeftTopY());
|
||
facePosition.setLtX(face.getLeftTopX());
|
||
facePosition.setRbY(face.getRightBtmY());
|
||
facePosition.setRbX(face.getRightBtmX());
|
||
if (ObjectUtil.isNotEmpty(subImageList) && CollUtil.isNotEmpty(subImageList.getSubImageInfoObject())) {
|
||
if (viidMode == 0) {
|
||
// 遍历每个图片对象
|
||
// 先找到type14的图片
|
||
List<SubImageInfoObject> type14ImageList = subImageList.getSubImageInfoObject().stream().filter(subImage -> "14".equals(subImage.getType())).collect(Collectors.toList());
|
||
for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
|
||
// base64转换成MultipartFIle
|
||
MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
|
||
String ext = subImage.getFileFormat();
|
||
if (ext.equalsIgnoreCase("jpeg")) {
|
||
ext = "jpg";
|
||
}
|
||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||
// Type=11 人脸
|
||
if (subImage.getType().equals("11")) {
|
||
// 上传oss
|
||
Long newFaceSampleId = SnowFlakeUtil.getLongId();
|
||
if (Integer.valueOf(1).equals(device.getStatus())) {
|
||
FaceSampleEntity faceSample = new FaceSampleEntity();
|
||
faceSample.setId(newFaceSampleId);
|
||
faceSample.setScenicId(scenicId);
|
||
faceSample.setDeviceId(device.getId());
|
||
faceSample.setStatus(0);
|
||
faceSample.setCreateAt(shotTime);
|
||
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
|
||
faceSample.setFaceUrl(url);
|
||
faceSampleMapper.add(faceSample);
|
||
ThreadPoolExecutor executor = getExecutor(device.getId().toString());
|
||
executor.execute(() -> {
|
||
if (faceBodyAdapter != null) {
|
||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), generateEntityId(faceSample), url, newFaceSampleId.toString());
|
||
if (addFaceResp != null) {
|
||
faceSample.setScore(addFaceResp.getScore());
|
||
faceSampleMapper.update(faceSample);
|
||
}
|
||
}
|
||
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
|
||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||
}
|
||
});
|
||
}
|
||
|
||
for (SubImageInfoObject _subImage : type14ImageList) {
|
||
facePosition.setImgHeight(_subImage.getHeight());
|
||
facePosition.setImgWidth(_subImage.getWidth());
|
||
SourceEntity source = new SourceEntity();
|
||
source.setId(SnowFlakeUtil.getLongId());
|
||
source.setDeviceId(device.getId());
|
||
source.setScenicId(device.getScenicId());
|
||
source.setFaceSampleId(newFaceSampleId);
|
||
source.setCreateTime(shotTime);
|
||
source.setType(2);
|
||
// 上传oss
|
||
MultipartFile _file = ImageUtils.base64ToMultipartFile(_subImage.getData());
|
||
String filename = StorageUtil.joinPath(PHOTO_PATH, UUID.randomUUID() + "." + ext);
|
||
String _sourceUrl = scenicStorageAdapter.uploadFile(_file, filename);
|
||
scenicStorageAdapter.setAcl(StorageAcl.PUBLIC_READ, filename);
|
||
source.setUrl(_sourceUrl);
|
||
source.setPosJson(JSON.toJSONString(facePosition));
|
||
sourceMapper.add(source);
|
||
}
|
||
log.info("人脸信息及原图{}张入库成功!设备ID:{}", type14ImageList.size(), deviceID);
|
||
}
|
||
}
|
||
} else if (viidMode == 1) {
|
||
for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
|
||
// base64转换成MultipartFIle
|
||
MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
|
||
String ext = subImage.getFileFormat();
|
||
if (ext.equalsIgnoreCase("jpeg")) {
|
||
ext = "jpg";
|
||
}
|
||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||
// Type=14 人脸,传™的,有这么传的嘛
|
||
if (subImage.getType().equals("14")) {
|
||
// 上传oss
|
||
if (Integer.valueOf(1).equals(device.getStatus())) {
|
||
FaceSampleEntity faceSample = new FaceSampleEntity();
|
||
Long newFaceSampleId = SnowFlakeUtil.getLongId();
|
||
faceSample.setId(newFaceSampleId);
|
||
faceSample.setScenicId(scenicId);
|
||
faceSample.setDeviceId(device.getId());
|
||
faceSample.setStatus(0);
|
||
faceSample.setCreateAt(shotTime);
|
||
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
|
||
faceSample.setFaceUrl(url);
|
||
faceSampleMapper.add(faceSample);
|
||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||
ThreadPoolExecutor executor = getExecutor(device.getId().toString());
|
||
executor.execute(() -> {
|
||
if (faceBodyAdapter != null) {
|
||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), generateEntityId(faceSample), url, newFaceSampleId.toString());
|
||
if (addFaceResp != null) {
|
||
faceSample.setScore(addFaceResp.getScore());
|
||
faceSampleMapper.update(faceSample);
|
||
}
|
||
}
|
||
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
|
||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||
}
|
||
});
|
||
log.info("模式1人脸信息入库成功!设备ID:{}", deviceID);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return new VIIDBaseResp(
|
||
new ResponseStatusObject(faceId, "/VIID/Faces", "0", "OK", sdfTime.format(new Date()))
|
||
);
|
||
}
|
||
|
||
@RequestMapping(value = "/Images", method = RequestMethod.POST)
|
||
@IgnoreLogReq
|
||
public VIIDBaseResp images(HttpServletRequest request, @RequestBody ImageUploadReq req) throws IOException {
|
||
// log.info("Images:{}", req);
|
||
HttpSaver.saveRequestToFile(request);
|
||
return new VIIDBaseResp(
|
||
new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
|
||
);
|
||
}
|
||
|
||
}
|