最近项目需要在线预览功能,所有临阵磨枪,去上网查找了资料,用office转pdf,然后通过pdf.js展示,期间出过大大小小的问题,通过查找资料解决了,试了两种解决方案:
1、第一种是SaveAsPDFandXPS.exe+jacob,但是不是跨平台的,服务器是Linux环境,所有只好换了下面方法;
2、第二种是OpenOffice+JodConverter,这个是跨平台,可以在Linux环境使用;
好了,开始行动吧。
一、引入manven配置
org.jodconverter
jodconverter-core
4.1.0
org.jodconverter
jodconverter-local
4.1.0
org.jodconverter
jodconverter-spring-boot-starter
4.1.0
org.libreoffice
juh
5.4.2
org.libreoffice
jurt
5.4.2
org.libreoffice
ridl
5.4.2
org.libreoffice
unoil
5.4.2
二、application.properties 配置如下:
jodconverter.enabled=true
jodconverter.portNumbers=8100, 8101, 8102, 8103, 8104, 8105, 8106, 8107, 8108, 8109
jodconverter.maxTasksPerProcess=10
三、java 代码
@Configuration
@ConditionalOnClass({DocumentConverter.class})
@ConditionalOnProperty(
prefix = "jodconverter",
name = {"enabled"},
havingValue = "true",
matchIfMissing = false
)
@EnableConfigurationProperties({JodConverterProperties.class})
public class JodConverterAutoConfiguration {
private JodConverterProperties properties;
public JodConverterAutoConfiguration(JodConverterProperties properties) {
this.properties = properties;
}
private OfficeManager createOfficeManager() {
Builder builder = LocalOfficeManager.builder();
if (!StringUtil.isBlank(this.properties.getPortNumbers())) {
Set iports = new HashSet();
String[] var3 = StringUtils.split(this.properties.getPortNumbers(), ", ");
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
String portNumber = var3[var5];
iports.add(NumberUtils.toInt(portNumber, 2002));
}
builder.portNumbers(ArrayUtils.toPrimitive((Integer[])iports.toArray(new Integer[iports.size()])));
}
String officeHome = LocalOfficeUtils.getDefaultOfficeHome().getPath();
builder.officeHome(officeHome);
//builder.officeHome(this.properties.getOfficeHome());
builder.workingDir(this.properties.getWorkingDir());
builder.templateProfileDir(this.properties.getTemplateProfileDir());
builder.killExistingProcess(this.properties.isKillExistingProcess());
builder.processTimeout(this.properties.getProcessTimeout());
builder.processRetryInterval(this.properties.getProcessRetryInterval());
builder.taskExecutionTimeout(this.properties.getTaskExecutionTimeout());
builder.maxTasksPerProcess(this.properties.getMaxTasksPerProcess());
builder.taskQueueTimeout(this.properties.getTaskQueueTimeout());
return builder.build();
}
@Bean(
initMethod = "start",
destroyMethod = "stop"
)
@ConditionalOnMissingBean
public OfficeManager officeManager() {
return this.createOfficeManager();
//return null;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({OfficeManager.class})
public DocumentConverter jodConverter(OfficeManager officeManager) {
return LocalConverter.make(officeManager);
//return null;
}
}
@ConfigurationProperties("jodconverter")
public class JodConverterProperties {
private boolean enabled;
private String officeHome;
private String portNumbers = "2002";
private String workingDir;
private String templateProfileDir;
private boolean killExistingProcess = true;
private long processTimeout = 120000L;
private long processRetryInterval = 250L;
private long taskExecutionTimeout = 120000L;
private int maxTasksPerProcess = 200;
private long taskQueueTimeout = 30000L;
public JodConverterProperties() {
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getOfficeHome() {
return this.officeHome;
}
public void setOfficeHome(String officeHome) {
this.officeHome = officeHome;
}
public String getPortNumbers() {
return this.portNumbers;
}
public void setPortNumbers(String portNumbers) {
this.portNumbers = portNumbers;
}
public String getWorkingDir() {
return this.workingDir;
}
public void setWorkingDir(String workingDir) {
this.workingDir = workingDir;
}
public String getTemplateProfileDir() {
return this.templateProfileDir;
}
public void setTemplateProfileDir(String templateProfileDir) {
this.templateProfileDir = templateProfileDir;
}
public boolean isKillExistingProcess() {
return this.killExistingProcess;
}
public void setKillExistingProcess(boolean killExistingProcess) {
this.killExistingProcess = killExistingProcess;
}
public long getProcessTimeout() {
return this.processTimeout;
}
public void setProcessTimeout(long processTimeout) {
this.processTimeout = processTimeout;
}
public long getProcessRetryInterval() {
return this.processRetryInterval;
}
public void setProcessRetryInterval(long procesRetryInterval) {
this.processRetryInterval = procesRetryInterval;
}
public long getTaskExecutionTimeout() {
return this.taskExecutionTimeout;
}
public void setTaskExecutionTimeout(long taskExecutionTimeout) {
this.taskExecutionTimeout = taskExecutionTimeout;
}
public int getMaxTasksPerProcess() {
return this.maxTasksPerProcess;
}
public void setMaxTasksPerProcess(int maxTasksPerProcess) {
this.maxTasksPerProcess = maxTasksPerProcess;
}
public long getTaskQueueTimeout() {
return this.taskQueueTimeout;
}
public void setTaskQueueTimeout(long taskQueueTimeout) {
this.taskQueueTimeout = taskQueueTimeout;
}
}
在这期间出现一个奇怪的问题,本来我是在application配置文件配置了openoffice服务安装路径的,但是我启动的时候老是报错,百度了也没有找到问题,最后在GitHub找到了解决办法https://github.com/sbraconnier/jodconverter,通过jar包本身自带的方法,
LocalOfficeUtils.getDefaultOfficeHome().getPath();获取服务路径,项目可以启动了。
四、在业务层引入DocumentConverter
@Autowired
private DocumentConverter documentConverter;
转换代码
File outFile = new File(outPath);//pdf目标文件
File file = new File(fullFileName);//源文件
in = new FileInputStream(file);
try{
if("doc".equals(fname.toLowerCase())){
documentConverter.convert(in).as(DefaultDocumentFormatRegistry.DOC).to(outFile).execute();
}else if("docx".equals(fname.toLowerCase())){
documentConverter.convert(in).as(DefaultDocumentFormatRegistry.DOCX).to(outFile).execute();
}else if("ppt".equals(fname.toLowerCase())){
documentConverter.convert(in).as(DefaultDocumentFormatRegistry.PPT).to(outFile).execute();
}else if("pptx".equals(fname.toLowerCase())){
documentConverter.convert(in).as(DefaultDocumentFormatRegistry.PPTX).to(outFile).execute();
}else if("xls".equals(fname.toLowerCase())){
documentConverter.convert(in).as(DefaultDocumentFormatRegistry.XLS).to(outFile).execute();
}else if("xlsx".equals(fname.toLowerCase())){
documentConverter.convert(in).as(DefaultDocumentFormatRegistry.XLSX).to(outFile).execute();
}else if("txt".equals(fname.toLowerCase())){
//因为会出现中文乱码问题,所以先通过字符流进行编码转换,再转换成字节流
bis = new BufferedReader(new InputStreamReader(in,"GBK"));
StringBuffer buf=new StringBuffer();
String temp;
while ((temp = bis.readLine()) != null) {
buf.append(temp).append(System.getProperty("line.separator"));
}
is = new ByteArrayInputStream(buf.toString().getBytes());
documentConverter.convert(is).as(DefaultDocumentFormatRegistry.TXT).to(outFile).execute();
}
return "成功";
}catch (OfficeException e) {
return "失败";
}
因为我本人是windows环境下开发,但是发布到Linux系统就出了问题,在Linux下安装好openOffice服务后,项目跑不起来,自己配置好的服务路径读取不到,网上都是配置的,但是我的不行,没找到原因,去看源代码,发现在LocalOfficeUtils下没有openoffice4的路径:
然后我去下载了LocalOfficeUtils.java这个类,在里面添加了一行,发现可以启动服务了
最后在Linux文件夹/usr/share/fonts下添加字体,解决中文乱码,OK。
最后非常感谢这两位的博客:
https://blog.csdn.net/starboyss/article/details/78498974
https://segmentfault.com/a/1190000011657122