初次提交

This commit is contained in:
yanghuanglin
2022-08-03 16:54:52 +08:00
parent 276c6f4a90
commit 22538415b9
19 changed files with 2511 additions and 5 deletions

View File

@@ -2,8 +2,8 @@
文书服务 文书服务
api下为调用的接口 api下为调用的接口,在需要处理文书的项目中引用,以`fegin方式`配置Service后进行调用
server下为使用jacob处理word文书使用openoffice来进行pdf转换 server下为使用jacob处理word文书使用openoffice来进行pdf转换`java -jar xxx.jar`启动
tl-server下仅进行word转pdf使用的docto调用office来转换 tl-server下仅进行word转pdf使用的docto调用office来转换`java -jar xxx.jar`启动

33
api/pom.xml Normal file
View File

@@ -0,0 +1,33 @@
<?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>1.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>

View File

@@ -0,0 +1,71 @@
package com.optima.document.api;
import java.util.List;
import java.util.Map;
/**
* 文档接口
* @author Elias
* @date 2021-09-28 16:00
*/
public interface DocumentService {
/**
* generate word
* @param templateData word模版流
* @param dataModel 数据模型
* @return 修改后的文档流
*/
default byte[] generateWord(byte[] templateData, Map<String, Object> dataModel) {
throw new UnsupportedOperationException();
}
/**
* word to pdf
* @param templateData word模版流
* @param clear 是否清除占位符
* @return
*/
default byte[] wordToPdf(byte[] templateData, boolean clear) {
throw new UnsupportedOperationException();
}
/**
* word to image
* @param templateData word模版流
* @param targetFormat 目标格式 支持jpeg, jpg, gif, tiff or png
* @return
*/
default byte[] wordToImage(byte[] templateData, String targetFormat) {
throw new UnsupportedOperationException();
}
/**
*
* @param source 文档
* @param toFindText 需要替换的文本
* @param imgSource 图片
* @param width 宽度
* @param height 高度
* @return 修改后的文档
*/
default byte[] insertJpeg(byte[] source, String toFindText, byte[] imgSource, int width, int height){
throw new UnsupportedOperationException();
}
/**
*
* @param source
* @param toFindText
* @param imgSource
* @param width
* @param height
* @return
*/
default byte[] insertJpeg(byte[] source, String toFindText, List<byte[]> imgSource, int width, int height) {
throw new UnsupportedOperationException();
}
default byte[] fieldToWord(byte[] source, Map<String, Object> infoMap) {
throw new UnsupportedOperationException();
}
}

17
pom.xml Normal file
View File

@@ -0,0 +1,17 @@
<?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>1.0.0</version>
<packaging>pom</packaging>
<name>document</name>
<description>文档操作模块</description>
<modules>
<module>api</module>
<module>server</module>
<module>tl-server</module>
</modules>
</project>

135
server/pom.xml Normal file
View File

@@ -0,0 +1,135 @@
<?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>1.0.0</version>
<name>document server</name>
<description>文档操作服务</description>
<properties>
<java.version>1.8</java.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>1.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>

View File

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

View File

@@ -0,0 +1,82 @@
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.DocumentService;
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 java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;
/**
* 服务接口实现
* @author Elias
* @date 2021-09-28 16:18
*/
@Slf4j
public class DocumentServiceImpl implements DocumentService {
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 sourceFormat, boolean clear) {
try {
if (clear) {
source = DocToPdfUtil.clearPlaceholder(source);
}
long t1 = System.currentTimeMillis();
String command = "D:\\OpenOffice4\\program\\soffice.exe -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard";
Process p = Runtime.getRuntime().exec(command);
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(sourceFormat), bos, formatRegistry.getFormatByFileExtension("pdf"));
connection.disconnect();
p.destroy();
log.info("word to pdf=======consuming{} milliseconds", System.currentTimeMillis() - t1);
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] wordToImage(byte[] source, String sourceFormat, String targetFormat) {
try {
byte[] pdfBytes = wordToPdf(source, sourceFormat, 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, targetFormat, bos, 300);
document.close();
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

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

View File

@@ -0,0 +1,493 @@
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;
}
}

View File

@@ -0,0 +1,792 @@
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;
}
}
}

View File

@@ -0,0 +1,486 @@
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;
// }
}

View File

@@ -0,0 +1,5 @@
server:
port: 8090
document:
doc-to-program: D:\\optima\\docto.exe

View File

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

102
tl-server/pom.xml Normal file
View File

@@ -0,0 +1,102 @@
<?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>1.0.0</version>
<name>document tl server</name>
<description>文档模版引擎服务</description>
<properties>
<java.version>1.8</java.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>1.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>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>
<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.0</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>

View File

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

View File

@@ -0,0 +1,170 @@
package com.optima.document.tl.server.api;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.policy.ListRenderPolicy;
import com.deepoove.poi.policy.PictureRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.xwpf.BodyContainer;
import com.deepoove.poi.xwpf.BodyContainerFactory;
import com.optima.document.api.DocumentService;
import com.optima.document.tl.server.config.DocumentConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
/**
* 服务接口实现
* @author Elias
* @date 2021-09-28 16:18
*/
@Slf4j
@Component
public class DocumentServiceImpl implements DocumentService {
/**
* 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();
@Resource
private DocumentConfig documentConfig;
@Override
public byte[] generateWord(byte[] templateData, Map<String, Object> dataModel) {
long start = System.currentTimeMillis();
XWPFTemplate template = XWPFTemplate.compile(new ByteArrayInputStream(templateData), wtlConfig).render(dataModel);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()){
template.write(bos);
log.info("word generate========consuming{} milliseconds", System.currentTimeMillis() - start);
return bos.toByteArray();
} catch (Exception e) {
log.error("word generate error", e);
return null;
}
}
@Override
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("清空占位符=======耗时:{} 毫秒", System.currentTimeMillis() - start);
} catch (Exception e) {
log.error("清空标签失败:", e);
return null;
}
}
Path tempFilePath = Files.createTempFile(UUID.randomUUID().toString(), ".docx");
Files.write(tempFilePath, source);
Path pdfPath = Files.createTempFile(UUID.randomUUID().toString(), ".pdf");
try {
long begin = System.currentTimeMillis();
String command = "%s -f %s -O %s -T wdFormatPDF";
command = String.format(command, documentConfig.getDocToProgram(), tempFilePath, pdfPath);
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
long end = System.currentTimeMillis();
log.info("docto take time in millis:" + (end - begin));
return Files.readAllBytes(pdfPath);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
Files.delete(tempFilePath);
Files.delete(pdfPath);
}
} catch (Exception e) {
log.error("word to pdf error", e);
return null;
}
}
@Override
public byte[] wordToImage(byte[] source, String targetFormat) {
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, targetFormat, bos, 300);
document.close();
log.info("word to image=======consuming{} milliseconds", System.currentTimeMillis() - start);
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

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

View File

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

View File

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