需求描述:
1.创建一个文档,将查询到的子父级数据写入文档中
2.中途可能存在img,pdf,doc,docx,excel类型的文档,需要依次插入到文档中作为内容
- 引入依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.15</version>
<type>pom</type>
</dependency>
2.开始实现
public boolean savePdf(String taskId, String taskName) {
//获取数据 数据类型为子父级结构
ClauseAction clauseAction = new ClauseAction();
clauseAction.setTaskId(taskId);
List<Map<String, Object>> list = responsibilityAuditReadService.queryAuditTasks(clauseAction);
if (ValidateUtil.isEmpty(list)) {
return false;
}
String filepath = "";
String datePath = "";
String fileNameUuid = UUIDUtils.getUUID();
datePath = com.yinhai.djps.utils.DateUtils.dateToString(new Date(), "yyyyMMdd");
String path = taskFilePath + File.separator + datePath;
filepath = path + File.separator + fileNameUuid + ".pdf";
File fileDirectory = new File(path);
//判断文件夹是否存在不存在则新增
if (!fileDirectory.exists() && fileDirectory.mkdirs()) {
log.debug("创建文件夹成功");
}
//根据任务id获取所有佐证材料 按条款id分组
Map<String, List<Map<String, Object>>> fileMap = responsibilityAuditReadService.queryFileByTaskIdGroupByDept(taskId);
List<String> imgTypeList = Arrays.asList("png", "jpg", "jpeg", "bmp", "gif");
try {
// 创建一个PdfWriter实例,将Document对象写入指定的文件路径
PdfWriter writer = new PdfWriter(filepath);
// 创建PdfDocument实例,与PdfWriter关联
PdfDocument pdfDoc = new PdfDocument(writer);
// 创建Document实例,指定页面大小和PdfDocument
// 注意:在iText 7中,应该使用PageSize.A4.getRectangle()来获取页面尺寸的Rectangle对象
Document document = new Document(pdfDoc);
// 设置中文字体
// 设置字体提供者,确保支持特殊字符
// 确定字体已安装在系统上,并且知道其名称和路径
PdfFont font = PdfFontFactory.createFont(getFilePath(), PdfEncodings.IDENTITY_H, true);
for (Map<String, Object> map : list) {
//开始写文件内容
getDocument(fileMap, imgTypeList, pdfDoc, document, font, map);
}
document.close();
//保存文件信息到本地
ThirdWorkTaskFile fileEntity = new ThirdWorkTaskFile();
fileEntity.setTaskId(taskId);
fileEntity.setFileName(taskName + ".pdf");
fileEntity.setFileStyle("pdf");
fileEntity.setDcsFileId("");
fileEntity.setFilePath(IConstants.PATH_SEPARATOR + IConstants.FILE_PATH + IConstants.PATH_SEPARATOR + datePath + IConstants.PATH_SEPARATOR + fileNameUuid + ".pdf");
thirdWorkTaskFileWriteService.saveFile(fileEntity);
} catch (IOException e) {
log.error("生成文件失败", e);
return false;
}
return true;
}
private void getDocument(Map<String, List<Map<String, Object>>> fileMap, List<String> imgTypeList, PdfDocument pdfDoc, Document document, PdfFont font, Map<String, Object> map) {
document.add(
new Paragraph(
new Text(
getObjectString(map.get("provisionNo")
+ getObjectString(map.get("provisionName")))
+ " [自评分]: "
+ getSelfRatingAndProvisionSum(map))
).setFont(font));
if (map.get(CHILDREN) instanceof ArrayList) {
for (Object obj : (List<?>) map.get(CHILDREN)) {
writeByProvision(fileMap, imgTypeList, pdfDoc, document, font, obj);
}
} else if (map.get(CHILDREN) != null) {
Object obj = map.get(CHILDREN);
writeByProvision(fileMap, imgTypeList, pdfDoc, document, font, obj);
}
}
private void writeByProvision(Map<String, List<Map<String, Object>>> fileMap, List<String> imgTypeList, PdfDocument pdfDoc, Document document, PdfFont font, Object obj) {
if (obj == null) {
return;
}
HashMap childMap;
try {
childMap = JSON.parseObject(JSON.toJSONString(obj), HashMap.class);
} catch (Exception e) {
log.error("Obj转map 失败 ", e);
return;
}
if (childMap == null) {
return;
}
//条款名称
document.add(new Paragraph(new Text(getObjectString(childMap.get("provisionName")))).setFont(font));
//责任科室
document.add(
new Paragraph(
new Text("[责任(牵头)科室]:"
+ getObjectString(childMap.get("secondaryDeptName"))
+ " ; [总分]:"
+ objectToString(childMap.get(PROVISION_SCORE))
+ " ; [目标分]:"
+ objectToString(childMap.get("targetRating"))
+ " ; [自评分]:"
+ objectToString(childMap.get(SELF_RATING))
)).setFont(font)
);
document.add(new Paragraph(new Text("[自评结论]:" + getObjectString(childMap.get("conclusion")))).setFont(font));
// 按承办科室拼接材料
List<Map<String, Object>> fileList = fileMap.get(getObjectString(childMap.get("provisionId")));
if (ValidateUtil.isEmpty(fileList)) {
return;
}
log.info("材料list长度:{}", fileList.size());
List<Map<String, Object>> filterList = fileList.stream().filter(item -> ValidateUtil.isNotEmpty(getObjectString(item.get("undertakeId")))).collect(toList());
if (ValidateUtil.isEmpty(filterList)) {
return;
}
Map<String, List<Map<String, Object>>> fileGroupByDept = filterList.stream()
.collect(Collectors.groupingBy(item -> getObjectString(item.get("undertakeId"))));
if (ValidateUtil.isEmpty(fileGroupByDept)) {
return;
}
//遍历承办科室
for (Map.Entry<String, List<Map<String, Object>>> entrySet : fileGroupByDept.entrySet()) {
List<Map<String, Object>> deptFileList = fileGroupByDept.get(entrySet.getKey());
if (ValidateUtil.isEmpty(deptFileList)) {
continue;
}
document.add(new Paragraph(new Text("[承办科室]:" + getObjectString(deptFileList.get(0).get("undertakeName")) + ", 佐证材料:")).setFont(font));
List<Map<String, Object>> imgList = deptFileList.stream().filter(file -> imgTypeList.contains(getObjectString(file.get(FILE_STYLE)))).collect(toList());
if (ValidateUtil.isNotEmpty(imgList)) {
addImg(document, font, imgList);
}
List<Map<String, Object>> addFileList = deptFileList.stream().filter(file -> !imgTypeList.contains(getObjectString(file.get(FILE_STYLE)))).collect(toList());
if (ValidateUtil.isNotEmpty(addFileList)) {
//向文档写入文件类型内容
addFile(pdfDoc, document, addFileList);
//分页
document.add(new AreaBreak(AreaBreakType.NEXT_AREA));
}
}
}
private void addFile(PdfDocument pdfDoc, Document document, List<Map<String, Object>> addFileList) {
log.info("文件数量:{}", addFileList.size());
for (Map<String, Object> addFile : addFileList) {
String fileRealPath = taskFilePath + File.separator + getObjectString(addFile.get(FILE_PATH)).replace("/file/", "").replace("/", File.separator);
if ("pdf".equalsIgnoreCase(getObjectString(addFile.get(FILE_STYLE)))) { //拼接pdf
log.info("================开始拼接pdf文档,文件id:{}=========", addFile.get("id"));
// 检查文件是否存在
if (!new File(fileRealPath).exists()) {
log.info("文件找不到:{}", fileRealPath);
} else {
//将pdf复制到已创建文档中
pdfCopyToDocument(pdfDoc, document, fileRealPath);
}
} else {//转成pdf再拼接
if ("doc".equalsIgnoreCase(getObjectString(addFile.get(FILE_STYLE))) || "docx".equalsIgnoreCase(getObjectString(addFile.get(FILE_STYLE)))) {
addWord(pdfDoc, document, addFile, fileRealPath);
} else if ("xlsx".equalsIgnoreCase(getObjectString(addFile.get(FILE_STYLE)))
|| "xls".equalsIgnoreCase(getObjectString(addFile.get(FILE_STYLE)))
|| "csv".equalsIgnoreCase(getObjectString(addFile.get(FILE_STYLE)))
) {
addExcel(pdfDoc, document, addFile, fileRealPath);
}
}
}
}
private void addExcel(PdfDocument pdfDoc, Document document, Map<String, Object> addFile, String fileRealPath) {
try {
log.info("================开始拼接excel文档,文件id:{}=========", addFile.get("id"));
FileInputStream fis;
File resultFile = new AsyncMethodUtil().getTempFile(getObjectString(addFile.get(FILE_NAME)), IConstants.FILE_FORMAT_PDF);
String tempFilePath;
tempFilePath = resultFile.getCanonicalPath();
new AsposeUtil().excel2Pdf(fileRealPath, tempFilePath);
fis = new FileInputStream(new File(tempFilePath));
// 将FileInputStream的内容读入到字节数组中
byte[] buffer;
buffer = new byte[fis.available()];
int read;
read = fis.read(buffer);
log.info("写出{}字节", read);
fis.close();
//将pdf复制到已创建文档中
if (read != 0) {
pdfCopyToDocument(pdfDoc, document, tempFilePath);
}
} catch (Exception e) {
log.info("Excel文件地址{}文件名称{}t_djps_material_task_file表id{}", addFile.get(FILE_PATH), addFile.get(FILE_NAME), addFile.get("id"));
log.error("Excel文件找不到", e);
}
}
private void addWord(PdfDocument pdfDoc, Document document, Map<String, Object> addFile, String fileRealPath) {
try {
log.info("================开始拼接word文档,文件id:{}=========", addFile.get("id"));
FileInputStream fis;
File resultFile = new AsyncMethodUtil().getTempFile(getObjectString(addFile.get(FILE_NAME)), IConstants.FILE_FORMAT_PDF);
String tempFilePath;
tempFilePath = resultFile.getCanonicalPath();
new AsposeUtil().word2Pdf2(fileRealPath, tempFilePath);
fis = new FileInputStream(new File(tempFilePath));
// 将FileInputStream的内容读入到字节数组中
byte[] buffer;
buffer = new byte[fis.available()];
int read;
read = fis.read(buffer);
log.info("写出{}字节", read);
fis.close();
//将pdf复制到已创建文档中
if (read != 0) {
pdfCopyToDocument(pdfDoc, document, tempFilePath);
}
} catch (Exception e) {
log.info("Word文件地址{}文件名称{}t_djps_material_task_file表id{}", addFile.get(FILE_PATH), addFile.get(FILE_NAME), addFile.get("id"));
log.error("Word文件找不到", e);
}
}
private void addImg(Document document, PdfFont font, List<Map<String, Object>> imgList) {
log.info("图片数量:{}", imgList.size());
for (Map<String, Object> file : imgList) {
String fileRealPath = taskFilePath + File.separator + getObjectString(file.get(FILE_PATH)).replace("/file/", "").replace("/", File.separator);
// 检查文件是否存在
if (!new File(fileRealPath).exists()) {
log.info("文件找不到:{}", fileRealPath);
} else {
try {
log.info("================开始拼接图片,文件id:{}=========", file.get("id"));
// 加载本地图片
// 加载图片文件并添加到文档中
ImageData imageData = ImageDataFactory.create(fileRealPath);
// 注意这里使用了Image类的静态方法create()来创建图片实例
new Image(imageData);
Image img = new Image(imageData);
// 设置图片的缩放比例
img.setHeight(200);
img.setWidth(200);
// 文件名称
document.add(
new Paragraph(
new Text(getObjectString(file.get(FILE_NAME))
).setFont(font)
));
document.add(img);
} catch (Exception e) {
log.info("图片文件地址{}文件名称{}t_djps_material_task_file表id{}", file.get(FILE_PATH), file.get(FILE_NAME), file.get("id"));
log.error("图片文件找不到", e);
}
}
}
}
public String objectToString(Object s) {
if (s == null) {
return "--";
}
return String.valueOf(s);
}
3.很重要! 这个方法实现了将pdf内容复制到创建的文档中
private void pdfCopyToDocument(PdfDocument pdfDoc, Document document, String fileRealPath) {
// 读取PDF文件
try {
//读取已存在的PDF文档 (文档2) 并准备复制其页面
PdfDocument pdfDoc2 = new PdfDocument(new PdfReader(fileRealPath));
int numberOfPages = pdfDoc2.getNumberOfPages();
if (numberOfPages == 0) {
return;
}
// Step 4: 复制文档2的每一页到文档1
for (int i = 1; i <= numberOfPages; i++) {
PdfPage page = pdfDoc2.getPage(i).copyTo(pdfDoc);
pdfDoc.addPage(page); // 在某些iText版本中,copyTo可能已经自动添加了页面
}
pdfDoc2.close();
//添加空页面 避免新加内容出现在复制的pdf上
for (int i = 1; i <= numberOfPages; i++) {
document.add(new AreaBreak(AreaBreakType.NEXT_AREA));
}
} catch (Exception e) {
log.error("文件找不到", e);
}
}
4.word转pdf
import com.aspose.cells.PageSetup;
import com.aspose.cells.PaperSizeType;
import com.aspose.cells.Workbook;
import com.aspose.cells.Worksheet;
import com.aspose.slides.Presentation;
import com.aspose.words.Document;
import com.aspose.words.FontSettings;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
/**
* word转pdf
* inpath: 输入word的路径
* outpath: 输出pdf的路径
*/
public void word2Pdf2(String inpath, String outpath) throws Exception {
if (!getLicense()) {
return;
}
File file = new File(outpath);
if (file.exists() && file.isFile() && (file.length() > 0)) {
return;
}
FileOutputStream os = new FileOutputStream(file);
//解决乱码
//如果是windows执行,不需要加这个
//如果是linux执行,需要添加这个字体路径
//FontSettings.setFontsFolder("/usr/share/fonts",true);
String property = System.getProperty("os.name");
Document doc = new Document(inpath);
log.info("os.name:" + property);
if (property.startsWith("Linux")) {
FontSettings fontSettings = new FontSettings();
fontSettings.setFontsFolder("/usr/share/fonts", true);
doc.setFontSettings(fontSettings);
}
//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
doc.save(os, SaveFormat.PDF);
os.close();
}
5.excel转pdf
import com.aspose.cells.PageSetup;
import com.aspose.cells.PaperSizeType;
import com.aspose.cells.Workbook;
import com.aspose.cells.Worksheet;
import com.aspose.slides.Presentation;
import com.aspose.words.Document;
import com.aspose.words.FontSettings;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
public void excel2Pdf(String path, String outpath) throws FileNotFoundException {
if (!getLicenseExcel()) {
return;
}
File file = new File(outpath);
if (file.exists() && file.isFile() && (file.length() > 0)) {
return;
}
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
Workbook wb = new Workbook(path);
//设置纸张大小为A3解决excel转pdf 一页内容被分割成多页pdf
// 遍历所有工作表
for (int i = 0; i < wb.getWorksheets().getCount(); i++) {
Worksheet worksheet = wb.getWorksheets().get(i);
// 获取页面设置
PageSetup pageSetup = worksheet.getPageSetup();
// 设置纸张大小为A3
pageSetup.setPaperSize(PaperSizeType.PAPER_A_3);
}
wb.save(fileOutputStream, com.aspose.cells.SaveFormat.PDF);
} catch (Exception e) {
log.error("excel2Pdf error", e);
}
}
创建临时文件
/**
* 创建临时文件(解决安全热点问题)
*
* @param fileName 文件名
* @param fileType 文件类型
* @return 临时文件
*/
public File getTempFile(String fileName, String fileType) {
File resultFile = null;
try {
if(SystemUtils.IS_OS_UNIX) {
log.info("IS_OS_UNIX临时文件开始=======");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------"));
resultFile = Files.createTempFile(fileName, fileType , attr).toFile();
}
else {
resultFile = Files.createTempFile(fileName, fileType).toFile();
boolean readAble = resultFile.setReadable(true, true);
boolean writable = resultFile.setWritable(true, true);
boolean executable = resultFile.setExecutable(true, true);
if (readAble && writable && executable) {
log.info("临时文件权限设置成功");
}
}
} catch (Exception e) {
log.info("材料文件转换失败WordToPdf: {}", e.getMessage());
}
return resultFile;
}
<!--Aspose相关依赖 需要在本地指定导入-->
<dependency>
<groupId>com.aspose</groupId>
<artifactId>cells</artifactId>
<version>8.5.2</version>
</dependency>
<dependency>
<groupId>com.aspose</groupId>
<artifactId>slides</artifactId>
<version>15.9.0</version>
</dependency>
<dependency>
<groupId>com.aspose</groupId>
<artifactId>words.jdk16</artifactId>
<version>16.8.0</version>
</dependency>