彻底铲除OSSUtil,抽象、修改

This commit is contained in:
Jerry Yan 2024-12-26 19:34:20 +08:00
parent 473e7080a1
commit 201a6617ac
45 changed files with 765 additions and 317 deletions

View File

@ -1,7 +1,12 @@
package com.ycwl.basic.config;
import com.ycwl.basic.storage.entity.AliOssStorageConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
@ -12,10 +17,10 @@ import org.springframework.stereotype.Component;
@Data
@Component
public class FaceDetectConfig {
@Value("${aliYunFace.accessKeyId}")
@Value("${aliFace.accessKeyId}")
private String accessKeyId;
@Value("${aliYunFace.accessKeySecret}")
@Value("${aliFace.accessKeySecret}")
private String accessKeySecret;
@Value("${aliYunFace.region}")
@Value("${aliFace.region}")
private String region;
}

View File

@ -1,29 +0,0 @@
package com.ycwl.basic.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 阿里云OSS配置
*
* @author songmingsong
**/
@Data
@Component
public class OssConfig {
@Value("${aliYunOss.endpoint}")
private String endPoint;
@Value("${aliYunOss.accessKeyId}")
private String accessKeyId;
@Value("${aliYunOss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliYunOss.bucketName}")
private String bucketName;
@Value("${aliYunOss.objectName}")
private String objectName;
@Value("${aliYunOss.url}")
private String url;
@Value("${aliYunOss.region}")
private String region;
}

View File

@ -3,7 +3,7 @@ package com.ycwl.basic.controller;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.enums.BizCodeEnum;
import com.ycwl.basic.service.FileService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
/**
* @Author: songmingsong
@ -29,14 +30,13 @@ import java.io.IOException;
@Api(tags = "文件接口")
public class FileController {
@Autowired
private FileService fileService;
@ApiOperation(value = "上传文件")
@PostMapping("/upload")
@IgnoreToken
public ApiResponse<?> upload(@RequestParam(value = "file") MultipartFile file) throws IOException {
String url = fileService.uploadFile(file);
String[] split = file.getOriginalFilename().split("\\.");
String ext = split[split.length - 1];
String url = StorageFactory.use("assets").uploadFile(file, "web", UUID.randomUUID()+"."+ext);
return ApiResponse.success(url);
}
@ -44,7 +44,7 @@ public class FileController {
@PostMapping("/delete")
@IgnoreToken
public ApiResponse<?> delete(@RequestParam(value = "fileName") String fileName) throws IOException {
Boolean flag = fileService.delete(fileName);
boolean flag = StorageFactory.use("assets").deleteFile("web", fileName);
return flag ? ApiResponse.success(BizCodeEnum.REQUEST_OK) : ApiResponse.fail(BizCodeEnum.FAIL.getMessage());
}
}

View File

@ -0,0 +1,30 @@
package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.common.BaseQueryParameterReq;
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
import com.ycwl.basic.service.pc.FaceDetectLogService;
import com.ycwl.basic.utils.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/face/detect_log/v1")
public class FaceDetectLogController {
@Autowired
private FaceDetectLogService service;
@PostMapping("/page")
public ApiResponse<PageInfo<FaceDetectLog>> pageQuery(@RequestBody BaseQueryParameterReq req) {
PageHelper.startPage(req.getPageNum(), req.getPageSize());
List<FaceDetectLog> list = service.listByTimeDesc();
PageInfo<FaceDetectLog> pageInfo = new PageInfo<>(list);
return ApiResponse.success(pageInfo);
}
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.config.FaceDetectConfig;
import com.ycwl.basic.mapper.DeviceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.SourceMapper;
@ -25,10 +26,11 @@ 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.service.task.TaskFaceService;
import com.ycwl.basic.utils.AliFaceUtil;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.utils.ImageUtils;
import com.ycwl.basic.utils.IpUtils;
import com.ycwl.basic.utils.OssUtil;
import com.ycwl.basic.utils.SnowFlakeUtil;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
@ -179,8 +181,6 @@ public class ViidController {
@Autowired
private TaskFaceService taskFaceService;
@Autowired
private OssUtil ossUtil;
/**
@ -223,6 +223,7 @@ public class ViidController {
if (ext.equalsIgnoreCase("jpeg")) {
ext = "jpg";
}
IStorageAdapter adapter = StorageFactory.use("faces");
// Type=11 人脸
if (subImage.getType().equals("11")) {
// 上传oss
@ -232,13 +233,7 @@ public class ViidController {
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(new Date());
String url;
try {
url = ossUtil.uploadFile(file.getInputStream(), UUID.randomUUID().toString() + "." + ext);
} catch (IOException e) {
log.error("文件上传失败!", e);
continue;
}
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
log.info("人脸信息入库成功!");
@ -255,13 +250,7 @@ public class ViidController {
source.setFaceSampleId(newFaceSampleId);
source.setType(2);
// 上传oss
String url;
try {
url = ossUtil.uploadFile(file.getInputStream(), "user-photo/", newFaceSampleId + "." + ext);
} catch (IOException e) {
log.error("文件上传失败!", e);
continue;
}
String url = adapter.uploadFile(file, "user-photo", UUID.randomUUID() + "." + ext);
source.setUrl(url);
source.setPosJson(JSON.toJSONString(facePosition));
sourceMapper.add(source);

View File

@ -29,7 +29,7 @@ public class TemplateEntity {
/**
* 父模版ID
*/
private Long pid;
private long pid = 0;
/**
* 是否是占位素材0不是1是
*/

