1、策略接口上下文
代码语言:javascript复制@Service
public class PathUploadStrategyContext {
@Resource
private Map<String, PathUploadStrategy> pathUploadStrategyMap;
public void getFileInferStrategy(PathUpLoadMessage message, String strategy) throws IOException {
pathUploadStrategyMap.get(IBaseEnum.getLabelByValue(strategy, PathUploadEnum.class)).upload(message,strategy);
}
}
2、策略抽象实现类
代码语言:javascript复制/**
* 服务器路径上传文件
*
* @author Eliauk
* @since 2023/9/28 15:16
*/
@Service
public abstract class AbstractPathUploadStrategyImpl implements PathUploadStrategy {
private final Logger LOG = LoggerFactory.getLogger(AbstractPathUploadStrategyImpl.class);
@Override
public void upload(PathUpLoadMessage message, String strategy) throws IOException {
LOG.info("开始执行{}服务器路径上传策略", strategy);
if (exist(message)){
LOG.info("档号为{}的档案已经存在,跳过上传",message.getFileName());
return;
}
uploadByPath(message, strategy);
}
/**
* 服务器路径上传抽象方法
* @param message 队列消息
* @param strategy 路径上传策略
* @since 2023/9/28 15:16
*/
abstract void uploadByPath(PathUpLoadMessage message, String strategy) throws IOException;
/**
* 判断当前任务是否已经上传抽象方法
* @param message 队列消息
* @return
* true:已经上传
* false:未上传
* @since 2023/9/28 15:16
*/
abstract boolean exist(PathUpLoadMessage message);
protected List<File> getAllPDFFiles(File rootFolder, List<String> legalSuffix) {
List<File> pdfFiles = new ArrayList<>();
if (rootFolder.isDirectory()) {
File[] fileList = rootFolder.listFiles();
if (fileList != null) {
for (File file : fileList) {
if (file.isDirectory()) {
pdfFiles.addAll(getAllPDFFiles(file, legalSuffix));
} else if (file.isFile() && legalSuffix.contains(getFileExtension(file)) && !file.getName().startsWith("._")) {
pdfFiles.add(file);
}
}
}
}
return pdfFiles;
}
/**
* 获取文件的后缀名
*/
private static String getFileExtension(File file) {
String fileName = file.getName();
int dotIndex = fileName.lastIndexOf(".");
if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
return fileName.substring(dotIndex 1).toLowerCase();
}
return "";
}
}
3、策略枚举类
代码语言:javascript复制/**
* 服务器路径上传策略枚举
*
* @author Eliauk
* @since 2023/9/28 14:32
*/
@Getter
@AllArgsConstructor
public enum PathUploadEnum implements IBaseEnum{
VOLUME("案卷合并", "volumePathUploadStrategy"),
PDF("PDF文件", "pdfPathUploadStrategy"),
IMAGE_TO_PDF("合并图片文件","mergePicturePathUploadStrategy"),
OFD("OFD文件", "ofdPathUploadStrategy");
private final String value;
private final String label;
@Override
public Object getValue() {
return this.value;
}
@Override
public String getLabel() {
return this.label;
}
}
4、实现类
1、 OdfPathUploadStrategyImpl
OFD转PDF工具源码
代码语言:javascript复制/**
* OFD文件服务器路径上传
*
* @author Eliauk
* @since 2023/10/10 9:58
*/
@Service("ofdPathUploadStrategy")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OdfPathUploadStrategyImpl extends AbstractPathUploadStrategyImpl{
private static Logger LOG = LoggerFactory.getLogger(OdfPathUploadStrategyImpl.class);
private final AppraisalFileRepository appraisalFileRepository;
private final AppraisalFileService appraisalFileService;
private final IOssEndPoint ossEndPoint;
@Override
void uploadByPath(PathUpLoadMessage message, String strategy) throws IOException {
// 接收所有包含pdf的文件夹
final File file = new File(message.getFile());
final String folderName = file.getName();
// 拿到任务ID
final Long taskId = Convert.toLong(message.getTaskId());
// 拿到租户ID
final String tenantId = message.getTenantId();
// 是否覆盖
final Boolean overWrite = Convert.toBool(message.getOverWrite());
LOG.info("当前进行服务器路径上传OFD的文件夹是{}", folderName);
final List<File> pdfFiles = getAllPDFFiles(file, List.of("ofd"));
long timeStart = DateUtil.current();
long countStart = DateUtil.current();
LOG.info("开始解析文件夹{},包含{}个OFD文件", folderName, pdfFiles.size());
for (int fileIndex = 0; fileIndex < pdfFiles.size(); fileIndex ) {
File ofdFile = pdfFiles.get(fileIndex);
String fileName = ofdFile.getName();
// 判断是否覆盖,如果覆盖就删除原文件,否则跳过
List<AppraisalFile> existingFiles = appraisalFileRepository.findByTaskIdAndFileName(taskId, fileName);
if (!existingFiles.isEmpty()) {
if (overWrite) {
List<Long> existingIds = existingFiles.stream().map(AppraisalFile::getId).collect(Collectors.toList());
appraisalFileService.deleteExistingFiles(existingIds);
} else {
LOG.info("已存在的文件将被跳过: {}", fileName);
continue;
}
}
Attach ofdAttach = null;
try {
// 使用第一个 FileInputStream
try (FileInputStream fileInputStream1 = new FileInputStream(ofdFile)) {
ofdAttach = ossEndPoint.putAttachWithTenant(
new InMemoryMultipartFile(fileName, fileInputStream1),
tenantId
).getData();
}
// 使用第二个 FileInputStream
try (FileInputStream fileInputStream2 = new FileInputStream(ofdFile)) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ConvertHelper.toPdf(fileInputStream2, stream);
Attach pdfAttach = ossEndPoint.putAttach(new InMemoryMultipartFile(IdUtil.randomUUID() ".pdf", stream.toByteArray())
).getData();
AppraisalFile appraisalFile = appraisalFileService.createAppraisalFile(taskId, fileName, pdfAttach);
appraisalFile.setOfdAttach(ofdAttach.getId());
appraisalFile.setFileType(InferFileType.OFD);
appraisalFileRepository.save(appraisalFile);
LOG.info("上传OFD成功所在文件夹名称{} - 当前进度: {}/{},文件名: {},共已耗时: {}s",file.getName(),
fileIndex 1, pdfFiles.size(), fileName, (DateUtil.current() - timeStart) / 1000.0);
}
} catch (Exception e) {
LOG.error("上传文件发生异常: {}", e.getMessage());
}
}
LOG.info("上传OFD成功 - 总文件数: {},耗时: {}s", pdfFiles.size(), (DateUtil.current() - countStart) / 1000.0);
}
@Override
boolean exist(PathUpLoadMessage message) {
return Boolean.FALSE;
}
}
2、VolumePathUploadStrategyImpl
代码语言:javascript复制/**
* 案卷合并服务器路径上传策略
*
* @author Eliauk
* @since 2023/9/28 16:13
*/
@Service("volumePathUploadStrategy")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class VolumePathUploadStrategyImpl extends AbstractPathUploadStrategyImpl {
private static Logger LOG = LoggerFactory.getLogger(VolumePathUploadStrategyImpl.class);
private final AppraisalFileRepository appraisalFileRepository;
private final AppraisalFileService appraisalFileService;
private final IOssEndPoint ossEndPoint;
@Override
void uploadByPath(PathUpLoadMessage message, String strategy) throws IOException {
final File uploadFileFolder = new File(message.getFile());
final Long taskId = Convert.toLong(message.getTaskId());
final String tenantId = message.getTenantId();
final Boolean overWrite = Convert.toBool(message.getOverWrite());
File[] imageFiles = uploadFileFolder.listFiles();
// 创建一个Map来存储文件名前缀和相应的文件列表
Map<String, List<File>> groupedFiles = new HashMap<>();
for (File imageFile : imageFiles) {
String name = imageFile.getName();
String prefix = name.substring(0, name.lastIndexOf('-')); // 假设前缀是直到最后一个'-'符号
groupedFiles.computeIfAbsent(prefix, k -> new ArrayList<>()).add(imageFile);
}
LOG.info("开始处理文件夹名称为{}的文件夹,里边最终会合并成{}个文件",uploadFileFolder.getName(),groupedFiles.size());
int pdfNum = 0;
for (Map.Entry<String, List<File>> entry : groupedFiles.entrySet()) {
String prefix = entry.getKey();
List<File> filesInGroup = entry.getValue();
String folderName = prefix; // 你可以根据需要修改
String fileName = folderName ".pdf";
//pathUpLoadProducer.syncSendPathUpload(tenantId,Convert.toStr(taskId),fileName,Convert.toStr(uploadFileFolder),Convert.toStr(overWrite),PathUploadType.PDF);
// 判断是否覆盖已存在的文件
List<AppraisalFile> existingFiles = appraisalFileRepository.findByTaskIdAndFileName(taskId, fileName);
if (existingFiles.size() > 0) {
if (overWrite) {
List<Long> existingFileIds = existingFiles.stream().map(AppraisalFile::getId).collect(Collectors.toList());
appraisalFileService.deleteExistingFiles(existingFileIds);
} else {
LOG.info("跳过已存在的文件");
pdfNum ;
continue;
}
}
List<byte[]> images = filesInGroup.stream()
.filter(File::isFile)
.map(imageFile -> {
try (InputStream fileInputStream = new FileInputStream(imageFile)) {
return IOUtils.toByteArray(fileInputStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (images.isEmpty()) {
pdfNum ;
LOG.info("跳过空文件夹");
continue;
}
final byte[] bytes = appraisalFileService.convertToPdf(images);
byte[] modifiedPdfData= null;
try (PDDocument document = PDDocument.load(bytes)) {
int lastPageNumber = document.getNumberOfPages();
// 删除最后一页
document.removePage(lastPageNumber - 1);
// 保存修改后的PDF
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
document.save(outputStream);
modifiedPdfData = outputStream.toByteArray();
} catch (IOException e) {
// 处理PDF操作异常
e.printStackTrace();
}
Attach pdfAttach = ossEndPoint.putAttachWithTenant(
new InMemoryMultipartFile(fileName, new ByteArrayInputStream(modifiedPdfData)),
tenantId
).getData();
AppraisalFile appraisalFile = appraisalFileService.createAppraisalFile(taskId, fileName, pdfAttach);
appraisalFileRepository.save(appraisalFile);
pdfNum ;
LOG.info("合并处理文件夹名称为{}的PDF成功,当前进度:{}/{},当前文件名:{},共{}页",
folderName, pdfNum, groupedFiles.size(), folderName, images.size());
}
}
@Override
boolean exist(PathUpLoadMessage message) {
return Boolean.FALSE;
}
}
3、MergePicturePathUploadStrategyImpl
代码语言:javascript复制/**
* 合并图片文件服务器路径上传策略
*
* @author Eliauk
* @since 2023/10/7 16:32
*/
@Service("mergePicturePathUploadStrategy")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MergePicturePathUploadStrategyImpl extends AbstractPathUploadStrategyImpl {
private static Logger LOG = LoggerFactory.getLogger(MergePicturePathUploadStrategyImpl.class);
private final AppraisalFileRepository appraisalFileRepository;
private final AppraisalFileService appraisalFileService;
private final IOssEndPoint ossEndPoint;
@Override
void uploadByPath(PathUpLoadMessage message, String strategy) throws IOException {
// 接收所有包含pdf的文件夹
final File file = new File(message.getFile());
final String folderName = file.getName();
// 拿到任务ID
final Long taskId = Convert.toLong(message.getTaskId());
// 拿到租户ID
final String tenantId = message.getTenantId();
// 是否覆盖
final Boolean overWrite = Convert.toBool(message.getOverWrite());
LOG.info("当前进行服务器路径上传进行合并图片文件的文件夹是{}", folderName);
final File[] imageFiles = file.listFiles();
if (ObjectUtil.isNotEmpty(imageFiles)) {
Arrays.sort(imageFiles, Comparator.comparing(File::getName));
}
String fileName = folderName ".pdf";
// 判断是否覆盖已存在的文件
List<AppraisalFile> existingFiles = appraisalFileRepository.findByTaskIdAndFileName(taskId, fileName);
if (!existingFiles.isEmpty()) {
if (overWrite) {
List<Long> existingFileIds = existingFiles.stream().map(AppraisalFile::getId).collect(Collectors.toList());
appraisalFileService.deleteExistingFiles(existingFileIds);
} else {
LOG.info("跳过已存在的文件");
return;
}
}
if (ObjectUtil.isNotEmpty(imageFiles)) {
Arrays.sort(imageFiles, Comparator.comparing(File::getName));
}
List<byte[]> images = Arrays.stream(imageFiles)
.filter(File::isFile)
.map(imageFile -> {
try (InputStream fileInputStream = new FileInputStream(imageFile)) {
return IOUtils.toByteArray(fileInputStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (images.isEmpty()) {
LOG.info("跳过空文件夹");
return;
}
final byte[] bytes = appraisalFileService.convertToPdf(images);
byte[] modifiedPdfData= null;
try (PDDocument document = PDDocument.load(bytes)) {
int lastPageNumber = document.getNumberOfPages();
// 删除最后一页
document.removePage(lastPageNumber - 1);
// 保存修改后的PDF
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
document.save(outputStream);
modifiedPdfData = outputStream.toByteArray();
} catch (IOException e) {
// 处理PDF操作异常
e.printStackTrace();
}
Attach pdfAttach = ossEndPoint.putAttachWithTenant(
new InMemoryMultipartFile(fileName, new ByteArrayInputStream(modifiedPdfData)),
tenantId
).getData();
AppraisalFile appraisalFile = appraisalFileService.createAppraisalFile(taskId, fileName, pdfAttach);
appraisalFileRepository.save(appraisalFile);
LOG.info("当前文件夹名称为{},当前文件名:{},共{}页", folderName ,fileName, images.size());
}
@Override
boolean exist(PathUpLoadMessage message) {
return Boolean.FALSE;
}
}