结合Oss使用Jod进行文件转换

一,docker部署JodConverter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
services:
jodconverter:
container_name: jodconverter
image: ghcr.io/jodconverter/jodconverter-examples:rest
ports:
- "8100:8080"
restart: always
deploy:
resources:
limits:
memory: 1G
cpus: '1'
logging:
driver: "json-file"
options:
max-size: "1g"

二,项目中

1, 引入依赖

1
2
3
4
5
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-remote</artifactId>
<version>4.4.2</version>
</dependency>

2, 创建工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import lombok.extern.slf4j.Slf4j;
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.remote.RemoteConverter;
import org.jodconverter.remote.office.RemoteOfficeManager;

import java.io.*;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class DocConvertUtil {

private static final List<String> fileTypes = Arrays.asList("md", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "pdf");

/**
* 将文档转换为 PDF
* @param sourceFile 输入文件(支持 .doc, .docx, .odt, .rtf, .txt 等)
* @return PDF文件
*/
public static File convertToPdf(RemoteOfficeManager officeManager, File sourceFile) {
log.info("开始转换 sourceFile to PDF...");
if (sourceFile == null || !sourceFile.exists() || !sourceFile.isFile()) {
log.error("文件不存在或已损坏.");
return null;
}

File pdfFile = null;
try {
String docxFileName = sourceFile.getName();
String pdfFileName = docxFileName.substring(0, docxFileName.lastIndexOf('.')) + ".pdf";

pdfFile = new File(sourceFile.getParentFile(), pdfFileName);

RemoteConverter
.builder()
.officeManager(officeManager)
.build()
.convert(sourceFile)
.to(pdfFile)
.execute();
return pdfFile;
} catch (OfficeException e) {
e.printStackTrace();
// 出错,删除临时pdf
if (pdfFile != null && pdfFile.exists()) {
pdfFile.delete();
}
}
return null;
}

public static void stop(RemoteOfficeManager officeManager) {
if (officeManager != null) {
try {
officeManager.stop();
} catch (OfficeException e) {
e.printStackTrace();
}
}
}

public static boolean checkFileCanBeConvertedToPdf(String fileName) {
String fileType = fileName.substring(fileName.lastIndexOf('.') + 1);
return fileTypes.contains(fileType);
}
}

