OpenOffice概述
Apache OpenOffice是一款先进的开源 办公软件套件,它包含文本文档、电子表格、演示文稿、绘图、数据库等。 它能够支持许多语言并且在所有普通计算机上工作。它将你所有的数据以国际开放标准格式存储下来,并能够读写从其它常用办公软件包来的文件。
一般使用在文件预览的功能中。
OpenOffice的安装
- 官网下载安装包
官网地址为:http://www.openoffice.org/
- 解压下载的安装包
tar -xzvf Apache_OpenOffice_4.1.3_Linux_x86-64_install-rpm_zh-CN.tar.gz
解压得到的文件夹是 zh-CN
- 安装编译
cd zh-CN/RPMS/
rpm -ivh *rpm
- 安装Redhat套件
cd desktop-integration/
rpm -ivh openoffice4.1.3-redhat-menus-4.1.3-9783.noarch.rpm
默认安装在 /opt/openoffice4
- 更改OpenOffice文件夹用户
chown -R jenkins:jenkins /opt/openoffice4/
- Supervisor中添加OpenOffice
[program:openoffice]
command=/opt/openoffice4/program/soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
user=root
autorestart=true
startsecs=5
服务器使用的是Supervisor进行服务器中进程的管理,需要在Supervisor的配置文件中添加如上配置,并执行 supervisorctl update 命令让配置生效
若需要提供给外部使用,需将 host=127.0.0.1 配置改为 host=0.0.0.0
- 上传中文字体(宋体和黑体)
在Windows电脑的 C:\Windows\Fonts 路径中有相应的字体文件,将其中的宋体和黑体的字体文件进行上传到服务器地址为 /usr/share/fonts,并在文件夹路径中执行相关命令:
mkfontscale
mkfontdir
fc-cache
// 查询服务器中中文字体列表
fc-list :lang=zh
上传中文字体文件是进行解决项目中使用OpenOffice转换的文件中出现的中文乱码的情况
- 设置字体文件权限
chmod -R 755 simhei.ttf
chmod -R 755 simsun.ttc
字体文件上传处理完需要重新启动OpenOffice才会生效
OpenOffice的使用
- 引用依赖
<!--open office依赖-->
<dependency>
<groupId>com.artofsolving</groupId>
<artifactId>jodconverter</artifactId>
<version>${jodconverter.version}</version>
</dependency>
<!--excel处理依赖-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>${easypoi-base.version}</version>
</dependency>
<!-- PDF转图片依赖 -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>${pdfbox-tools.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
- OpenOffice的相关操作
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import com.artofsolving.jodconverter.openoffice.converter.StreamOpenOfficeDocumentConverter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.Map;
import static org.apache.pdfbox.rendering.ImageType.RGB;
/**
* 项目名称:spring-boot-demo
* 类名称:OpenOfficeUtil
* 类描述:OpenOffice工具类
* 创建人:yingx
* 创建时间: 2021/2/7
* 修改人:yingx
* 修改时间: 2021/2/7
* 修改备注:
*/
public class OpenOfficeUtil {
private static final Logger logger = LoggerFactory.getLogger(OpenOfficeUtil.class);
/**
* OpenOffice安装的服务器的IP地址
**/
public static final String LOCAL_HOST = "";
public static final int LOCAL_PORT = 8100;
/**
* 将项目内的模板输出到系统临时目录
*
* @param path : 项目内的模板路径
* @desc : easypoi的ExcelCache问题(路径转换)
*/
public static String convertTemplatePath(String path) {
Resource resource = new ClassPathResource(path);
FileOutputStream fileOutputStream = null;
// 将模版文件写入到 tomcat临时目录
String folder = System.getProperty("java.io.tmpdir");
File tempFile = new File(folder + File.separator + path);
// 文件存在时 删除历史临时文件
if (tempFile.exists()) {
//删除文件
tempFile.delete();
}
File parentFile = tempFile.getParentFile();
// 判断父文件夹是否存在
if (!parentFile.exists()) {
//不存在则创建
parentFile.mkdirs();
}
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(resource.getInputStream());
fileOutputStream = new FileOutputStream(tempFile);
byte[] buffer = new byte[10240];
int len;
while ((len = bufferedInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return tempFile.getPath();
}
/**
* Workbook输出文件
*
* @param wb excel
* @param fileName 文件
*/
public static void workbookWriteFile(Workbook wb, String fileName) {
try (FileOutputStream fileOutputStream = new FileOutputStream(fileName)) {
wb.write(fileOutputStream);
} catch (Exception e) {
}
}
/**
* @param inputFilePath 待转换的文件路径
* @param outputFilePath 输出文件路径
* @desc
* @auth josnow
* @date 2017年6月9日 下午4:11:04
*/
public static void convert(String inputFilePath, String outputFilePath) throws ConnectException {
convert(inputFilePath, outputFilePath, LOCAL_HOST, LOCAL_PORT);
}
/**
* @param inputFilePath 待转换的文件路径
* @param outputFilePath 输出文件路径
* @param connectIp 远程调用ip
* @param connectPort 远程调用端口
* @desc
* @auth josnow
* @date 2017年6月9日 下午4:12:29
*/
public static void convert(String inputFilePath, String outputFilePath, String connectIp, int connectPort)
throws ConnectException {
if (StringUtils.isEmpty(inputFilePath) || StringUtils.isEmpty(outputFilePath) || StringUtils.isEmpty(
connectIp)) {
logger.error("inputFilePath={}, outputFilePath={}, connectIp={}", inputFilePath, outputFilePath, connectIp);
throw new IllegalArgumentException("参数异常!!");
}
File inputFile = new File(inputFilePath);
File outputFile = new File(outputFilePath);
if (!inputFile.exists()) {
logger.error(inputFilePath + "输入文件不存在!");
throw new IllegalArgumentException("输入文件不存在!");
}
if (!outputFile.getPath()
.equals(outputFile.getAbsolutePath())) {
logger.warn("输出文件采用相对路径!相对路径为:{} ,绝对路径为:{}", outputFile.getPath(),
outputFile.getAbsolutePath());
}
File outputFilePa = outputFile.getParentFile();
if (outputFilePa != null && !outputFilePa.exists()) {
// 目录不存在则创建
boolean mkdirs = outputFilePa.mkdirs();
if (!mkdirs) {
logger.error("输出文件目录创建失败:" + outputFilePa.getAbsolutePath());
}
}
OpenOfficeConnection connection = new SocketOpenOfficeConnection(connectIp, connectPort);
connection.connect();
DocumentConverter converter = getConverter(connectIp, connection);
converter.convert(new File(inputFilePath), new File(outputFilePath));
connection.disconnect();
}
private static DocumentConverter getConverter(String connectIp, OpenOfficeConnection connection) {
return "localhost".equalsIgnoreCase(connectIp) || "127.0.0.1".equals(connectIp)
|| "0:0:0:0:0:0:0:1".equals(connectIp) ? new OpenOfficeDocumentConverter(connection) :
new StreamOpenOfficeDocumentConverter(connection);
}
/**
* 实现PDF转图片
*
* @param pdfFile
* @author yingx
* @date 2020/12/29
*/
public static void pdf2Image(File pdfFile) throws IOException {
// 生成图片后的路径
String path = pdfFile.getParent() + File.separator;
String fileName = pdfFile.getName().replace(".pdf", "");
PDDocument doc = PDDocument.load(pdfFile);
BufferedImage imageNew = null;
PDFRenderer pdfRenderer = new PDFRenderer(doc);
int pageCounter = 0;
int width = 0;
int height = 0;
for (PDPage page : doc.getPages()) {
//dpi为缩放参数,越小图片越模糊
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageCounter++, 100, RGB);
// 图片宽度 图片高度
width = Math.max(width, bim.getWidth());
height = Math.max(height, bim.getHeight());
}
int count = doc.getPages().getCount();
//多张图片垂直排列 , 所以长度要叠加
imageNew = new BufferedImage(width, height * count, BufferedImage.TYPE_INT_RGB);
pageCounter = 0;
for (PDPage page : doc.getPages()) {
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageCounter++, 100, RGB);
// 图片宽度 图片高度
int w = bim.getWidth();
int h = bim.getHeight();
int[] imageArrayOne = new int[width * height];
imageArrayOne = bim.getRGB(0, 0, w, h, imageArrayOne, 0, w);
// 第三,第四参数,不是终点位置,而是要填充内容的 宽 高
imageNew.setRGB(0, height * (pageCounter - 1), w, h, imageArrayOne, 0, w);
}
ImageIOUtil.writeImage(imageNew, path + fileName + ".png", 100);
doc.close();
}
/**
* 保存pdf到本地磁盘
*
* @param pdfSavePath pdf保存路径
* @param pdfContent pdf内容
*/
public static void savePdfToDisk(String pdfSavePath, String pdfContent) {
byte[] decodeBase64 = org.apache.commons.codec.binary.Base64.decodeBase64(pdfContent);
//修复异常数据
for (int i = 0; i < decodeBase64.length; i++) {
if (decodeBase64[i] < 0) {
decodeBase64[i] += 256;
}
}
try (OutputStream out = new FileOutputStream(pdfSavePath)) {
logger.info("将Base64的PDF文件进行保存至 ---{}", pdfSavePath);
IOUtils.write(decodeBase64, out);
} catch (IOException e) {
e.printStackTrace();
}
}
}
- OpenOffice的使用
public static void main(String[] args) throws IOException {
// 获取项目内 Excel模板路径
String excelTemplate = "templates/test_template.xls";
// 获取生成pdf的存储路径
String pdfPath = OpenOfficeUtil.convertTemplatePath(excelTemplate);
// 初始化 Excel 模板参数
TemplateExportParams params = new TemplateExportParams(pdfPath);
Map<String, Object> templateData = new HashMap<>(16);
templateData.put("Name", "java");
Workbook workbook = ExcelExportUtil.exportExcel(params, templateData);
String pdfName = "测试.pdf";
String exportFilePath = String.join("/", "/srv/upload/attachments", "test") + "/";
String xlseName = "test_template.xls";
File pdfAddressFolder = new File(exportFilePath);
if (StringUtils.isEmpty(exportFilePath)) {
logger.info("pdf文件夹配置为空");
} else if (!pdfAddressFolder.exists()) {
// 目录不存在则创建
boolean mkdirs = pdfAddressFolder.mkdirs();
if (!mkdirs) {
logger.error("输出文件目录创建失败 ---{}", pdfAddressFolder.getAbsolutePath());
}
}
String fullPdfName = exportFilePath + pdfName;
String xlsePath = exportFilePath + xlseName;
if (workbook != null) {
OpenOfficeUtil.workbookWriteFile(workbook, xlsePath);
OpenOfficeUtil.convert(xlsePath, fullPdfName);
//PDF转成图片并存储服务器中(PDF文件同一路径)
OpenOfficeUtil.pdf2Image(new File(fullPdfName));
}
}
剩下的就是将Excel模板文件放置在项目的 src\main\resources\templates目录下,并在模板中需要添加数据的位置添加占位符,如上代码需要使用 {{Name}} 占位符,执行完代码后,该位置将会替换成 对应的数据。