You've already forked FrameTour-BE
Compare commits
4 Commits
a7ede3303d
...
56e1081304
| Author | SHA1 | Date | |
|---|---|---|---|
| 56e1081304 | |||
| 658e741611 | |||
| d5cd1924f5 | |||
| 645afbaf0c |
@@ -5,6 +5,5 @@ public class StorageConstant {
|
||||
public static final String VIDEO_PIECE_PATH = "source_video";
|
||||
public static final String PHOTO_PATH = "source_photo";
|
||||
public static final String PHOTO_WATERMARKED_PATH = "photo_w";
|
||||
public static final String VIID_FACE = "viid_face";
|
||||
public static final String USER_FACE = "user_face";
|
||||
public static final String USER_FACE = "user_face";
|
||||
}
|
||||
|
||||
@@ -1,487 +0,0 @@
|
||||
package com.ycwl.basic.controller.viid;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.ycwl.basic.annotation.IgnoreLogReq;
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.facebody.entity.AddFaceResp;
|
||||
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
||||
import com.ycwl.basic.integration.device.dto.device.CreateDeviceRequest;
|
||||
import com.ycwl.basic.integration.device.dto.device.UpdateDeviceRequest;
|
||||
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
||||
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.DeviceCropConfig;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
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.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.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 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 jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.awt.image.RasterFormatException;
|
||||
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.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.ycwl.basic.constant.StorageConstant.PHOTO_PATH;
|
||||
import static com.ycwl.basic.constant.StorageConstant.VIID_FACE;
|
||||
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
// 摄像头对接接口
|
||||
@RequestMapping("/VIID")
|
||||
@Slf4j
|
||||
public class ViidController {
|
||||
@Autowired
|
||||
private DeviceIntegrationService deviceIntegrationService;
|
||||
private static final String serverId = "00000000000000000001";
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private TaskFaceService taskFaceService;
|
||||
private final Map<Long, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
private ThreadPoolExecutor getExecutor(Long scenicId) {
|
||||
return executors.computeIfAbsent(scenicId, k -> {
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setNamePrefix("VIID-" + scenicId + "-t")
|
||||
.build();
|
||||
return new ThreadPoolExecutor(
|
||||
8, 32, 10L, TimeUnit.SECONDS, // 核心2个线程,最大20个线程,空闲60秒回收
|
||||
new ArrayBlockingQueue<>(1024), // 队列大小从1024降至100
|
||||
threadFactory,
|
||||
new ThreadPoolExecutor.CallerRunsPolicy() // 队列满时由调用线程执行,提供背压控制
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 通过zt-device服务创建新设备
|
||||
CreateDeviceRequest createRequest = new CreateDeviceRequest();
|
||||
createRequest.setName(device.getName());
|
||||
createRequest.setNo(device.getNo());
|
||||
createRequest.setType("IPC"); // 默认类型为IPC
|
||||
createRequest.setIsActive(0);
|
||||
createRequest.setScenicId(0L);
|
||||
createRequest.setSort(0);
|
||||
try {
|
||||
DeviceV2DTO createdDevice = deviceIntegrationService.createDevice(createRequest);
|
||||
device.setId(createdDevice.getId());
|
||||
} catch (Exception e) {
|
||||
log.warn("创建设备失败,设备编号: {}, 错误: {}", deviceId, e.getMessage());
|
||||
}
|
||||
}
|
||||
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));
|
||||
// 通过zt-device服务创建新设备
|
||||
CreateDeviceRequest createRequest = new CreateDeviceRequest();
|
||||
createRequest.setName(device.getName());
|
||||
createRequest.setNo(device.getNo());
|
||||
createRequest.setType("IPC"); // 默认类型为IPC
|
||||
createRequest.setIsActive(0);
|
||||
createRequest.setScenicId(0L);
|
||||
createRequest.setSort(0);
|
||||
try {
|
||||
DeviceV2DTO createdDevice = deviceIntegrationService.createDevice(createRequest);
|
||||
device.setId(createdDevice.getId());
|
||||
} catch (Exception e) {
|
||||
log.warn("创建设备失败,设备编号: {}, 错误: {}", deviceId, e.getMessage());
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
DeviceConfigManager deviceConfig = deviceRepository.getDeviceConfigManager(device.getId());
|
||||
DeviceConfigEntity deviceConfigEntity = deviceRepository.getDeviceConfig(device.getId());
|
||||
if (deviceConfig == null) {
|
||||
log.warn("设备配置不存在:" + deviceID);
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject(faceId, "/VIID/Faces", "0", "OK", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
Integer viidMode = deviceConfig.getInteger("viid_mode", 0);
|
||||
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 (!DateUtil.isSameDay(shotTime, new Date())) {
|
||||
log.warn("时间不是今天,使用当前时间。错误entity:{}", face);
|
||||
shotTime = new Date();
|
||||
}
|
||||
if (Math.abs(shotTime.getTime() - System.currentTimeMillis()) > 3600 * 1000) {
|
||||
String jsonString = JacksonUtil.toJSONStringCompat(req);
|
||||
log.warn("时间差超过1小时。device:{},错误entity:{}", device, jsonString);
|
||||
}
|
||||
Long scenicId = device.getScenicId();
|
||||
if (scenicId == null) {
|
||||
continue;
|
||||
}
|
||||
IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId);
|
||||
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
|
||||
if (faceBodyAdapter == null) {
|
||||
log.warn("人脸上传适配器不存在:" + scenicId);
|
||||
continue;
|
||||
}
|
||||
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())).toList();
|
||||
for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
|
||||
// base64转换成MultipartFIle
|
||||
MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
|
||||
String ext;
|
||||
if (subImage.getFileFormat().equalsIgnoreCase("jpeg")) {
|
||||
ext = "jpg";
|
||||
} else {
|
||||
ext = subImage.getFileFormat();
|
||||
}
|
||||
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, VIID_FACE, UUID.randomUUID() + "." + ext);
|
||||
faceSample.setFaceUrl(url);
|
||||
faceSampleMapper.add(faceSample);
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||||
AddFaceResp addFaceResp;
|
||||
try {
|
||||
addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("人脸添加失败:{}", e.getMessage());
|
||||
return;
|
||||
}
|
||||
if (addFaceResp != null) {
|
||||
faceSample.setScore(addFaceResp.getScore());
|
||||
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
|
||||
|
||||
}
|
||||
if (Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) {
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (SubImageInfoObject _subImage : type14ImageList) {
|
||||
facePosition.setImgHeight(_subImage.getHeight());
|
||||
facePosition.setImgWidth(_subImage.getWidth());
|
||||
SourceEntity source = new SourceEntity();
|
||||
source.setDeviceId(device.getId());
|
||||
source.setScenicId(device.getScenicId());
|
||||
source.setFaceSampleId(newFaceSampleId);
|
||||
source.setCreateTime(shotTime);
|
||||
source.setType(2);
|
||||
// 上传oss
|
||||
MultipartFile _file = ImageUtils.base64ToMultipartFile(_subImage.getData());
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
List<DeviceCropConfig> cropConfigs = deviceConfigEntity._getCropConfig();
|
||||
for (DeviceCropConfig cropConfig : cropConfigs) {
|
||||
source.setId(SnowFlakeUtil.getLongId());
|
||||
String filename = StorageUtil.joinPath(PHOTO_PATH, UUID.randomUUID() + "." + ext);
|
||||
MultipartFile _finalFile = _file;
|
||||
if (cropConfig.getCropType() == 1) {
|
||||
// 按固定位置截图
|
||||
try {
|
||||
_finalFile = ImageUtils.cropImage(_file, cropConfig.getTargetX(), cropConfig.getTargetY(), cropConfig.getTargetWidth(), cropConfig.getTargetHeight());
|
||||
} catch (IOException e) {
|
||||
log.error("裁切图片失败!", e);
|
||||
} catch (RasterFormatException e) {
|
||||
log.error("裁切图片出错!", e);
|
||||
}
|
||||
} else if (cropConfig.getCropType() == 2) {
|
||||
// 按人脸位置
|
||||
try {
|
||||
int targetX = facePosition.getLtX() - (cropConfig.getTargetWidth() - facePosition.getWidth())/2;
|
||||
int targetY = facePosition.getLtY() - (cropConfig.getTargetHeight() - facePosition.getHeight())/2;
|
||||
_finalFile = ImageUtils.cropImage(_file, targetX, targetY, cropConfig.getTargetWidth(), cropConfig.getTargetHeight());
|
||||
} catch (IOException e) {
|
||||
log.error("裁切图片失败!", e);
|
||||
} catch (RasterFormatException e) {
|
||||
log.error("裁切图片出错!", e);
|
||||
}
|
||||
facePosition.setImgHeight(cropConfig.getTargetHeight());
|
||||
facePosition.setImgWidth(cropConfig.getTargetWidth());
|
||||
}
|
||||
String _sourceUrl = scenicStorageAdapter.uploadFile(_finalFile, filename);
|
||||
scenicStorageAdapter.setAcl(StorageAcl.PUBLIC_READ, filename);
|
||||
source.setUrl(_sourceUrl);
|
||||
source.setPosJson(JacksonUtil.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, VIID_FACE, UUID.randomUUID() + "." + ext);
|
||||
faceSample.setFaceUrl(url);
|
||||
faceSampleMapper.add(faceSample);
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||||
AddFaceResp addFaceResp;
|
||||
try {
|
||||
addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("人脸添加失败:{}", e.getMessage());
|
||||
return;
|
||||
}
|
||||
if (addFaceResp != null) {
|
||||
faceSample.setScore(addFaceResp.getScore());
|
||||
faceSampleMapper.updateScore(faceSample.getId(), addFaceResp.getScore());
|
||||
if (Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) {
|
||||
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 {
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class DeviceIdObject implements Serializable {
|
||||
|
||||
@JsonProperty("DeviceID")
|
||||
private String deviceId;
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class FaceListObject {
|
||||
@JsonProperty("FaceObject")
|
||||
private List<FaceObject> faceObject;
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceObject {
|
||||
@JsonProperty("FaceID")
|
||||
private String FaceID;
|
||||
@JsonProperty("InfoKind")
|
||||
private Integer InfoKind;
|
||||
@JsonProperty("SourceID")
|
||||
private String SourceID;
|
||||
@JsonProperty("DeviceID")
|
||||
private String DeviceID;
|
||||
@JsonProperty("LeftTopX")
|
||||
private Integer LeftTopX;
|
||||
@JsonProperty("LeftTopY")
|
||||
private Integer LeftTopY;
|
||||
@JsonProperty("RightBtmX")
|
||||
private Integer RightBtmX;
|
||||
@JsonProperty("RightBtmY")
|
||||
private Integer RightBtmY;
|
||||
@JsonProperty("IDNumber")
|
||||
private String IDNumber;
|
||||
@JsonProperty("Name")
|
||||
private String Name;
|
||||
@JsonProperty("UsedName")
|
||||
private String UsedName;
|
||||
@JsonProperty("Alias")
|
||||
private String Alias;
|
||||
@JsonProperty("AgeUpLimit")
|
||||
private Integer AgeUpLimit;
|
||||
@JsonProperty("AgeLowerLimit")
|
||||
private Integer AgeLowerLimit;
|
||||
@JsonProperty("EthicCode")
|
||||
private String EthicCode;
|
||||
@JsonProperty("NationalityCode")
|
||||
private String NationalityCode;
|
||||
@JsonProperty("NativeCityCode")
|
||||
private String NativeCityCode;
|
||||
@JsonProperty("ResidenceAdminDivision")
|
||||
private String ResidenceAdminDivision;
|
||||
@JsonProperty("ChineseAccentCode")
|
||||
private String ChineseAccentCode;
|
||||
@JsonProperty("JobCategory")
|
||||
private String JobCategory;
|
||||
@JsonProperty("AccompanyNumber")
|
||||
private Integer AccompanyNumber;
|
||||
@JsonProperty("SkinColor")
|
||||
private String SkinColor;
|
||||
@JsonProperty("FaceStyle")
|
||||
private String FaceStyle;
|
||||
@JsonProperty("FacialFeature")
|
||||
private String FacialFeature;
|
||||
@JsonProperty("PhysicalFeature")
|
||||
private String PhysicalFeature;
|
||||
@JsonProperty("IsDriver")
|
||||
private Integer IsDriver;
|
||||
@JsonProperty("IsForeigner")
|
||||
private Integer IsForeigner;
|
||||
@JsonProperty("ImmigrantTypeCode")
|
||||
private String ImmigrantTypeCode;
|
||||
@JsonProperty("IsSuspectedTerrorist")
|
||||
private Integer IsSuspectedTerrorist;
|
||||
@JsonProperty("SuspectedTerroristNumber")
|
||||
private String SuspectedTerroristNumber;
|
||||
@JsonProperty("IsCriminalInvolved")
|
||||
private Integer IsCriminalInvolved;
|
||||
@JsonProperty("CriminalInvolvedSpecilisationCode")
|
||||
private String CriminalInvolvedSpecilisationCode;
|
||||
@JsonProperty("BodySpeciallMark")
|
||||
private String BodySpeciallMark;
|
||||
@JsonProperty("CrimeMethod")
|
||||
private String CrimeMethod;
|
||||
@JsonProperty("CrimeCharacterCode")
|
||||
private String CrimeCharacterCode;
|
||||
@JsonProperty("EscapedCriminalNumber")
|
||||
private String EscapedCriminalNumber;
|
||||
@JsonProperty("IsDetainees")
|
||||
private Integer IsDetainees;
|
||||
@JsonProperty("DetentionHouseCode")
|
||||
private String DetentionHouseCode;
|
||||
@JsonProperty("DetaineesSpecialIdentity")
|
||||
private String DetaineesSpecialIdentity;
|
||||
@JsonProperty("MemberTypeCode")
|
||||
private String MemberTypeCode;
|
||||
@JsonProperty("IsVictim")
|
||||
private String IsVictim;
|
||||
@JsonProperty("VictimType")
|
||||
private String VictimType;
|
||||
@JsonProperty("CorpseConditionCode")
|
||||
private String CorpseConditionCode;
|
||||
@JsonProperty("IsSuspiciousPerson")
|
||||
private String IsSuspiciousPerson;
|
||||
@JsonProperty("Attitude")
|
||||
private String Attitude;
|
||||
@JsonProperty("Similaritydegree")
|
||||
private String Similaritydegree;
|
||||
@JsonProperty("EyebrowStyle")
|
||||
private String EyebrowStyle;
|
||||
@JsonProperty("NoseStyle")
|
||||
private String NoseStyle;
|
||||
@JsonProperty("MustacheStyle")
|
||||
private String MustacheStyle;
|
||||
@JsonProperty("LipStyle")
|
||||
private String LipStyle;
|
||||
@JsonProperty("WrinklePouch")
|
||||
private String WrinklePouch;
|
||||
@JsonProperty("AcneStain")
|
||||
private String AcneStain;
|
||||
@JsonProperty("FreckleBirthmark")
|
||||
private String FreckleBirthmark;
|
||||
@JsonProperty("ScarDimple")
|
||||
private String ScarDimple;
|
||||
@JsonProperty("TabID")
|
||||
private String TabID;
|
||||
@JsonProperty("OtherFeature")
|
||||
private String OtherFeature;
|
||||
@JsonProperty("Maritalstatus")
|
||||
private String Maritalstatus;
|
||||
@JsonProperty("FamilyAddress")
|
||||
private String FamilyAddress;
|
||||
@JsonProperty("CollectorOrg")
|
||||
private String CollectorOrg;
|
||||
@JsonProperty("CollectorID")
|
||||
private String CollectorID;
|
||||
@JsonProperty("DeviceSNNo")
|
||||
private String DeviceSNNo;
|
||||
@JsonProperty("APSId")
|
||||
private String APSId;
|
||||
@JsonProperty("LocationMarkTime")
|
||||
private String LocationMarkTime;
|
||||
@JsonProperty("FaceAppearTime")
|
||||
private String FaceAppearTime;
|
||||
@JsonProperty("FaceDisAppearTime")
|
||||
private String FaceDisAppearTime;
|
||||
@JsonProperty("ShotTime")
|
||||
private String ShotTime;
|
||||
@JsonProperty("IDType")
|
||||
private String IDType;
|
||||
@JsonProperty("GenderCode")
|
||||
private String GenderCode;
|
||||
@JsonProperty("HairStyle")
|
||||
private String HairStyle;
|
||||
@JsonProperty("HairColor")
|
||||
private String HairColor;
|
||||
@JsonProperty("RespiratorColor")
|
||||
private String RespiratorColor;
|
||||
@JsonProperty("CapStyle")
|
||||
private String CapStyle;
|
||||
@JsonProperty("CapColor")
|
||||
private String CapColor;
|
||||
@JsonProperty("GlassStyle")
|
||||
private String GlassStyle;
|
||||
@JsonProperty("GlassColor")
|
||||
private String GlassColor;
|
||||
@JsonProperty("PassportType")
|
||||
private String PassportType;
|
||||
@JsonProperty("DetaineesIdentity")
|
||||
private String DetaineesIdentity;
|
||||
@JsonProperty("InjuredDegree")
|
||||
private String InjuredDegree;
|
||||
@JsonProperty("EntryTime")
|
||||
private String EntryTime;
|
||||
@JsonProperty("SubImageList")
|
||||
private SubImageList subImageList;
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FacePositionObject {
|
||||
private Integer imgWidth;
|
||||
private Integer imgHeight;
|
||||
private Integer ltX;
|
||||
private Integer ltY;
|
||||
private Integer rbX;
|
||||
private Integer rbY;
|
||||
@JsonProperty("width")
|
||||
public Integer getWidth(){
|
||||
return rbX - ltX;
|
||||
}
|
||||
@JsonProperty("height")
|
||||
public Integer getHeight(){
|
||||
return rbY - ltY;
|
||||
}
|
||||
|
||||
public Integer centerX(){
|
||||
return (ltX + rbX) / 2;
|
||||
}
|
||||
public Integer centerY(){
|
||||
return (ltY + rbY) / 2;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ImageInfoObject {
|
||||
@JsonProperty("ContentDescription")
|
||||
private String contentDescription;
|
||||
|
||||
@JsonProperty("EventSort")
|
||||
private int eventSort;
|
||||
|
||||
@JsonProperty("FileFormat")
|
||||
private String fileFormat;
|
||||
|
||||
@JsonProperty("FileSize")
|
||||
private long fileSize;
|
||||
|
||||
@JsonProperty("Height")
|
||||
private int height;
|
||||
|
||||
@JsonProperty("ImageID")
|
||||
private String imageID;
|
||||
|
||||
@JsonProperty("ImageSource")
|
||||
private String imageSource;
|
||||
|
||||
@JsonProperty("InfoKind")
|
||||
private int infoKind;
|
||||
|
||||
@JsonProperty("SecurityLevel")
|
||||
private String securityLevel;
|
||||
|
||||
@JsonProperty("ShotPlaceFullAdress")
|
||||
private String shotPlaceFullAdress;
|
||||
|
||||
@JsonProperty("ShotTime")
|
||||
private String shotTime;
|
||||
|
||||
@JsonProperty("Title")
|
||||
private String title;
|
||||
|
||||
@JsonProperty("Width")
|
||||
private int width;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ImageListObject {
|
||||
@JsonProperty("Image")
|
||||
private List<ImageObject> imageObject;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ImageObject {
|
||||
@JsonProperty("Data")
|
||||
private String data;
|
||||
|
||||
@JsonProperty("FaceList")
|
||||
private FaceListObject faceListObject;
|
||||
|
||||
@JsonProperty("ImageInfo")
|
||||
private ImageInfoObject imageInfoObject;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ResponseStatusObject {
|
||||
|
||||
@JsonProperty("Id")
|
||||
private String id;
|
||||
@JsonProperty("RequestURL")
|
||||
private String requestUrl;
|
||||
@JsonProperty("StatusCode")
|
||||
private String statusCode;
|
||||
@JsonProperty("StatusString")
|
||||
private String statusString;
|
||||
@JsonProperty("LocalTime")
|
||||
private String localTime;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SubImageInfoObject {
|
||||
@JsonProperty("ImageID")
|
||||
private String ImageID;
|
||||
@JsonProperty("EventSort")
|
||||
private Integer EventSort;
|
||||
@JsonProperty("DeviceID")
|
||||
private String DeviceID;
|
||||
@JsonProperty("StoragePath")
|
||||
private String StoragePath;
|
||||
@JsonProperty("Type")
|
||||
private String Type;
|
||||
@JsonProperty("FileFormat")
|
||||
private String FileFormat;
|
||||
@JsonProperty("Width")
|
||||
private Integer Width;
|
||||
@JsonProperty("Height")
|
||||
private Integer Height;
|
||||
@JsonProperty("ShotTime")
|
||||
private String ShotTime;
|
||||
@JsonProperty("Data")
|
||||
private String Data;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SubImageList {
|
||||
|
||||
@JsonProperty("SubImageInfoObject")
|
||||
private List<SubImageInfoObject> subImageInfoObject;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SystemTimeObject {
|
||||
@JsonProperty("VIIDServerID")
|
||||
private String viidServerId;
|
||||
@JsonProperty("TimeMode")
|
||||
private String timeMode;
|
||||
@JsonProperty("LocalTime")
|
||||
private String localTime;
|
||||
@JsonProperty("TimeZone")
|
||||
private String timezone;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.req;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.FaceListObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FaceUploadReq {
|
||||
@JsonProperty("FaceListObject")
|
||||
private FaceListObject faceListObject;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.req;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.ImageListObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ImageUploadReq {
|
||||
@JsonProperty("ImageListObject")
|
||||
private ImageListObject imageListObject;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.req;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class KeepaliveReq {
|
||||
@JsonProperty("KeepaliveObject")
|
||||
private DeviceIdObject keepaliveObject;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.req;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RegisterReq {
|
||||
@JsonProperty("RegisterObject")
|
||||
private DeviceIdObject registerObject;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.req;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UnRegisterReq {
|
||||
|
||||
@JsonProperty("UnRegisterObject")
|
||||
private DeviceIdObject unRegisterObject;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.resp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.SystemTimeObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SystemTimeResp {
|
||||
@JsonProperty("SystemTimeObject")
|
||||
private SystemTimeObject systemTimeObject;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.ycwl.basic.model.viid.resp;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class VIIDBaseResp {
|
||||
|
||||
@JsonProperty("ResponseStatusObject")
|
||||
private ResponseStatusObject responseStatusObject;
|
||||
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
package com.ycwl.basic.service.printer.impl;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.constant.StorageConstant;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
import com.ycwl.basic.exception.BaseException;
|
||||
import com.ycwl.basic.image.watermark.ImageWatermarkFactory;
|
||||
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
|
||||
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
|
||||
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
|
||||
import com.ycwl.basic.image.watermark.operator.IOperator;
|
||||
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
|
||||
import com.ycwl.basic.mapper.MemberMapper;
|
||||
import com.ycwl.basic.mapper.OrderMapper;
|
||||
import com.ycwl.basic.mapper.PrintTaskMapper;
|
||||
@@ -31,9 +39,15 @@ import com.ycwl.basic.model.printer.req.WorkerAuthReqVo;
|
||||
import com.ycwl.basic.model.printer.resp.PrintTaskResp;
|
||||
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.repository.PriceRepository;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.mobile.WxPayService;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.ImageUtils;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -43,6 +57,7 @@ import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
@@ -75,6 +90,8 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
private PrintTaskMapper printTaskMapper;
|
||||
@Autowired
|
||||
private IPriceCalculationService priceCalculationService;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
@Override
|
||||
public List<PrinterResp> listByScenicId(Long scenicId) {
|
||||
@@ -421,10 +438,108 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
List<MemberPrintResp> userPhotoListByOrderId = getUserPhotoListByOrderId(orderId);
|
||||
userPhotoListByOrderId.forEach(item -> {
|
||||
PrinterEntity printer = printerMapper.getById(item.getPrinterId());
|
||||
|
||||
// 水印处理逻辑
|
||||
String printUrl = item.getCropUrl();
|
||||
try {
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(item.getScenicId());
|
||||
String printWatermarkType = scenicConfig.getString("print_watermark_type");
|
||||
|
||||
if (StringUtils.isNotBlank(printWatermarkType)) {
|
||||
ImageWatermarkOperatorEnum watermarkType = ImageWatermarkOperatorEnum.getByCode(printWatermarkType);
|
||||
if (watermarkType != null) {
|
||||
// 准备存储适配器
|
||||
IStorageAdapter adapter;
|
||||
String storeType = scenicConfig.getString("store_type");
|
||||
if (storeType != null) {
|
||||
adapter = StorageFactory.get(storeType);
|
||||
String storeConfigJson = scenicConfig.getString("store_config_json");
|
||||
if (StringUtils.isNotBlank(storeConfigJson)) {
|
||||
adapter.loadConfig(JacksonUtil.parseObject(storeConfigJson, Map.class));
|
||||
}
|
||||
} else {
|
||||
adapter = StorageFactory.use("assets-ext");
|
||||
}
|
||||
|
||||
// 准备水印处理器
|
||||
IOperator operator = ImageWatermarkFactory.get(watermarkType);
|
||||
|
||||
// 下载原图
|
||||
File originalFile = new File("print_" + item.getId() + ".jpg");
|
||||
File watermarkedFile = new File("print_" + item.getId() + "_" + watermarkType.getType() + "." + watermarkType.getPreferFileType());
|
||||
File rotatedOriginalFile = null;
|
||||
File rotatedWatermarkedFile = null;
|
||||
boolean needRotation = false;
|
||||
|
||||
try {
|
||||
HttpUtil.downloadFile(item.getCropUrl().replace("oss.zhentuai.com", "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com"), originalFile);
|
||||
|
||||
// 判断图片方向并处理旋转
|
||||
boolean isLandscape = ImageUtils.isLandscape(originalFile);
|
||||
log.info("打印照片方向检测,照片ID: {}, 是否为横图: {}", item.getId(), isLandscape);
|
||||
|
||||
if (!isLandscape) {
|
||||
// 竖图需要旋转为横图
|
||||
needRotation = true;
|
||||
rotatedOriginalFile = new File("print_" + item.getId() + "_rotated.jpg");
|
||||
ImageUtils.rotateImage90(originalFile, rotatedOriginalFile);
|
||||
log.info("竖图已旋转为横图,照片ID: {}", item.getId());
|
||||
}
|
||||
|
||||
// 处理水印
|
||||
WatermarkInfo watermarkInfo = new WatermarkInfo();
|
||||
watermarkInfo.setOriginalFile(needRotation ? rotatedOriginalFile : originalFile);
|
||||
watermarkInfo.setWatermarkedFile(watermarkedFile);
|
||||
|
||||
operator.process(watermarkInfo);
|
||||
|
||||
// 如果之前旋转了,需要将水印图片旋转回去
|
||||
if (needRotation) {
|
||||
rotatedWatermarkedFile = new File("print_" + item.getId() + "_final_" + watermarkType.getType() + "." + watermarkType.getPreferFileType());
|
||||
ImageUtils.rotateImage270(watermarkedFile, rotatedWatermarkedFile);
|
||||
log.info("水印图片已旋转回竖图,照片ID: {}", item.getId());
|
||||
// 删除中间的横图水印文件
|
||||
if (watermarkedFile.exists()) {
|
||||
watermarkedFile.delete();
|
||||
}
|
||||
// 将最终的竖图水印文件赋值给watermarkedFile
|
||||
watermarkedFile = rotatedWatermarkedFile;
|
||||
}
|
||||
|
||||
// 上传水印图片
|
||||
String watermarkedUrl = adapter.uploadFile(null, watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
|
||||
printUrl = watermarkedUrl;
|
||||
log.info("水印处理成功,打印照片ID: {}, 水印URL: {}", item.getId(), watermarkedUrl);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("水印处理失败,使用原始照片进行打印。照片ID: {}", item.getId(), e);
|
||||
} finally {
|
||||
// 清理临时文件
|
||||
if (originalFile != null && originalFile.exists()) {
|
||||
originalFile.delete();
|
||||
}
|
||||
if (rotatedOriginalFile != null && rotatedOriginalFile.exists()) {
|
||||
rotatedOriginalFile.delete();
|
||||
}
|
||||
if (watermarkedFile != null && watermarkedFile.exists()) {
|
||||
watermarkedFile.delete();
|
||||
}
|
||||
if (rotatedWatermarkedFile != null && rotatedWatermarkedFile.exists()) {
|
||||
rotatedWatermarkedFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取景区配置失败,使用原始照片进行打印。景区ID: {}, 照片ID: {}", item.getScenicId(), item.getId(), e);
|
||||
}
|
||||
|
||||
PrintTaskEntity task = new PrintTaskEntity();
|
||||
task.setPrinterId(printer.getId());
|
||||
task.setStatus(0);
|
||||
task.setUrl(item.getCropUrl());
|
||||
task.setUrl(printUrl);
|
||||
task.setHeight(printer.getPreferH());
|
||||
task.setWidth(printer.getPreferW());
|
||||
task.setCreateTime(new Date());
|
||||
|
||||
@@ -81,7 +81,9 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class TaskTaskServiceImpl implements TaskService {
|
||||
private static final String WORKER_SELF_HOSTED_CACHE_KEY = "worker_self_hosted_scenic:%s";
|
||||
private static final String VIDEO_NOTIFICATION_CACHE_KEY = "video_notification_member:%s";
|
||||
private static final int CACHE_EXPIRE_MINUTES = 3;
|
||||
private static final int NOTIFICATION_CACHE_EXPIRE_MINUTES = 2;
|
||||
@Autowired
|
||||
private TaskMapper taskMapper;
|
||||
@Autowired
|
||||
@@ -621,6 +623,15 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
|
||||
@Override
|
||||
public void sendVideoGeneratedServiceNotification(Long taskId, Long memberId) {
|
||||
// 检查Redis中该memberId是否在3分钟内已发送过通知
|
||||
String notificationCacheKey = String.format(VIDEO_NOTIFICATION_CACHE_KEY, memberId);
|
||||
String cachedValue = redisTemplate.opsForValue().get(notificationCacheKey);
|
||||
|
||||
if (cachedValue != null) {
|
||||
log.info("memberId:{} 在3分钟内已发送过通知,跳过本次发送", memberId);
|
||||
return;
|
||||
}
|
||||
|
||||
MemberVideoEntity item = videoMapper.queryRelationByMemberTask(memberId, taskId);
|
||||
MemberRespVO member = memberMapper.getById(memberId);
|
||||
String openId = member.getOpenId();
|
||||
@@ -673,6 +684,10 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
msg.setSendReason("视频生成通知");
|
||||
msg.setSendBiz("视频生成");
|
||||
ztMessageProducerService.send(msg);
|
||||
|
||||
// 发送成功后,设置Redis缓存,2分钟过期
|
||||
redisTemplate.opsForValue().set(notificationCacheKey, String.valueOf(System.currentTimeMillis()), NOTIFICATION_CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
|
||||
log.debug("memberId:{} 通知发送成功,已设置{}分钟缓存", memberId, NOTIFICATION_CACHE_EXPIRE_MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
||||
import static com.ycwl.basic.constant.StorageConstant.VIID_FACE;
|
||||
|
||||
@Component
|
||||
@EnableScheduling
|
||||
@@ -229,19 +228,8 @@ public class FaceCleaner {
|
||||
log.info("开始清理人脸文件");
|
||||
List<FaceSampleRespVO> list = faceSampleMapper.list(new FaceSampleReqQuery());
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
List<StorageFileObject> fileObjectList = adapter.listDir(VIID_FACE);
|
||||
fileObjectList.parallelStream().forEach(fileObject -> {
|
||||
if (fileObject.getModifyTime() != null) {
|
||||
// 如果是一天以内修改的,则跳过
|
||||
if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) < 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(list.parallelStream().noneMatch(faceSampleRespVO -> faceSampleRespVO.getFaceUrl().contains(fileObject.getName()))){
|
||||
log.info("删除人脸文件:{}", fileObject);
|
||||
adapter.deleteFile(fileObject.getFullPath());
|
||||
}
|
||||
});
|
||||
// VIID相关功能已移除,不再清理VIID_FACE目录
|
||||
log.info("VIID人脸文件清理功能已移除");
|
||||
}
|
||||
public void cleanSourceOss() {
|
||||
log.info("开始清理源视频素材文件");
|
||||
|
||||
@@ -5,6 +5,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -77,6 +79,120 @@ public class ImageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断图片是否为横图(宽度大于高度)
|
||||
*
|
||||
* @param file 图片文件
|
||||
* @return true表示横图,false表示竖图
|
||||
* @throws IOException 读取文件失败
|
||||
*/
|
||||
public static boolean isLandscape(File file) throws IOException {
|
||||
BufferedImage image = null;
|
||||
try {
|
||||
image = ImageIO.read(file);
|
||||
if (image == null) {
|
||||
throw new IOException("无法读取图片文件: " + file.getPath());
|
||||
}
|
||||
return image.getWidth() > image.getHeight();
|
||||
} finally {
|
||||
if (image != null) {
|
||||
image.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转图片90度(顺时针)
|
||||
*
|
||||
* @param sourceFile 源图片文件
|
||||
* @param targetFile 目标图片文件
|
||||
* @throws IOException 读取或写入文件失败
|
||||
*/
|
||||
public static void rotateImage90(File sourceFile, File targetFile) throws IOException {
|
||||
BufferedImage sourceImage = null;
|
||||
BufferedImage rotatedImage = null;
|
||||
try {
|
||||
sourceImage = ImageIO.read(sourceFile);
|
||||
if (sourceImage == null) {
|
||||
throw new IOException("无法读取图片文件: " + sourceFile.getPath());
|
||||
}
|
||||
|
||||
int width = sourceImage.getWidth();
|
||||
int height = sourceImage.getHeight();
|
||||
|
||||
// 创建旋转后的图片(宽高互换)
|
||||
rotatedImage = new BufferedImage(height, width, sourceImage.getType());
|
||||
Graphics2D g2d = rotatedImage.createGraphics();
|
||||
|
||||
// 设置旋转变换
|
||||
AffineTransform transform = new AffineTransform();
|
||||
transform.translate(height / 2.0, width / 2.0);
|
||||
transform.rotate(Math.PI / 2);
|
||||
transform.translate(-width / 2.0, -height / 2.0);
|
||||
|
||||
g2d.setTransform(transform);
|
||||
g2d.drawImage(sourceImage, 0, 0, null);
|
||||
g2d.dispose();
|
||||
|
||||
// 保存旋转后的图片
|
||||
ImageIO.write(rotatedImage, "jpg", targetFile);
|
||||
log.info("图片旋转成功,原始尺寸: {}x{}, 旋转后尺寸: {}x{}", width, height, height, width);
|
||||
} finally {
|
||||
if (sourceImage != null) {
|
||||
sourceImage.flush();
|
||||
}
|
||||
if (rotatedImage != null) {
|
||||
rotatedImage.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转图片270度(逆时针90度)
|
||||
*
|
||||
* @param sourceFile 源图片文件
|
||||
* @param targetFile 目标图片文件
|
||||
* @throws IOException 读取或写入文件失败
|
||||
*/
|
||||
public static void rotateImage270(File sourceFile, File targetFile) throws IOException {
|
||||
BufferedImage sourceImage = null;
|
||||
BufferedImage rotatedImage = null;
|
||||
try {
|
||||
sourceImage = ImageIO.read(sourceFile);
|
||||
if (sourceImage == null) {
|
||||
throw new IOException("无法读取图片文件: " + sourceFile.getPath());
|
||||
}
|
||||
|
||||
int width = sourceImage.getWidth();
|
||||
int height = sourceImage.getHeight();
|
||||
|
||||
// 创建旋转后的图片(宽高互换)
|
||||
rotatedImage = new BufferedImage(height, width, sourceImage.getType());
|
||||
Graphics2D g2d = rotatedImage.createGraphics();
|
||||
|
||||
// 设置旋转变换
|
||||
AffineTransform transform = new AffineTransform();
|
||||
transform.translate(height / 2.0, width / 2.0);
|
||||
transform.rotate(-Math.PI / 2);
|
||||
transform.translate(-width / 2.0, -height / 2.0);
|
||||
|
||||
g2d.setTransform(transform);
|
||||
g2d.drawImage(sourceImage, 0, 0, null);
|
||||
g2d.dispose();
|
||||
|
||||
// 保存旋转后的图片
|
||||
ImageIO.write(rotatedImage, "jpg", targetFile);
|
||||
log.info("图片旋转成功,原始尺寸: {}x{}, 旋转后尺寸: {}x{}", width, height, height, width);
|
||||
} finally {
|
||||
if (sourceImage != null) {
|
||||
sourceImage.flush();
|
||||
}
|
||||
if (rotatedImage != null) {
|
||||
rotatedImage.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Base64DecodedMultipartFile implements MultipartFile {
|
||||
|
||||
private final byte[] imgContent;
|
||||
|
||||
Reference in New Issue
Block a user