执行任务的步骤截图,异步上传优化
1.文件服务的数据库cctp_attachment的表增加字段:存储路径storage_path,长度128位 2.cctp-commons关于的文件上传增加支持外部传入指定id的逻辑 3.由于使用了seaweedfs,上传完成后会使用volume id和file key重新作为附件的id存入到数据,所以增加了storage_path保存外部传入id 4.在下载附件的逻辑的增加判断,如果分割后的字符串存在多个/那么使用storagePath查询附件id再下载 5.执行引擎的修改是对pc的截图异步上传。 6.上位机的修改是ios和安卓的截图异步上传。 7.大致逻辑:步骤截图后,将文件名、文件路径、任务id、xy坐标、租户id、业务代码存入到本地h2数据库;通过定时任务,如果线程池是空闲,那么每次查询前20条数据,使用线程池进行遍历上传。master
parent
c053ed2583
commit
8666c2cf92
|
@ -0,0 +1,8 @@
|
|||
package net.northking.cctp.se.attach;
|
||||
|
||||
public interface AttachInfoService {
|
||||
|
||||
AttachmentDB save(String filename, String filePath, String tenantId, String objectId, String bizCode);
|
||||
|
||||
AttachmentDB save(String filename, String filePath, String tenantId, int x, int y, String objectId, String bizCode);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package net.northking.cctp.se.attach;
|
||||
|
||||
|
||||
import net.northking.cctp.se.repository.AttachmentInfoRepository;
|
||||
import net.northking.cctp.se.util.AttachUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class AttachInfoServiceImpl implements AttachInfoService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AttachInfoServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private AttachmentInfoRepository attachRepo;
|
||||
|
||||
@Override
|
||||
public AttachmentDB save(String filename, String filePath, String tenantId, String objectId, String bizCode) {
|
||||
return save(filename, filePath, tenantId, -1, -1, objectId, bizCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachmentDB save(String filename, String filePath, String tenantId, int x, int y, String objectId, String bizCode) {
|
||||
AttachmentDB attachmentDB = new AttachmentDB();
|
||||
attachmentDB.setId(AttachUtils.createId(filename));
|
||||
attachmentDB.setUrl(AttachUtils.exchangeToUrl(attachmentDB.getId(), tenantId));
|
||||
attachmentDB.setFilename(filename);
|
||||
attachmentDB.setFilePath(filePath);
|
||||
attachmentDB.setCreatedTime(new Date());
|
||||
attachmentDB.setTenantId(tenantId);
|
||||
attachmentDB.setFailureTimes(0);
|
||||
attachmentDB.setX(x);
|
||||
attachmentDB.setY(y);
|
||||
attachmentDB.setObjectId(objectId);
|
||||
attachmentDB.setBizCode(bizCode);
|
||||
attachRepo.saveAndFlush(attachmentDB);
|
||||
return attachmentDB;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package net.northking.cctp.se.attach;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import net.northking.cctp.se.file.Attachment;
|
||||
import net.northking.cctp.se.repository.AttachmentInfoRepository;
|
||||
import net.northking.cctp.se.util.HttpUtils;
|
||||
import net.northking.cctp.se.util.SpringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 附件信息上传
|
||||
*
|
||||
*/
|
||||
public class AttachInfoUpload implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AttachInfoUpload.class);
|
||||
|
||||
private AttachmentDB attachmentDB;
|
||||
|
||||
public AttachInfoUpload(AttachmentDB attachmentDB) {
|
||||
this.attachmentDB = attachmentDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (attachmentDB.getX() > 0 && attachmentDB.getY() > 0) {
|
||||
addSignature();
|
||||
}
|
||||
AttachmentInfoRepository repo = SpringUtils.getBean(AttachmentInfoRepository.class);
|
||||
try {
|
||||
Attachment upload = HttpUtils.upload(attachmentDB.getFilePath(),
|
||||
attachmentDB.getTenantId(), attachmentDB.getObjectId(),
|
||||
attachmentDB.getBizCode(), attachmentDB.getId());
|
||||
if (upload != null && StringUtils.isNotBlank(upload.getUrlPath())) {
|
||||
// 上传成功
|
||||
logger.debug("文件上传成功:{}, storagePath -> {}", BeanUtil.beanToMap(upload).toString(), attachmentDB.getId());
|
||||
// 删除数据库信息
|
||||
repo.deleteById(attachmentDB.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("附件上传失败", e);
|
||||
// 附件信息的失败次数加1,并更新数据库数据
|
||||
attachmentDB.setFailureTimes(attachmentDB.getFailureTimes() + 1);
|
||||
repo.saveAndFlush(attachmentDB);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addSignature() {
|
||||
// 根据信息添加红点或者其他标记
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package net.northking.cctp.se.attach;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 附件对象
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "attachment_info")
|
||||
@ToString
|
||||
public class AttachmentDB {
|
||||
// 格式:/yyyy/MM/dd/32位uuid.文件类型
|
||||
@Id
|
||||
private String id;
|
||||
// 格式: tenantId_yyyy_MM_dd_32位uuid.文件类型
|
||||
private String url;
|
||||
|
||||
private String filename;
|
||||
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdTime;
|
||||
|
||||
/**
|
||||
* 红点x坐标
|
||||
*/
|
||||
private int x;
|
||||
|
||||
/**
|
||||
* 红点y坐标
|
||||
*/
|
||||
private int y;
|
||||
|
||||
/**
|
||||
* 租户id
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 上传失败次数
|
||||
*/
|
||||
private int failureTimes;
|
||||
|
||||
private String objectId;
|
||||
|
||||
private String bizCode;
|
||||
}
|
|
@ -2,6 +2,7 @@ package net.northking.cctp.se.config;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.Data;
|
||||
import net.northking.cctp.se.thread.AttachInfoExecutorPool;
|
||||
import net.northking.cctp.se.thread.ExecutorPool;
|
||||
import net.northking.cctp.se.util.SpringUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -26,6 +27,11 @@ public class ExecutorPoolConfig {
|
|||
return executorPool;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AttachInfoExecutorPool createAttachInfoPool() {
|
||||
AttachInfoExecutorPool pool = new AttachInfoExecutorPool();
|
||||
return pool;
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "atu.engine.executor-pool")
|
||||
@Configuration
|
||||
|
|
|
@ -13,9 +13,12 @@ import net.northking.cctp.common.http.ResultWrapper;
|
|||
import net.northking.cctp.element.core.exception.ExecuteException;
|
||||
import net.northking.cctp.pc.driver.dto.EngineResultDto;
|
||||
import net.northking.cctp.pc.driver.socket.PCDriver;
|
||||
import net.northking.cctp.se.attach.AttachInfoService;
|
||||
import net.northking.cctp.se.attach.AttachmentDB;
|
||||
import net.northking.cctp.se.file.Attachment;
|
||||
import net.northking.cctp.se.util.HttpUtils;
|
||||
import net.northking.cctp.se.util.JsonUtils;
|
||||
import net.northking.cctp.se.util.SpringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
|
||||
|
@ -281,11 +284,13 @@ public class PCDeviceConnection extends AbstractDeviceConnection {
|
|||
log.debug("截图上传入参tenantId:{}",tenantId);
|
||||
log.debug("截图上传入参initData:{}", JSONObject.toJSONString(initData));
|
||||
log.debug("截图入参taskId,{}", initData.get("taskId"));
|
||||
Attachment upload = HttpUtils.upload(localPath, tenantId, (String)initData.get("taskId"), FileBusinessTypeEnum.PC_TASK_SCREENSHOT.getCode());
|
||||
// Attachment upload = HttpUtils.upload(localPath, tenantId, (String)initData.get("taskId"), FileBusinessTypeEnum.PC_TASK_SCREENSHOT.getCode());
|
||||
String filename = localPath.substring(localPath.lastIndexOf("\\") + 1);
|
||||
AttachmentDB upload = SpringUtils.getBean(AttachInfoService.class).save(filename, localPath, tenantId, (String)initData.get("taskId"), FileBusinessTypeEnum.PC_TASK_SCREENSHOT.getCode());
|
||||
if (ObjectUtil.isNull(upload) || StringUtils.isBlank(upload.getId())){
|
||||
throw new RuntimeException("截图文件上传信息为空");
|
||||
}
|
||||
return upload.getUrlPath();
|
||||
return upload.getUrl();
|
||||
}catch (Exception e){
|
||||
log.error("截图上传失败", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package net.northking.cctp.se.repository;
|
||||
|
||||
import net.northking.cctp.se.attach.AttachmentDB;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface AttachmentInfoRepository extends JpaRepository<AttachmentDB, String> {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package net.northking.cctp.se.scheduler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.northking.cctp.se.attach.AttachInfoUpload;
|
||||
import net.northking.cctp.se.attach.AttachmentDB;
|
||||
import net.northking.cctp.se.config.AtuServerConfig;
|
||||
import net.northking.cctp.se.repository.AttachmentInfoRepository;
|
||||
import net.northking.cctp.se.thread.AttachInfoExecutorPool;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title: AttachUploadScheduler</p>
|
||||
* <p>Description: 附件信息上传检查</p>
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AttachUploadScheduler {
|
||||
|
||||
@Autowired
|
||||
private AtuServerConfig atuServerConfig;
|
||||
|
||||
@Autowired
|
||||
private AttachmentInfoRepository repo;
|
||||
|
||||
@Autowired
|
||||
private AttachInfoExecutorPool pool;
|
||||
|
||||
/**
|
||||
* 附件信息检查
|
||||
* 初始延迟时间 20秒, 3秒检测一次
|
||||
*/
|
||||
@Scheduled(initialDelay = 20 * 1000, fixedDelay = 3 * 1000)
|
||||
public void upload() {
|
||||
try {
|
||||
// 是否都空闲了
|
||||
if (!pool.isUploadAvailable()) {
|
||||
return;
|
||||
}
|
||||
// 查询前面20条数据
|
||||
Sort orderBy = Sort.by(Sort.Order.asc("failureTimes"), Sort.Order.asc("createdTime"));
|
||||
Pageable pageable = PageRequest.of(0, 10, orderBy);
|
||||
Page<AttachmentDB> resultPage = repo.findAll(pageable);
|
||||
List<AttachmentDB> content = resultPage.getContent();
|
||||
if (!content.isEmpty()) {
|
||||
for (AttachmentDB db : content) {
|
||||
AttachInfoUpload uploadRunnable = new AttachInfoUpload(db);
|
||||
pool.uploadTaskSubmit(uploadRunnable);
|
||||
}
|
||||
}
|
||||
// 便利
|
||||
}catch (Exception e){
|
||||
log.error("发送任务执行心跳异常", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,8 @@ import net.northking.cctp.element.core.exception.ExecuteException;
|
|||
import net.northking.cctp.element.core.exception.KeywordNotFoundException;
|
||||
import net.northking.cctp.element.core.keyword.KeywordArgument;
|
||||
import net.northking.cctp.element.core.type.LibraryConstant;
|
||||
import net.northking.cctp.se.attach.AttachInfoService;
|
||||
import net.northking.cctp.se.attach.AttachmentDB;
|
||||
import net.northking.cctp.se.component.ComponentLibrary;
|
||||
import net.northking.cctp.se.component.ComponentManagementService;
|
||||
import net.northking.cctp.se.component.InternalComponent;
|
||||
|
@ -1368,12 +1370,15 @@ public class ScriptRuntimeExecutor implements ScriptExecutor {
|
|||
log.debug("localPath = " + stepSnapshot);
|
||||
log.debug("tenantId = " + tenantId);
|
||||
if (StrUtil.isNotEmpty(tenantId) && StrUtil.isNotEmpty(stepSnapshot)){
|
||||
Attachment upload = HttpUtils.upload(stepSnapshot, tenantId, currentTaskId, FileBusinessTypeEnum.PC_TASK_SCREENSHOT.getCode());
|
||||
// Attachment upload = HttpUtils.upload(stepSnapshot, tenantId, currentTaskId, FileBusinessTypeEnum.PC_TASK_SCREENSHOT.getCode());
|
||||
String filename = stepSnapshot.substring(stepSnapshot.lastIndexOf("\\") + 1);
|
||||
AttachmentDB upload = SpringUtils.getBean(AttachInfoService.class).save(filename, stepSnapshot, tenantId, currentTaskId, FileBusinessTypeEnum.PC_TASK_SCREENSHOT.getCode());
|
||||
|
||||
if (ObjectUtil.isNull(upload) || StringUtils.isBlank(upload.getId())) {
|
||||
throw new RuntimeException("截图文件上传信息为空");
|
||||
}
|
||||
log.debug("截图文件上传结果,{}", JSON.toJSONString(upload));
|
||||
stepRet.setActualImgUri(upload.getUrlPath());
|
||||
stepRet.setActualImgUri(upload.getUrl());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取步骤执行时截图失败", e);
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package net.northking.cctp.se.thread;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 附件上传
|
||||
*/
|
||||
public class AttachInfoExecutorPool {
|
||||
|
||||
private ThreadPoolExecutor uploadPool;
|
||||
|
||||
private ThreadPoolExecutor savePool;
|
||||
|
||||
public AttachInfoExecutorPool() {
|
||||
uploadPool = new ThreadPoolExecutor(1, 3,
|
||||
0L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
savePool = new ThreadPoolExecutor(1, 3,
|
||||
0L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提交执行附件上传任务
|
||||
* @param task
|
||||
*/
|
||||
public void uploadTaskSubmit(Runnable task) {
|
||||
uploadPool.submit(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 线程池是否空闲
|
||||
* @return
|
||||
*/
|
||||
public boolean isUploadAvailable() {
|
||||
return uploadPool.getActiveCount() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 队列中任务剩余数量
|
||||
* @return
|
||||
*/
|
||||
public int uploadTaskLeft() {
|
||||
return uploadPool.getQueue().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交执行附件保存任务
|
||||
* @param task
|
||||
*/
|
||||
public void saveTaskSubmit(Runnable task) {
|
||||
savePool.submit(task);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package net.northking.cctp.se.util;
|
||||
|
||||
import net.northking.cctp.common.util.UUIDUtil;
|
||||
import net.northking.cctp.element.core.exception.ExecuteException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 附件相关工具类
|
||||
*/
|
||||
public class AttachUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AttachUtils.class);
|
||||
|
||||
/**
|
||||
* 生成附件id
|
||||
* /yyyy/MM/dd/32位uuid[.文件后缀]
|
||||
*
|
||||
* @param filename 附件名称
|
||||
* @return 附件id
|
||||
*/
|
||||
public static String createId(String filename) {
|
||||
if (StringUtils.isBlank(filename)) {
|
||||
logger.error("上传资源失败:附件名称不能为空");
|
||||
throw new ExecuteException("上传资源失败:附件名称不能为空");
|
||||
}
|
||||
String id;
|
||||
int i = filename.lastIndexOf(".");
|
||||
if (i <= 0) { // 文件没有后缀名称
|
||||
id = createDatePath() + UUIDUtil.create32UUID();
|
||||
} else { // 文件存在后缀名称
|
||||
String postfix = filename.substring(i + 1);
|
||||
id = createDatePath() + UUIDUtil.create32UUID() + "." + postfix;
|
||||
}
|
||||
logger.debug("文件[{}] --> id: {}", filename, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public static String exchangeToUrl(String attachId, String tenantId) {
|
||||
return String.format("%s%s", tenantId, encodeAttachId(attachId));
|
||||
}
|
||||
|
||||
private static String encodeAttachId(String id) {
|
||||
return id.replace("/", "_");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据日期创建目录
|
||||
*
|
||||
* @return 根据日期创建目录
|
||||
*/
|
||||
private static String createDatePath()
|
||||
{
|
||||
SimpleDateFormat format = new SimpleDateFormat("/yyyy/MM/dd/");
|
||||
return format.format(new Date());
|
||||
}
|
||||
|
||||
}
|
|
@ -120,13 +120,17 @@ public class HttpUtils {
|
|||
return response.getBody();
|
||||
}
|
||||
|
||||
public static Attachment upload(String filePath, String tenantId, String objId, String businessCode) {
|
||||
return upload(filePath, tenantId, objId, businessCode, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传资源
|
||||
* @param filePath
|
||||
* @param tenantId
|
||||
* @return
|
||||
*/
|
||||
public static Attachment upload(String filePath, String tenantId, String objId, String businessCode) {
|
||||
public static Attachment upload(String filePath, String tenantId, String objId, String businessCode, String attachId) {
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
throw new ExecuteException("上传资源失败:缺少租户信息");
|
||||
}
|
||||
|
@ -141,6 +145,9 @@ public class HttpUtils {
|
|||
multipartMap.add("tenantId", tenantId);
|
||||
multipartMap.add("objId", objId);
|
||||
multipartMap.add("businessCode", businessCode);
|
||||
if (StringUtils.isNotBlank(attachId)) {
|
||||
multipartMap.add("attachId", attachId);
|
||||
}
|
||||
FormHttpMessageConverter converter = new FormHttpMessageConverter();
|
||||
converter.addPartConverter(new ResourceHttpMessageConverter());
|
||||
template.getMessageConverters().add(converter);
|
||||
|
|
|
@ -37,6 +37,11 @@ spring:
|
|||
pool:
|
||||
max-active: 5
|
||||
max-idle: 5
|
||||
task:
|
||||
scheduling:
|
||||
pool:
|
||||
size: 3
|
||||
thread-name-prefix: scheduler-task-
|
||||
|
||||
management:
|
||||
endpoints:
|
||||
|
|
|
@ -176,6 +176,14 @@
|
|||
<artifactId>thumbnailator</artifactId>
|
||||
<version>0.4.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
package net.northking.cctp.upperComputer.attach;
|
||||
|
||||
public interface AttachInfoService {
|
||||
|
||||
AttachmentDB save(String filename, String filePath, String tenantId, String objectId, String bizCode);
|
||||
|
||||
AttachmentDB save(String filename, String filePath, String tenantId, int x, int y, String objectId, String bizCode);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.northking.cctp.upperComputer.attach;
|
||||
|
||||
|
||||
import net.northking.cctp.upperComputer.utils.AttachUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class AttachInfoServiceImpl implements AttachInfoService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AttachInfoServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private AttachmentInfoRepository attachRepo;
|
||||
|
||||
@Override
|
||||
public AttachmentDB save(String filename, String filePath, String tenantId, String objectId, String bizCode) {
|
||||
return save(filename, filePath, tenantId, -1, -1, objectId, bizCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachmentDB save(String filename, String filePath, String tenantId, int x, int y, String objectId, String bizCode) {
|
||||
AttachmentDB attachmentDB = new AttachmentDB();
|
||||
attachmentDB.setId(AttachUtils.createId(filename));
|
||||
attachmentDB.setUrl(AttachUtils.exchangeToUrl(attachmentDB.getId(), tenantId));
|
||||
attachmentDB.setFilename(filename);
|
||||
attachmentDB.setFilePath(filePath);
|
||||
attachmentDB.setCreatedTime(new Date());
|
||||
attachmentDB.setTenantId(tenantId);
|
||||
attachmentDB.setFailureTimes(0);
|
||||
attachmentDB.setX(x);
|
||||
attachmentDB.setY(y);
|
||||
attachmentDB.setObjectId(objectId);
|
||||
attachmentDB.setBizCode(bizCode);
|
||||
attachRepo.saveAndFlush(attachmentDB);
|
||||
return attachmentDB;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package net.northking.cctp.upperComputer.attach;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import net.northking.cctp.upperComputer.entity.Attachment;
|
||||
import net.northking.cctp.upperComputer.entity.DebuggerDeviceInfo;
|
||||
import net.northking.cctp.upperComputer.utils.HttpUtils;
|
||||
import net.northking.cctp.upperComputer.utils.SpringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 附件信息上传
|
||||
*
|
||||
*/
|
||||
public class AttachInfoUpload implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AttachInfoUpload.class);
|
||||
|
||||
private AttachmentDB attachmentDB;
|
||||
|
||||
public AttachInfoUpload(AttachmentDB attachmentDB) {
|
||||
this.attachmentDB = attachmentDB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
AttachmentInfoRepository repo = SpringUtils.getBean(AttachmentInfoRepository.class);
|
||||
try {
|
||||
String filePath = attachmentDB.getFilePath();
|
||||
if (attachmentDB.getX() > 0 && attachmentDB.getY() > 0) {
|
||||
filePath = addSignatureToImage(attachmentDB.getFilePath(), attachmentDB.getX(), attachmentDB.getY());
|
||||
}
|
||||
String serverAddr = SpringUtils.getProperties("nk.mobile-computer.serverAddr");
|
||||
String publicUploadAddr = SpringUtils.getProperties("nk.mobile-computer.publicUploadAddr");
|
||||
String uploadUrl = serverAddr + publicUploadAddr;
|
||||
Attachment upload = HttpUtils.upload(uploadUrl,
|
||||
filePath, attachmentDB.getTenantId(),
|
||||
attachmentDB.getObjectId(), attachmentDB.getBizCode(),
|
||||
attachmentDB.getId());
|
||||
if (upload != null && StringUtils.isNotBlank(upload.getUrlPath())) {
|
||||
// 上传成功
|
||||
logger.debug("文件上传成功:{}, storagePath -> {}", BeanUtil.beanToMap(upload).toString(), attachmentDB.getId());
|
||||
// 删除数据库信息
|
||||
repo.deleteById(attachmentDB.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("附件上传失败", e);
|
||||
// 附件信息的失败次数加1,并更新数据库数据
|
||||
attachmentDB.setFailureTimes(attachmentDB.getFailureTimes() + 1);
|
||||
repo.saveAndFlush(attachmentDB);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 给截图增加红点操作。
|
||||
* @param filePath
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
private String addSignatureToImage(String filePath, Integer x, Integer y) {
|
||||
if (x == null || y == null) {
|
||||
return filePath;
|
||||
}
|
||||
File originFile = new File(filePath);
|
||||
if (!originFile.exists()) {
|
||||
logger.info("截图文件不存在:{}", originFile.getAbsolutePath());
|
||||
return filePath;
|
||||
}
|
||||
String fullName = originFile.getName();
|
||||
String suffix = fullName.substring(fullName.lastIndexOf(".") + 1);
|
||||
String name = fullName.substring(0, fullName.lastIndexOf("."));
|
||||
File targetFile = new File(originFile.getParentFile().getAbsolutePath() + File.separator + name + "_with_dot" + "." + suffix);
|
||||
try {
|
||||
BufferedImage bi = ImageIO.read(originFile);
|
||||
Graphics2D g2d = bi.createGraphics(); // 生成画布
|
||||
g2d.setColor(Color.RED); // 红色
|
||||
g2d.fillOval(x, y, 20, 20); // 在图片的x,y上画上一个直径20的实心原点
|
||||
g2d.dispose();
|
||||
ImageIO.write(bi, suffix, targetFile);
|
||||
} catch (IOException e) {
|
||||
logger.error("io异常", e);
|
||||
} catch (Exception e) {
|
||||
logger.error("添加红点失败", e);
|
||||
}
|
||||
if (!targetFile.exists()) {
|
||||
targetFile = originFile;
|
||||
}
|
||||
return targetFile.getAbsolutePath();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package net.northking.cctp.upperComputer.attach;
|
||||
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 附件对象
|
||||
*/
|
||||
@Table(name = "attachment_info")
|
||||
public class AttachmentDB {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String url;
|
||||
|
||||
private String filename;
|
||||
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdTime;
|
||||
|
||||
/**
|
||||
* 红点x坐标
|
||||
*/
|
||||
private int x;
|
||||
|
||||
/**
|
||||
* 红点y坐标
|
||||
*/
|
||||
private int y;
|
||||
|
||||
/**
|
||||
* 租户id
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 上传失败次数
|
||||
*/
|
||||
private int failureTimes;
|
||||
|
||||
private String objectId;
|
||||
|
||||
private String bizCode;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public Date getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
public void setCreatedTime(Date createdTime) {
|
||||
this.createdTime = createdTime;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public String getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(String tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
public int getFailureTimes() {
|
||||
return failureTimes;
|
||||
}
|
||||
|
||||
public void setFailureTimes(int failureTimes) {
|
||||
this.failureTimes = failureTimes;
|
||||
}
|
||||
|
||||
public String getObjectId() {
|
||||
return objectId;
|
||||
}
|
||||
|
||||
public void setObjectId(String objectId) {
|
||||
this.objectId = objectId;
|
||||
}
|
||||
|
||||
public String getBizCode() {
|
||||
return bizCode;
|
||||
}
|
||||
|
||||
public void setBizCode(String bizCode) {
|
||||
this.bizCode = bizCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AttachmentDB{" +
|
||||
"id='" + id + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", filename='" + filename + '\'' +
|
||||
", filePath='" + filePath + '\'' +
|
||||
", createdTime=" + createdTime +
|
||||
", x=" + x +
|
||||
", y=" + y +
|
||||
", tenantId='" + tenantId + '\'' +
|
||||
", failureTimes=" + failureTimes +
|
||||
", objectId='" + objectId + '\'' +
|
||||
", bizCode='" + bizCode + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package net.northking.cctp.upperComputer.attach;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface AttachmentInfoRepository extends JpaRepository<AttachmentDB, String> {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package net.northking.cctp.upperComputer.config;
|
||||
|
||||
import net.northking.cctp.upperComputer.thread.AttachInfoExecutorPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ExecutorPoolConfig {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ExecutorPoolConfig.class);
|
||||
|
||||
|
||||
@Bean
|
||||
public AttachInfoExecutorPool createAttachInfoPool() {
|
||||
AttachInfoExecutorPool pool = new AttachInfoExecutorPool();
|
||||
return pool;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,8 @@ import com.alibaba.fastjson.JSONObject;
|
|||
import io.appium.java_client.AppiumDriver;
|
||||
import io.appium.java_client.android.AndroidDriver;
|
||||
import io.appium.java_client.ios.IOSDriver;
|
||||
import net.northking.cctp.upperComputer.attach.AttachInfoService;
|
||||
import net.northking.cctp.upperComputer.attach.AttachmentDB;
|
||||
import net.northking.cctp.upperComputer.config.MobileProperty;
|
||||
import net.northking.cctp.upperComputer.deviceManager.screen.AndroidScreenResponseThread;
|
||||
import net.northking.cctp.upperComputer.deviceManager.thread.AndroidDeviceInitThread;
|
||||
|
@ -40,10 +42,14 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static io.appium.java_client.remote.AndroidMobileCapabilityType.RESET_KEYBOARD;
|
||||
|
@ -70,6 +76,9 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
|
|||
|
||||
private Adb adb;
|
||||
|
||||
@Autowired
|
||||
private AttachInfoService attachInfoService;
|
||||
|
||||
@Value("${appium.server.host:127.0.0.1}")
|
||||
private String appiumHost;
|
||||
|
||||
|
@ -731,11 +740,13 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
|
|||
String tenantId = info.getTenantId();
|
||||
logger.debug("开始上传截图,任务信息:{}",JSON.toJSONString(info));
|
||||
String taskId = info.getTaskId();
|
||||
Attachment upload = HttpUtils.upload(mobileProperty.getServerAddr() + mobileProperty.getPublicUploadAddr(), file.getAbsolutePath(), tenantId, taskId, FileBusinessTypeEnum.MOBILE_TASK_SCREENSHOT.getCode());
|
||||
// Attachment upload = HttpUtils.upload(mobileProperty.getServerAddr() + mobileProperty.getPublicUploadAddr(), file.getAbsolutePath(), tenantId, taskId, FileBusinessTypeEnum.MOBILE_TASK_SCREENSHOT.getCode());
|
||||
// todo: 把截图信息保存到数据库待处理
|
||||
AttachmentDB upload = attachInfoService.save(file.getName(), file.getAbsolutePath(), tenantId, info.getX(), info.getY(), taskId, FileBusinessTypeEnum.MOBILE_TASK_SCREENSHOT.getCode());
|
||||
if (null != upload && StringUtils.isNotBlank(upload.getId())) {
|
||||
logger.debug("文件上传成功,返回id:{}", upload.getId());
|
||||
|
||||
path = upload.getUrlPath();
|
||||
path = upload.getUrl();
|
||||
}
|
||||
} catch (ExecuteException e) {
|
||||
logger.error("上传截图失败", e);
|
||||
|
|
|
@ -4,6 +4,8 @@ import cn.hutool.core.codec.Base64;
|
|||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.appium.java_client.AppiumDriver;
|
||||
import net.northking.cctp.upperComputer.attach.AttachInfoService;
|
||||
import net.northking.cctp.upperComputer.attach.AttachmentDB;
|
||||
import net.northking.cctp.upperComputer.config.MobileProperty;
|
||||
import net.northking.cctp.upperComputer.deviceManager.common.PyMobileDevice;
|
||||
import net.northking.cctp.upperComputer.deviceManager.screen.IosScreenResponseThread;
|
||||
|
@ -58,6 +60,9 @@ public class IosDebuggerServiceImpl extends AbstractDebuggerService {
|
|||
super.setMobileProperty(mobileProperty);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private AttachInfoService attachInfoService;
|
||||
|
||||
@Override
|
||||
public Object getUiTree(String deviceId) {
|
||||
PhoneEntity phoneEntity = IOSDeviceManager.getInstance().getPhoneEntity(deviceId);
|
||||
|
@ -194,17 +199,19 @@ public class IosDebuggerServiceImpl extends AbstractDebuggerService {
|
|||
|
||||
@Override
|
||||
public String uploadShotAllScreen(DebuggerDeviceInfo info) {
|
||||
File file = ScreenShotUtils.getIOSMobileScreenShot(info.getDeviceId());
|
||||
File file = deviceHandleHelper.getScreenShotFile(info.getDeviceId());
|
||||
String path = null;
|
||||
try {
|
||||
//租户id
|
||||
String tenantId = info.getTenantId();
|
||||
String taskId = info.getTaskId();
|
||||
logger.debug("开始上传截图,任务信息:{}",JSON.toJSONString(info));
|
||||
Attachment upload = HttpUtils.upload(mobileProperty.getServerAddr() + mobileProperty.getPublicUploadAddr(), file.getAbsolutePath(), tenantId, taskId, FileBusinessTypeEnum.MOBILE_TASK_SCREENSHOT.getCode());
|
||||
// Attachment upload = HttpUtils.upload(mobileProperty.getServerAddr() + mobileProperty.getPublicUploadAddr(), file.getAbsolutePath(), tenantId, taskId, FileBusinessTypeEnum.MOBILE_TASK_SCREENSHOT.getCode());
|
||||
// todo: 把截图信息保存到数据库待处理
|
||||
AttachmentDB upload = attachInfoService.save(file.getName(), file.getAbsolutePath(), tenantId, info.getX(), info.getY(), taskId, FileBusinessTypeEnum.MOBILE_TASK_SCREENSHOT.getCode());
|
||||
if (null != upload && org.apache.commons.lang3.StringUtils.isNotBlank(upload.getId())) {
|
||||
logger.debug("文件上传成功,返回id:{}", upload.getId());
|
||||
path = upload.getUrlPath();
|
||||
path = upload.getUrl();
|
||||
}
|
||||
} catch (ExecuteException e) {
|
||||
logger.error("截图失败",e);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package net.northking.cctp.upperComputer.thread;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 附件上传
|
||||
*/
|
||||
public class AttachInfoExecutorPool {
|
||||
|
||||
private ThreadPoolExecutor uploadPool;
|
||||
|
||||
private ThreadPoolExecutor savePool;
|
||||
|
||||
public AttachInfoExecutorPool() {
|
||||
uploadPool = new ThreadPoolExecutor(1, 3,
|
||||
0L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
savePool = new ThreadPoolExecutor(1, 3,
|
||||
0L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提交执行附件上传任务
|
||||
* @param task
|
||||
*/
|
||||
public void uploadTaskSubmit(Runnable task) {
|
||||
uploadPool.submit(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 线程池是否空闲
|
||||
* @return
|
||||
*/
|
||||
public boolean isUploadAvailable() {
|
||||
return uploadPool.getActiveCount() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 队列中任务剩余数量
|
||||
* @return
|
||||
*/
|
||||
public int uploadTaskLeft() {
|
||||
return uploadPool.getQueue().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交执行附件保存任务
|
||||
* @param task
|
||||
*/
|
||||
public void saveTaskSubmit(Runnable task) {
|
||||
savePool.submit(task);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package net.northking.cctp.upperComputer.utils;
|
||||
|
||||
import net.northking.cctp.upperComputer.exception.ParamMistakeException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 附件相关工具类
|
||||
*/
|
||||
public class AttachUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AttachUtils.class);
|
||||
|
||||
/**
|
||||
* 生成附件id
|
||||
* /yyyy/MM/dd/32位uuid[.文件后缀]
|
||||
*
|
||||
* @param filename 附件名称
|
||||
* @return 附件id
|
||||
*/
|
||||
public static String createId(String filename) {
|
||||
if (StringUtils.isBlank(filename)) {
|
||||
logger.error("上传资源失败:附件名称不能为空");
|
||||
throw new ParamMistakeException("上传资源失败:附件名称不能为空");
|
||||
}
|
||||
String id;
|
||||
int i = filename.lastIndexOf(".");
|
||||
if (i <= 0) { // 文件没有后缀名称
|
||||
id = createDatePath() + UUID.randomUUID().toString().replace("-","");
|
||||
} else { // 文件存在后缀名称
|
||||
String postfix = filename.substring(i + 1);
|
||||
id = createDatePath() + UUID.randomUUID().toString().replace("-","") + "." + postfix;
|
||||
}
|
||||
logger.debug("文件[{}] --> id: {}", filename, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public static String exchangeToUrl(String attachId, String tenantId) {
|
||||
return String.format("%s%s", tenantId, encodeAttachId(attachId));
|
||||
}
|
||||
|
||||
private static String encodeAttachId(String id) {
|
||||
return id.replace("/", "_");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据日期创建目录
|
||||
*
|
||||
* @return 根据日期创建目录
|
||||
*/
|
||||
private static String createDatePath()
|
||||
{
|
||||
SimpleDateFormat format = new SimpleDateFormat("/yyyy/MM/dd/");
|
||||
return format.format(new Date());
|
||||
}
|
||||
|
||||
}
|
|
@ -311,6 +311,7 @@ public class HttpUtils {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传资源
|
||||
* @param filePath
|
||||
|
@ -318,6 +319,16 @@ public class HttpUtils {
|
|||
* @return
|
||||
*/
|
||||
public static Attachment upload(String url, String filePath, String tenantId, String objId, String businessCode) {
|
||||
return upload(url, filePath, tenantId, objId, businessCode, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传资源
|
||||
* @param filePath
|
||||
* @param tenantId
|
||||
* @return
|
||||
*/
|
||||
public static Attachment upload(String url, String filePath, String tenantId, String objId, String businessCode, String attachId) {
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
throw new ExecuteException("上传资源失败:缺少租户信息");
|
||||
}
|
||||
|
@ -330,6 +341,9 @@ public class HttpUtils {
|
|||
multipartMap.add("tenantId", tenantId);
|
||||
multipartMap.add("objId", objId);
|
||||
multipartMap.add("businessCode", businessCode);
|
||||
if (StringUtils.isNotBlank(attachId)) {
|
||||
multipartMap.add("attachId", attachId);
|
||||
}
|
||||
FormHttpMessageConverter converter = new FormHttpMessageConverter();
|
||||
converter.addPartConverter(new ResourceHttpMessageConverter());
|
||||
template.getMessageConverters().add(converter);
|
||||
|
|
|
@ -14,6 +14,29 @@ spring:
|
|||
jackson:
|
||||
serialization:
|
||||
write-dates-as-timestamps: true
|
||||
jpa:
|
||||
show-sql: false
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
database: h2
|
||||
open-in-view: false
|
||||
datasource:
|
||||
url: jdbc:h2:file:./.h2/db
|
||||
username: engine
|
||||
password: 123456
|
||||
driver-class-name: org.h2.Driver
|
||||
h2:
|
||||
console:
|
||||
path: /h2
|
||||
enabled: true
|
||||
settings:
|
||||
trace: false
|
||||
web-allow-others: true
|
||||
task:
|
||||
scheduling:
|
||||
pool:
|
||||
size: 3
|
||||
thread-name-prefix: scheduler-task-
|
||||
nk:
|
||||
mobile-computer:
|
||||
password: 123456
|
||||
|
|
|
@ -19,6 +19,7 @@ public class S3File implements NKFile
|
|||
private String tenantId;
|
||||
private String objId;
|
||||
private String businessCode;
|
||||
private String storagePath;
|
||||
|
||||
public S3File()
|
||||
{
|
||||
|
@ -47,6 +48,33 @@ public class S3File implements NKFile
|
|||
}
|
||||
}
|
||||
|
||||
public S3File(String bucket, String tenantId, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode, String attachId) {
|
||||
this.bucket = bucket;
|
||||
this.tenantId = tenantId;
|
||||
this.contentType = multipartFile.getContentType();
|
||||
this.length = multipartFile.getSize();
|
||||
this.fileName = multipartFile.getOriginalFilename();
|
||||
this.objId = objId;
|
||||
this.businessCode = businessCode.getCode();
|
||||
assert fileName != null;
|
||||
int index = fileName.lastIndexOf(".");
|
||||
if (null != attachId && attachId.length() > 0) {
|
||||
this.id = attachId;
|
||||
this.storagePath = attachId;
|
||||
} else {
|
||||
if (index <= 0) {
|
||||
// 文件没有后缀名
|
||||
this.id = createDatePath() + UUIDUtil.create32UUID();
|
||||
this.storagePath = this.id;
|
||||
} else {
|
||||
String postfix = fileName.substring(index + 1);
|
||||
// 文件ID长度= 32 + 11 + 32 + 后缀名(<10)
|
||||
this.id = createDatePath() + UUIDUtil.create32UUID() + "." + postfix;
|
||||
this.storagePath = this.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public S3File(String bucket, String tenantId, String suffixName)
|
||||
{
|
||||
this.bucket = bucket;
|
||||
|
@ -209,4 +237,12 @@ public class S3File implements NKFile
|
|||
public void setBusinessCode(String businessCode) {
|
||||
this.businessCode = businessCode;
|
||||
}
|
||||
|
||||
public String getStoragePath() {
|
||||
return storagePath;
|
||||
}
|
||||
|
||||
public void setStoragePath(String storagePath) {
|
||||
this.storagePath = storagePath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,18 @@ public interface SimpleStorageService
|
|||
* @throws FileUploadException 异常
|
||||
*/
|
||||
NKFile upload(String tenant, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode) throws FileUploadException, IOException;
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param tenant 租户
|
||||
* @param multipartFile 文件
|
||||
* @param objId 关联对象Id
|
||||
* @param businessCode 文件业务类型枚举
|
||||
* @param attachId 文件id
|
||||
* @return 文件记录
|
||||
* @throws FileUploadException 异常
|
||||
*/
|
||||
NKFile upload(String tenant, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode, String attachId) throws FileUploadException, IOException;
|
||||
|
||||
/**
|
||||
* 文件分片上传
|
||||
|
|
|
@ -73,6 +73,29 @@ public class MinioFileStorage implements SimpleStorageService {
|
|||
return s3File;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param tenant 租户
|
||||
* @param multipartFile 文件
|
||||
* @param objId 关联对象Id
|
||||
* @param businessCode 文件业务类型枚举
|
||||
* @param attachId 文件id
|
||||
* @return 文件记录
|
||||
* @throws FileUploadException 异常
|
||||
*/
|
||||
@Override
|
||||
public NKFile upload(String tenant, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode, String attachId) throws FileUploadException, IOException {
|
||||
S3File s3File = new S3File(properties.getBucket(), tenant, multipartFile, objId, businessCode, attachId);
|
||||
putObject(s3File, multipartFile.getInputStream());
|
||||
|
||||
if (properties.isUseMsgQueue() && attachmentProducer != null)
|
||||
{
|
||||
attachmentProducer.process(s3File);
|
||||
}
|
||||
return s3File;
|
||||
}
|
||||
|
||||
public NKFile uploadChunk(String tenantId, MultipartFile multipartFile, String uploadId, String chunkIndex) throws FileUploadException, IOException
|
||||
{
|
||||
S3File s3File = new S3File(properties.getBucket(), tenantId, multipartFile, uploadId, chunkIndex);
|
||||
|
|
|
@ -74,6 +74,30 @@ public class SeaweedFileStorage implements SimpleStorageService {
|
|||
return s3File;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param tenant 租户
|
||||
* @param multipartFile 文件
|
||||
* @param objId 关联对象Id
|
||||
* @param businessCode 文件业务类型枚举
|
||||
* @param attachId 文件id
|
||||
* @return 文件记录
|
||||
* @throws FileUploadException 异常
|
||||
*/
|
||||
@Override
|
||||
public NKFile upload(String tenant, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode, String attachId) throws FileUploadException, IOException {
|
||||
logger.debug("配置动态刷新:AmazonS3Properties:{}", JSON.toJSONString(properties));
|
||||
S3File s3File = new S3File(properties.getBucket(), tenant, multipartFile, objId, businessCode, attachId);
|
||||
putObject(s3File, multipartFile.getInputStream());
|
||||
|
||||
if (properties.isUseMsgQueue() && attachmentProducer != null)
|
||||
{
|
||||
attachmentProducer.process(s3File);
|
||||
}
|
||||
return s3File;
|
||||
}
|
||||
|
||||
public NKFile uploadChunk(String tenantId, MultipartFile multipartFile, String uploadId, String chunkIndex) throws FileUploadException, IOException
|
||||
{
|
||||
logger.debug("tenantId:{},uploadId:{},chunkIndex:{},fileName:{},size:{}",tenantId, uploadId, chunkIndex, multipartFile.getOriginalFilename(), multipartFile.getSize());
|
||||
|
|
|
@ -164,7 +164,8 @@ public class AttachFileCtrl
|
|||
@RequestParam("file") MultipartFile multipartFile,
|
||||
@RequestParam("tenantId") String tenantId,
|
||||
@RequestParam(value = "objId", required = false) String objId,
|
||||
@RequestParam("businessCode") String businessCode) {
|
||||
@RequestParam("businessCode") String businessCode,
|
||||
@RequestParam(value = "attachId", required = false) String attachId) {
|
||||
ResultWrapper<Map<String, Object>> wrapper = new ResultWrapper<>();
|
||||
FileBusinessTypeEnum fileBusinessTypeByCode = FileBusinessTypeEnum.getFileBusinessTypeByCode(businessCode);
|
||||
if (null == fileBusinessTypeByCode) {
|
||||
|
@ -176,7 +177,7 @@ public class AttachFileCtrl
|
|||
return wrapper;
|
||||
}
|
||||
NKSecurityContext.setTenantId(tenantId);
|
||||
return attachFileService.uploadResource(response, multipartFile, objId, fileBusinessTypeByCode);
|
||||
return attachFileService.uploadResource(response, multipartFile, objId, fileBusinessTypeByCode, attachId);
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/v1/uploadForApp"},
|
||||
|
|
|
@ -68,7 +68,7 @@ public interface AttachFileService
|
|||
ResultWrapper<String> mergeChunkFiles(ChunkFiles chunkFiles);
|
||||
|
||||
|
||||
ResultWrapper<Map<String, Object>> uploadResource(HttpServletResponse response, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode);
|
||||
ResultWrapper<Map<String, Object>> uploadResource(HttpServletResponse response, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode, String attachId);
|
||||
|
||||
ResultWrapper<String> update(Map<String, String> file);
|
||||
|
||||
|
|
|
@ -104,8 +104,15 @@ public class AttachFileServiceImpl implements AttachFileService
|
|||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return;
|
||||
}
|
||||
|
||||
Attachment attachment = attachmentService.findByPK(tenantId, objectId);
|
||||
String id = objectId;
|
||||
// 判断objectId是id还是storagePath,如果是id,那么只有一个/
|
||||
if (objectId.lastIndexOf("/") > 0) {
|
||||
Attachment attachment = attachmentService.queryByStoragePath(tenantId, objectId); // 通过storagePath查询附件的id
|
||||
if (attachment != null) {
|
||||
id = attachment.getId();
|
||||
}
|
||||
}
|
||||
Attachment attachment = attachmentService.findByPK(tenantId, id);
|
||||
boolean check = false;
|
||||
int i=0;
|
||||
while (i<10){
|
||||
|
@ -115,7 +122,7 @@ public class AttachFileServiceImpl implements AttachFileService
|
|||
} catch (Exception e) {
|
||||
logger.error("等待报错",e);
|
||||
}
|
||||
attachment = attachmentService.findByPK(tenantId, objectId);
|
||||
attachment = attachmentService.findByPK(tenantId, id);
|
||||
}else{
|
||||
check=true;
|
||||
break;
|
||||
|
@ -194,7 +201,7 @@ public class AttachFileServiceImpl implements AttachFileService
|
|||
}
|
||||
|
||||
@Override
|
||||
public ResultWrapper<Map<String, Object>> uploadResource(HttpServletResponse response, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode)
|
||||
public ResultWrapper<Map<String, Object>> uploadResource(HttpServletResponse response, MultipartFile multipartFile, String objId, FileBusinessTypeEnum businessCode, String attachId)
|
||||
{
|
||||
ResultWrapper<Map<String, Object>> resultWrapper = new ResultWrapper<>();
|
||||
resultWrapper.setData(new HashMap<>());
|
||||
|
@ -202,7 +209,7 @@ public class AttachFileServiceImpl implements AttachFileService
|
|||
String userId = NKSecurityContext.getUserId();
|
||||
try
|
||||
{
|
||||
NKFile nkFile = storageService.upload(tenantId, multipartFile, objId, businessCode);
|
||||
NKFile nkFile = storageService.upload(tenantId, multipartFile, objId, businessCode, attachId);
|
||||
|
||||
Attachment attachment = new Attachment();
|
||||
BeanUtils.copyProperties(nkFile, attachment);
|
||||
|
@ -211,6 +218,7 @@ public class AttachFileServiceImpl implements AttachFileService
|
|||
attachment.setObjId(objId);
|
||||
attachment.setBusinessCode(businessCode.getCode());
|
||||
attachment.setOverTime(businessCode.getOverTime());
|
||||
attachment.setStoragePath(attachId);
|
||||
attachmentService.insert(attachment);
|
||||
|
||||
String urlPath = tenantId + encodeFileId(nkFile.getId());
|
||||
|
|
|
@ -50,4 +50,6 @@ public interface AttachmentDao extends AttachmentMapper {
|
|||
List<Attachment> queryByOverTime(@Param("overTime") LocalDateTime overTime, @Param("tableSuffix") String tableSuffix);
|
||||
|
||||
List<Attachment> queryByBusiness(@Param("date") LocalDate date, @Param("tableSuffix") String tableSuffix);
|
||||
|
||||
Attachment queryByStoragePath(Attachment attachment);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,10 @@ public class Attachment extends TenantPartition implements NKFile, POJO
|
|||
* 关联对象
|
||||
*/
|
||||
private String objId;
|
||||
/**
|
||||
* 关联对象
|
||||
*/
|
||||
private String storagePath;
|
||||
/**
|
||||
* 文件业务类型
|
||||
*/
|
||||
|
@ -219,4 +223,12 @@ public class Attachment extends TenantPartition implements NKFile, POJO
|
|||
public void setOverTime(Date overTime) {
|
||||
this.overTime = overTime;
|
||||
}
|
||||
|
||||
public String getStoragePath() {
|
||||
return storagePath;
|
||||
}
|
||||
|
||||
public void setStoragePath(String storagePath) {
|
||||
this.storagePath = storagePath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,5 +173,15 @@ public class AttachmentServiceImpl extends TenantPaginationService<Attachment> i
|
|||
return attachmentDao.findByPK(attachment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attachment queryByStoragePath(String tenantId, String storagePath)
|
||||
{
|
||||
Attachment attachment = new Attachment();
|
||||
attachment.setTenantId(tenantId);
|
||||
attachment.setStoragePath(storagePath);
|
||||
return attachmentDao.queryByStoragePath(attachment);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -86,4 +86,6 @@ public interface AttachmentService extends BasicService<Attachment>
|
|||
List<Attachment> queryByOverTime(LocalDateTime now);
|
||||
|
||||
List<Attachment> queryByBusiness(LocalDate now);
|
||||
|
||||
Attachment queryByStoragePath(String tenantId, String storagePath);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
<result column="length" jdbcType="BIGINT" property="length"/>
|
||||
<!-- 关联对象-->
|
||||
<result column="obj_id" jdbcType="VARCHAR" property="objId"/>
|
||||
<!-- 关联对象-->
|
||||
<result column="storage_path" jdbcType="VARCHAR" property="storagePath"/>
|
||||
<!-- 业务编码-->
|
||||
<result column="business_code" jdbcType="VARCHAR" property="businessCode"/>
|
||||
<!-- 过期时间-->
|
||||
|
@ -41,6 +43,7 @@
|
|||
,content_type
|
||||
,length
|
||||
,obj_id
|
||||
,storage_path
|
||||
,business_code
|
||||
,over_time
|
||||
,created_by
|
||||
|
@ -112,6 +115,9 @@
|
|||
</if>
|
||||
<if test="objId != null">
|
||||
AND obj_id=#{objId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="storagePath != null">
|
||||
AND storage_path=#{storage_path,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="businessCode != null">
|
||||
AND business_code=#{businessCode,jdbcType=VARCHAR}
|
||||
|
@ -156,6 +162,9 @@
|
|||
<if test="objId != null">
|
||||
obj_id,
|
||||
</if>
|
||||
<if test="storagePath != null">
|
||||
storage_path,
|
||||
</if>
|
||||
<if test="businessCode != null">
|
||||
business_code,
|
||||
</if>
|
||||
|
@ -197,6 +206,9 @@
|
|||
<if test="objId != null">
|
||||
#{objId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="storagePath != null">
|
||||
#{storagePath,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="businessCode != null">
|
||||
#{businessCode,jdbcType=VARCHAR},
|
||||
</if>
|
||||
|
@ -233,6 +245,7 @@
|
|||
content_type,
|
||||
length,
|
||||
obj_id,
|
||||
storage_path,
|
||||
business_code,
|
||||
over_time,
|
||||
created_by,
|
||||
|
@ -250,6 +263,7 @@
|
|||
#{item.contentType, jdbcType=VARCHAR},
|
||||
#{item.length, jdbcType=BIGINT},
|
||||
#{item.objId, jdbcType=VARCHAR},
|
||||
#{item.storagePath, jdbcType=VARCHAR},
|
||||
#{item.businessCode, jdbcType=VARCHAR},
|
||||
#{item.overTime, jdbcType=TIMESTAMP},
|
||||
#{item.createdBy, jdbcType=VARCHAR},
|
||||
|
@ -278,6 +292,9 @@
|
|||
<if test="objId != null">
|
||||
obj_id = #{objId, jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="storagePath != null">
|
||||
storage_path = #{storagePath, jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="businessCode != null">
|
||||
business_code = #{businessCode, jdbcType=VARCHAR},
|
||||
</if>
|
||||
|
@ -327,6 +344,9 @@
|
|||
<if test="objId != null">
|
||||
AND obj_id = #{objId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="storagePath != null">
|
||||
AND storage_path = #{storagePath,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="businessCode != null">
|
||||
AND business_code = #{businessCode,jdbcType=VARCHAR}
|
||||
</if>
|
||||
|
@ -370,6 +390,9 @@
|
|||
<if test="objId != null">
|
||||
AND obj_id=#{objId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="storagePath != null">
|
||||
AND storage_path=#{storagePath,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="businessCode != null">
|
||||
AND business_code=#{businessCode,jdbcType=VARCHAR}
|
||||
</if>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
length BIGINT comment '文件长度',
|
||||
business_code varchar(50) DEFAULT NULL,
|
||||
obj_id varchar(50) DEFAULT NULL COMMENT '关联对象Id',
|
||||
storage_path varchar(128) DEFAULT NULL COMMENT '存储路径',
|
||||
over_time DATETIME DEFAULT NULL,
|
||||
created_by VARCHAR(32) COMMENT '创建人' ,
|
||||
created_time DATETIME COMMENT '创建时间' ,
|
||||
|
@ -183,4 +184,13 @@
|
|||
)
|
||||
limit 5000
|
||||
</select>
|
||||
<select id="queryByStoragePath" resultType="net.northking.cctp.attachment.db.entity.Attachment" parameterType="net.northking.cctp.attachment.db.entity.Attachment">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM
|
||||
<include refid="Table_Name" />
|
||||
WHERE
|
||||
storage_path = #{storagePath,jdbcType=VARCHAR}
|
||||
limit 1
|
||||
</select>
|
||||
</mapper>
|
Loading…
Reference in New Issue