package cn.cslg.pas.service; import cn.cslg.pas.common.core.base.Constants; import cn.cslg.pas.common.model.dto.PatentDTO; import cn.cslg.pas.common.model.dto.UploadFileDTO; import cn.cslg.pas.common.model.vo.PatentInstructionVO; import cn.cslg.pas.common.model.vo.PatentVO; import cn.cslg.pas.common.model.vo.SystemFile; import cn.cslg.pas.common.utils.*; import cn.cslg.pas.common.utils.SecurityUtils.LoginUtils; import cn.cslg.pas.domain.Patent; import cn.cslg.pas.domain.PatentInstruction; import cn.cslg.pas.domain.Task; import cn.cslg.pas.mapper.PatentInstructionMapper; import cn.cslg.pas.service.upLoadPatent.MessageService; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ZipUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.pdfbox.multipdf.PDFMergerUtility; import org.apache.pdfbox.multipdf.Splitter; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import org.springframework.web.multipart.MultipartFile; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.util.List; import java.util.*; import java.util.stream.Collectors; /** *

* 专利说明书 服务类 *

* * @author 王岩 * @since 2022-03-02 */ @Slf4j @Service @RequiredArgsConstructor(onConstructor_ = {@Lazy}) public class PatentInstructionService extends ServiceImpl { private final PatentService patentService; private final TaskService taskService; private final MessageService messageService; private final FileManagerService fileManagerService; private final FileUtils fileUtils; private final LoginUtils loginUtils; public IPage getPageList(PatentInstructionVO params) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StringUtils.isNotEmpty(params.getPatentNo())) { queryWrapper.like(PatentInstruction::getPatentNo, params.getPatentNo()); } if (params.getType() != null) { queryWrapper.eq(PatentInstruction::getType, params.getType()); } if (params.getPatentId() != null) { queryWrapper.eq(PatentInstruction::getPatentId, params.getPatentId()); } IPage pageList = this.page(new Page<>(params.getCurrent(), params.getSize()), queryWrapper); return pageList; } public List getPatentInstructionByPatentNo(String patentNo) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(PatentInstruction::getPatentNo, patentNo); return this.list(queryWrapper); } public List getPatentInstructionByPatentNo(List patentNo) { if (patentNo == null || patentNo.size() == 0) { return new ArrayList<>(); } LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(PatentInstruction::getPatentNo, patentNo); return this.list(queryWrapper); } public PatentInstruction getPatentInstructionByPatentNoAndType(String patentNo, Integer type) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(PatentInstruction::getType, type); queryWrapper.eq(PatentInstruction::getPatentNo, patentNo).last("Limit 1"); return this.getOne(queryWrapper); } @Async("singleThreadAsyncTaskExecutor") @Transactional(rollbackFor = Exception.class) public void batchUpload(String url, Integer type, String remark, Integer userId) { String tempPath = null; try { String tempDirectoryName = IdUtil.simpleUUID(); tempPath = fileUtils.getSystemPath(tempDirectoryName); File tempDirectory = new File(tempPath); if (!tempDirectory.exists()) { tempDirectory.mkdir(); } ZipUtil.unzip(fileUtils.getSystemPath(url), tempPath); List fileList = FileUtil.loopFiles(tempPath).stream().filter(item -> FileUtil.getType(item).equals("pdf")).collect(Collectors.toList()); for (int i = 0; i < fileList.size(); i++) { File file = fileList.get(i); String fileName = file.getName(); String patentNo = FileUtil.getPrefix(file); String saveName = IdUtil.simpleUUID() + ".pdf"; String saveUrl = fileUtils.getDirectory(saveName); String savePath = fileUtils.getSystemPath(saveUrl); FileUtil.copy(file.getPath(), savePath, true); PatentInstruction temp = this.getPatentInstructionByPatentNoAndType(patentNo, type); if (temp == null) { temp = new PatentInstruction(); } else { FileUtil.del(fileUtils.getSystemPath(temp.getUrl())); } temp.setPatentNo(patentNo); temp.setFileName(saveName); temp.setSize(FileUtil.size(file)); temp.setUrl(saveUrl); temp.setRemark(remark); temp.setCreateBy(userId); temp.setType(type); temp.insertOrUpdate(); Map data = new HashMap<>(); data.put("index", i); data.put("total", fileList.size()); WebSocketServer.sendInfo(Response.websocket(data, ResponseEnum.BATCH_UPLOAD_INSTRUCTION_TASK_SUCCESS), String.valueOf(userId)); } } catch (Exception e) { e.printStackTrace(); WebSocketServer.sendInfo(Response.error(ResponseEnum.BATCH_UPLOAD_INSTRUCTION_TASK_ERROR), String.valueOf(userId)); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } finally { FileUtil.del(tempPath); } } public String add(MultipartFile file, PatentInstruction patentInstruction) { UploadFileDTO fileDTO = fileUtils.uploadFile(file); patentInstruction.setCreateBy(loginUtils.getId()); patentInstruction.setUrl(fileDTO.getPath()); patentInstruction.setFileName(fileDTO.getFileName()); patentInstruction.insert(); return Response.success(patentInstruction.getId()); } @Transactional public String edit(MultipartFile file, PatentInstruction patentInstruction) { this.deleteByPatentNoAndType(patentInstruction.getPatentNo(), patentInstruction.getType()); if (StringUtils.isNotEmpty(patentInstruction.getUrl())) { FileUtil.del(fileUtils.getSystemPath(patentInstruction.getUrl())); } UploadFileDTO fileDTO = fileUtils.uploadFile(file); patentInstruction.setCreateBy(loginUtils.getId()); patentInstruction.setUrl(fileDTO.getPath()); patentInstruction.setFileName(fileDTO.getFileName()); patentInstruction.setSize(fileDTO.getFileSize()); patentInstruction.insert(); return Response.success(true); } /** * 说明书pdf数据入库 * * @param patentNo 专利号 * @param pdf 装载pdf数据对象 */ @Transactional public String edit(String patentNo, UploadFileDTO pdf) { //先把实体类对象赋好值 PatentInstruction patentInstruction = new PatentInstruction(); patentInstruction.setUrl(pdf.getPath()); patentInstruction.setFileName(pdf.getFileName()); patentInstruction.setSize(pdf.getFileSize()); patentInstruction.setPatentNo(patentNo); patentInstruction.setType(1); //根据专利号和pdf类型(1公开 2授权)查询该专利号是否已有公开的pdf List patentInstructions = this.list(new LambdaQueryWrapper().eq(PatentInstruction::getPatentNo, patentNo).eq(PatentInstruction::getType, 1)); if (patentInstructions != null && patentInstructions.size() > 0) { //若有则更新 patentInstruction.setId(patentInstructions.get(0).getId()); this.updateById(patentInstruction); } else { //若没有则新增 this.save(patentInstruction); } return Response.success(true); } @Transactional public String edit2(String patentNo, UploadFileDTO pdf2) { //先把实体类对象赋好值 PatentInstruction patentInstruction = new PatentInstruction(); patentInstruction.setUrl(pdf2.getPath()); patentInstruction.setFileName(pdf2.getFileName()); patentInstruction.setSize(pdf2.getFileSize()); patentInstruction.setPatentNo(patentNo); patentInstruction.setType(2); //根据专利号和pdf类型(1公开 2授权)查询该专利号是否已有授权的pdf List patentInstructions = this.list(new LambdaQueryWrapper().eq(PatentInstruction::getPatentNo, patentNo).eq(PatentInstruction::getType, 2)); //若有则更新 if (patentInstructions != null && patentInstructions.size() > 0) { patentInstruction.setId(patentInstructions.get(0).getId()); this.updateById(patentInstruction); } else { //若没有则新增 this.save(patentInstruction); } return Response.success(true); } @Transactional public String edit12(String patentNo, UploadFileDTO pdf1, UploadFileDTO pdf2) { //处理公开pdf文档(更新或新增) PatentInstruction patentInstruction1 = new PatentInstruction(); patentInstruction1.setUrl(pdf1.getPath()); patentInstruction1.setFileName(pdf1.getFileName()); patentInstruction1.setSize(pdf1.getFileSize()); patentInstruction1.setPatentNo(patentNo); patentInstruction1.setType(1); //先查询库中是否已有该专利号的公开pdf文档 List patentInstructions1 = this.list(new LambdaQueryWrapper().eq(PatentInstruction::getPatentNo, patentNo).eq(PatentInstruction::getType, 1)); //若有则更新 if (patentInstructions1 != null && patentInstructions1.size() > 0) { patentInstruction1.setId(patentInstructions1.get(0).getId()); this.updateById(patentInstruction1); } else { //若没有则新增 this.save(patentInstruction1); } //处理授权pdf文档(更新或新增) PatentInstruction patentInstruction2 = new PatentInstruction(); patentInstruction2.setUrl(pdf2.getPath()); patentInstruction2.setFileName(pdf2.getFileName()); patentInstruction2.setSize(pdf2.getFileSize()); patentInstruction2.setPatentNo(patentNo); patentInstruction2.setType(2); //再查询库中是否已有该专利号的授权pdf文档 List patentInstructions2 = this.list(new LambdaQueryWrapper().eq(PatentInstruction::getPatentNo, patentNo).eq(PatentInstruction::getType, 2)); //若有则更新 if (patentInstructions2 != null && patentInstructions2.size() > 0) { patentInstruction2.setId(patentInstructions2.get(0).getId()); this.updateById(patentInstruction2); } else { //若没有则新增 this.save(patentInstruction2); } return Response.success(true); } public String delete(Integer id) { PatentInstruction temp = this.getById(id); this.removeById(id); if (StringUtils.isNotEmpty(temp.getUrl())) { FileUtil.del(fileUtils.getSystemPath(temp.getUrl())); } return Response.success(true); } public void deleteByPatentNoAndType(String patentNo, Integer type) { this.remove(Wrappers.lambdaQuery().eq(PatentInstruction::getPatentNo, patentNo).eq(PatentInstruction::getType, type)); } public void importPatentInstruction(Integer userId, String tempPath, String patentIdPatentNoJson, String patentInstructionJson) { List importPatentList = JsonUtils.jsonToList(patentIdPatentNoJson, Patent.class); List importPatentInstructionList = JsonUtils.jsonToList(patentInstructionJson, PatentInstruction.class); List localPatentInstructionList = this.getPatentInstructionByPatentNo(importPatentList.stream().map(Patent::getPatentNo).collect(Collectors.toList())); for (PatentInstruction patentInstruction : importPatentInstructionList) { String fileName = IdUtil.simpleUUID() + "." + FileUtil.extName(patentInstruction.getFileName()); String saveUrl = fileUtils.getDirectory(fileName); String savePath = fileUtils.getSystemPath(saveUrl); String tempInstruction = tempPath + FileUtils.FILE_SEPARATOR + Constants.PATENT_INSTRUCTION_DIRECTORY_NAME + FileUtils.FILE_SEPARATOR + patentInstruction.getFileName(); patentInstruction.setId(null); patentInstruction.setFileName(fileName); patentInstruction.setUrl(saveUrl); patentInstruction.setCreateBy(userId); patentInstruction.setCreateTime(new Date()); if (FileUtil.exist(tempInstruction)) { patentInstruction.insert(); FileUtil.copy(tempInstruction, savePath, true); } } localPatentInstructionList.forEach(item -> { item.deleteById(); FileUtil.del(fileUtils.getSystemPath(item.getUrl())); }); } public void queryPatentPdfFirstPages(PatentVO params) throws IOException { log.info("开始处理【合并多个专利pdf首页】的业务,业务参数为:{}", params); //根据筛选条件分页查询专利清单(这一次查询目的只是获得专利总数和总页数) IPage pageList0 = patentService.getPageList(params); if (pageList0 == null || pageList0.getRecords() == null || pageList0.getRecords().size() == 0) { ThrowException.throwXiaoShiException("合并专利pdf首页文档失败,无专利信息!"); } int total = (int) pageList0.getTotal(); //专利总数(作为任务进度总数) long pages = pageList0.getPages(); //总页数(用来计算要检索几次) ArrayList filePaths = new ArrayList<>(); //存放所有临时文件(说明书pdf首页的文件)路径 String mergedFilePath = StringUtils.getUUID() + ".pdf"; //合并后的pdf文件路径 PDFMergerUtility pdfMerger = new PDFMergerUtility(); //pdf合并工具 //上传任务 Task task = new Task() .setFileName(mergedFilePath) .setProjectId(params.getProjectId()) .setType(6) .setCreateBy(loginUtils.getId()) .setStartTime(DateUtils.getDateTime()) .setTotal(total) .setStatus(6) .setDefaultNum(0) .setSuccessNum(0) .setTrueSuccessNum(0); taskService.save(task); //一页一页检索 for (long i = 1; i <= pages; i++) { params.setCurrent(i); IPage pageList = patentService.getPageList(params); //根据筛选条件分页查询专利清单 List patents = pageList.getRecords(); //取出专利清单 List patentNos = patents.stream().map(PatentDTO::getPatentNo).collect(Collectors.toList()); //过滤取出专利号 //根据专利号patentNos查询出所有pdf文档数据 List patentInstructions = this.list(new LambdaQueryWrapper().in(PatentInstruction::getPatentNo, patentNos)); //遍历当前专利号清单 for (String patentNo : patentNos) { List patentInstructionList = patentInstructions.stream().filter(item -> item.getPatentNo().equals(patentNo)).collect(Collectors.toList()); //若有说明书pdf数据 PatentInstruction patentInstruction = new PatentInstruction(); if (patentInstructionList.size() > 1) { //若有多个,则过滤取出授权文档 patentInstruction = patentInstructionList.stream().filter(item -> item.getType() == 2).collect(Collectors.toList()).get(0); } else if (patentInstructionList.size() == 1) { //若只有一个pdf,则直接取出 patentInstruction = patentInstructionList.get(0); } String filePath = fileUtils.getSystemPath() + patentInstruction.getUrl(); File pdfFile = new File(filePath); //若没有说明书pdf数据,则手写空白页显示该专利没有说明书pdf if (patentInstructionList.size() == 0 || !pdfFile.exists()) { //创建文件,设置页码 PDDocument doc = new PDDocument(); PDPage pageOne = new PDPage(PDRectangle.A4); doc.addPage(pageOne); //创建页面内容流 PDPageContentStream contents = new PDPageContentStream(doc, pageOne, true, true, true); //设置要使用的字体类型 //PDFont font = PDType1Font.COURIER_BOLD_OBLIQUE; PDFont font = PDType1Font.HELVETICA; //要写入的文本内容 String message = "no pdf of " + patentNo; float fontSize = 36.0f; PDRectangle pageSize = pageOne.getMediaBox(); float stringWidth = font.getStringWidth(message) * fontSize / 1000f; //计算页中心位置 int rotation = pageOne.getRotation(); boolean rotate = rotation == 90 || rotation == 270; float pageWidth = rotate ? pageSize.getHeight() : pageSize.getWidth(); float pageHeight = rotate ? pageSize.getWidth() : pageSize.getHeight(); double centeredXPosition = rotate ? pageHeight / 2f : (pageWidth - stringWidth) / 2f; double centeredYPosition = rotate ? (pageWidth - stringWidth) / 2f : pageHeight / 2f; contents.beginText(); //设置字体和大小 contents.setFont(font, fontSize); //设置文本颜色 contents.setNonStrokingColor(Color.BLACK); if (rotate) { // rotate the text according to the page rotation contents.setTextRotation(Math.PI / 2, centeredXPosition, centeredYPosition); } else { contents.setTextTranslation(centeredXPosition, centeredYPosition); } contents.showText(message); contents.endText(); //记得关闭流对象要不然是无法成功保存pdf文档的 contents.close(); String newFilePath = StringUtils.getUUID() + ".pdf"; doc.save(newFilePath); filePaths.add(newFilePath); pdfMerger.addSource(newFilePath); doc.close(); //更新任务表(完成数量+1)并发送进度 task.setSuccessNum(task.getSuccessNum() + 1); task.setTrueSuccessNum(task.getTrueSuccessNum() + 1); sendMessage(total, task); //continue; } else { PDDocument doc = PDDocument.load(pdfFile); Splitter splitter = new Splitter(); splitter.setStartPage(1); splitter.setEndPage(1); PDDocument needDoc = splitter.split(doc).get(0); String newFilePath = StringUtils.getUUID() + ".pdf"; needDoc.save(newFilePath); filePaths.add(newFilePath); pdfMerger.addSource(newFilePath); needDoc.close(); doc.close(); //更新任务表(完成数量+1)并发送进度 task.setSuccessNum(task.getSuccessNum() + 1); task.setTrueSuccessNum(task.getTrueSuccessNum() + 1); sendMessage(total, task); } } } // 设置合并生成pdf文件名称 pdfMerger.setDestinationFileName(mergedFilePath); // 合并PDF pdfMerger.mergeDocuments(); //若最终合并成的pdf文件不存在 if (!new File(mergedFilePath).exists()) { ThrowException.throwXiaoShiException("当前批次所有专利的说明书文档不存在或已丢失"); } //File文件转成MultipartFile MultipartFile multipartFile = FileToMultipartFileUtiles.fileToMultipartFile(mergedFilePath); ArrayList multipartFiles = new ArrayList<>(); multipartFiles.add(multipartFile); String res = fileManagerService.uploadFile(multipartFiles); JSONObject jsonObject = JSONObject.parseObject(res); List fileIds = JSONArray.parseArray(jsonObject.get("data").toString(), Integer.class); res = fileManagerService.getSystemFileFromFMS(fileIds); List systemFiles = JSONArray.parseArray(res, SystemFile.class); SystemFile systemFile = systemFiles.get(0); Task updateTask = new Task(); updateTask.setId(task.getId()); updateTask.setSystemFileId(fileIds.get(0)); updateTask.setUrl(systemFile.getFilePath().substring(systemFile.getFilePath().indexOf("file") + 4)); updateTask.setFileSize(Long.valueOf(systemFile.getFileLength())); taskService.updateById(updateTask); //最后要记得删除所有PDF首页临时文件 for (String filePath : filePaths) { //删除每个pdf首页文件 new File(filePath).delete(); } //删除最终合并的pdf首页文件 new File(mergedFilePath).delete(); } /** * 更新任务表(完成数量+1)、发送websocket进度 * * @param total 任务专利总数量 * @param task 任务对象 */ private void sendMessage(int total, Task task) { //更新任务表(完成数量+1),并发送进度+1 Task updateTask = new Task(); updateTask.setId(task.getId()); updateTask.setSuccessNum(task.getSuccessNum()); updateTask.setTrueSuccessNum(task.getTrueSuccessNum()); taskService.updateById(updateTask); long percentage = (long) Math.floor((task.getSuccessNum() + 0D) / total * 100D); //当全部完成时 if (task.getSuccessNum().equals(total)) { percentage = 100L; //任务表更新最终数据 task.setStatus(2); updateTask.setStatus(task.getStatus()); updateTask.setEndTime(DateUtils.getDateTime()); taskService.updateById(updateTask); } //websocket发送进度 messageService.sendWebsocketMessage(task, total, task.getSuccessNum(), percentage); } public void generateBookIamge(File inputFile, File outputFile) { try { PDDocument doc = PDDocument.load(inputFile); PDFRenderer pdfRenderer = new PDFRenderer(doc); // 提取的页码 int pageNumber = 0; // 以300 dpi 读取存入 BufferedImage 对象 int dpi = 300; RenderedImage buffImage = pdfRenderer.renderImageWithDPI(pageNumber, dpi, ImageType.RGB); // 将 BufferedImage 写入到 png ImageIO.write(buffImage, "png", outputFile); // 关闭文档 doc.close(); } catch (Exception e) { e.printStackTrace(); } } }