diff --git a/README.md b/README.md
index 462ee04..199776e 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-# document
-
+# document
+
文书服务
-api下为调用的接口
+api下为调用的接口,在需要处理文书的项目中引用,以`fegin方式`配置Service后进行调用
-server下为使用jacob处理word文书,使用openoffice来进行pdf转换
+server下为使用jacob处理word文书,使用openoffice来进行pdf转换,`java -jar xxx.jar`启动
-tl-server下仅进行word转pdf,使用的docto调用office来转换
\ No newline at end of file
+tl-server下仅进行word转pdf,使用的docto调用office来转换,`java -jar xxx.jar`启动
\ No newline at end of file
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..cac84eb
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+ com.optima
+ document-api
+ 1.0.0
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
+
+
+ document api
+ 文档操作api
+
+ 1.8
+
+
+
+ org.projectlombok
+ lombok
+ 1.16.20
+ provided
+
+
+
diff --git a/api/src/main/java/com/optima/document/api/DocumentService.java b/api/src/main/java/com/optima/document/api/DocumentService.java
new file mode 100644
index 0000000..8cc94d1
--- /dev/null
+++ b/api/src/main/java/com/optima/document/api/DocumentService.java
@@ -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 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 imgSource, int width, int height) {
+ throw new UnsupportedOperationException();
+ }
+
+ default byte[] fieldToWord(byte[] source, Map infoMap) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b213655
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+ com.optima
+ document
+ 1.0.0
+ pom
+ document
+ 文档操作模块
+
+ api
+ server
+ tl-server
+
+
+
diff --git a/server/pom.xml b/server/pom.xml
new file mode 100644
index 0000000..9af7075
--- /dev/null
+++ b/server/pom.xml
@@ -0,0 +1,135 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.3.RELEASE
+
+
+ com.optima
+ document-server
+ 1.0.0
+ document server
+ 文档操作服务
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.optima
+ document-api
+ 1.0.0
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.3.2
+
+
+
+ net.sf.jacob-project
+ jacob
+ 1.18
+ system
+ ${basedir}/src/main/resources/libs/jacob.jar
+
+
+ com.artofsolving
+ jodconverter
+ 2.2.2
+ system
+ ${basedir}/src/main/resources/libs/jodconverter-2.2.2.jar
+
+
+
+ apache
+ poi2
+ 1.0
+ system
+ ${basedir}/src/main/resources/libs/poi2-1.0.jar
+
+
+
+ org.apache.poi
+ poi
+ 3.14
+
+
+ org.apache.poi
+ poi-ooxml
+ 3.14
+
+
+
+ org.apache.poi
+ poi-scratchpad
+ 3.14
+
+
+ joda-time
+ joda-time
+ 2.1
+
+
+ org.projectlombok
+ lombok
+ 1.16.20
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.jodconverter
+ jodconverter-core
+ 4.0.0-RELEASE
+
+
+ commons-io
+ commons-io
+
+
+ commons-lang3
+ org.apache.commons
+
+
+ json
+ org.json
+
+
+
+
+ org.apache.commons
+ commons-io
+ 1.3.2
+
+
+ org.apache.pdfbox
+ pdfbox-tools
+ 2.0.25
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+
+
+
+
+
+
diff --git a/server/src/main/java/com/optima/document/server/DocumentServer.java b/server/src/main/java/com/optima/document/server/DocumentServer.java
new file mode 100644
index 0000000..437ed56
--- /dev/null
+++ b/server/src/main/java/com/optima/document/server/DocumentServer.java
@@ -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);
+ }
+
+}
diff --git a/server/src/main/java/com/optima/document/server/api/DocumentServiceImpl.java b/server/src/main/java/com/optima/document/server/api/DocumentServiceImpl.java
new file mode 100644
index 0000000..cf2d7f9
--- /dev/null
+++ b/server/src/main/java/com/optima/document/server/api/DocumentServiceImpl.java
@@ -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 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 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;
+ }
+}
diff --git a/server/src/main/java/com/optima/document/server/config/DocumentConfig.java b/server/src/main/java/com/optima/document/server/config/DocumentConfig.java
new file mode 100644
index 0000000..d997137
--- /dev/null
+++ b/server/src/main/java/com/optima/document/server/config/DocumentConfig.java
@@ -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;
+ }
+
+}
diff --git a/server/src/main/java/com/optima/document/server/utils/CastUtil.java b/server/src/main/java/com/optima/document/server/utils/CastUtil.java
new file mode 100644
index 0000000..5192f39
--- /dev/null
+++ b/server/src/main/java/com/optima/document/server/utils/CastUtil.java
@@ -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="