实现使用jodconverter调用libreoffice将word转pdf

This commit is contained in:
2025-07-01 11:50:59 +08:00
parent 4483f3ef4c
commit a4c4994759
32 changed files with 636 additions and 2282 deletions

View File

@@ -0,0 +1,13 @@
package com.optima.document.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DoctoDocumentServer {
public static void main(String[] args) {
SpringApplication.run(DoctoDocumentServer.class, args);
}
}

View File

@@ -0,0 +1,199 @@
package com.optima.document.server.api;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.policy.ListRenderPolicy;
import com.deepoove.poi.policy.PictureRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.xwpf.BodyContainer;
import com.deepoove.poi.xwpf.BodyContainerFactory;
import com.optima.document.api.DocumentService;
import com.optima.document.server.config.DocumentConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* 服务接口实现
*
* @author Elias
* @since 2021-09-28 16:18
*/
@SuppressWarnings("rawtypes")
@Slf4j
@Service
public class DocumentServiceImpl implements DocumentService {
@Resource
private DocumentConfig documentConfig;
/**
* word模版引擎配置
*/
Configure wtlConfig = Configure.builder().buildGramer("${", "}")
.setValidErrorHandler(new Configure.DiscardHandler())
.addPlugin('%', new ListRenderPolicy() {
@Override
public void doRender(RenderContext<List<Object>> context) throws Exception {
XWPFRun run = context.getRun();
List<?> dataList = context.getData();
Iterator<?> var5 = dataList.iterator();
while (var5.hasNext()) {
Object data = var5.next();
if (data instanceof TextRenderData) {
run.setText(((TextRenderData) data).getText());
if (var5.hasNext()) {
run.setText("");
}
} else if (data instanceof PictureRenderData) {
PictureRenderPolicy.Helper.renderPicture(run, (PictureRenderData) data);
}
}
}
})
.setRenderDataComputeFactory(envModel ->
el -> {
Object data = envModel.getRoot();
if ("#this".equals(el)) {
return data;
} else if (data instanceof Map) {
Map dataMap = ((Map) data);
if (dataMap.containsKey(el)) {
return dataMap.get(el);
}
}
return null;
})
.build();
public byte[] convert(byte[] source, String sourceExtension, String targetExtension, String targetFormat) {
try {
sourceExtension = sourceExtension.replace(".", "");
targetExtension = targetExtension.replace(".", "");
Path sourcePath = Files.createTempFile(UUID.randomUUID().toString(), "." + sourceExtension);
Path targetPath = Files.createTempFile(UUID.randomUUID().toString(), "." + targetExtension);
Files.write(sourcePath, source);
try {
long begin = System.currentTimeMillis();
String command;
if (sourceExtension.contains("xls")) {
command = "%s -XL -f %s -O %s -T %s";
} else if (sourceExtension.contains("ppt")) {
command = "%s -PP -f %s -O %s -T %s";
} else {
command = "%s -WD -f %s -O %s -T %s";
}
command = String.format(command, documentConfig.getDocToProgram(), sourcePath, targetPath, targetFormat);
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
long end = System.currentTimeMillis();
log.info("convert {} to {} take time in millis:{}", sourceExtension, targetExtension, (end - begin));
return Files.readAllBytes(targetPath);
} catch (Exception e) {
log.error("convert {} to {} error", sourceExtension, targetExtension, e);
return null;
} finally {
Files.delete(sourcePath);
Files.delete(targetPath);
}
} catch (IOException e) {
log.error("convert error", e);
}
return null;
}
public byte[] generateWord(byte[] sourceTemplate, Map<String, Object> dataModel) {
long start = System.currentTimeMillis();
XWPFTemplate template = XWPFTemplate.compile(new ByteArrayInputStream(sourceTemplate), wtlConfig).render(dataModel);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
template.write(bos);
log.info("word generate take time in millis:{}", System.currentTimeMillis() - start);
return bos.toByteArray();
} catch (Exception e) {
log.error("word generate error", e);
return null;
}
}
public byte[] wordToPdf(byte[] source, String sourceFormat, boolean clear) {
return wordToPdf(source, clear);
}
public byte[] wordToPdf(byte[] source, boolean clear) {
try {
long start = System.currentTimeMillis();
if (clear) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
XWPFTemplate template = XWPFTemplate.compile(new ByteArrayInputStream(source), wtlConfig);
BodyContainer bodyContainer = BodyContainerFactory.getBodyContainer(template.getXWPFDocument());
template.getElementTemplates().forEach(it -> {
if (it instanceof RunTemplate) {
RunTemplate rt = (RunTemplate) it;
bodyContainer.clearPlaceholder(rt.getRun());
}
});
template.writeAndClose(bos);
source = bos.toByteArray();
log.info("clear placeholder take time in millis:{}", System.currentTimeMillis() - start);
} catch (Exception e) {
log.error("clear placeholder error", e);
return null;
}
}
return convert(source, "docx", "pdf", "wdFormatPDF");
} catch (Exception e) {
log.error("word to pdf error", e);
return null;
}
}
public byte[] wordToImage(byte[] source, String targetExtension) {
try {
byte[] pdfBytes = wordToPdf(source, true);
long start = System.currentTimeMillis();
PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes));
PDFRenderer pdfRenderer = new PDFRenderer(document);
BufferedImage bim = pdfRenderer.renderImageWithDPI(0, 300, ImageType.RGB);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIOUtil.writeImage(bim, targetExtension, bos, 300);
document.close();
log.info("word to image take time in millis:{}", System.currentTimeMillis() - start);
return bos.toByteArray();
} catch (Exception e) {
log.error("word to image error", e);
}
return null;
}
public byte[] wordToImage(byte[] source, String sourceExtension, String targetExtension) {
return wordToImage(source, targetExtension);
}
public byte[] docToDocx(byte[] source) {
return convert(source, "doc", "docx", "wdFormatDocumentDefault");
}
public byte[] xlsToXlsx(byte[] source) {
return convert(source, "xls", "xlsx", "xlWorkbookDefault");
}
}

View File

@@ -0,0 +1,37 @@
package com.optima.document.server.config;
import com.optima.document.api.DocumentService;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
/**
* 服务端配置
*
* @author Elias
* @since 2021-09-28 16:12
*/
@SuppressWarnings("deprecation")
@Configuration
@ConfigurationProperties(prefix = "document")
@Data
public class DocumentConfig {
private String docToProgram;
/**
* 文档接口
*
* @return httpinvoker
*/
@Bean(name = "/document-service")
HttpInvokerServiceExporter wordService(DocumentService documentService) {
HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
exporter.setService(documentService);
exporter.setServiceInterface(DocumentService.class);
return exporter;
}
}

View File

@@ -0,0 +1,5 @@
server:
port: 9004
document:
doc-to-program: C:\\DocumentServer\\docto.exe

View File

@@ -0,0 +1,6 @@
██████╗ ██████╗ ██████╗██╗ ██╗███╗ ███╗███████╗███╗ ██╗████████╗
██╔══██╗██╔═══██╗██╔════╝██║ ██║████╗ ████║██╔════╝████╗ ██║╚══██╔══╝
██║ ██║██║ ██║██║ ██║ ██║██╔████╔██║█████╗ ██╔██╗ ██║ ██║
██║ ██║██║ ██║██║ ██║ ██║██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ██║
██████╔╝╚██████╔╝╚██████╗╚██████╔╝██║ ╚═╝ ██║███████╗██║ ╚████║ ██║
╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