实现使用jodconverter调用libreoffice将word转pdf
This commit is contained in:
11
README.md
11
README.md
@@ -2,8 +2,13 @@
|
||||
|
||||
文书服务
|
||||
|
||||
api下为调用的接口,在需要处理文书的项目中引用,以`fegin方式`配置Service后进行调用
|
||||
+ api下为调用的接口,在需要处理文书的项目中引用,以`Http Invoker`配置Service后进行调用
|
||||
+ 参考[在Spring Boot中使用Http Invoker](https://codeleading.com/article/15413828287/) 的`Client`部分
|
||||
|
||||
server下为使用jacob处理word文书,使用openoffice来进行pdf转换,`java -jar xxx.jar`启动
|
||||
+ [jod-document-server](document-server/jod-document-server)下使用poi-tl处理word文件,使用jacob处理调用[LibreOffice](https://zh-cn.libreoffice.org/)来进行格式转换,`java -jar xxx.jar`启动
|
||||
+ 参考:[springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice](https://blog.csdn.net/qq_42882229/article/details/140917550)
|
||||
+ 在Linux下,需要注意word文件的字体,必须在Linux中存在
|
||||
+ 若出现格式问题,需先使用LibreOffice打开修复后,在进行转换
|
||||
|
||||
tl-server下仅进行word转pdf,使用的docto调用office来转换,`java -jar xxx.jar`启动
|
||||
+ [docto-document-server](document-server/docto-document-server)下使用poi-tl处理word文件,使用docto调用`Microsoft Office`来转换格式,`java -jar xxx.jar`启动
|
||||
+ 仅能运行在Windows,兼容性最好,比较慢
|
||||
33
api/pom.xml
33
api/pom.xml
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<name>document api</name>
|
||||
<description>文档操作api</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.20</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.optima.document.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文档接口,此类中用的jacob生成word文档,插入图片等,使用openoffice进行格式转换
|
||||
*
|
||||
* @author Elias
|
||||
* @since 2021-09-28 16:00
|
||||
*/
|
||||
public interface LegacyDocumentService extends BaseDocumentService {
|
||||
/**
|
||||
* 通过jacob向文档中插入图片,仅server模块下实现
|
||||
*
|
||||
* @param source 文档流
|
||||
* @param toFindText 需要替换的文本
|
||||
* @param imgSource 图片流
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @return word文档流
|
||||
*/
|
||||
default byte[] insertJpeg(byte[] source, String toFindText, byte[] imgSource, int width, int height) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过jacob向文档中插入多张图片,仅server模块下实现
|
||||
*
|
||||
* @param source 文档流
|
||||
* @param toFindText 需要替换的文本
|
||||
* @param imgSource 图片流列表
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @return word文档流
|
||||
*/
|
||||
default byte[] insertJpeg(byte[] source, String toFindText, List<byte[]> imgSource, int width, int height) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过jacob向word填充属性字段,仅server模块下实现
|
||||
*
|
||||
* @param source 文档流
|
||||
* @param infoMap 字段集合,${key}为占位字符,value为对应替换内容
|
||||
* @return word文档流
|
||||
*/
|
||||
default byte[] fieldToWord(byte[] source, Map<String, Object> infoMap) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
58
document-api/pom.xml
Normal file
58
document-api/pom.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<artifactId>document-api</artifactId>
|
||||
<name>Document API</name>
|
||||
<description>文档操作api</description>
|
||||
<properties>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.20</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 1. 使用 maven-jar-plugin 打包当前模块的代码(不含依赖) -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<!-- 可选:指定主类(如果需要可执行) -->
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.example.MyApp</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- 2. 使用 maven-source-plugin 生成源码 JAR -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,17 +1,34 @@
|
||||
package com.optima.document.api;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yanghuanglin
|
||||
* @since 2022/12/28
|
||||
*/
|
||||
public interface BaseDocumentService {
|
||||
/**
|
||||
* 格式转换,server和tl-server下均实现
|
||||
* 格式转换
|
||||
*
|
||||
* @param source 源文件流,tl-server下仅支持docx格式
|
||||
* @param source 源文件流,仅支持docx格式
|
||||
* @param sourceExtension 源文件后缀名,不包含"."
|
||||
* @param targetExtension 目标文件后缀名,不包含"."
|
||||
* @param targetFormat 目标文件格式,需与目标文件后缀名匹配,server下此参数无效。,tl-server下参考: <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word.wdsaveformat">word格式</a>
|
||||
* @return 转换后的文件流
|
||||
*/
|
||||
default byte[] convert(byte[] source, String sourceExtension, String targetExtension) {
|
||||
return convert(source, sourceExtension, targetExtension, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式转换
|
||||
*
|
||||
* @param source 源文件流,仅支持docx格式
|
||||
* @param sourceExtension 源文件后缀名,不包含"."
|
||||
* @param targetExtension 目标文件后缀名,不包含"."
|
||||
* @param targetFormat 目标文件格式,需与目标文件后缀名匹配。
|
||||
* server下此参数无效。
|
||||
* tl-server下参考:
|
||||
* <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word.wdsaveformat">word格式</a>
|
||||
* 或 <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.xlfileformat">excel格式</a>
|
||||
* 或 <a href="https://docs.microsoft.com/en-us/office/vba/api/powerpoint.presentation.saveas">powerpoint格式</a>
|
||||
* @return 转换后的文件流
|
||||
@@ -21,9 +38,20 @@ public interface BaseDocumentService {
|
||||
}
|
||||
|
||||
/**
|
||||
* word转为pdf,server和tl-server下均实现
|
||||
* 通过调用poi生成word
|
||||
*
|
||||
* @param source word文件流,tl-server下仅支持docx格式
|
||||
* @param sourceTemplate word模版流,仅支持docx格式
|
||||
* @param dataModel 数据模型
|
||||
* @return word文档流
|
||||
*/
|
||||
default byte[] generateWord(byte[] sourceTemplate, Map<String, Object> dataModel) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* word转为pdf
|
||||
*
|
||||
* @param source word文件流,仅支持docx格式
|
||||
* @param sourceFormat 源文件后缀名,不包含".",tl-server下此参数无效
|
||||
* @param clear 是否清除占位符,如果为true,则在tl-server下源文件只支持docx格式
|
||||
* @return pdf文档流
|
||||
@@ -35,7 +63,7 @@ public interface BaseDocumentService {
|
||||
/**
|
||||
* 通过pdfbox将word转图片
|
||||
*
|
||||
* @param source word文件流,tl-server下仅支持docx格式
|
||||
* @param source word文件流,仅支持docx格式
|
||||
* @param sourceExtension 源文件后缀名,不包含".",server下此参数无效
|
||||
* @param targetExtension 目标格式 支持jpeg, jpg, gif, tiff or png
|
||||
* @return 图片流
|
||||
@@ -45,7 +73,7 @@ public interface BaseDocumentService {
|
||||
}
|
||||
|
||||
/**
|
||||
* doc转为docx,server和tl-server下均实现
|
||||
* doc转为docx
|
||||
*
|
||||
* @param source doc文档流
|
||||
* @return docx文档流
|
||||
@@ -55,7 +83,7 @@ public interface BaseDocumentService {
|
||||
}
|
||||
|
||||
/**
|
||||
* xls转为xlsx,server和tl-server下均实现
|
||||
* xls转为xlsx
|
||||
*
|
||||
* @param source xls文档流
|
||||
* @return xlsx文档流
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.optima.document.api;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文档接口,此类中用的poi2生成word文档,使用docto进行格式转换
|
||||
*
|
||||
@@ -10,18 +8,7 @@ import java.util.Map;
|
||||
*/
|
||||
public interface DocumentService extends BaseDocumentService {
|
||||
/**
|
||||
* 通过调用poi生成word,仅tl-server模块下实现,仅支持docx格式
|
||||
*
|
||||
* @param sourceTemplate word模版流,仅支持docx格式
|
||||
* @param dataModel 数据模型
|
||||
* @return word文档流
|
||||
*/
|
||||
default byte[] generateWord(byte[] sourceTemplate, Map<String, Object> dataModel) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过调用poi将word转pdf,仅tl-server模块下实现,如果clear为true,则仅支持docx格式
|
||||
* 通过调用poi将word转pdf,如果clear为true,则仅支持docx格式
|
||||
*
|
||||
* @param source word模版流,仅支持docx格式
|
||||
* @param clear 是否清除占位符
|
||||
20
document-server/docto-document-server/pom.xml
Normal file
20
document-server/docto-document-server/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-server</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<artifactId>docto-document-server</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<name>Docto Document server</name>
|
||||
<description>Docto 文档操作服务</description>
|
||||
|
||||
<properties>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.optima.document.tl.server;
|
||||
package com.optima.document.server;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DocumentServer {
|
||||
public class DoctoDocumentServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DocumentServer.class, args);
|
||||
SpringApplication.run(DoctoDocumentServer.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.optima.document.tl.server.api;
|
||||
package com.optima.document.server.api;
|
||||
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
@@ -11,7 +11,7 @@ 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.tl.server.config.DocumentConfig;
|
||||
import com.optima.document.server.config.DocumentConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
@@ -42,11 +42,13 @@ import java.util.UUID;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DocumentServiceImpl implements DocumentService {
|
||||
@Resource
|
||||
private DocumentConfig documentConfig;
|
||||
|
||||
/**
|
||||
* word模版引擎配置
|
||||
*/
|
||||
private static final Configure wtlConfig = Configure.builder().buildGramer("${", "}")
|
||||
Configure wtlConfig = Configure.builder().buildGramer("${", "}")
|
||||
.setValidErrorHandler(new Configure.DiscardHandler())
|
||||
.addPlugin('%', new ListRenderPolicy() {
|
||||
@Override
|
||||
@@ -84,9 +86,6 @@ public class DocumentServiceImpl implements DocumentService {
|
||||
})
|
||||
.build();
|
||||
|
||||
@Resource
|
||||
private DocumentConfig documentConfig;
|
||||
|
||||
public byte[] convert(byte[] source, String sourceExtension, String targetExtension, String targetFormat) {
|
||||
try {
|
||||
sourceExtension = sourceExtension.replace(".", "");
|
||||
@@ -108,17 +107,17 @@ public class DocumentServiceImpl implements DocumentService {
|
||||
Process p = Runtime.getRuntime().exec(command);
|
||||
p.waitFor();
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("docto convert {} to {} take time in millis:{}", sourceExtension, targetExtension, (end - begin));
|
||||
log.info("convert {} to {} take time in millis:{}", sourceExtension, targetExtension, (end - begin));
|
||||
return Files.readAllBytes(targetPath);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("convert {} to {} error", sourceExtension, targetExtension, e);
|
||||
return null;
|
||||
} finally {
|
||||
Files.delete(sourcePath);
|
||||
Files.delete(targetPath);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("docto convert error", e);
|
||||
log.error("convert error", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -155,9 +154,9 @@ public class DocumentServiceImpl implements DocumentService {
|
||||
});
|
||||
template.writeAndClose(bos);
|
||||
source = bos.toByteArray();
|
||||
log.info("清空占位符=======耗时:{} 毫秒", System.currentTimeMillis() - start);
|
||||
log.info("clear placeholder take time in millis:{}", System.currentTimeMillis() - start);
|
||||
} catch (Exception e) {
|
||||
log.error("清空标签失败:", e);
|
||||
log.error("clear placeholder error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.optima.document.tl.server.config;
|
||||
package com.optima.document.server.config;
|
||||
|
||||
import com.optima.document.api.DocumentService;
|
||||
import lombok.Data;
|
||||
@@ -13,7 +13,7 @@ import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
|
||||
* @author Elias
|
||||
* @since 2021-09-28 16:12
|
||||
*/
|
||||
@SuppressWarnings("VulnerableCodeUsages")
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "document")
|
||||
@Data
|
||||
@@ -0,0 +1,5 @@
|
||||
server:
|
||||
port: 9004
|
||||
|
||||
document:
|
||||
doc-to-program: C:\\DocumentServer\\docto.exe
|
||||
32
document-server/jod-document-server/pom.xml
Normal file
32
document-server/jod-document-server/pom.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-server</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<artifactId>jod-document-server</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<name>Jod Document Server</name>
|
||||
<description>Jod 文档操作服务</description>
|
||||
|
||||
<properties>
|
||||
<jodconverter.version>4.4.9</jodconverter.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jodconverter</groupId>
|
||||
<artifactId>jodconverter-local</artifactId>
|
||||
<version>${jodconverter.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jodconverter</groupId>
|
||||
<artifactId>jodconverter-spring-boot-starter</artifactId>
|
||||
<version>${jodconverter.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -4,10 +4,10 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DocumentServer {
|
||||
public class JodDocumentServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DocumentServer.class, args);
|
||||
SpringApplication.run(JodDocumentServer.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
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 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.jodconverter.core.DocumentConverter;
|
||||
import org.jodconverter.core.document.DefaultDocumentFormatRegistry;
|
||||
import org.jodconverter.core.document.DocumentFormat;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 服务接口实现
|
||||
*
|
||||
* @author Elias
|
||||
* @since 2021-09-28 16:18
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DocumentServiceImpl implements DocumentService {
|
||||
@Resource
|
||||
private DocumentConverter documentConverter;
|
||||
|
||||
/**
|
||||
* word模版引擎配置
|
||||
*/
|
||||
private static final 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();
|
||||
|
||||
/**
|
||||
* 文件格式转换
|
||||
*
|
||||
* @param source 源文件流
|
||||
* @param sourceExtension 源文件后缀名,不包含"."
|
||||
* @param targetExtension 目标文件后缀名
|
||||
* @return 转换后的文件流
|
||||
*/
|
||||
public byte[] convert(byte[] source, String sourceExtension, String targetExtension) {
|
||||
try {
|
||||
sourceExtension = sourceExtension.replace(".", "");
|
||||
targetExtension = targetExtension.replace(".", "");
|
||||
long start = System.currentTimeMillis();
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DocumentFormat sourceFormat = DefaultDocumentFormatRegistry.getFormatByExtension(sourceExtension);
|
||||
DocumentFormat targetFormat = DefaultDocumentFormatRegistry.getFormatByExtension(targetExtension);
|
||||
assert sourceFormat != null;
|
||||
assert targetFormat != null;
|
||||
documentConverter.convert(new ByteArrayInputStream(source))
|
||||
.as(sourceFormat)
|
||||
.to(bos)
|
||||
.as(targetFormat)
|
||||
.execute();
|
||||
log.info("convert {} to {} take time in millis:{}", sourceExtension, targetExtension, System.currentTimeMillis() - start);
|
||||
return bos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
log.error("convert {} to {} error", sourceExtension, targetExtension, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] convert(byte[] source, String sourceExtension, String targetExtension, String targetFormat) {
|
||||
return convert(source, sourceExtension, targetExtension);
|
||||
}
|
||||
|
||||
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");
|
||||
} 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");
|
||||
}
|
||||
|
||||
public byte[] xlsToXlsx(byte[] source) {
|
||||
return convert(source, "xls", "xlsx");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.optima.document.server.config;
|
||||
|
||||
import com.optima.document.api.LegacyDocumentService;
|
||||
import com.optima.document.api.DocumentService;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -13,26 +13,21 @@ import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
|
||||
* @author Elias
|
||||
* @since 2021-09-28 16:12
|
||||
*/
|
||||
@SuppressWarnings("VulnerableCodeUsages")
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "document")
|
||||
@Data
|
||||
public class DocumentConfig {
|
||||
|
||||
private String tempDir;
|
||||
|
||||
private String openOfficeHome;
|
||||
|
||||
/**
|
||||
* 文档接口
|
||||
*
|
||||
* @return httpinvoker
|
||||
*/
|
||||
@Bean(name = "/document-service")
|
||||
HttpInvokerServiceExporter wordService(LegacyDocumentService legacyDocumentService) {
|
||||
HttpInvokerServiceExporter wordService(DocumentService documentService) {
|
||||
HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
|
||||
exporter.setService(legacyDocumentService);
|
||||
exporter.setServiceInterface(LegacyDocumentService.class);
|
||||
exporter.setService(documentService);
|
||||
exporter.setServiceInterface(DocumentService.class);
|
||||
return exporter;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
server:
|
||||
port: 9005
|
||||
|
||||
jodconverter:
|
||||
local:
|
||||
# 启动本地转换
|
||||
enabled: true
|
||||
# macOS下:program/soffice 的 program 所在目录 或 MacOS/soffice 的 MacOS 所在目录
|
||||
# windows下:program/soffice.exe 的 program 所在目录
|
||||
# linux下:program/soffice.bin 的 program 所在目录
|
||||
# 如果不配置,则自动查找
|
||||
office-home: /Applications/LibreOffice.app/Contents
|
||||
# 一个端口表示一个常驻进程,默认只有一个进程,端口为2002
|
||||
port-numbers: [ 2002 ]
|
||||
# 每个进程最多处理多个任务,默认为200
|
||||
max-tasks-per-process: 200
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.optima.document.server;
|
||||
|
||||
import com.optima.document.api.DocumentService;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Disabled
|
||||
public class JodDocumentServerTest {
|
||||
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
DocumentService documentService = buildDocumentService();
|
||||
|
||||
File sourceDocx = new File("/Users/yanghuanglin/Downloads/test.docx");
|
||||
File targetPdf = new File("/Users/yanghuanglin/Downloads/test.pdf");
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("callerName", "张三");
|
||||
byte[] sourceBytes = documentService.generateWord(Files.readAllBytes(sourceDocx.toPath()), params);
|
||||
|
||||
byte[] bytes = documentService.wordToPdf(sourceBytes, false);
|
||||
FileUtils.writeByteArrayToFile(targetPdf, bytes);
|
||||
}
|
||||
|
||||
private static DocumentService buildDocumentService() {
|
||||
// 创建客户端代理
|
||||
HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
|
||||
factoryBean.setServiceUrl("http://10.211.55.13:9005/document-service");
|
||||
factoryBean.setServiceInterface(DocumentService.class);
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
return (DocumentService) factoryBean.getObject();
|
||||
}
|
||||
}
|
||||
163
document-server/pom.xml
Normal file
163
document-server/pom.xml
Normal file
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<artifactId>document-server</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Document Server</name>
|
||||
<description>文档操作模块</description>
|
||||
<modules>
|
||||
<module>docto-document-server</module>
|
||||
<module>jod-document-server</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<pdfbox-tools.version>2.0.25</pdfbox-tools.version>
|
||||
<log4j.version>2.17.2</log4j.version>
|
||||
<lombok.version>1.16.20</lombok.version>
|
||||
<poi-tl.version>1.12.1</poi-tl.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox-tools</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.deepoove</groupId>
|
||||
<artifactId>poi-tl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>2.7.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<version>2.7.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>2.7.18</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox-tools</artifactId>
|
||||
<version>${pdfbox-tools.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.deepoove</groupId>
|
||||
<artifactId>poi-tl</artifactId>
|
||||
<version>${poi-tl.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<finalName>document-server-${version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>application.yml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
50
pom.xml
50
pom.xml
@@ -1,16 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>document</name>
|
||||
<description>文档操作模块</description>
|
||||
<modules>
|
||||
<module>api</module>
|
||||
<module>server</module>
|
||||
<module>tl-server</module>
|
||||
</modules>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Document</name>
|
||||
<description>文档操作模块</description>
|
||||
<modules>
|
||||
<module>document-api</module>
|
||||
<module>document-server</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.7.18</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
136
server/pom.xml
136
server/pom.xml
@@ -1,136 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.3.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-server</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<name>document server</name>
|
||||
<description>文档操作服务</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<tomcat.version>8.5.100</tomcat.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.3.2</version>
|
||||
</dependency>
|
||||
<!-- jacob -->
|
||||
<dependency>
|
||||
<groupId>net.sf.jacob-project</groupId>
|
||||
<artifactId>jacob</artifactId>
|
||||
<version>1.18</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/src/main/resources/libs/jacob.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.artofsolving</groupId>
|
||||
<artifactId>jodconverter</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/src/main/resources/libs/jodconverter-2.2.2.jar</systemPath>
|
||||
</dependency>
|
||||
<!-- poi2 依赖 -->
|
||||
<dependency>
|
||||
<groupId>apache</groupId>
|
||||
<artifactId>poi2</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/src/main/resources/libs/poi2-1.0.jar</systemPath>
|
||||
</dependency>
|
||||
<!-- poi依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>3.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>3.14</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-scratchpad</artifactId>
|
||||
<version>3.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.20</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jodconverter</groupId>
|
||||
<artifactId>jodconverter-core</artifactId>
|
||||
<version>4.0.0-RELEASE</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>json</artifactId>
|
||||
<groupId>org.json</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox-tools</artifactId>
|
||||
<version>2.0.25</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,120 +0,0 @@
|
||||
package com.optima.document.server.api;
|
||||
|
||||
import com.artofsolving.jodconverter.DefaultDocumentFormatRegistry;
|
||||
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.optima.document.api.LegacyDocumentService;
|
||||
import com.optima.document.server.config.DocumentConfig;
|
||||
import com.optima.document.server.utils.DocToPdfUtil;
|
||||
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.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 服务接口实现
|
||||
*
|
||||
* @author Elias
|
||||
* @since 2021-09-28 16:18
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class LegacyDocumentServiceImpl implements LegacyDocumentService {
|
||||
@Resource
|
||||
private DocumentConfig documentConfig;
|
||||
|
||||
/**
|
||||
* 文件格式转换
|
||||
*
|
||||
* @param source 源文件流
|
||||
* @param sourceExtension 源文件后缀名,不包含"."
|
||||
* @param targetExtension 目标文件后缀名
|
||||
* @return 转换后的文件流
|
||||
*/
|
||||
private byte[] convert(byte[] source, String sourceExtension, String targetExtension) {
|
||||
try {
|
||||
sourceExtension = sourceExtension.replace(".","");
|
||||
targetExtension = targetExtension.replace(".","");
|
||||
long start = System.currentTimeMillis();
|
||||
String command = "%s -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard";
|
||||
Process p = Runtime.getRuntime().exec(String.format(command, documentConfig.getOpenOfficeHome()));
|
||||
OpenOfficeConnection connection = new SocketOpenOfficeConnection();
|
||||
connection.connect();
|
||||
DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DefaultDocumentFormatRegistry formatRegistry = new DefaultDocumentFormatRegistry();
|
||||
converter.convert(new ByteArrayInputStream(source), formatRegistry.getFormatByFileExtension(sourceExtension), bos, formatRegistry.getFormatByFileExtension(targetExtension));
|
||||
connection.disconnect();
|
||||
p.destroy();
|
||||
log.info("openoffice convert {} to {} take time in millis:{}", sourceExtension, targetExtension, System.currentTimeMillis() - start);
|
||||
return bos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] fieldToWord(byte[] source, Map<String, Object> infoMap) {
|
||||
return DocToPdfUtil.fieldToWord(source, infoMap);
|
||||
}
|
||||
|
||||
public byte[] insertJpeg(byte[] source, String toFindText, byte[] imgSource, int width, int height) {
|
||||
return DocToPdfUtil.insertJpeg(source, toFindText, imgSource, width, height);
|
||||
}
|
||||
|
||||
public byte[] insertJpeg(byte[] source, String toFindText, List<byte[]> imgSource, int width, int height) {
|
||||
return DocToPdfUtil.insertJpeg(source, toFindText, imgSource, width, height);
|
||||
}
|
||||
|
||||
public byte[] wordToPdf(byte[] source, String sourceExtension, boolean clear) {
|
||||
try {
|
||||
if (clear) {
|
||||
source = DocToPdfUtil.clearPlaceholder(source);
|
||||
}
|
||||
return convert(source, sourceExtension, "pdf");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] convert(byte[] source, String sourceExtension, String targetExtension, String targetFormat) {
|
||||
return convert(source, sourceExtension, targetExtension);
|
||||
}
|
||||
|
||||
public byte[] wordToImage(byte[] source, String sourceExtension, String targetExtension) {
|
||||
try {
|
||||
byte[] pdfBytes = wordToPdf(source, sourceExtension, true);
|
||||
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();
|
||||
return bos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] docToDocx(byte[] source) {
|
||||
return convert(source, "doc", "docx");
|
||||
}
|
||||
|
||||
public byte[] xlsToXlsx(byte[] source) {
|
||||
return convert(source, "xls", "xlsx");
|
||||
}
|
||||
}
|
||||
@@ -1,493 +0,0 @@
|
||||
package com.optima.document.server.utils;
|
||||
|
||||
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DateFormat;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by xianjun on 2016/6/17.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 转型操作工具类
|
||||
*/
|
||||
public final class CastUtil {
|
||||
|
||||
/**
|
||||
* 转为String 型 默认为空
|
||||
*/
|
||||
public static String castString(Object obj) {
|
||||
return CastUtil.castString(obj, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为String 型(提供默认值)
|
||||
*/
|
||||
public static String castString(Object obj, String defaultValue) {
|
||||
return obj != null ? String.valueOf(obj) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为double型 默认为0
|
||||
*/
|
||||
public static double castDouble(Object obj) {
|
||||
return CastUtil.castDouble(obj, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为double型(提供默认值)
|
||||
*/
|
||||
public static double castDouble(Object obj, double defaultValue) {
|
||||
double doubleValue = defaultValue;
|
||||
if (obj != null) {
|
||||
String strValue = castString(obj);
|
||||
if (StringUtils.isNotEmpty(strValue)) {
|
||||
try {
|
||||
doubleValue = Double.parseDouble(strValue);
|
||||
} catch (NumberFormatException e) {
|
||||
doubleValue = defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为long型,默认值为0
|
||||
*/
|
||||
public static long castLong(Object obj) {
|
||||
return CastUtil.castLong(obj, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为long型(提供默认值)
|
||||
*/
|
||||
public static long castLong(Object obj, long defaultValue) {
|
||||
long longValue = defaultValue;
|
||||
if (obj != null) {
|
||||
String strValue = castString(obj);
|
||||
if (!StringUtils.isEmpty(strValue)) {
|
||||
try {
|
||||
longValue = Long.parseLong(strValue);
|
||||
} catch (NumberFormatException e) {
|
||||
longValue = defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return longValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为int型 默认值为0
|
||||
*/
|
||||
public static int castInt(Object obj) {
|
||||
return CastUtil.castInt(obj, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为int型(提供默认值)
|
||||
*/
|
||||
public static int castInt(Object obj, int defaultValue) {
|
||||
int intValue = defaultValue;
|
||||
if (obj != null) {
|
||||
String strValue = castString(obj);
|
||||
if (StringUtils.isNotEmpty(strValue)) {
|
||||
try {
|
||||
intValue = Integer.parseInt(strValue);
|
||||
} catch (NumberFormatException e) {
|
||||
intValue = defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return intValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为double型,默认值为false
|
||||
*/
|
||||
public static boolean castBoolean(Object obj) {
|
||||
return CastUtil.castBoolean(obj, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为double型,提供默认值
|
||||
*/
|
||||
public static boolean castBoolean(Object obj, boolean defaultValue) {
|
||||
boolean booleanValue = defaultValue;
|
||||
if (obj != null) {
|
||||
booleanValue = Boolean.parseBoolean(castString(obj));
|
||||
}
|
||||
return booleanValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转时间戳为date类型
|
||||
*
|
||||
* @param time
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public static Date castDate(long time, Date defaultValue) {
|
||||
Date dateValue = defaultValue;
|
||||
if (time != 0) {
|
||||
DateTime dateTime = new DateTime(time);
|
||||
dateValue = dateTime.toDate();
|
||||
}
|
||||
|
||||
return dateValue;
|
||||
}
|
||||
|
||||
public static Date castDateNo(long time) {
|
||||
return castDate(time, new Date(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转时间戳为date类型
|
||||
*/
|
||||
public static Date castDate(long time) {
|
||||
return castDate(time, new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开始时间
|
||||
*
|
||||
* @Title: getStartTime
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param date
|
||||
* @param monthTime
|
||||
* @param dateTime
|
||||
* @param hour
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static Date getStartTime(Date date, int monthTime, int dateTime, int hour) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(CastUtil.castInt(CastUtil.castStringByDate(date, "yyyy")), date.getMonth() + monthTime, date.getDate() + dateTime, 0 + hour, 0, 0);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结束时间
|
||||
*
|
||||
* @Title: getEndTime
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param date
|
||||
* @param monthTime
|
||||
* @param dateTime
|
||||
* @param hour
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static Date getEndTime(Date date, int monthTime, int dateTime, int hour) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(CastUtil.castInt(CastUtil.castStringByDate(date, "yyyy")), date.getMonth() + monthTime, date.getDate() + dateTime, 23 + hour, 59, 59);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转日期格式为字符串
|
||||
*/
|
||||
public static String castStringDate(Date date, Date defaultValue) {
|
||||
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Date dateValue = defaultValue;
|
||||
String dateString = "";
|
||||
if (date != null) {
|
||||
dateString = fmt.format(date);
|
||||
} else {
|
||||
dateString = fmt.format(dateValue);
|
||||
}
|
||||
|
||||
return dateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换日期格式为年-月-日
|
||||
* @Title: castStringIntegerDate
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param date
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String castStringIntegerDate(Date date) {
|
||||
return castStringIntegerDate(date, new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换格式为年-月-日
|
||||
* @Title: castStringIntegerDate
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param date
|
||||
* @param defaultValue
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String castStringIntegerDate(Date date, Date defaultValue) {
|
||||
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Date dateValue = defaultValue;
|
||||
String dateString = "";
|
||||
if (date != null) {
|
||||
dateString = fmt.format(date);
|
||||
} else {
|
||||
dateString = fmt.format(dateValue);
|
||||
}
|
||||
|
||||
return dateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的格式,转换为不同的日期
|
||||
*
|
||||
* @Title: castStringByDate
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param date
|
||||
* @param pattern
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String castStringByDate(Date date, String pattern) {
|
||||
SimpleDateFormat fmt = new SimpleDateFormat(pattern);
|
||||
Date dateValue = new Date();
|
||||
String dateString = "";
|
||||
if (date != null) {
|
||||
dateString = fmt.format(date);
|
||||
} else {
|
||||
dateString = fmt.format(dateValue);
|
||||
}
|
||||
return dateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转日期格式为字符串
|
||||
*/
|
||||
public static String castStringDate(Date date) {
|
||||
return castStringDate(date, new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 转 字符串为日期格式
|
||||
*/
|
||||
public static Date castDateByString(String defaultDate){
|
||||
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
Date date = fmt.parse(defaultDate);
|
||||
return date;
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转BigDecimal为字符串
|
||||
*/
|
||||
public static String castStringByDecimal(BigDecimal value, String pattern) {
|
||||
DecimalFormat fmt = new DecimalFormat(pattern);
|
||||
try {
|
||||
String tempValue = fmt.format(value.stripTrailingZeros());
|
||||
return tempValue;
|
||||
} catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
e.printStackTrace();
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换字符串,判断是否非空
|
||||
* @Title: castStringByString
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param defaultString
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String castStringByString(String defaultString) {
|
||||
String value = defaultString == null ? "" : defaultString;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除html标签
|
||||
* @Title: delHTMLTag
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param htmlStr
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String delHTMLTag(String htmlStr){
|
||||
String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
|
||||
String regEx_style="<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
|
||||
String regEx_html="<[^>]+>"; //定义HTML标签的正则表达式
|
||||
|
||||
Pattern p_script=Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_script=p_script.matcher(htmlStr);
|
||||
htmlStr=m_script.replaceAll(""); //过滤script标签
|
||||
|
||||
Pattern p_style=Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_style=p_style.matcher(htmlStr);
|
||||
htmlStr=m_style.replaceAll(""); //过滤style标签
|
||||
|
||||
Pattern p_html=Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
|
||||
Matcher m_html=p_html.matcher(htmlStr);
|
||||
htmlStr=m_html.replaceAll(""); //过滤html标签
|
||||
|
||||
return htmlStr.trim(); //返回文本字符串
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过身份证号码获取出生日期、性别、年龄
|
||||
* @author xianjun
|
||||
* @param certificateNo
|
||||
* @return 返回的出生日期格式:1990-01-01 性别格式:F-女,M-男
|
||||
*/
|
||||
public static Map<String, String> getBirAgeSex(String certificateNo) {
|
||||
String birthday = "";
|
||||
String age = "";
|
||||
String sexCode = "";
|
||||
|
||||
int year = Calendar.getInstance().get(Calendar.YEAR);
|
||||
char[] number = certificateNo.toCharArray();
|
||||
boolean flag = true;
|
||||
if (number.length == 15) {
|
||||
for (int x = 0; x < number.length; x++) {
|
||||
if (!flag) return new HashMap<String, String>();
|
||||
flag = Character.isDigit(number[x]);
|
||||
}
|
||||
} else if (number.length == 18) {
|
||||
for (int x = 0; x < number.length - 1; x++) {
|
||||
if (!flag) return new HashMap<String, String>();
|
||||
flag = Character.isDigit(number[x]);
|
||||
}
|
||||
}
|
||||
if (flag && certificateNo.length() == 15) {
|
||||
birthday = "19" + certificateNo.substring(6, 8) + "-"
|
||||
+ certificateNo.substring(8, 10) + "-"
|
||||
+ certificateNo.substring(10, 12);
|
||||
sexCode = Integer.parseInt(certificateNo.substring(certificateNo.length() - 3, certificateNo.length())) % 2 == 0 ? "F" : "M";
|
||||
age = (year - Integer.parseInt("19" + certificateNo.substring(6, 8))) + "";
|
||||
} else if (flag && certificateNo.length() == 18) {
|
||||
birthday = certificateNo.substring(6, 10) + "-"
|
||||
+ certificateNo.substring(10, 12) + "-"
|
||||
+ certificateNo.substring(12, 14);
|
||||
sexCode = Integer.parseInt(certificateNo.substring(certificateNo.length() - 4, certificateNo.length() - 1)) % 2 == 0 ? "F" : "M";
|
||||
age = (year - Integer.parseInt(certificateNo.substring(6, 10))) + "";
|
||||
}
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("birthday", birthday);
|
||||
map.put("age", age);
|
||||
map.put("sexCode", sexCode);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description 将Date类型的时间转为long类型的时间戳
|
||||
* @Author SuXingYong
|
||||
* @Date 2020/1/10 10:40
|
||||
* @Param [date]
|
||||
* @Return long
|
||||
**/
|
||||
public static long castDateForLong(Date date){
|
||||
long result = 0;
|
||||
if (date != null){
|
||||
result = date.getTime();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description 将 yyyy-MM-dd HH:mm:ss 类型的时间字符串转换为long类型的时间戳
|
||||
* @Author SuXingYong
|
||||
* @Date 2020/1/10 10:46
|
||||
* @Param [dateStr]
|
||||
* @Return long
|
||||
**/
|
||||
public static long castDateStrForLong(String dateStr){
|
||||
long result = 0;
|
||||
Date date = CastUtil.castDateByString(dateStr);
|
||||
if (date != null){
|
||||
result = date.getTime();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description 将java.sql.Timestamp转化为对应格式的String
|
||||
* @Author SuXingYong
|
||||
* @Date 2020/3/10 15:13
|
||||
* @Param [time, strFormat]
|
||||
* @Return java.lang.String
|
||||
**/
|
||||
public static String castTimestampForString(java.sql.Timestamp time, String strFormat) {
|
||||
DateFormat df = new SimpleDateFormat(strFormat);
|
||||
String str = df.format(time);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某年某月的第一天
|
||||
* @author xianjun
|
||||
* @param year
|
||||
* @param month
|
||||
* @return
|
||||
*/
|
||||
public static String getFirstDayByMonth(int year, int month) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
// 设置年份
|
||||
cal.set(Calendar.YEAR,year);
|
||||
// 设置月份
|
||||
cal.set(Calendar.MONTH, month-1);
|
||||
// 获取某月最小天数
|
||||
int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
|
||||
// 设置最小天数
|
||||
cal.set(Calendar.DAY_OF_MONTH, firstDay);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
// 格式化
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String firstDayOfMonth = sdf.format(cal.getTime());
|
||||
return firstDayOfMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某年某月的最后一天
|
||||
*
|
||||
* @author xianjun
|
||||
* @param year
|
||||
* @param month
|
||||
* @return
|
||||
*/
|
||||
public static String getLastDayByMonth(int year, int month) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
// 设置年份
|
||||
cal.set(Calendar.YEAR, year);
|
||||
// 设置月份
|
||||
cal.set(Calendar.MONTH, month-1);
|
||||
// 获取某月最大天数
|
||||
int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
// 设置日历中月份的最大天数
|
||||
cal.set(Calendar.DAY_OF_MONTH, lastDay);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 23);
|
||||
// 格式化时间
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String lastDayOfMonth = sdf.format(cal.getTime());
|
||||
return lastDayOfMonth;
|
||||
}
|
||||
}
|
||||
@@ -1,792 +0,0 @@
|
||||
package com.optima.document.server.utils;
|
||||
|
||||
import com.jacob.activeX.ActiveXComponent;
|
||||
import com.jacob.com.ComThread;
|
||||
import com.jacob.com.Dispatch;
|
||||
import com.jacob.com.Variant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author xianjun
|
||||
* @version 2017年4月20日 上午10:48:46 word转pdf工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class DocToPdfUtil {
|
||||
|
||||
private static final int wdFormatPDF = 17; // pdf格式
|
||||
private static final int xlTypePDF = 0;
|
||||
private static final int ppSaveAsPDF = 32;
|
||||
// 代表一个word 程序
|
||||
private static ActiveXComponent MsWordApp = null;
|
||||
// 代表进行处理的word 文档
|
||||
private static Dispatch document = null;
|
||||
// word文档
|
||||
private Dispatch doc;
|
||||
// word运行程序
|
||||
private ActiveXComponent word;
|
||||
// 所有word文档集合
|
||||
private Dispatch documents;
|
||||
// 选定的范围和插入点
|
||||
private Dispatch selection;
|
||||
|
||||
private boolean saveOnExit = true;
|
||||
|
||||
public DocToPdfUtil() throws Exception {
|
||||
ComThread.InitSTA();
|
||||
if (word == null) {
|
||||
word = new ActiveXComponent("Word.Application");
|
||||
// 不可见打开word
|
||||
word.setProperty("Visible", new Variant(false));
|
||||
// 禁用宏
|
||||
word.setProperty("AutomationSecurity", new Variant(3));
|
||||
}
|
||||
|
||||
if (documents == null)
|
||||
documents = word.getProperty("Documents").toDispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置退出时参数
|
||||
*
|
||||
* @Title: setSaveOnExit
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param saveOnExit true-退出时保存文件,false-退出时不保存文件
|
||||
* @throws
|
||||
*/
|
||||
public void setSaveOnExit(boolean saveOnExit) {
|
||||
this.saveOnExit = saveOnExit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开一个已存在的文档
|
||||
*
|
||||
* @Title: openDocument
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param docPath
|
||||
* @throws
|
||||
*/
|
||||
public void openDocument(String docPath) {
|
||||
closeDocument();
|
||||
doc = Dispatch.call(documents, "Open", docPath).toDispatch();
|
||||
selection = Dispatch.get(word, "Selection").toDispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件保存或另存为路径
|
||||
*
|
||||
* @Title: save
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param savePath
|
||||
* @throws
|
||||
*/
|
||||
public void save(String savePath) {
|
||||
Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(), "FileSaveAs", savePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭文档
|
||||
* @Title: closeDocument
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param val 0不保存修改 -1 保存修改 -2 提示是否保存修改
|
||||
* @throws
|
||||
*/
|
||||
public void closeDocument(int val) {
|
||||
Dispatch.call(doc, "Close", new Variant(val));
|
||||
doc = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭当前word文档
|
||||
*
|
||||
* @Title: cloaseDocument
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @throws
|
||||
*/
|
||||
public void cloaseDocument() {
|
||||
if (doc != null) {
|
||||
Dispatch.call(doc, "Save");
|
||||
Dispatch.call(doc, "Close", new Variant(saveOnExit));
|
||||
doc = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭全部应用
|
||||
*
|
||||
* @Title: close
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @throws
|
||||
*/
|
||||
public void close() {
|
||||
if (word != null) {
|
||||
//Dispatch.call(word, "Quit");
|
||||
word.invoke("Quit",0);
|
||||
word = null;
|
||||
}
|
||||
selection = null;
|
||||
documents = null;
|
||||
ComThread.Release();
|
||||
}
|
||||
|
||||
/**
|
||||
* word转pdf
|
||||
*
|
||||
* @author xianjun
|
||||
* @version 2017年4月20日 上午9:56:09
|
||||
* @describe
|
||||
* @param fromAddress
|
||||
* 待转地址
|
||||
* toAddress 新文件地址
|
||||
*/
|
||||
// public static String wordToPdf(String fromAddress) {
|
||||
// //ActiveXComponent ax = null;
|
||||
// String toAddress = splitSuffx(fromAddress);
|
||||
// try {
|
||||
// PoiWordUtil.wordToPdf(fromAddress,toAddress);
|
||||
// return toAddress;
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /*try {
|
||||
// long startTime = System.currentTimeMillis();
|
||||
//
|
||||
// *//**
|
||||
// * 创建不同的控件调用不同的值 Word-Word.Application Excel-Excel.Application
|
||||
// * Powerpoint-Powerpoint.Application Outlook-Outlook.Application
|
||||
// *//*
|
||||
// ax = new ActiveXComponent("Word.Application");
|
||||
// *//**
|
||||
// * 设置打开文件不可见
|
||||
// *//*
|
||||
// ax.setProperty("Visible", false);
|
||||
// *//**
|
||||
// * 获取word文档中所有内容
|
||||
// *//*
|
||||
// Dispatch docs = ax.getProperty("Documents").toDispatch();
|
||||
// *//**
|
||||
// * 打开word文档,并设置word为不可编辑和不需确认
|
||||
// *//*
|
||||
// Dispatch doc = Dispatch.call(docs, "Open", fromAddress, false, true).toDispatch();
|
||||
// File tofile = new File(toAddress);
|
||||
// if (tofile.exists()) {
|
||||
// tofile.delete();
|
||||
// }
|
||||
// // word文件另存为pdf文件
|
||||
// Dispatch.call(doc, "SaveAs", toAddress, wdFormatPDF);
|
||||
// // 关闭word文档
|
||||
// Dispatch.call(doc, "Close", false);
|
||||
// long endTime = System.currentTimeMillis();
|
||||
// System.out.println("转换完成,总共耗时" + (endTime - startTime));
|
||||
// return toAddress;
|
||||
// } catch (Exception e) {
|
||||
// System.out.println("=============Error:文档转换失败:" + e.getMessage());
|
||||
// return null;
|
||||
// } */
|
||||
// }
|
||||
|
||||
// public static String wordToPdf(String fromAddress, String fileName) throws Exception{
|
||||
// String fileRootPath = UploadFileUtils.getPath("write");
|
||||
// String dateUrl = CastUtil.castStringByDate(new Date(), "yyyy-MM-dd");
|
||||
// String htmlFileDirPath = File.separator + dateUrl;
|
||||
// File htmlDirFile = new File(fileRootPath + htmlFileDirPath);
|
||||
// if (!htmlDirFile.exists()) {
|
||||
// htmlDirFile.mkdirs();
|
||||
// }
|
||||
// //html文件路径
|
||||
// String pdfFilePath = htmlDirFile.getPath() + File.separator + fileName + "." + "pdf";
|
||||
// long startTime = System.currentTimeMillis();
|
||||
// File tofile = new File(pdfFilePath);
|
||||
// if (tofile.exists()) {
|
||||
// tofile.delete();
|
||||
// }
|
||||
// // word文件另存为pdf文件
|
||||
// PoiWordUtil.wordToPdf(fromAddress,pdfFilePath);
|
||||
// // 关闭word文档
|
||||
// long endTime = System.currentTimeMillis();
|
||||
// System.out.println("转换完成,总共耗时" + (endTime - startTime));
|
||||
// return "/"+dateUrl + "/" + fileName + "." + "pdf";
|
||||
// }
|
||||
|
||||
public static String excel2PDF(String fromAddress){
|
||||
String toAddress = splitSuffx(fromAddress);
|
||||
try{
|
||||
long startTime = System.currentTimeMillis();
|
||||
ActiveXComponent app = new ActiveXComponent("Excel.Application");
|
||||
app.setProperty("Visible", false);
|
||||
Dispatch excels = app.getProperty("Workbooks").toDispatch();
|
||||
Dispatch excel = Dispatch.call(excels,"Open",fromAddress,false,true).toDispatch();
|
||||
File tofile = new File(toAddress);
|
||||
if (tofile.exists()) {
|
||||
tofile.delete();
|
||||
}
|
||||
Dispatch.call(excel,"ExportAsFixedFormat",xlTypePDF,toAddress);
|
||||
Dispatch.call(excel, "Close",false);
|
||||
long endTime = System.currentTimeMillis();
|
||||
System.out.println("转换完成,总共耗时" + (endTime - startTime));
|
||||
return toAddress;
|
||||
} catch (Exception e) {
|
||||
System.out.println("=============Error:文档转换失败:" + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
public static String ppt2PDF(String fromAddress){
|
||||
String toAddress = splitSuffx(fromAddress);
|
||||
try{
|
||||
long startTime = System.currentTimeMillis();
|
||||
ActiveXComponent app = new ActiveXComponent("PowerPoint.Application");
|
||||
//app.setProperty("Visible", msofalse);
|
||||
Dispatch ppts = app.getProperty("Presentations").toDispatch();
|
||||
|
||||
Dispatch ppt = Dispatch.call(ppts,
|
||||
"Open",
|
||||
fromAddress,
|
||||
true,//ReadOnly
|
||||
true,//Untitled指定文件是否有标题
|
||||
false//WithWindow指定文件是否可见
|
||||
).toDispatch();
|
||||
|
||||
Dispatch.call(ppt,
|
||||
"SaveAs",
|
||||
toAddress,
|
||||
ppSaveAsPDF
|
||||
);
|
||||
|
||||
Dispatch.call(ppt, "Close");
|
||||
long endTime = System.currentTimeMillis();
|
||||
System.out.println("转换完成,总共耗时" + (endTime - startTime));
|
||||
return toAddress;
|
||||
} catch (Exception e) {
|
||||
System.out.println("=============Error:文档转换失败:" + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径处理函数,提取路径后缀
|
||||
*
|
||||
* @author xianjun
|
||||
* @version 2017年4月20日 上午10:54:49
|
||||
* @describe
|
||||
* @param fromAddress
|
||||
* @return
|
||||
*/
|
||||
public static String splitSuffx(String fromAddress) {
|
||||
String toAddress = fromAddress.substring(0, fromAddress.lastIndexOf(".") + 1);
|
||||
toAddress = toAddress + "pdf";
|
||||
return toAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从选定内容或插入点开始查找文本
|
||||
*
|
||||
* @param toFindText
|
||||
* 要查找的文本
|
||||
* @return boolean true-查找到并选中该文本,false-未查找到文本
|
||||
*/
|
||||
public static boolean find(ActiveXComponent ax,String toFindText) {
|
||||
if (toFindText == null || toFindText.equals(""))
|
||||
return false;
|
||||
Dispatch selection = Dispatch.get(ax, "Selection").toDispatch(); // 输入内容需要的对象
|
||||
// 从selection所在位置开始查询
|
||||
Dispatch find1 = Dispatch.call(selection, "Find").toDispatch();
|
||||
// 设置要查找的内容
|
||||
Dispatch.put(find1, "Text", toFindText);
|
||||
// 向前查找
|
||||
Dispatch.put(find1, "Forward", "True");
|
||||
// 设置格式
|
||||
Dispatch.put(find1, "Format", "True");
|
||||
// 大小写匹配
|
||||
Dispatch.put(find1, "MatchCase", "True");
|
||||
// 全字匹配
|
||||
Dispatch.put(find1, "MatchWholeWord", "True");
|
||||
// 查找并选中
|
||||
return Dispatch.call(find1, "Execute").getBoolean();
|
||||
}
|
||||
|
||||
// 向文档中添加 一个图片,
|
||||
public static void insertJpeg(ActiveXComponent ax,String toFindText,String jpegFilePath,int width,int height) {
|
||||
Dispatch selection = Dispatch.get(ax, "Selection").toDispatch();
|
||||
// Dispatch image = Dispatch.get(selection, "InLineShapes").toDispatch();
|
||||
// Dispatch.call(image, "AddPicture", jpegFilePath);
|
||||
|
||||
|
||||
if (find(ax,toFindText)) {
|
||||
Dispatch picture = Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(), "AddPicture", jpegFilePath).toDispatch(); // 添加图片
|
||||
Dispatch.call(picture, "Select"); // 选中图片
|
||||
Dispatch.put(picture, "Width", new Variant(width)); // 图片的宽度
|
||||
Dispatch.put(picture, "Height", new Variant(height)); // 图片的高度
|
||||
Dispatch ShapeRange = Dispatch.call(picture, "ConvertToShape").toDispatch(); // 取得图片区域
|
||||
Dispatch WrapFormat = Dispatch.get(ShapeRange, "WrapFormat").toDispatch(); // 取得图片的格式对象
|
||||
Dispatch.put(WrapFormat, "Type", 7); // 设置环绕格式(0 - 7)下面是参数说明
|
||||
|
||||
// wdWrapInline 7 将形状嵌入到文字中。
|
||||
// wdWrapNone 3 将形状放在文字前面。请参阅 wdWrapFront 。
|
||||
// wdWrapSquare 0 使文字环绕形状。行在形状的另一侧延续。
|
||||
// wdWrapThrough 2 使文字环绕形状。
|
||||
// wdWrapTight 1 使文字紧密地环绕形状。
|
||||
// wdWrapTopBottom 4 将文字放在形状的上方和下方。
|
||||
// wdWrapBehind 5 将形状放在文字后面。
|
||||
// wdWrapFront 6 将形状放在文字前面。
|
||||
}
|
||||
}
|
||||
// 保存文档的更改
|
||||
public static void save() {
|
||||
Dispatch.call(document, "Save");
|
||||
}
|
||||
public static void closeDocument() {
|
||||
// Close the document without saving changes
|
||||
// 0 = wdDoNotSaveChanges
|
||||
// -1 = wdSaveChanges
|
||||
// -2 = wdPromptToSaveChanges
|
||||
if(document != null) {
|
||||
Dispatch.call(document, "Close", new Variant(false));
|
||||
document = null;
|
||||
}
|
||||
}
|
||||
public static void closeWord() {
|
||||
Dispatch.call(MsWordApp, "Quit");
|
||||
MsWordApp = null;
|
||||
document = null;
|
||||
}
|
||||
|
||||
public static void openAnExistsFileTest(String wordFilePath,String toFindText,String imagePath,int width,int height) {
|
||||
ActiveXComponent ax = null;
|
||||
ax = new ActiveXComponent("Word.Application");
|
||||
ax.setProperty("Visible", new Variant(false));// 是否前台打开word 程序,或者后台运行
|
||||
Dispatch documents = Dispatch.get(ax, "Documents").toDispatch();
|
||||
documents = Dispatch.call(documents, "Open", wordFilePath,
|
||||
new Variant(true)/* 是否进行转换ConfirmConversions */,
|
||||
new Variant(false)/* 是否只读 */).toDispatch();
|
||||
//Dispatch selection = Dispatch.get(MsWordApp, "Selection").toDispatch();
|
||||
insertJpeg(ax,toFindText,imagePath,width,height); // 插入图片(注意刚打开的word,光标处于开头,故,图片在最前方插入)
|
||||
// word文件另存为pdf文件
|
||||
String toAddress = splitSuffx(wordFilePath);
|
||||
Dispatch.call(documents, "Save");
|
||||
//Dispatch.call(documents, "Quit");
|
||||
Dispatch.call(documents, "SaveAs", toAddress, wdFormatPDF);
|
||||
Dispatch.call(documents, "Close", new Variant(false));
|
||||
//save();
|
||||
//closeDocument();
|
||||
//closeWord();
|
||||
// 关闭word文档
|
||||
//Dispatch.call(documents, "Close", false);
|
||||
}
|
||||
|
||||
public boolean findText(Dispatch selection, String toFindText,String matchWholeWord) {
|
||||
return findText(selection, toFindText, matchWholeWord, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找文本
|
||||
* @param selection
|
||||
* @param toFindText
|
||||
* @param matchWholeWord 匹配全词
|
||||
* @param matchWildcards 使用通配符
|
||||
* @return
|
||||
*/
|
||||
public boolean findText(Dispatch selection, String toFindText,String matchWholeWord, boolean matchWildcards) {
|
||||
if (toFindText == null || "".equals(toFindText))
|
||||
return false;
|
||||
// 从selection所在位置开始查询
|
||||
Dispatch find1 = Dispatch.call(selection, "Find").toDispatch();
|
||||
// 设置要查找的内容
|
||||
Dispatch.put(find1, "Text", toFindText);
|
||||
// 向前查找
|
||||
Dispatch.put(find1, "Forward", "True");
|
||||
// 通配符
|
||||
Dispatch.put(find1, "MatchWildcards", matchWildcards);
|
||||
// 设置格式
|
||||
Dispatch.put(find1, "Format", "True");
|
||||
// 大小写匹配
|
||||
Dispatch.put(find1, "MatchCase", "False");
|
||||
// 全字匹配
|
||||
Dispatch.put(find1, "MatchWholeWord", matchWholeWord);
|
||||
// 查找并选中
|
||||
return Dispatch.call(find1, "Execute").getBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入图片
|
||||
*
|
||||
* @Title: insertJpeg
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param source
|
||||
* @param toFindText
|
||||
* @param imgSource
|
||||
* @param width
|
||||
* @param height
|
||||
* @throws
|
||||
*/
|
||||
public static byte[] insertJpeg(byte[] source, String toFindText, byte[] imgSource, int width, int height) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
Path tempFilePath = null;
|
||||
Path imgTempFilePath = null;
|
||||
byte[] result = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
tempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);
|
||||
Files.write(tempFilePath, source);
|
||||
docToPdfUtil.openDocument(tempFilePath.toString());
|
||||
if (docToPdfUtil.findText(docToPdfUtil.selection, toFindText,"True")) {
|
||||
imgTempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);
|
||||
Files.write(imgTempFilePath, imgSource);
|
||||
Dispatch picture = Dispatch.call(Dispatch.get(docToPdfUtil.selection, "InLineShapes").toDispatch(), "AddPicture", imgTempFilePath.toString()).toDispatch(); // 添加图片
|
||||
Dispatch.call(picture, "Select"); // 选中图片
|
||||
if (width!=0) {
|
||||
Dispatch.put(picture, "Width", new Variant(width)); // 图片的宽度
|
||||
Dispatch.put(picture, "Height", new Variant(height)); // 图片的高度
|
||||
}
|
||||
|
||||
// Dispatch ShapeRange = Dispatch.call(picture, "ConvertToShape").toDispatch(); // 取得图片区域
|
||||
// Dispatch WrapFormat = Dispatch.get(ShapeRange, "WrapFormat").toDispatch(); // 取得图片的格式对象
|
||||
// Dispatch.put(WrapFormat, "Type", 0); // 设置环绕格式(0 - 7)下面是参数说明
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
if (tempFilePath != null) {
|
||||
try {
|
||||
result = Files.readAllBytes(tempFilePath);
|
||||
Files.delete(tempFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (imgTempFilePath != null) {
|
||||
try {
|
||||
Files.delete(imgTempFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("insert image=======consuming:{} milliseconds", System.currentTimeMillis() - t1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入图片
|
||||
*
|
||||
* @Title: insertJpeg
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param source
|
||||
* @param toFindText
|
||||
* @param imgSources
|
||||
* @param width
|
||||
* @param height
|
||||
* @throws
|
||||
*/
|
||||
public static byte[] insertJpeg(byte[] source, String toFindText, List<byte[]> imgSources, int width, int height) {
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
Path tempFilePath = null;
|
||||
Path imgTempFilePath = null;
|
||||
byte[] result = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
tempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);
|
||||
Files.write(tempFilePath, source);
|
||||
docToPdfUtil.openDocument(tempFilePath.toString());
|
||||
String replaceText = "";
|
||||
for (int i = 0; i < imgSources.size(); i++) {
|
||||
replaceText += "${" + toFindText + "_" + i + "}";
|
||||
}
|
||||
String searchText = "${" + toFindText + "}";
|
||||
boolean flag = docToPdfUtil.findText(docToPdfUtil.selection, searchText, "True");
|
||||
if (flag) {
|
||||
setKeyAndValue(docToPdfUtil, replaceText, searchText);
|
||||
}
|
||||
for (int i = 0; i < imgSources.size(); i++) {
|
||||
Dispatch.call(docToPdfUtil.selection,"HomeKey",new Variant(6));
|
||||
if (docToPdfUtil.findText(docToPdfUtil.selection, "${" + toFindText + "_" + i + "}" ,"True")) {
|
||||
imgTempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);
|
||||
Files.write(imgTempFilePath, imgSources.get(i));
|
||||
Dispatch picture = Dispatch.call(Dispatch.get(docToPdfUtil.selection, "InLineShapes").toDispatch(), "AddPicture", imgTempFilePath.toString()).toDispatch(); // 添加图片
|
||||
Dispatch.call(picture, "Select"); // 选中图片
|
||||
if (width != 0) {
|
||||
Dispatch.put(picture, "Width", new Variant(width)); // 图片的宽度
|
||||
Dispatch.put(picture, "Height", new Variant(height)); // 图片的高度
|
||||
}
|
||||
// Dispatch ShapeRange = Dispatch.call(picture, "ConvertToShape").toDispatch(); // 取得图片区域
|
||||
// Dispatch WrapFormat = Dispatch.get(ShapeRange, "WrapFormat").toDispatch(); // 取得图片的格式对象
|
||||
// Dispatch.put(WrapFormat, "Type", 0); // 设置环绕格式(0 - 7)下面是参数说明
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
if (tempFilePath != null) {
|
||||
try {
|
||||
result = Files.readAllBytes(tempFilePath);
|
||||
Files.delete(tempFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (imgTempFilePath != null) {
|
||||
try {
|
||||
Files.delete(imgTempFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void insertJpeg(String wordFilePath, List<String> findTexts, List<String> imagePaths, List<Map<String, Object>> imageSelections) {
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
docToPdfUtil.openDocument(wordFilePath);
|
||||
if (findTexts != null && findTexts.size() > 0) {
|
||||
for (int i=0; i< findTexts.size(); i++) {
|
||||
String toFindText = findTexts.get(i);
|
||||
String imagePath = imagePaths.get(i);
|
||||
Map<String, Object> imageSelection = imageSelections.get(i);
|
||||
int height = CastUtil.castInt(imageSelection.get("Height"));
|
||||
int width = CastUtil.castInt(imageSelection.get("Width"));
|
||||
if (docToPdfUtil.findText(docToPdfUtil.selection, toFindText,"True")) {
|
||||
Dispatch picture = Dispatch.call(Dispatch.get(docToPdfUtil.selection, "InLineShapes").toDispatch(), "AddPicture", imagePath).toDispatch(); // 添加图片
|
||||
Dispatch.call(picture, "Select"); // 选中图片
|
||||
if (width!=0) {
|
||||
Dispatch.put(picture, "Width", new Variant(width)); // 图片的宽度
|
||||
Dispatch.put(picture, "Height", new Variant(height)); // 图片的高度
|
||||
}
|
||||
|
||||
Dispatch ShapeRange = Dispatch.call(picture, "ConvertToShape").toDispatch(); // 取得图片区域
|
||||
Dispatch WrapFormat = Dispatch.get(ShapeRange, "WrapFormat").toDispatch(); // 取得图片的格式对象
|
||||
Dispatch.put(WrapFormat, "Type", 0); // 设置环绕格式(0 - 7)下面是参数说明
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换字段
|
||||
*
|
||||
* @Title: wordFindReplace
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param wordpath
|
||||
* @param oldtext
|
||||
* @param newtext
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String wordFindReplace(String wordpath,String oldtext,String newtext) {
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
docToPdfUtil.openDocument(wordpath);
|
||||
boolean flag = docToPdfUtil.findText(docToPdfUtil.selection, oldtext,"True");
|
||||
if (flag) {
|
||||
Dispatch.put(docToPdfUtil.selection,"Text",newtext);
|
||||
Dispatch.call(docToPdfUtil.selection, "MoveRight");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向word填充属性字段
|
||||
*
|
||||
* @Title: fieldToWord
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param source 源
|
||||
* @param infoMap 属性字段
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static byte[] fieldToWord(byte[] source, Map<String, Object> infoMap) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
Path tempFilePath = null;
|
||||
byte[] result = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
tempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);
|
||||
Files.write(tempFilePath, source);
|
||||
docToPdfUtil.openDocument(tempFilePath.toString());
|
||||
for (String key : infoMap.keySet()) {
|
||||
String replaceText = "${" + key.trim() + "}";
|
||||
boolean flag = docToPdfUtil.findText(docToPdfUtil.selection, replaceText,"True");
|
||||
if (flag) {
|
||||
String value = CastUtil.castString(infoMap.get(key));
|
||||
setKeyAndValue(docToPdfUtil, value, replaceText);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
if (tempFilePath != null) {
|
||||
try {
|
||||
result = Files.readAllBytes(tempFilePath);
|
||||
Files.delete(tempFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("insert text=======consuming:{} milliseconds", System.currentTimeMillis() - t1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除占位符
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static byte[] clearPlaceholder(byte[] source) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
Path tempFilePath = null;
|
||||
byte[] result = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
tempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);
|
||||
Files.write(tempFilePath, source);
|
||||
docToPdfUtil.openDocument(tempFilePath.toString());
|
||||
String replaceText = "$\\{*\\}";
|
||||
boolean flag = docToPdfUtil.findText(docToPdfUtil.selection, replaceText, "True", true);
|
||||
if (flag) {
|
||||
setKeyAndValue(docToPdfUtil, "", replaceText, true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
if (tempFilePath != null) {
|
||||
try {
|
||||
result = Files.readAllBytes(tempFilePath);
|
||||
Files.delete(tempFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("clear placeholder=======consuming:{} milliseconds", System.currentTimeMillis() - t1);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setKeyAndValue(DocToPdfUtil docToPdfUtil, String value, String replaceText) {
|
||||
setKeyAndValue(docToPdfUtil, value, replaceText, false);
|
||||
}
|
||||
|
||||
public static void setKeyAndValue(DocToPdfUtil docToPdfUtil, String value,String replaceText, boolean matchWildcards) {
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
value = CastUtil.delHTMLTag(value);
|
||||
if (value.indexOf("\n\n") != -1) {
|
||||
value = value.replace("\n\n", CastUtil.castString((char) 11));
|
||||
}
|
||||
if (value.indexOf("\n") != -1) {
|
||||
value = value.replace("\n", CastUtil.castString((char) 11));
|
||||
}
|
||||
|
||||
Dispatch.put(docToPdfUtil.selection, "Text", value);
|
||||
|
||||
//Dispatch.call(docToPdfUtil.selection, "MoveStart");
|
||||
Dispatch.call(docToPdfUtil.selection,"HomeKey",new Variant(6));
|
||||
boolean flag = docToPdfUtil.findText(docToPdfUtil.selection, replaceText,"True", matchWildcards);
|
||||
if (flag) {
|
||||
setKeyAndValue(docToPdfUtil, value, replaceText, matchWildcards);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* word转pdf
|
||||
* @Title: wordCnoverPdf
|
||||
* @author: xianjun
|
||||
* @Description: TODO
|
||||
* @param fromAddress
|
||||
* @return
|
||||
* @throws
|
||||
*/
|
||||
public static String wordCnoverPdf(String fromAddress) {
|
||||
String toAddress = splitSuffx(fromAddress);
|
||||
DocToPdfUtil docToPdfUtil = null;
|
||||
try {
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
long startTime = System.currentTimeMillis();
|
||||
docToPdfUtil = new DocToPdfUtil();
|
||||
docToPdfUtil.openDocument(fromAddress);
|
||||
File tofile = new File(toAddress);
|
||||
if (tofile.exists()) {
|
||||
tofile.delete();
|
||||
}
|
||||
// word文件另存为pdf文件
|
||||
Dispatch.call(docToPdfUtil.doc, "SaveAs", toAddress, wdFormatPDF);
|
||||
// 关闭word文档
|
||||
long endTime = System.currentTimeMillis();
|
||||
System.out.println("转换完成,总共耗时" + (endTime - startTime));
|
||||
if(docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
return toAddress;
|
||||
} catch (Exception e) {
|
||||
if(docToPdfUtil != null) {
|
||||
docToPdfUtil.cloaseDocument();
|
||||
docToPdfUtil.close();
|
||||
}
|
||||
System.out.println("=============Error:文档转换失败:" + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,486 +0,0 @@
|
||||
package com.optima.document.server.utils;/**
|
||||
* Created by xianjun on 2019/3/22.16:30
|
||||
*/
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.model.PicturesTable;
|
||||
import org.apache.poi.hwpf.usermodel.Bookmarks;
|
||||
import org.apache.poi.hwpf.usermodel.Range;
|
||||
import org.apache.poi.xwpf.usermodel.*;
|
||||
import org.apache.xmlbeans.XmlToken;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 文书替换工具类
|
||||
* @author xianjun
|
||||
* @version 2019/3/22 16:30
|
||||
*
|
||||
*/
|
||||
public class PoiWordUtil {
|
||||
/**
|
||||
* word为doc后缀
|
||||
*/
|
||||
private static final String DOC = "doc";
|
||||
/**
|
||||
* word为docx后缀
|
||||
*/
|
||||
private static final String DOCX = "docx";
|
||||
/**
|
||||
* 服务器为windows
|
||||
*/
|
||||
private static final String SYSTEM_TYPE_W = "Windows";
|
||||
/**
|
||||
* 服务器为Linux
|
||||
*/
|
||||
private static final String SYSTEM_TYPE_L = "Linux";
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private static String errorMsg = "";
|
||||
/**
|
||||
* 模板路径
|
||||
*/
|
||||
private static String templatePath = "";
|
||||
/**
|
||||
* 新文件的路径
|
||||
*/
|
||||
private static String newFilePath = "";
|
||||
|
||||
/**
|
||||
* 文书临时存放的目录
|
||||
*/
|
||||
private static String tempFilePath = "";
|
||||
|
||||
/**
|
||||
* 替换模板方法
|
||||
* @param path 文书路径
|
||||
* @param tempPath 临时路径
|
||||
* @param paramMap 替换参数
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
// public static Map<String,String> executeWord(String path, String tempPath, Map<String, Object> paramMap) throws Exception {
|
||||
// //获取模板路径
|
||||
// getTemplate(path);
|
||||
// //获取新文件生成路径
|
||||
// getFileStore(path);
|
||||
// newFilePath = tempPath;
|
||||
// //判断模板类型
|
||||
// if(templatePath.endsWith(DOC)){
|
||||
// //处理03版word
|
||||
// //replaceWordDoc(paramMap);
|
||||
// }else if(templatePath.endsWith(DOCX)){
|
||||
// //处理07版word
|
||||
// replaceWordDocx(paramMap);
|
||||
// }
|
||||
//
|
||||
// //返回处理结果(新生成文件路径、错误信息)
|
||||
// Map<String,String> map = new HashMap<String,String>();
|
||||
// map.put("newFilePath", newFilePath);
|
||||
// map.put("errorMsg", errorMsg);
|
||||
// return map;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 替换模板文本内容(2007)
|
||||
* @param paramMap 替换参数
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void replaceWordDocx(Map<String, Object> paramMap) throws Exception{
|
||||
InputStream is = new FileInputStream(tempFilePath);
|
||||
XWPFDocument doc = new XWPFDocument(is);
|
||||
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
|
||||
Iterator<XWPFTable> it = doc.getTablesIterator();
|
||||
XWPFParagraph para;
|
||||
XWPFTable patab;
|
||||
//替换文本
|
||||
while (iterator.hasNext()) {
|
||||
para = iterator.next();
|
||||
replaceInParaDocx(doc, para, paramMap);
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
patab = it.next();
|
||||
List<XWPFTableRow> rows = patab.getRows();
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
XWPFTableRow row = rows.get(i);//读取每一列数据
|
||||
List<XWPFTableCell> cells = row.getTableCells();
|
||||
for (int j = 0; j < cells.size(); j++) {
|
||||
XWPFTableCell cell = cells.get(j);
|
||||
//输出当前的单元格的数据
|
||||
//System.out.print(cell.getText() + "\t");
|
||||
List<XWPFParagraph> paragraphs = cell.getParagraphs();
|
||||
for (XWPFParagraph xwpfParagraph : paragraphs) {
|
||||
replaceInParaDocx(doc, xwpfParagraph, paramMap);
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
//写出文件
|
||||
OutputStream out = new FileOutputStream(newFilePath);
|
||||
doc.write(out);
|
||||
//关闭输出流
|
||||
close(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换方法(2007)
|
||||
* @param para
|
||||
* @param paramMap
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void replaceInParaDocx(XWPFDocument doc, XWPFParagraph para, Map<String, Object> paramMap) throws Exception {
|
||||
List<XWPFRun> runs;
|
||||
Matcher matcher;
|
||||
String imgPath = "";
|
||||
int width = 100,height = 100;
|
||||
String txt = para.getParagraphText();
|
||||
if (matcher(txt.trim()).find()) {
|
||||
runs = para.getRuns();
|
||||
for (int i=0; i<runs.size(); i++) {
|
||||
XWPFRun run = runs.get(i);
|
||||
String runText = run.toString();
|
||||
matcher = matcher(runText);
|
||||
if (matcher.find()) {
|
||||
Map<String,Object> infoMap = new HashMap<String,Object>();
|
||||
if ((matcher = matcher(runText)).find()) {
|
||||
System.err.println("查找替换标签:" + matcher.group());
|
||||
String tx = matcher.group().substring(2,matcher.group().length()-1);
|
||||
if (paramMap.get(tx) instanceof Map) {
|
||||
infoMap = (Map<String,Object>)paramMap.get(tx);
|
||||
if (runText.contains("_img") || runText.contains("_sign") || runText.contains("_map")) {
|
||||
imgPath = CastUtil.castString(infoMap.get("Text"));
|
||||
width = CastUtil.castInt(infoMap.get("Width"));
|
||||
height = CastUtil.castInt(infoMap.get("Height"));
|
||||
if (imgPath !=null && !"".equalsIgnoreCase(imgPath)) {
|
||||
runText = "";
|
||||
}
|
||||
} else {
|
||||
String tempText = CastUtil.castString(infoMap.get("Text"));
|
||||
if (tempText != null && !"".equalsIgnoreCase(tempText)) {
|
||||
runText = CastUtil.castString(infoMap.get("Text"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (runText.contains("_img") || runText.contains("_sign") || runText.contains("_map")) {
|
||||
imgPath = CastUtil.castString(paramMap.get(tx));
|
||||
if (imgPath !=null && !"".equalsIgnoreCase(imgPath)) {
|
||||
runText = "";
|
||||
}
|
||||
} else {
|
||||
String tempText = CastUtil.castString(paramMap.get(tx));
|
||||
if (tempText != null && !"".equalsIgnoreCase(tempText)) {
|
||||
runText = tempText;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,
|
||||
//所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。
|
||||
para.removeRun(i);
|
||||
XWPFRun newRun = para.insertNewRun(i);
|
||||
newRun.setText(runText);
|
||||
if(!infoMap.isEmpty()){
|
||||
//设置字体样式
|
||||
setFont(newRun, infoMap);
|
||||
}
|
||||
if(StringUtils.isNoneEmpty(imgPath)){
|
||||
//获得当前CTInline
|
||||
CTInline inline = newRun.getCTR().addNewDrawing().addNewInline();
|
||||
doc.addPictureData(new FileInputStream(imgPath), 5);
|
||||
insertPicture(doc, inline, width, height);
|
||||
}
|
||||
imgPath = "";
|
||||
//infoMap.clear();
|
||||
System.err.println("替换");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2007字体样式设置
|
||||
* @param run
|
||||
* @param param
|
||||
*/
|
||||
private static void setFont(XWPFRun run, Map<String,Object> param) {
|
||||
CTRPr pRpr = null;
|
||||
if (run.getCTR() != null) {
|
||||
pRpr = run.getCTR().getRPr();
|
||||
if (pRpr == null) {
|
||||
pRpr = run.getCTR().addNewRPr();
|
||||
}
|
||||
}
|
||||
|
||||
// 设置字体
|
||||
if(param.get("Name") != null){
|
||||
CTFonts fonts = pRpr.isSetRFonts()?pRpr.getRFonts():pRpr.addNewRFonts();
|
||||
fonts.setAscii(param.get("Name").toString());
|
||||
fonts.setEastAsia(param.get("Name").toString());
|
||||
fonts.setHAnsi(param.get("Name").toString());
|
||||
}
|
||||
//粗体
|
||||
run.setBold(param.get("Bold")!=null?true:false);
|
||||
//斜体
|
||||
run.setItalic(param.get("Italic")!=null?true:false);
|
||||
//下划线
|
||||
if (param.get("Underline") != null) {
|
||||
run.setUnderline(UnderlinePatterns.SINGLE);
|
||||
}
|
||||
//字体大小
|
||||
if(param.get("Size") != null){
|
||||
CTHpsMeasure sz = pRpr.isSetSz() ? pRpr.getSz() : pRpr.addNewSz();
|
||||
sz.setVal(new BigInteger(param.get("Size").toString()));
|
||||
CTHpsMeasure szCs = pRpr.isSetSzCs() ? pRpr.getSzCs() : pRpr.addNewSzCs();
|
||||
szCs.setVal(new BigInteger(param.get("Size").toString()));
|
||||
}
|
||||
//字体颜色
|
||||
if (param.get("Color") != null) {
|
||||
run.setColor(param.get("Color").toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入图片
|
||||
*
|
||||
* @param document
|
||||
* @param inline
|
||||
* @param width
|
||||
* @param height
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void insertPicture(XWPFDocument document, CTInline inline, int width, int height) throws Exception {
|
||||
int id = document.getAllPictures().size()-1;
|
||||
final int EMU = 9525;
|
||||
width *= EMU;
|
||||
height *= EMU;
|
||||
String blipId = document.getAllPictures().get(id).getPackageRelationship().getId();
|
||||
|
||||
String picXml = ""
|
||||
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
|
||||
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
|
||||
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
|
||||
+ " <pic:nvPicPr>"
|
||||
+ " <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>"
|
||||
+ " <pic:cNvPicPr/>"
|
||||
+ " </pic:nvPicPr>"
|
||||
+ " <pic:blipFill>"
|
||||
+ " <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
|
||||
+ " <a:stretch>"
|
||||
+ " <a:fillRect/>"
|
||||
+ " </a:stretch>"
|
||||
+ " </pic:blipFill>"
|
||||
+ " <pic:spPr>"
|
||||
+ " <a:xfrm>"
|
||||
+ " <a:off x=\"0\" y=\"0\"/>"
|
||||
+ " <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>"
|
||||
+ " </a:xfrm>"
|
||||
+ " <a:prstGeom prst=\"rect\">"
|
||||
+ " <a:avLst/>"
|
||||
+ " </a:prstGeom>"
|
||||
+ " </pic:spPr>"
|
||||
+ " </pic:pic>"
|
||||
+ " </a:graphicData>"
|
||||
+ "</a:graphic>";
|
||||
|
||||
inline.addNewGraphic().addNewGraphicData();
|
||||
XmlToken xmlToken = null;
|
||||
xmlToken = XmlToken.Factory.parse(picXml);
|
||||
inline.set(xmlToken);
|
||||
inline.setDistT(0);
|
||||
inline.setDistB(0);
|
||||
inline.setDistL(0);
|
||||
inline.setDistR(0);
|
||||
CTPositiveSize2D extent = inline.addNewExtent();
|
||||
extent.setCx(width);
|
||||
extent.setCy(height);
|
||||
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
|
||||
docPr.setId(id);
|
||||
docPr.setName("IMG_" + id);
|
||||
docPr.setDescr("IMG_" + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换模板文本内容(2003)
|
||||
* @param paramMap 替换参数
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void replaceWordDoc(Map<String, Object> paramMap) throws Exception{
|
||||
InputStream is = new FileInputStream(templatePath);
|
||||
HWPFDocument doc = new HWPFDocument(is);
|
||||
Range bodyRange = doc.getRange();
|
||||
//替换文本
|
||||
replaceInParaDoc(doc, bodyRange, paramMap);
|
||||
//输出新文件
|
||||
FileOutputStream out = new FileOutputStream(newFilePath);
|
||||
doc.write(out);
|
||||
out.flush();
|
||||
//关闭输出流
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换方法(2003)
|
||||
* @param range
|
||||
* @param paramMap
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void replaceInParaDoc(HWPFDocument doc, Range range, Map<String, Object> paramMap) {
|
||||
Matcher matcher;
|
||||
String imgPath = "";
|
||||
int width = 0,height = 0;
|
||||
while ((matcher = matcher(range.text())).find()) {
|
||||
String key = matcher.group();
|
||||
Map<String, Object> infoMap = (Map<String, Object>) paramMap.get(key);
|
||||
if (infoMap.get("Type") !=null && "img".equalsIgnoreCase(CastUtil.castString(infoMap.get("Type")))) {
|
||||
//处理图片
|
||||
imgPath = infoMap.get("Path").toString();
|
||||
width = Integer.parseInt(infoMap.get("Width").toString());
|
||||
height = Integer.parseInt(infoMap.get("Height").toString());
|
||||
} else {
|
||||
range.replaceText(matcher.group(), String.valueOf(infoMap.get("Text")));
|
||||
}
|
||||
if(StringUtils.isNoneEmpty(imgPath)){
|
||||
Bookmarks bookmarks = doc.getBookmarks();
|
||||
PicturesTable picturesTable = doc.getPicturesTable();
|
||||
}
|
||||
imgPath = "";
|
||||
/*int index = Integer.valueOf(matcher.group(1)) - 1;
|
||||
if(index >= params.size()) break;
|
||||
if(params.get(index) instanceof String){
|
||||
range.replaceText(matcher.group(), String.valueOf(params.get(index)));
|
||||
}else if(params.get(index) instanceof Map){
|
||||
Map<String,Object> infoMap = (Map<String,Object>)params.get(index);
|
||||
range.replaceText(matcher.group(), String.valueOf(infoMap.get("Text")));
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 正则匹配字符串
|
||||
* @param str 带替换字符串
|
||||
* @return
|
||||
*/
|
||||
public static Matcher matcher(String str) {
|
||||
String remax = "\\$.+?}";
|
||||
//String remax = "\\$\\{(.+?)\\}"Pattern.CASE_INSENSITIVE;
|
||||
Pattern pattern = Pattern.compile(remax);
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件模板路径
|
||||
* @param path 模板文件路径
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void getTemplate(String path) throws Exception {
|
||||
//String path = UploadFileUtils.getPath("write");
|
||||
// String docPath = path + templateName + ".doc";
|
||||
//String docxPath = path + templateName + ".docx";
|
||||
templatePath = path;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 获取文件存储路径
|
||||
// * @param templatePath 模板文件名称
|
||||
// * @return
|
||||
// * @throws IOException
|
||||
// */
|
||||
// private static void getFileStore(String templatePath) throws IOException {
|
||||
// //操作系统类型(Windows、Linux)
|
||||
// String sysType = UploadFileUtils.getPath("fileserver.system.type");
|
||||
// //文件存储跟目录
|
||||
// String fileRoot = UploadFileUtils.getPath("fileserver.local.root");
|
||||
// //文件生产目录
|
||||
// String fileStore = UploadFileUtils.getPath("fileserver.store");
|
||||
// //生成文件名称
|
||||
// String name = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
|
||||
//
|
||||
// if(SYSTEM_TYPE_W.equals(sysType)){
|
||||
// //Windows
|
||||
// tempFilePath = fileRoot + fileStore + "/" ;
|
||||
// }else if(SYSTEM_TYPE_L.equals(sysType)){
|
||||
// //Linux
|
||||
// tempFilePath = File.separator + "usr/fileserver/";
|
||||
// }else{
|
||||
// //其他服务器系统处理
|
||||
// }
|
||||
//
|
||||
// //生成目录不存在创建目录
|
||||
// File file = new File(tempFilePath);
|
||||
// if(!file.exists()){
|
||||
// file.mkdirs();
|
||||
// }
|
||||
// tempFilePath = tempFilePath + name + ".docx";
|
||||
// FileUtils.copyFile(templatePath, tempFilePath);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 关闭输出流
|
||||
* @param os
|
||||
*/
|
||||
public static void close(OutputStream os) {
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭输入流
|
||||
* @param in
|
||||
*/
|
||||
public static void close(InputStream in) {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* word转pdf
|
||||
* @throws Exception
|
||||
* @return
|
||||
*/
|
||||
// public static byte[] wordToPdf(byte[] source) throws Exception{
|
||||
// // 临时文件
|
||||
// Path tempFilePath = Files.createTempFile(UUID.randomUUID().toString(), null);;
|
||||
// Files.write(tempFilePath, source);
|
||||
// String command = "D:/OpenOffice4/program/soffice.exe -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\"";
|
||||
// Process p = Runtime.getRuntime().exec(command);
|
||||
// OpenOfficeConnection connection = new SocketOpenOfficeConnection();
|
||||
// connection.connect();
|
||||
// // 转换
|
||||
// DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
|
||||
// converter.convert(new ByteArrayInputStream(source), tempFilePath.toString());
|
||||
// // 关闭连接
|
||||
// connection.disconnect();
|
||||
// // 关闭进程
|
||||
// p.destroy();
|
||||
// return null;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
server:
|
||||
port: 8090
|
||||
document:
|
||||
open-office-home: D:\\OpenOffice4\\program\\soffice.exe
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.3.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-tl-server</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<name>document tl server</name>
|
||||
<description>文档模版引擎服务</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<tomcat.version>8.5.100</tomcat.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.optima</groupId>
|
||||
<artifactId>document-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.20</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jodconverter</groupId>
|
||||
<artifactId>jodconverter-core</artifactId>
|
||||
<version>4.0.0-RELEASE</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>json</artifactId>
|
||||
<groupId>org.json</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox-tools</artifactId>
|
||||
<version>2.0.25</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.deepoove</groupId>
|
||||
<artifactId>poi-tl</artifactId>
|
||||
<version>1.12.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,4 +0,0 @@
|
||||
server:
|
||||
port: 9004
|
||||
document:
|
||||
doc-to-program: C:\\DocumentServer\\docto.exe
|
||||
Reference in New Issue
Block a user