3, jod的操作类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @program:
* @author: Ren blog.igotu.top
* @create: 2025-05-27 13:50
* @description: 文档转换服务
**/
public interface RemoteConversionService {

/**
* 将文档转换为 PDF
* @param ossPrefix oss前缀 例如 资源管理/pdf-preview/
* @param ossFileUrl 输入文件的oss地址(支持 .doc, .docx, .odt, .rtf, .txt 等)
* @return PDF文件的oss地址
*/
RemoteFile convertDocumentToPdf(String ossPrefix, String ossFileUrl);

String getServerUrl();

void stop();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import com.ren.common.core.utils.DateUtils;
import com.ren.common.core.utils.file.DocConvertUtil;
import com.ren.common.core.utils.file.FileUtils;
import com.ren.common.oss.constant.OssConstant;
import com.ren.common.oss.core.OssClient;
import com.ren.common.oss.factory.OssFactory;
import com.ren.common.redis.utils.RedisUtils;
import com.ren.resource.api.RemoteFileService;
import com.ren.resource.api.domain.RemoteFile;
import com.ren.system.api.RemoteConversionService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;

import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.remote.office.RemoteOfficeManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;

/**
* 文档转换服务
*/
@Service
@DubboService
public class RemoteDocConversionServiceImpl implements RemoteConversionService {

// 从 Nacos 配置中注入 URL
@Value("${jodconverter.server.url:http://localhost:8100/lool/convert-to}")
private String serverUrl;

private RemoteOfficeManager officeManager;
@DubboReference
private RemoteFileService remoteFileService;

@PostConstruct
public void init() {
officeManager = RemoteOfficeManager.builder()
.urlConnection(serverUrl)
.build();
try {
officeManager.start();
System.out.println("JODConverter RemoteOfficeManager 已启动,URL: " + serverUrl);
} catch (OfficeException e) {
System.err.println("启动 JODConverter RemoteOfficeManager 失败: " + e.getMessage());
e.printStackTrace();
}
}

@PreDestroy
public void shutdown() {
if (officeManager != null && officeManager.isRunning()) {
try {
officeManager.stop();
System.out.println("JODConverter RemoteOfficeManager 已停止。");
} catch (OfficeException e) {
System.err.println("停止 JODConverter RemoteOfficeManager 失败: " + e.getMessage());
e.printStackTrace();
}
}
}

/**
* 将文档转换为 PDF
* @param ossFileUrl 输入文件oss地址(支持 .doc, .docx, .odt, .rtf, .txt 等)
* @return 返回的pdf文件oss地址
* @description 此处不进行错误处理,如果转换失败,则返回 null。
*/
@Override
public RemoteFile convertDocumentToPdf(String ossPrefix, String ossFileUrl) {
Path tempOriginalFilePath = null;
File convertedPdfFile = null;
try {
OssClient storage = OssFactory.instance(RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY));
tempOriginalFilePath = storage.fileDownload(ossFileUrl);
File originalFile = tempOriginalFilePath.toFile();

convertedPdfFile = DocConvertUtil.convertToPdf(officeManager, originalFile);

String keyPrefix = ossPrefix + DateUtils.datePath();
byte[] pdfData = Files.readAllBytes(convertedPdfFile.toPath());
return remoteFileService.upload(convertedPdfFile.getName(), keyPrefix, pdfData);
} catch (Exception e) {
return null;
} finally {
if (tempOriginalFilePath != null) {
try {
FileUtils.del(tempOriginalFilePath.toFile());
} catch (Exception e) {
System.err.println("删除临时原始文件失败:" + e.getMessage());
}
}
if (convertedPdfFile != null) {
try {
FileUtils.del(convertedPdfFile);
} catch (Exception e) {
System.err.println("删除临时PDF文件失败:" + e.getMessage());
}
}
}
}

public String getServerUrl() {
return serverUrl;
}

public void stop() {
if (officeManager != null && officeManager.isRunning()) {
try {
officeManager.stop();
System.out.println("JODConverter RemoteOfficeManager 已停止。");
} catch (OfficeException e) {
System.err.println("停止 JODConverter RemoteOfficeManager 失败: " + e.getMessage());
e.printStackTrace();
}
}
}
}

三,如果是单模块项目

直接在工具类中进行Jod officeManager注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import lombok.extern.slf4j.Slf4j;
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.remote.RemoteConverter;
import org.jodconverter.remote.office.RemoteOfficeManager;

import java.io.*;

@Slf4j
public class DocConvertUtil {

private static final String SERVER_URL = "http://localhost:8100/lool/convert-to";
private static final RemoteOfficeManager officeManager = RemoteOfficeManager.builder()
.urlConnection(SERVER_URL)
.build();

static {
try {
officeManager.start();
System.out.println("JODConverter RemoteOfficeManager 已启动,URL: " + SERVER_URL);
} catch (OfficeException e) {
System.err.println("启动 JODConverter RemoteOfficeManager 失败: " + e.getMessage());
e.printStackTrace();
}
}

/**
* 将文档转换为 PDF
* @param sourceFile 输入文件(支持 .doc, .docx, .odt, .rtf, .txt 等)
* @return PDF文件
*/
public static File convertToPdf(File sourceFile) {
log.info("开始转换 sourceFile to PDF...");
if (sourceFile == null || !sourceFile.exists() || !sourceFile.isFile()) {
log.error("文件不存在或已损坏.");
return null;
}

File pdfFile = null;
try {
String docxFileName = sourceFile.getName();
String pdfFileName = docxFileName.substring(0, docxFileName.lastIndexOf('.')) + ".pdf";

pdfFile = new File(sourceFile.getParentFile(), pdfFileName);

RemoteConverter
.builder()
.officeManager(officeManager)
.build()
.convert(sourceFile)
.to(pdfFile)
.execute();
return pdfFile;
} catch (OfficeException e) {
e.printStackTrace();
// 出错,删除临时pdf
if (pdfFile != null && pdfFile.exists()) {
pdfFile.delete();
}
}
return null;
}

public static void stop() {
if (officeManager != null) {
try {
officeManager.stop();
} catch (OfficeException e) {
e.printStackTrace();
}
}
}
}