package com.gw.crm.doc.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.aspose.words.Document;
import com.aspose.words.FontSettings;
import com.aspose.words.ImportFormatMode;
import com.aspose.words.SaveFormat;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.HackLoopTableRenderPolicy;
import com.gw.crm.doc.util.StringUtil;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.*;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
String data = "{\n" +
"\t\"appendix\": [{\n" +
"\t\t\"appendixId\": \"84a306bc270a4c75aef82e72cc7706de\",\n" +
"\t\t\"appendixVars\": {}\n" +
"\t}, {\n" +
"\t\t\"appendixId\": \"84a306bc270a4c75aef82e72cc7706d\",\n" +
"\t\t\"appendixVars\": {}\n" +
"\t}, {\n" +
"\t\t\"appendixId\": \"84a306bc270a4c75aef82e72cc770\",\n" +
"\t\t\"appendixVars\": {\n" +
"\t\t\t\"speEquipment_finalUser_name\": \"\",\n" +
"\t\t\t\"speEquipment_finalUser_address\": \"\",\n" +
"\t\t\t\"speEquipment_finalUser_contactName\": \"\",\n" +
"\t\t\t\"speEquipment_finalUser_contactPhone\": \"\",\n" +
"\t\t\t\"speEquipment_sellerName\": \"\",\n" +
"\t\t\t\"speEquipment_sellerAddress\": \"\",\n" +
"\t\t\t\"speEquipment_sellerContactName\": \"\",\n" +
"\t\t\t\"speEquipment_sellerContactPhone\": \"\",\n" +
"\t\t\t\"speEquipment_user_governOrg\": \"\",\n" +
"\t\t\t\"speEquipment_user_secretQualityOrg\": \"\",\n" +
"\t\t\t\"speEquipment_user_safeQualityOrg\": \"\",\n" +
"\t\t\t\"speEquipment_user_elseOrg\": \"\",\n" +
"\t\t\t\"speEquipment_seller_promise\": \"\",\n" +
"\t\t\t\"speEquipment_seller_signName\": \"\",\n" +
"\t\t\t\"speEquipment_seller_signTime\": \"\"\n" +
"\t\t}\n" +
"\t}, {\n" +
"\t\t\"appendixId\": \"0644fedd6d054fc8805acbe0b88c87b7\",\n" +
"\t\t\"appendixVars\": {}\n" +
"\t}],\n" +
"\t\"contractId\": \"0005e63b4cfe4ce3ad7eee58586379c3\",\n" +
"\t\"contractName\": \"销售类合同-宁都东芯科技有限公司-河北移动合同流程测试项目-20221228\",\n" +
"\t\"contractVars\": {\n" +
"\t\t\"second_taxRate\": \"\",\n" +
"\t\t\"first_payPart_scale\": \"\",\n" +
"\t\t\"quality_inspection_time\": \"5\",\n" +
"\t\t\"first_pay_month\": \"\",\n" +
"\t\t\"contract_copies\": \"\",\n" +
"\t\t\"second_contactEmail\": \"sdsda.qq.8520\",\n" +
"\t\t\"first_payAll_time\": \"\",\n" +
"\t\t\"second_sign_year\": \"\",\n" +
"\t\t\"first_payment_typeNumber\": \"\",\n" +
"\t\t\"second_accountName\": \"张晓\",\n" +
"\t\t\"first_contractCopies\": \"\",\n" +
"\t\t\"speEquipment_letter\": true,\n" +
"\t\t\"overDue_pay_time\": \"10\",\n" +
"\t\t\"second_contactAddress\": \"北京\",\n" +
"\t\t\"second_bankName\": \"中国人民银行之西城区分行\",\n" +
"\t\t\"first_bankName\": \"\",\n" +
"\t\t\"contract_upperMoney\": \"柒拾万元整\",\n" +
"\t\t\"first_name\": \"\",\n" +
"\t\t\"first_contactPhone\": \"852020\",\n" +
"\t\t\"first_accountNumber\": \"\",\n" +
"\t\t\"first_contactEmail\": \"1144981288@qq.com\",\n" +
"\t\t\"second_accountNumber\": \"1\",\n" +
"\t\t\"notSecret_scale\": \"6\",\n" +
"\t\t\"second_contractCopies\": \"\",\n" +
"\t\t\"first_payPart_time\": \"\",\n" +
"\t\t\"export_control_letter\": true,\n" +
"\t\t\"first_payRest_time\": \"\",\n" +
"\t\t\"first_pay_year\": \"\",\n" +
"\t\t\"first_contactName\": \"张三\",\n" +
"\t\t\"second_contactName\": \"赵苏\",\n" +
"\t\t\"first_taxNumber\": \"\",\n" +
"\t\t\"speEquipment_finalUser_register\": true,\n" +
"\t\t\"second_sign_day\": \"\",\n" +
"\t\t\"first_contactAddress\": \"银谷大厦\",\n" +
"\t\t\"contract_money\": 700000,\n" +
"\t\t\"first_pay_day\": \"\",\n" +
"\t\t\"firt_payment_type\": \"1\",\n" +
"\t\t\"receipt\": true,\n" +
"\t\t\"firt_payment_else\": \"\",\n" +
"\t\t\"second_sign_month\": \"\",\n" +
"\t\t\"second_contactPhone\": \"85200\",\n" +
"\t\t\"firt_payment_typeElse\": \"\",\n" +
"\t\t\"transport_typeNumber\": null,\n" +
"\t\t\"delivery_typeNumber\": \"1\",\n" +
"\t\t\"send_place\": \"上海外滩十八号\",\n" +
"\t\t\"first_delivery_receiverName\": \"赵武\",\n" +
"\t\t\"first_delivery_receiverPhone\": \"12520000\",\n" +
"\t\t\"contract_first_party\": \"宁都东芯科技有限公司\",\n" +
"\t\t\"contract_second_party\": \"中国长城科技集团股份有限公司\",\n" +
"\t\t\"proj_name\": \"河北移动合同流程测试项目\",\n" +
"\t\t\"productList\": [{\n" +
"\t\t\t\"index\": 1,\n" +
"\t\t\t\"name\": \"标配产品4\",\n" +
"\t\t\t\"configure\": \"\",\n" +
"\t\t\t\"customized\": \"√是□否\",\n" +
"\t\t\t\"zxyProduct\": \"□是√否\",\n" +
"\t\t\t\"pnCode\": \"5181809\",\n" +
"\t\t\t\"price\": 7000,\n" +
"\t\t\t\"count\": 50,\n" +
"\t\t\t\"totalAmountExcludingTax\": \"--\",\n" +
"\t\t\t\"totalAmountIncludingTax\": 350000\n" +
"\t\t}]\n" +
"\t},\n" +
"\t\"contract_conf_id\": \"2c46bac81a7742ddbf1512e279ab1c9f\"\n" +
"}";
JSONObject param = JSONObject.parseObject(data);
String contractId = param.getString("contract_conf_id");
String contractName = param.getString("contractName");
JSONObject jsonObject = param.getJSONObject("contractVars");
String contractVars = jsonObject.toJSONString();
Map<String, Object> jsonMap = JSON.parseObject(contractVars, new TypeReference<HashMap<String, Object>>() {});
String template = "/word/20221229/2022122916464428_20221228版本产品销售合同正文.docx";
String templateDirectory = "/Users/fukui/IdeaProjects/xc-crm/crm-doc/src/main/resources";
template = templateDirectory + template;
String dest = getOutputTemporaryFile(template);
String contract = genDocxTemplate(template,dest,jsonMap,"productList");
String outPut = getOutputFile(template,contractName);
appendToOneDoc(contract,outPut);
JSONArray jsonA = param.getJSONArray("appendix");
if(jsonA == null || jsonA.isEmpty() || jsonA.size()<1){
}else {
for (int i=0;i< jsonA.size();i++){
String appendixVars = jsonA.getJSONObject(i).getJSONObject("appendixVars").toJSONString();//附件内容
Map<String, Object> jsonFu1 = JSON.parseObject(appendixVars, new TypeReference<HashMap<String, Object>>() {});
String templatFu = "";
if (i==0){
templatFu = "/word/20221228160854709_附件1出口管制承诺函(1).docx";
}
if (i==1){
templatFu = "/word/20221228160909649_附件2专用信息设备销售和使用承诺.docx";
}
if (i==2){
templatFu = "/word/20221228160924328_附件3专用信息设备最终用户情况登记表(1).docx";
}
if (i==3){
templatFu = "/word/20221228160938733_附件4签收单(1).docx";
}
templatFu = templateDirectory + templatFu;
String destFu = getOutputTemporaryFile(templatFu);
String enclosure = genDocxTemplate(templatFu,destFu,jsonFu1,"productList");
threeDocToOneDoc(enclosure,outPut);
}
}
String outPdf = outPut.replace(".docx",".pdf");
docxToPdf(outPut,outPdf);
Files.deleteIfExists(Paths.get(outPut));
String finaPutPath = outPdf.replace("删除文字","");
Boolean addWaterMark = genPdfTemplatePicture(outPdf, finaPutPath);
Files.deleteIfExists(Paths.get(outPdf));
encryptionPdf(finaPutPath,"admin");
}
/**
* 拼接生成输出文件路径.
*/
private static String getOutputFile(String template,String name) throws Exception {
if (StringUtil.isEmpty(template)) {
throw new Exception("模板路径不能为空");
}
//截取模板文件名称
SimpleDateFormat sdf_time = new SimpleDateFormat("HHmmssS");
//拼接输出文件名称
String output_fileName = name + "_" + "删除文字" + sdf_time.format(new Date()) + ".docx";
SimpleDateFormat sdf_date = new SimpleDateFormat("yyyyMMdd");
//拼接输出文件全路径
String outputFolder = "/Users/fukui/IdeaProjects/xc-crm/crm-doc/src/main/resources";
String output_fullFolder = outputFolder + File.separator + sdf_date.format(new Date());
//如果目录不存在,就创建目录
File output_fileFolder = new File(output_fullFolder);
if (!output_fileFolder.exists()) {
output_fileFolder.mkdirs();
}
return output_fullFolder + File.separator + output_fileName;
}
/**
* 拼接生成合同、附件输出文件路径.
*/
private static String getOutputTemporaryFile(String template) throws Exception {
if (StringUtil.isEmpty(template)) {
throw new Exception("模板路径不能为空");
}
//截取模板文件名称
String template_fileName = template.substring(template.lastIndexOf("/") + 1,template.lastIndexOf("."));
SimpleDateFormat sdf_time = new SimpleDateFormat("HHmmssS");
//拼接输出文件名称
String output_fileName = template_fileName + "_" + sdf_time.format(new Date()) ;
SimpleDateFormat sdf_date = new SimpleDateFormat("yyyyMMdd");
//拼接输出文件全路径
String outputFolder = "/Users/fukui/IdeaProjects/xc-crm/crm-doc/src/main/resources";
String output_fullFolder = outputFolder + File.separator + "temporary"+ File.separator + sdf_date.format(new Date());
// 如果目录不存在,就创建目录
File output_fileFolder = new File(output_fullFolder);
if (!output_fileFolder.exists()) {
output_fileFolder.mkdirs();
}
return output_fullFolder + File.separator + output_fileName;
}
/**
* 不加水印
* @param template
* @param dest
* @param vars
* @param tableField
* @return
*/
public static String genDocxTemplate(String template, String dest, Map<String, Object> vars, String tableField) {
File file = new File(dest);
if (file.isDirectory() && !file.exists()) {
file.mkdirs();
}
String dest_docx = dest + ".docx";
try {
genDocxOnTemplate(template, dest_docx, vars, tableField);
Document doc = new Document(dest_docx);
doc.save( dest_docx );
} catch (Exception e) {
e.printStackTrace();
}
return dest_docx;
}
/**
* 基于docx模版生成docx文档,支持表格动态渲染。
*
* @param template 模版文件路径
* @param dest 结果文件路径
* @param vars 变量数据
* @param tableField 表格域名称
* @return 成功:true,失败:false
*/
public static boolean genDocxOnTemplate(String template, String dest, Map<String, Object> vars, String tableField) {
try {
HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
XWPFTemplate compile;
if (tableField != null) {
Configure config = Configure.newBuilder().bind(tableField, policy).build();
compile = XWPFTemplate.compile(template, config);
} else {
compile = XWPFTemplate.compile(template);
}
compile.render(vars);
compile.writeToFile(dest);
return true;
} catch (IOException e) {
// logger.error(e.getMessage(),e);
}
return false;
}
/**
* 根据 inputContractWord 文件生成 outContractWord 文件
* inputContractWord 要合并的合同
* outContractWord 最终输出的拼接后的合同
* @throws Exception
*/
public static void appendToOneDoc(String inputContractWord,String outContractWord) throws Exception {
Document doc2 = new Document(inputContractWord);
Document doc4 = new Document();
doc4.removeAllChildren();
doc4.appendDocument( doc2, ImportFormatMode.KEEP_DIFFERENT_STYLES );
doc4.save(outContractWord);
}
/**
* 将docx文档转化为pdf文件。
*
* @param docxPath docx文档
* @param outPath pdf文档
* @return 成功:true,失败:false
*/
public static boolean docxToPdf(String docxPath, String outPath) {
FileOutputStream os = null;
try {
File file = new File(outPath);
os = new FileOutputStream(file);
Document doc = new Document(docxPath);
Document _doc = new Document(docxPath);
doc.copyStylesFromTemplate(_doc);
FontSettings.getDefaultInstance().setFontsFolder("/Users/fukui/IdeaProjects/xc-crm/crm-doc/src/main/resources/tiff", true);
doc.save(os, SaveFormat.PDF);
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (os != null) {
try {
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
/**
* 把 inputContractWord 文件合并到 outContractWord 里面
* inputContractWord 要合并的合同
* inputEnclosureWord 要合并的附件
* outContractWord 最终输出的拼接后的合同
* @throws Exception
*/
public static void threeDocToOneDoc(String inputContractWord,String outContractWord) throws Exception {
Document doc1 = new Document(outContractWord);
Document doc2 = new Document(inputContractWord);
Document doc4 = new Document();
doc4.removeAllChildren();
doc4.appendDocument( doc1, ImportFormatMode.USE_DESTINATION_STYLES );
doc4.appendDocument( doc2, ImportFormatMode.USE_DESTINATION_STYLES );
doc4.save(outContractWord);
}
/**
* 加图片水印.
*/
public static boolean genPdfTemplatePicture(String inputFile, String outputFile) {
try {
String inputImage = "/Users/fukui/IdeaProjects/xc-crm/crm-doc/src/main/resources/word/77.png";
// imageFileWaterPrint(inputImage,inputFile, outputFile);
// return addWaterMark(inputFile, outputFile, inputImage, 130, 40, 4, 3, 30, 0.1f);
addWaterMark(inputFile, outputFile, "/Users/fukui/IdeaProjects/xc-crm/crm-doc/src/main/resources/word/77.png", 78, 300, 30, 0.1f);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
//加图片水印
public static boolean addWaterMark(String inputFile,String outputFile,
String picFilePath, float picHeight, float picWidth, int picRowNum, int picColNum,
int rotateDegree, float transDegree) {
try {
PdfReader reader = new PdfReader(inputFile);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
int total = reader.getNumberOfPages() + 1;
PdfContentByte watermark;
// 遍历pdf文件的每页以处理
for (int i = 1; i < total; i++) {
// 获得PDF最顶层
watermark = stamper.getOverContent(i); //在内容上方加水印
watermark.saveState();
PdfGState gs = new PdfGState();
// 设置透明度范围为0到1
gs.setFillOpacity(transDegree);
watermark.setGState(gs);
watermark.beginText();
watermark.setColorFill(BaseColor.BLACK); //字体颜色
// 计算水印X,Y坐标
float x = reader.getPageSize(i).getWidth() / (picColNum+1);
float y = reader.getPageSize(i).getHeight() / (picRowNum+1);
for (int col = 1; col < picColNum+1; col++) {
for (int row = 1; row < picRowNum+1; row++) {
// 设置文字水印
if (picFilePath != null || !"".contentEquals(picFilePath)) {
// 设置图片水印
com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(picFilePath);
image.setAbsolutePosition(col*x, row*y); // 设置坐标 绝对位置 X Y
image.setRotationDegrees(rotateDegree); // 旋转 角度
// image.scaleAbsolute(picHeight, picWidth); // 自定义大小
image.scalePercent(5); // 原来图像的比例
watermark.setGState(gs); // 设置透明度
watermark.addImage(image); // 添加水印图片
}
}
}
watermark.endText();
watermark.setLineWidth(1f);
watermark.stroke();
}
stamper.close();
reader.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 加图片水印
*/
public static boolean addWaterMark(String inputFile, String outputFile, String picFilePath, float picHeight, float picWidth, int rotateDegree, float transDegree) {
try {
PdfReader reader = new PdfReader(inputFile);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
int total = reader.getNumberOfPages() + 1;
PdfContentByte watermark;
int count = 0;
// 遍历pdf文件的每页以处理
for (int i = 1; i < total; i++) {
// 获得PDF最顶层
watermark = stamper.getUnderContent(i);
watermark.saveState();
PdfGState gs = new PdfGState();
// 设置透明度范围为0到1
gs.setFillOpacity(transDegree);
watermark.setGState(gs);
watermark.beginText();
// 计算水印X,Y坐标
float scale = 1.8f;
float pageHeight = reader.getPageSize(i).getHeight();
float pageWidth = reader.getPageSize(i).getWidth();
float inW = picWidth / scale;
float inH = picHeight / scale;
for (int col = 0; col < 50; col++) {
float x = (col * inW) - inW / 2;
if (x > 0) {
x += col * inW * 0.8f;
}
if (x > pageWidth) {
break;
}
for (int row = 0; row < 50; row++) {
float y = row * inH + 2f * inH;
if (y > 0) {
y += row * inH * 5.5f;
}
if (y > pageHeight) {
break;
}
if (x + inW < 0 || y + inH < 0 || x > pageWidth || y > pageHeight) {
continue;
}
// 设置图片水印
com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(picFilePath);
// 原来图像的比例
image.scaleAbsolute(inW, inH);
// 设置透明度
watermark.setGState(gs);
// 设置坐标 绝对位置 X Y
image.setAbsolutePosition(x, y);
// 旋转 角度
image.setRotationDegrees(rotateDegree);
// 添加水印图片
watermark.addImage(image);
count++;
}
}
watermark.endText();
watermark.setLineWidth(1f);
watermark.stroke();
}
stamper.close();
reader.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//加密pdf
public static void encryptionPdf(String inPutFile,String password) throws FileNotFoundException, DocumentException {
try {
InputStream is = new FileInputStream(new File(inPutFile));
PdfReader pdfReader = new PdfReader(is);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(inPutFile));
pdfStamper.setEncryption(password.getBytes(), null, 0, PdfWriter.ENCRYPTION_AES_256);
pdfStamper.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
下面是对应的pom文件
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId>
<version>2.0.1</version>
<exclusions>
<exclusion>
<artifactId>2.1.7</artifactId>
<groupId>fr.opensagres.xdocreport.itext</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.aspose.words</groupId>
<artifactId>aspose-words</artifactId>
<version>19.5</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/aspose-words-19.5.jar</systemPath>
</dependency>
下面是目录结构