View File

@ -1,36 +0,0 @@
package com.ycwl.basic.service;
import cn.hutool.core.util.StrUtil;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.utils.OssUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Objects;
/**
* file请求服务
*
* @author songmingsong
*/
@Service
public class FileService {
@Autowired
private OssUtil ossUtil;
public String uploadFile(MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
if (StrUtil.isBlank(originalFilename)) {
throw new BaseException("文件上传失败,文件名不能为空");
}
String fileName=System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
return ossUtil.uploadFile(file.getInputStream(), fileName);
}
public Boolean delete(String fileName) {
return ossUtil.deleteFile(fileName);
}
}

View File

@ -0,0 +1,22 @@
package com.ycwl.basic.service.impl.pc;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycwl.basic.mapper.FaceDetectLogMapper;
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
import com.ycwl.basic.service.pc.FaceDetectLogService;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class FaceDetectLogServiceImpl extends ServiceImpl<FaceDetectLogMapper, FaceDetectLog> implements FaceDetectLogService {
@Override
public List<FaceDetectLog> listByTimeDesc() {
LambdaQueryWrapper<FaceDetectLog> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(FaceDetectLog::getCreateTime);
return list(queryWrapper);
}
}

View File

@ -16,6 +16,10 @@ import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.task.FaceCleaner;
import com.ycwl.basic.utils.*;
import lombok.extern.slf4j.Slf4j;
@ -31,6 +35,7 @@ import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
@ -45,8 +50,6 @@ public class FaceServiceImpl implements FaceService {
@Autowired
private FaceMapper faceMapper;
@Autowired
private OssUtil ossUtil;
@Autowired
private TaskFaceService faceService;
@Autowired
private StatisticsMapper statisticsMapper;
@ -56,8 +59,6 @@ public class FaceServiceImpl implements FaceService {
private float strictScore = 90F;
@Autowired
private TaskService taskTaskService;
@Autowired
private FaceCleaner faceCleaner;
@Override
public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
@ -123,17 +124,21 @@ public class FaceServiceImpl implements FaceService {
log.info("当前登录用户信息:{}",worker);
//1上传人脸照片
String faceUrl = uploadFileALiOss(file, userId);
IStorageAdapter adapter = StorageFactory.use("faces");
String filePath = StorageUtil.joinPath("user-faces", DateUtils.format(new Date(),"yyyy-MM-dd"));
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.split("\\.", 2)[1];
String fileName = UUID.randomUUID().toString() + "." + suffix;
String faceUrl = adapter.uploadFile(file, filePath, fileName);
SearchFaceRespVo scenicDbSearchResult = faceService.searchFace(scenicId, faceUrl);
if (scenicDbSearchResult == null) {
ossUtil.deleteFileByUrl(faceUrl);
adapter.deleteFile(filePath, fileName);
throw new BaseException("人脸照片校验失败,请重新上传");
}
float score = scenicDbSearchResult.getScore();
if (score<faceScore) {
//校验失败删除提示重新上传
ossUtil.deleteFileByUrl(faceUrl);
adapter.deleteFile(filePath, fileName);
throw new BaseException("人脸照片校验失败,请重新上传");
}
// 2通过人脸查找用户库
@ -194,37 +199,4 @@ public class FaceServiceImpl implements FaceService {
return ApiResponse.success(faceMapper.getByMemberId(memberId, 3928516560393736192L));
}
/**
* 阿里oss图片上传
*
* @param file file
* @param userId 用户id
* @return 地址
*/
private String uploadFileALiOss(MultipartFile file,Long userId) {
if (file.isEmpty()) {
throw new RuntimeException("文件不存在!");
}
String originalFilename = file.getOriginalFilename();
//获取文件名后缀
String suffix = originalFilename.split("\\.")[1];
if ("Jpeg".equals(suffix)) {
suffix = "jpg";
}
//文件储存路径
String filePath="";
String dateStr = DateUtils.format(new Date(),"yyyy-MM-dd");
filePath=filePath+dateStr+"/";
// 生成文件名
String fileName= userId+"." + suffix;
InputStream inputStream ;
try {
inputStream = file.getInputStream();
} catch (IOException e) {
log.error("文件上传失败!", e);
return null;
}
return ossUtil.uploadFile(inputStream,filePath+fileName) ;
}
}

View File

@ -33,6 +33,11 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.task.resp.AddFaceSampleRespVo;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
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.StorageType;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -41,7 +46,10 @@ import org.springframework.stereotype.Service;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -117,9 +125,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
if (matchList.get(0).getFaceItems().isEmpty()) {
return respVo;
}
List<SearchFaceResponse.Data.MatchListItem.FaceItemsItem> faceItems = matchList.get(0).getFaceItems().stream()
.filter(faceItemsItem -> faceItemsItem.getConfidence() > 50).collect(Collectors.toList());
List<MatchLocalRecord> records = faceItems.stream()
List<MatchLocalRecord> records = matchList.get(0).getFaceItems().stream()
.map(item -> {
MatchLocalRecord record = new MatchLocalRecord();
record.setIdStr(item.getExtraData());
@ -135,6 +141,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
.collect(Collectors.toList());
log.matchLocalRecord(records);
List<Long> faceSampleIds = records.stream()
.filter(record -> record.getConfidence() > 60)
.map(MatchLocalRecord::getFaceSampleId)
.collect(Collectors.toList());
respVo.setFirstMatchRate(matchList.get(0).getFaceItems().get(0).getConfidence());
@ -310,6 +317,30 @@ public class TaskFaceServiceImpl implements TaskFaceService {
}
}
@Override
public String uploadFile(MultipartFile file, Long userId) {
if (file.isEmpty()) {
throw new RuntimeException("文件不存在!");
}
String originalFilename = file.getOriginalFilename();
//获取文件名后缀
String suffix = originalFilename.split("\\.")[1];
if ("Jpeg".equals(suffix)) {
suffix = "jpg";
}
//文件储存路径
String filePath = StorageUtil.joinPath("user-faces", DateUtils.format(new Date(),"yyyy-MM-dd"));
// 生成文件名
String fileName= userId + "." + suffix;
IStorageAdapter adapter = StorageFactory.use("faces");
try {
return adapter.uploadFile(file.getInputStream(), filePath, fileName);
} catch (IOException e) {
log.error("文件上传失败!", e);
return null;
}
}
public void addFaceDBCache(String dbName) {
redisTemplate.opsForValue().set(FaceConstant.FACE_DB_NAME_PFX + dbName, "1");
}

View File

@ -2,11 +2,6 @@ package com.ycwl.basic.service.impl.task;
import com.alibaba.fastjson.JSON;
import com.ycwl.basic.constant.TaskConstant;
import com.ycwl.basic.device.DeviceFactory;
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
import com.ycwl.basic.mapper.DeviceMapper;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.RenderWorkerMapper;
@ -31,8 +26,10 @@ import com.ycwl.basic.model.task.req.TaskReqVo;
import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.task.VideoPieceGetter;
import com.ycwl.basic.utils.OssUtil;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
@ -68,8 +65,6 @@ public class TaskTaskServiceImpl implements TaskService {
@Autowired
private SourceMapper sourceMapper;
@Autowired
private OssUtil ossUtil;
@Autowired
private VideoMapper videoMapper;
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
@ -334,15 +329,16 @@ public class TaskTaskServiceImpl implements TaskService {
if (task == null) {
return null;
}
IStorageAdapter adapter = StorageFactory.use("faces");
String filename = task.getId() + "_" + task.getScenicId() + ".mp4";
if (StringUtils.isBlank(task.getVideoUrl())) {
// 生成
String url = ossUtil.generateUrlOfFile("user-video/", filename);
String url = adapter.getUrl("user-video", filename);
TaskEntity updateTask = new TaskEntity();
updateTask.setId(taskId);
updateTask.setVideoUrl(url);
taskMapper.update(updateTask);
}
return ossUtil.generateSignedUrlForUpload("user-video/", filename);
return adapter.getUrlForUpload("user-video", filename);
}
}

View File

@ -0,0 +1,10 @@
package com.ycwl.basic.service.pc;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
import java.util.List;
public interface FaceDetectLogService extends IService<FaceDetectLog> {
List<FaceDetectLog> listByTimeDesc();
}

View File

@ -2,6 +2,7 @@ package com.ycwl.basic.service.task;
import com.ycwl.basic.model.task.resp.AddFaceSampleRespVo;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import org.springframework.web.multipart.MultipartFile;
public interface TaskFaceService {
@ -22,4 +23,6 @@ public interface TaskFaceService {
void createFaceDB(String scenicId);
void assureFaceDB(String scenicId);
String uploadFile(MultipartFile file, Long userId);
}

View File

@ -0,0 +1,53 @@
package com.ycwl.basic.storage;
import com.ycwl.basic.storage.adapters.AliOssAdapter;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.adapters.LocalStorageAdapter;
import com.ycwl.basic.storage.entity.StorageConfig;
import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.storage.exceptions.StorageUndefinedException;
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
import java.util.HashMap;
import java.util.Map;
public class StorageFactory {
public static IStorageAdapter get(StorageType storageType, StorageConfig config) {
IStorageAdapter adapter = get(storageType);
adapter.setConfig(config);
return adapter;
}
public static IStorageAdapter get(StorageType storageType) {
switch (storageType) {
case LOCAL:
return new LocalStorageAdapter();
case ALI_OSS:
return new AliOssAdapter();
default:
throw new StorageUnsupportedException(storageType.getType());
}
}
public static IStorageAdapter get(String type) {
StorageType storageType = StorageType.getStorageType(type);
if (storageType == null) {
throw new StorageUnsupportedException(type);
}
return get(storageType);
}
public static Map<String, IStorageAdapter> definedName = new HashMap<>();
public static void register(String name, IStorageAdapter adapter) {
definedName.put(name, adapter);
}
public static IStorageAdapter use(String name) {
IStorageAdapter adapter = definedName.get(name);
if (adapter == null) {
throw new StorageUndefinedException(name);
}
return adapter;
}
}

View File

@ -0,0 +1,46 @@
package com.ycwl.basic.storage.adapters;
import com.ycwl.basic.storage.entity.StorageConfig;
import com.ycwl.basic.storage.exceptions.UploadFileFailedException;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Date;
public abstract class AStorageAdapter implements IStorageAdapter {
@Override
public String uploadFile(File file, String path, String filename) {
if (file == null) {
return null;
}
try {
InputStream inputStream = new FileInputStream(file);
return uploadFile(inputStream, path, filename);
} catch (FileNotFoundException e) {
throw new UploadFileFailedException("文件不存在");
}
}
@Override
public String uploadFile(MultipartFile file, String path, String filename) {
if (file == null) {
return null;
}
try {
InputStream inputStream = file.getInputStream();
return uploadFile(inputStream, path, filename);
} catch (Exception e) {
throw new UploadFileFailedException("文件上传失败");
}
}
@Override
public String getUrlForUpload(String path, String filename) {
return getUrlForUpload(path, filename, new Date(System.currentTimeMillis() + 1000 * 60 * 60));
}
}

View File

@ -0,0 +1,102 @@
package com.ycwl.basic.storage.adapters;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import com.ycwl.basic.storage.entity.AliOssStorageConfig;
import com.ycwl.basic.storage.entity.StorageConfig;
import com.ycwl.basic.storage.exceptions.StorageConfigException;
import com.ycwl.basic.storage.exceptions.UploadFileFailedException;
import com.ycwl.basic.storage.utils.StorageUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.Map;
public class AliOssAdapter extends AStorageAdapter {
private AliOssStorageConfig config;
@Override
public void loadConfig(Map<String, String> _config) {
AliOssStorageConfig config = new AliOssStorageConfig();
config.setAccessKeyId(_config.get("accessKeyId"));
config.setAccessKeySecret(_config.get("accessKeySecret"));
config.setBucketName(_config.get("bucketName"));
config.setEndpoint(_config.get("endpoint"));
config.setRegion(_config.get("region"));
config.setUrl(_config.get("url"));
config.setPrefix(_config.get("prefix"));
config.checkEverythingOK();
this.config = config;
}
@Override
public void setConfig(StorageConfig config) {
if (config == null) {
throw new StorageConfigException("配置为空");
}
if (config instanceof AliOssStorageConfig) {
this.config = (AliOssStorageConfig) config;
} else {
throw new StorageConfigException("配置类型错误,传入的类为:" + config.getClass().getName());
}
}
@Override
public String uploadFile(InputStream inputStream, String path, String filename) {
if (inputStream == null) {
return null;
}
String fullPath = buildPath(path, filename);
OSS ossClient = getOssClient();
try {
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream);
ossClient.putObject(putObjectRequest);
return getUrl(path, filename);
} catch (ClientException e) {
throw new UploadFileFailedException("上传文件失败:" + e.getErrorMessage());
}
}
@Override
public boolean deleteFile(String path, String filename) {
OSS ossClient = getOssClient();
try {
ossClient.deleteObject(config.getBucketName(), buildPath(path, filename));
return true;
} catch (ClientException e) {
return false;
}
}
@Override
public String getUrl(String path, String filename) {
return config.getUrl() + buildPath(path, filename);
}
@Override
public String getUrlForUpload(String path, String filename, Date expireDate) {
OSS ossClient = getOssClient();
URL url = ossClient.generatePresignedUrl(config.getBucketName(), buildPath(path, filename), expireDate, HttpMethod.PUT);
return url.toString();
}
private OSS getOssClient() {
OSS ossClient = new OSSClientBuilder().build(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret());
return ossClient;
}
private String buildPath(String ...paths) {
if (StringUtils.isNotBlank(config.getPrefix())) {
return StorageUtil.joinPath(config.getPrefix(), paths);
} else {
return StorageUtil.joinPath(paths);
}
}
}

View File

@ -0,0 +1,21 @@
package com.ycwl.basic.storage.adapters;
import com.ycwl.basic.storage.entity.StorageConfig;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
public interface IStorageAdapter {
void loadConfig(Map<String, String> config);
void setConfig(StorageConfig config);
String uploadFile(InputStream inputStream, String path, String filename);
String uploadFile(File file, String path, String filename);
String uploadFile(MultipartFile file, String path, String filename);
boolean deleteFile(String path, String filename);
String getUrl(String path, String filename);
String getUrlForUpload(String path, String filename);
String getUrlForUpload(String path, String filename, Date expireDate);
}

View File

@ -0,0 +1,39 @@
package com.ycwl.basic.storage.adapters;
import com.ycwl.basic.storage.entity.StorageConfig;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
public class LocalStorageAdapter extends AStorageAdapter{
@Override
public void loadConfig(Map<String, String> config) {
}
@Override
public void setConfig(StorageConfig config) {
}
@Override
public String uploadFile(InputStream inputStream, String path, String filename) {
return "";
}
@Override
public boolean deleteFile(String path, String filename) {
return false;
}
@Override
public String getUrl(String path, String filename) {
return "";
}
@Override
public String getUrlForUpload(String path, String filename, Date expireDate) {
return "";
}
}

View File

@ -0,0 +1,21 @@
package com.ycwl.basic.storage.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class AliOssStorageConfig extends StorageConfig {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
private String url;
private String region;
private String prefix;
@Override
public void checkEverythingOK() {
// TODO: 检查配置是否正确
}
}

View File

@ -0,0 +1,5 @@
package com.ycwl.basic.storage.entity;
public abstract class StorageConfig {
public abstract void checkEverythingOK();
}

View File

@ -0,0 +1,27 @@
package com.ycwl.basic.storage.enums;
import com.ycwl.basic.storage.adapters.AliOssAdapter;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.adapters.LocalStorageAdapter;
import lombok.Getter;
public enum StorageType {
LOCAL("LOCAL"),
ALI_OSS("ALI_OSS");
@Getter
private final String type;
StorageType(String type) {
this.type = type;
}
public static StorageType getStorageType(String type) {
for (StorageType storageType : StorageType.values()) {
if (storageType.getType().equals(type)) {
return storageType;
}
}
return null;
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.storage.exceptions;
public class StorageConfigException extends StorageException {
public StorageConfigException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.storage.exceptions;
public class StorageException extends RuntimeException {
public StorageException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.storage.exceptions;
public class StorageUndefinedException extends StorageException {
public StorageUndefinedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.storage.exceptions;
public class StorageUnsupportedException extends StorageException {
public StorageUnsupportedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.storage.exceptions;
public class UploadFileFailedException extends StorageException {
public UploadFileFailedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,30 @@
package com.ycwl.basic.storage.starter;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.starter.config.OverallStorageConfig;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
@Configuration
public class StorageAutoConfiguration {
private final OverallStorageConfig config;
public StorageAutoConfiguration(OverallStorageConfig config) {
this.config = config;
if (config != null) {
loadConfig();
}
}
private void loadConfig() {
config.getConfigs().forEach(item -> {
String name = item.getName();
String type = item.getType();
IStorageAdapter adapter = StorageFactory.get(type);
Map<String, String> config = item.getConfig();
adapter.loadConfig(config);
StorageFactory.register(name, adapter);
});
}
}

View File

@ -0,0 +1,15 @@
package com.ycwl.basic.storage.starter.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "storage")
@Data
public class OverallStorageConfig {
private List<StorageConfigItem> configs;
}

View File

@ -0,0 +1,12 @@
package com.ycwl.basic.storage.starter.config;
import lombok.Data;
import java.util.Map;
@Data
public class StorageConfigItem {
private String name;
private String type;
private Map<String, String> config;
}

View File

@ -0,0 +1,19 @@
package com.ycwl.basic.storage.tests;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.AliOssAdapter;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageType;
public class TestInitializationSpeed {
public static void main(String[] args) {
int i = 0;
long currentTimestamp = System.currentTimeMillis();
System.out.println("开始测试");
while (i++ < 100000000) {
// IStorageAdapter adapter = new AliOssAdapter();
StorageFactory.get(StorageType.ALI_OSS);
}
System.out.println("结束测试,耗时:" + (System.currentTimeMillis() - currentTimestamp) + "ms");
}
}

View File

@ -0,0 +1,41 @@
package com.ycwl.basic.storage.utils;
import org.apache.commons.lang3.StringUtils;
public class StorageUtil {
public static String joinPath(String path, String subPath) {
if (StringUtils.isBlank(path)) {
return subPath;
}
if (subPath.startsWith("/")) {
subPath = subPath.substring(1);
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
if (StringUtils.isBlank(subPath)) {
return path;
}
if (path.endsWith("/")) {
return path + subPath;
} else {
return path + "/" + subPath;
}
}
public static String joinPath(String ...names) {
String name = names[0];
for (int i = 1; i < names.length; i++) {
name = joinPath(name, names[i]);
}
return name;
}
public static String joinPath(String name, String ...names) {
for (String s : names) {
name = joinPath(name, s);
}
return name;
}
}

View File

@ -78,6 +78,7 @@ public class DynamicTaskGenerator {
}
}
Integer minimalPlaceholderFill = templateConfig.getMinimalPlaceholderFill();
int maxPlaceholder = 0;
List<String> placeholderList = new ArrayList<>();
if (minimalPlaceholderFill == null) {
minimalPlaceholderFill = 0;
@ -90,6 +91,7 @@ public class DynamicTaskGenerator {
}
if (minimalPlaceholderFill == 0) {
for (TemplateRespVO subTemplate : subTemplateList) {
maxPlaceholder += 1;
if (subTemplate.getIsPlaceholder() == 1) {
minimalPlaceholderFill += 1;
}
@ -127,7 +129,11 @@ public class DynamicTaskGenerator {
matchedPlaceholder += 1;
}
}
if (matchedPlaceholder >= minimalPlaceholderFill) {
if (matchedPlaceholder >= maxPlaceholder) {
log.info("当前人脸样本{}已超过最大占位素材{},自动创建任务", face.getFaceUrl(), maxPlaceholder);
taskService.createRenderTask(scenic.getId(), template.getId(), face.getId());
faceMapper.finishedJourney(face.getId());
} else if (matchedPlaceholder >= minimalPlaceholderFill) {
log.info("当前人脸样本{}已超过最小占位素材{},自动创建任务", face.getFaceUrl(), minimalPlaceholderFill);
taskService.createRenderTask(scenic.getId(), template.getId(), face.getId());
faceMapper.finishedJourney(face.getId());

View File

@ -10,7 +10,9 @@ 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.resp.FaceSampleRespVO;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.utils.OssUtil;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@ -44,8 +46,6 @@ public class VideoPieceGetter {
@Autowired
private DeviceMapper deviceMapper;
@Autowired
private OssUtil ossUtil;
@Autowired
private SourceMapper sourceMapper;
@Data
@ -123,9 +123,8 @@ public class VideoPieceGetter {
return;
}
log.info("视频裁切成功");
try {
InputStream inputStream = new FileInputStream(outFile);
String url = ossUtil.uploadFile(inputStream, "user-video-source/", outFile.getName());
IStorageAdapter adapter = StorageFactory.use("assets");
String url = adapter.uploadFile(outFile, "video-source", outFile.getName());
SourceEntity imgSource = sourceMapper.findBySampleId(faceSample.getId());
SourceEntity sourceEntity = new SourceEntity();
sourceEntity.setId(SnowFlakeUtil.getLongId());
@ -141,9 +140,6 @@ public class VideoPieceGetter {
sourceEntity.setDeviceId(faceSample.getDeviceId());
sourceEntity.setType(1);
sourceMapper.add(sourceEntity);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public boolean startFfmpegTask(FfmpegTask task) {

View File

@ -1,126 +0,0 @@
package com.ycwl.basic.utils;
import cn.hutool.core.date.DateUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.ycwl.basic.config.OssConfig;
import com.ycwl.basic.enums.BizCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.net.URI;
import java.util.Date;
@Slf4j
@Component
public class OssUtil {
@Autowired
private OssConfig ossConfig;
/**
* 上传文件到oss
* @param inputStream 文件数据流
* @param filename 文件全路径名称
* @return
*/
public String uploadFile(InputStream inputStream, String filename) {
return uploadFile(inputStream, ossConfig.getObjectName(), filename);
}
public String uploadAssetFile(InputStream inputStream, String filename) {
return uploadFile(inputStream, "assets/", filename);
}
public String uploadFile(InputStream inputStream, String path, String filename) {
String uploadFileName = path + filename;
OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
try {
PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), uploadFileName, inputStream);
ossClient.putObject(putObjectRequest);
String fileUrl = ossConfig.getUrl() + uploadFileName;
return fileUrl;
} catch (OSSException oe) {
log.error("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason."
+ " \n Error Message:" + oe.getErrorMessage()
+ " \n Error Code:" + oe.getErrorCode()
+ " \n Request ID:" + oe.getRequestId()
+ " \n Host ID:" + oe.getHostId()
);
} catch (ClientException ce) {
log.error("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network."
+ "Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return BizCodeEnum.UPLOAD_FAILED.getMessage();
}
public String generateSignedUrlForDownload(String path, String filename) {
String downloadFile = path + filename;
return generateSignedUrl(downloadFile, HttpMethod.GET);
}
public String generateSignedUrlForUpload(String path, String filename) {
String uploadFileName = path + filename;
return generateSignedUrl(uploadFileName, HttpMethod.PUT);
}
public String generateSignedUrl(String objectName, HttpMethod method) {
OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
return ossClient.generatePresignedUrl(ossConfig.getBucketName(), objectName, DateUtil.offsetHour(new Date(), 1), method).toString();
}
public String generateUrlOfFile(String path, String filename) {
String objectName = path + filename;
return ossConfig.getUrl() + objectName;
}
public boolean deleteFile(String filename) {
// 填写文件完整路径文件完整路径中不能包含Bucket名称
String objectName = filename;
OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
try {
// 删除文件或目录如果要删除目录目录必须为空
ossClient.deleteObject(ossConfig.getBucketName(), objectName);
return true;
} catch (OSSException oe) {
log.error("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason."
+ " \n Error Message:" + oe.getErrorMessage()
+ " \n Error Code:" + oe.getErrorCode()
+ " \n Request ID:" + oe.getRequestId()
+ " \n Host ID:" + oe.getHostId()
);
} catch (ClientException ce) {
log.error("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network."
+ "Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return false;
}
public void deleteFileByUrl(String faceUrl) {
URI uri = URI.create(faceUrl);
String objectName = uri.getPath();
deleteFile(objectName);
}
}

View File

@ -0,0 +1,4 @@
package com.ycwl.basic.videoTask;
public class VideoTaskFactory {
}

View File

@ -0,0 +1,4 @@
package com.ycwl.basic.videoTask.adapters;
public class DefaultAdapter implements IAdapter {
}

View File

@ -0,0 +1,4 @@
package com.ycwl.basic.videoTask.adapters;
public interface IAdapter {
}

View File

@ -0,0 +1,22 @@
package com.ycwl.basic.videoTask.chains;
import com.ycwl.basic.videoTask.chains.interceptor.IVidTaskGenChainInterceptor;
import com.ycwl.basic.videoTask.entity.VideoTaskGeneratorContext;
import java.util.ArrayList;
import java.util.List;
public class VideoTaskGeneratorChain {
private final List<IVidTaskGenChainInterceptor> interceptors = new ArrayList<>();
private int index = 0;
public void addInterceptor(IVidTaskGenChainInterceptor interceptor) {
interceptors.add(interceptor);
}
public void process(VideoTaskGeneratorContext context) {
if (index < interceptors.size()) {
interceptors.get(index++).process(context, this);
}
}
}

View File

@ -0,0 +1,11 @@
package com.ycwl.basic.videoTask.chains.interceptor;
import com.ycwl.basic.videoTask.chains.VideoTaskGeneratorChain;
import com.ycwl.basic.videoTask.entity.VideoTaskGeneratorContext;
public class CheckFaceCountInterceptor implements IVidTaskGenChainInterceptor {
@Override
public void process(VideoTaskGeneratorContext ctx, VideoTaskGeneratorChain chain) {
}
}

View File

@ -0,0 +1,8 @@
package com.ycwl.basic.videoTask.chains.interceptor;
import com.ycwl.basic.videoTask.chains.VideoTaskGeneratorChain;
import com.ycwl.basic.videoTask.entity.VideoTaskGeneratorContext;
public interface IVidTaskGenChainInterceptor {
void process(VideoTaskGeneratorContext ctx, VideoTaskGeneratorChain chain);
}

View File

@ -0,0 +1,4 @@
package com.ycwl.basic.videoTask.daos;
public class TemplateDao {
}

View File

@ -0,0 +1,4 @@
package com.ycwl.basic.videoTask.entity;
public class VideoTaskGeneratorContext {
}

View File

@ -0,0 +1,22 @@
package com.ycwl.basic.videoTask.enums;
import lombok.Getter;
import lombok.Setter;
public enum VideoTaskTriggerReason {
DEVICE_UPLOAD("设备检测人脸"),
USER_MANUAL("用户手动触发"),
ADMIN_MANUAL("后台手动触发"),
SCHEDULE("定时触发"),
USER_FACE_UPLOAD("用户上传人脸触发");
@Getter
private final String desc;
@Getter
@Setter
private String extData;
VideoTaskTriggerReason(String desc) {
this.desc = desc;
}
}

View File

@ -119,17 +119,32 @@ YfkdFNxtYLdVAwuylMoV3fKI
face:
score: 80
#阿里云OSS
aliYunOss:
# 存储
storage:
configs:
- name: "faces"
type: "ALI_OSS"
config:
endpoint: "https://oss-cn-shanghai.aliyuncs.com"
accessKeyId: "LTAI5tCa641QdNHH9Ybg9u7V"
accessKeySecret: "RRVIgekoqx96Fgm2Gs7eQshMShcEpk"
bucketName: "frametour-assets"
objectName: "user-faces/"
prefix: "user-faces/"
url: "https://frametour-assets.oss-cn-shanghai.aliyuncs.com/"
region: "cn-shanghai"
- name: "assets"
type: "ALI_OSS"
config:
endpoint: "https://oss-cn-shanghai.aliyuncs.com"
accessKeyId: "LTAI5tCa641QdNHH9Ybg9u7V"
accessKeySecret: "RRVIgekoqx96Fgm2Gs7eQshMShcEpk"
bucketName: "frametour-assets"
prefix: "user-assets/"
url: "https://oss.zhentuai.com"
region: "cn-shanghai"
#阿里云人脸检测
aliYunFace:
aliFace:
accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx"
accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c"
region: "cn-shanghai"

View File

@ -117,17 +117,32 @@ YfkdFNxtYLdVAwuylMoV3fKI
face:
score: 80
#阿里云OSS
aliYunOss:
endpoint: "https://oss-cn-shanghai.aliyuncs.com"
# 存储
storage:
configs:
- name: "faces"
type: "ALI_OSS"
config:
endpoint: "https://oss-cn-shanghai-internal.aliyuncs.com"
accessKeyId: "LTAI5tCa641QdNHH9Ybg9u7V"
accessKeySecret: "RRVIgekoqx96Fgm2Gs7eQshMShcEpk"
bucketName: "frametour-assets"
objectName: "user-faces/"
prefix: "user-faces/"
url: "https://frametour-assets.oss-cn-shanghai.aliyuncs.com/"
region: "cn-shanghai"
- name: "assets"
type: "ALI_OSS"
config:
endpoint: "https://oss-cn-shanghai-internal.aliyuncs.com"
accessKeyId: "LTAI5tCa641QdNHH9Ybg9u7V"
accessKeySecret: "RRVIgekoqx96Fgm2Gs7eQshMShcEpk"
bucketName: "frametour-assets"
prefix: "user-assets/"
url: "https://oss.zhentuai.com"
region: "cn-shanghai"
#阿里云人脸检测
aliYunFace:
aliFace:
accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx"
accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c"
region: "cn-shanghai"