最近接了个任务,需要对模板进行填充,使用word模板进行填充,尝试后,使用.docx的文档。
以下是dome:
/**
* 模板附件上传
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void legalConUploadTemplate(ConBase conBase) {
/**
*1.先根据模板参数去法务获取副本的流,获取到后进行填充,然后保存到本地,然后再从本地获取这附件,上传到法务
*/
String legalId = baseSysVarClient.getValueByCode("conTemplateLegalId");
//判断是否已生成模板附件
List<ConLegalFile> conLegalFileList = conLegalFileService.selectByConBaseIdAndName(conBase.getConBaseId(), "conBase");
for (ConLegalFile file : conLegalFileList){
this.deletelegalFile(file, conBase.getUpdateUserCode());
}
//获取模板信息
ConTemplateAttach attach = conTemplateAttachService.selectByLegalId(legalId);
JSONObject js = new JSONObject();
js.put("attachmentId",attach.getAttachmentId());
js.put("mipAccount",conBase.getCreateUserCode());
js.put("fileId",attach.getLegalId());
byte[] legalDownLoad = this.legalDownLoad(js);
List<ConItemCenter> info = conItemCenterService.getInfo(conBase.getConBaseId());
InputStream inputStream = ConTemplateCtr.getInstance().print(new ByteArrayInputStream(legalDownLoad), conBase, info);
//转换成MultipartFile
MultipartFile multipartFile = null;
String name = conBase.getConName() + ".docx";
try {
multipartFile = new MockMultipartFile(name, name,
ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
} catch (IOException e) {
e.printStackTrace();
}
this.legalConUpload(multipartFile,"ContractNeedStamp",
"conBase",conBase.getConBaseId().toString(), conBase.getCreateUserCode());
}
方法入口
InputStream inputStream = ConTemplateCtr.getInstance().print(new ByteArrayInputStream(legalDownLoad), conBase, info);
注意这行代码,在这里面进行填充
import com.midea.dmr.common.utils.DateUtils;
import com.midea.dmr.cont.domain.bean.ConBase;
import com.midea.dmr.cont.domain.bean.ConItemCenter;
import java.io.InputStream;
import java.util.*;
public class ConTemplateCtr {
private ConTemplateCtr() {
}
private static class ConTemplateCtrInstance {
private static final ConTemplateCtr INSTANCE = new ConTemplateCtr();
}
public static ConTemplateCtr getInstance() {
return ConTemplateCtrInstance.INSTANCE;
}
/**
* 模板替换
*/
public InputStream print(InputStream in, ConBase conBase, List<ConItemCenter> info) {
// 模板全的路径
//String templatePaht = "D:\\物料制作年度框架协议.docx";
// 输出位置
String outPath = "D:\\物料制作年度框架协议3.docx";
Map<String, Object> paramMap = new HashMap(16);
// 普通的占位符示例 参数数据结构 {str,str}
paramMap.put("vendorName", conBase.getVendorName());
Date effectiveTime = conBase.getEffectiveTime();
paramMap.put("effectiveYear", DateUtils.getYear(effectiveTime));
paramMap.put("effectiveMonth", DateUtils.getMonth(effectiveTime));
paramMap.put("effectiveDay", DateUtils.getDay(effectiveTime));
Date expirationTime = conBase.getExpirationTime();
paramMap.put("expirationYear", DateUtils.getYear(expirationTime));
paramMap.put("expirationMonth", DateUtils.getMonth(expirationTime));
paramMap.put("expirationDay", DateUtils.getDay(expirationTime));
paramMap.put("detailedAddress1", conBase.getDetailedAddress1());
paramMap.put("vendorUserName", conBase.getVendorUserName());
paramMap.put("vendorMobile", conBase.getVendorMobile());
paramMap.put("vendorMail", conBase.getVendorMail());
paramMap.put("operationCenterName", conBase.getOperationCenterName());
List<List<String>> tbRow = new ArrayList();
for (int i = 0; i < info.size(); i++) {
List<String> tbRow1 = new ArrayList();
ConItemCenter conItemCenter = info.get(i);
tbRow1.add(conItemCenter.getCostemCode());
tbRow1.add(conItemCenter.getProductName());
tbRow1.add(conItemCenter.getMaterialProcessDesc());
tbRow1.add(conItemCenter.getMaterialSpec());
tbRow1.add(conItemCenter.getMaterialBulkSize());
tbRow1.add(conItemCenter.getUomName());
if (null != conItemCenter.getRealPrice()) {
tbRow1.add(String.valueOf(conItemCenter.getRealPrice().setScale(2)));
}
tbRow.add(tbRow1);
}
//获取参数
paramMap.put(PoiWordUtils.addRowText + "tb1", tbRow);
//模板渲染
return DynWordUtils.process(paramMap, in, outPath);
}
}
这里主要是参数配置
//模板渲染
return DynWordUtils.process(paramMap, in, outPath);
后面的就是方式类
ConTemplateCtr类
package com.midea.dmr.cont.ctr;
import com.midea.dmr.common.utils.DateUtils;
import com.midea.dmr.cont.domain.bean.ConBase;
import com.midea.dmr.cont.domain.bean.ConItemCenter;
import java.io.InputStream;
import java.util.*;
public class ConTemplateCtr {
private ConTemplateCtr() {
}
private static class ConTemplateCtrInstance {
private static final ConTemplateCtr INSTANCE = new ConTemplateCtr();
}
public static ConTemplateCtr getInstance() {
return ConTemplateCtrInstance.INSTANCE;
}
/**
* 模板替换
*/
public InputStream print(InputStream in, ConBase conBase, List<ConItemCenter> info) {
// 模板全的路径
//String templatePaht = "D:\\物料制作年度框架协议.docx";
// 输出位置
String outPath = "D:\\物料制作年度框架协议3.docx";
Map<String, Object> paramMap = new HashMap(16);
// 普通的占位符示例 参数数据结构 {str,str}
paramMap.put("vendorName", conBase.getVendorName());
Date effectiveTime = conBase.getEffectiveTime();
paramMap.put("effectiveYear", DateUtils.getYear(effectiveTime));
paramMap.put("effectiveMonth", DateUtils.getMonth(effectiveTime));
paramMap.put("effectiveDay", DateUtils.getDay(effectiveTime));
Date expirationTime = conBase.getExpirationTime();
paramMap.put("expirationYear", DateUtils.getYear(expirationTime));
paramMap.put("expirationMonth", DateUtils.getMonth(expirationTime));
paramMap.put("expirationDay", DateUtils.getDay(expirationTime));
paramMap.put("detailedAddress1", conBase.getDetailedAddress1());
paramMap.put("vendorUserName", conBase.getVendorUserName());
paramMap.put("vendorMobile", conBase.getVendorMobile());
paramMap.put("vendorMail", conBase.getVendorMail());
paramMap.put("operationCenterName", conBase.getOperationCenterName());
List<List<String>> tbRow = new ArrayList();
for (int i = 0; i < info.size(); i++) {
List<String> tbRow1 = new ArrayList();
ConItemCenter conItemCenter = info.get(i);
tbRow1.add(conItemCenter.getCostemCode());
tbRow1.add(conItemCenter.getProductName());
tbRow1.add(conItemCenter.getMaterialProcessDesc());
tbRow1.add(conItemCenter.getMaterialSpec());
tbRow1.add(conItemCenter.getMaterialBulkSize());
tbRow1.add(conItemCenter.getUomName());
if (null != conItemCenter.getRealPrice()) {
tbRow1.add(String.valueOf(conItemCenter.getRealPrice().setScale(2)));
}
tbRow.add(tbRow1);
}
//获取参数
paramMap.put(PoiWordUtils.addRowText + "tb1", tbRow);
//模板渲染
return DynWordUtils.process(paramMap, in, outPath);
}
}
DynWordUtils类
package com.midea.dmr.cont.ctr;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.*;
/**
* Create by IntelliJ Idea 2018.2
*
* @author: qyp
* Date: 2019-10-25 14:48
*/
public class DynWordUtils {
private static final Logger logger = LoggerFactory.getLogger(DynWordUtils.class);
/**
* 被list替换的段落 被替换的都是oldParagraph
*/
private XWPFParagraph oldParagraph;
/**
* 参数
*/
private Map<String, Object> paramMap;
/**
* 当前元素的位置
*/
int n = 0;
/**
* 判断当前是否是遍历的表格
*/
boolean isTable = false;
/**
* 模板对象
*/
XWPFDocument templateDoc;
/**
* 默认字体的大小
*/
public static final int DEFAULT_FONT_SIZE = 10;
/**
* 重复模式的占位符所在的行索引
*/
private int currentRowIndex;
/**
* 入口
*
* @param paramMap 模板中使用的参数
* @param templatePaht 模板全路径
* @param outPath 生成的文件存放的本地全路径
*/
public static void process(Map<String, Object> paramMap, String templatePaht, String outPath) {
DynWordUtils dynWordUtils = new DynWordUtils();
dynWordUtils.setParamMap(paramMap);
dynWordUtils.createWord(templatePaht, outPath);
}
/**
* 入口
*
* @param paramMap 模板中使用的参数
* @param outPath 生成的文件存放的本地全路径
*/
public static InputStream process(Map<String, Object> paramMap, InputStream in, String outPath) {
DynWordUtils dynWordUtils = new DynWordUtils();
dynWordUtils.setParamMap(paramMap);
return dynWordUtils.createWord(in, outPath);
}
/**
* 生成动态的word
*
* @param outPath
*/
public InputStream createWord(InputStream in, String outPath) {
ByteArrayOutputStream outStream = null;
InputStream inputStream = null;
try {
Date date = new Date();
logger.info("生成动态的createWord_outPath:" + outPath);
outStream = new ByteArrayOutputStream();
templateDoc = new XWPFDocument(in);
parseTemplateWord();
logger.info("生成动态的createWord成功。" + date.getTime());
templateDoc.write(outStream);
inputStream = new ByteArrayInputStream(outStream.toByteArray());
} catch (Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
String className = stackTrace[0].getClassName();
String methodName = stackTrace[0].getMethodName();
int lineNumber = stackTrace[0].getLineNumber();
logger.info("错误:第:" + lineNumber + "行, 类名:" + className + ", 方法名:" + methodName);
logger.info("生成动态的word失败_" + e.getMessage());
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
logger.info("关闭流失败:" + e.getMessage());
}
}
}
return inputStream;
}
/**
* 生成动态的word
*
* @param templatePath
* @param outPath
*/
public void createWord(String templatePath, String outPath) {
FileOutputStream outStream = null;
try {
logger.info("生成动态的createWord_templatePath:" + templatePath + "_outPath:" + outPath);
outStream = new FileOutputStream(outPath);
templateDoc = new XWPFDocument(OPCPackage.open(templatePath));
parseTemplateWord();
templateDoc.write(outStream);
} catch (Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
String className = stackTrace[0].getClassName();
String methodName = stackTrace[0].getMethodName();
int lineNumber = stackTrace[0].getLineNumber();
logger.info("错误:第:" + lineNumber + "行, 类名:" + className + ", 方法名:" + methodName);
logger.info("createWord_生成动态的word失败:{}", e.getMessage());
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
logger.info("createWord_关闭流失败:" + e.getMessage());
}
}
}
}
/**
* 解析word模板
*/
public void parseTemplateWord() throws Exception {
List<IBodyElement> elements = templateDoc.getBodyElements();
for (; n < elements.size(); n++) {
IBodyElement element = elements.get(n);
// 普通段落
if (element instanceof XWPFParagraph) {
XWPFParagraph paragraph = (XWPFParagraph) element;
oldParagraph = paragraph;
if (paragraph.getParagraphText().isEmpty()) {
continue;
}
delParagraph(paragraph);
} else if (element instanceof XWPFTable) {
// 表格
isTable = true;
XWPFTable table = (XWPFTable) element;
delTable(table, paramMap);
isTable = false;
}
}
}
/**
* 处理段落
*/
private void delParagraph(XWPFParagraph paragraph) throws Exception {
List<XWPFRun> runs = oldParagraph.getRuns();
StringBuilder sb = new StringBuilder();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text == null) {
continue;
}
sb.append(text);
run.setText("", 0);
}
placeholder(paragraph, runs, sb);
}
/**
* 匹配传入信息集合与模板
*
* @param placeholder 模板需要替换的区域()
* @param paramMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
public void changeValue(XWPFRun currRun, String placeholder, Map<String, Object> paramMap) throws Exception {
String placeholderValue = placeholder;
if (paramMap == null || paramMap.isEmpty()) {
return;
}
Set<Map.Entry<String, Object>> textSets = paramMap.entrySet();
for (Map.Entry<String, Object> textSet : textSets) {
//匹配模板与替换值 格式${key}
String mapKey = textSet.getKey();
String docKey = PoiWordUtils.getDocKey(mapKey);
if (placeholderValue.indexOf(docKey) != -1) {
Object obj = textSet.getValue();
// 需要添加一个list
if (obj instanceof List) {
placeholderValue = delDynList(placeholder, (List) obj);
} else {
placeholderValue = placeholderValue.replaceAll(
PoiWordUtils.getPlaceholderReg(mapKey)
, String.valueOf(obj));
}
}
}
currRun.setText(placeholderValue, 0);
}
/**
* 处理的动态的段落(参数为list)
*
* @param placeholder 段落占位符
* @param obj
* @return
*/
private String delDynList(String placeholder, List obj) {
String placeholderValue = placeholder;
List dataList = obj;
Collections.reverse(dataList);
for (int i = 0, size = dataList.size(); i < size; i++) {
Object text = dataList.get(i);
// 占位符的那行, 不用重新创建新的行
if (i == 0) {
placeholderValue = String.valueOf(text);
} else {
XWPFParagraph paragraph = createParagraph(String.valueOf(text));
if (paragraph != null) {
oldParagraph = paragraph;
}
// 增加段落后doc文档的element的size会随着增加(在当前行的上面添加
// 这里减操作是回退并解析新增的行(因为可能新增的带有占位符,这里为了支持图片和表格)
if (!isTable) {
n--;
}
}
}
return placeholderValue;
}
/**
* 创建段落 <p></p>
*
* @param texts
*/
public XWPFParagraph createParagraph(String... texts) {
// 使用游标创建一个新行
XmlCursor cursor = oldParagraph.getCTP().newCursor();
XWPFParagraph newPar = templateDoc.insertNewParagraph(cursor);
// 设置段落样式
newPar.getCTP().setPPr(oldParagraph.getCTP().getPPr());
copyParagraph(oldParagraph, newPar, texts);
return newPar;
}
/**
* 处理表格(遍历)
*
* @param table 表格
* @param paramMap 需要替换的信息集合
*/
public void delTable(XWPFTable table, Map<String, Object> paramMap) throws Exception {
List<XWPFTableRow> rows = table.getRows();
for (int i = 0, size = rows.size(); i < size; i++) {
XWPFTableRow row = rows.get(i);
currentRowIndex = i;
// 如果是动态添加行 直接处理后返回
if (delAndJudgeRow(table, paramMap, row)) {
return;
}
}
}
/**
* 判断并且是否是动态行,并且处理表格占位符
*
* @param table 表格对象
* @param paramMap 参数map
* @param row 当前行
* @return
* @throws Exception
*/
private boolean delAndJudgeRow(XWPFTable table, Map<String, Object> paramMap, XWPFTableRow row) throws Exception {
// 当前行是动态行标志
if (PoiWordUtils.isAddRow(row)) {
List<XWPFTableRow> xwpfTableRows = addAndGetRows(table, row, paramMap);
// 回溯添加的行,这里是试图处理动态添加的图片
for (XWPFTableRow tbRow : xwpfTableRows) {
delAndJudgeRow(table, paramMap, tbRow);
}
return true;
}
// 如果是重复添加的行
if (PoiWordUtils.isAddRowRepeat(row)) {
List<XWPFTableRow> xwpfTableRows = addAndGetRepeatRows(table, row, paramMap);
// 回溯添加的行,这里是试图处理动态添加的图片
for (XWPFTableRow tbRow : xwpfTableRows) {
delAndJudgeRow(table, paramMap, tbRow);
}
return true;
}
// 当前行非动态行标签
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if (PoiWordUtils.checkText(cell.getText())) {
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
StringBuilder sb = new StringBuilder();
for (XWPFRun run : runs) {
sb.append(run.toString());
run.setText("", 0);
}
placeholder(paragraph, runs, sb);
}
}
}
return false;
}
/**
* 处理占位符
*
* @param runs 当前段的runs
* @param sb 当前段的内容
* @throws Exception
*/
private void placeholder(XWPFParagraph currentPar, List<XWPFRun> runs, StringBuilder sb) throws Exception {
if (runs.size() > 0) {
String text = sb.toString();
XWPFRun currRun = runs.get(0);
if (PoiWordUtils.isPicture(text)) {
// 该段落是图片占位符
ImageEntity imageEntity = (ImageEntity) PoiWordUtils.getValueByPlaceholder(paramMap, text);
int indentationFirstLine = currentPar.getIndentationFirstLine();
// 清除段落的格式,否则图片的缩进有问题
currentPar.getCTP().setPPr(null);
//设置缩进
currentPar.setIndentationFirstLine(indentationFirstLine);
// addPicture(currRun, imageEntity);
} else {
changeValue(currRun, text, paramMap);
}
}
}
/**
* 添加图片
* @param currRun 当前run
* @param imageEntity 图片对象
* @throws InvalidFormatException
* @throws FileNotFoundException
*/
/*private void addPicture(XWPFRun currRun, ImageEntity imageEntity) throws InvalidFormatException, FileNotFoundException {
Integer typeId = imageEntity.getTypeId().getTypeId();
String picId = currRun.getDocument().addPictureData(new FileInputStream(imageEntity.getUrl()), typeId);
ImageUtils.createPicture(currRun, picId, templateDoc.getNextPicNameNumber(typeId),
imageEntity.getWidth(), imageEntity.getHeight());
}*/
/**
* 添加行 标签行不是新创建的
*
* @param table
* @param flagRow flagRow 表有标签的行
* @param paramMap 参数
*/
private List<XWPFTableRow> addAndGetRows(XWPFTable table, XWPFTableRow flagRow, Map<String, Object> paramMap) throws Exception {
List<XWPFTableCell> flagRowCells = flagRow.getTableCells();
XWPFTableCell flagCell = flagRowCells.get(0);
String text = flagCell.getText();
List<List<String>> dataList = (List<List<String>>) PoiWordUtils.getValueByPlaceholder(paramMap, text);
if (dataList == null || dataList.size() <= 0) {
return new ArrayList();
}
// 新添加的行
List<XWPFTableRow> newRows = new ArrayList(dataList.size());
XWPFTableRow currentRow = flagRow;
int cellSize = flagRow.getTableCells().size();
for (int i = 0, size = dataList.size(); i < size; i++) {
if (i != 0) {
currentRow = table.createRow();
// 复制样式
if (flagRow.getCtRow() != null) {
currentRow.getCtRow().setTrPr(flagRow.getCtRow().getTrPr());
}
}
addRow(flagCell, currentRow, cellSize, dataList.get(i));
newRows.add(currentRow);
}
return newRows;
}
/**
* 添加重复多行 动态行 每一行都是新创建的
*
* @param table
* @param flagRow
* @param paramMap
* @return
* @throws Exception
*/
private List<XWPFTableRow> addAndGetRepeatRows(XWPFTable table, XWPFTableRow flagRow, Map<String, Object> paramMap) throws Exception {
List<XWPFTableCell> flagRowCells = flagRow.getTableCells();
XWPFTableCell flagCell = flagRowCells.get(0);
String text = flagCell.getText();
List<List<String>> dataList = (List<List<String>>) PoiWordUtils.getValueByPlaceholder(paramMap, text);
String tbRepeatMatrix = PoiWordUtils.getTbRepeatMatrix(text);
//Assert.assertNotNull("模板矩阵不能为空", tbRepeatMatrix);
// 新添加的行
if (dataList == null || dataList.size() <= 0) {
return new ArrayList();
}
List<XWPFTableRow> newRows = new ArrayList(dataList.size());
String[] split = tbRepeatMatrix.split(PoiWordUtils.tbRepeatMatrixSeparator);
int startRow = Integer.parseInt(split[0]);
int endRow = Integer.parseInt(split[1]);
int startCell = Integer.parseInt(split[2]);
int endCell = Integer.parseInt(split[3]);
XWPFTableRow currentRow;
for (int i = 0, size = dataList.size(); i < size; i++) {
int flagRowIndex = i % (endRow - startRow + 1);
XWPFTableRow repeatFlagRow = table.getRow(flagRowIndex);
// 清除占位符那行
if (i == 0) {
table.removeRow(currentRowIndex);
}
currentRow = table.createRow();
// 复制样式
if (repeatFlagRow.getCtRow() != null) {
currentRow.getCtRow().setTrPr(repeatFlagRow.getCtRow().getTrPr());
}
addRowRepeat(startCell, endCell, currentRow, repeatFlagRow, dataList.get(i));
newRows.add(currentRow);
}
return newRows;
}
/**
* 根据模板cell添加新行
*
* @param flagCell 模板列(标记占位符的那个cell)
* @param row 新增的行
* @param cellSize 每行的列数量(用来补列补足的情况)
* @param rowDataList 每行的数据
*/
private void addRow(XWPFTableCell flagCell, XWPFTableRow row, int cellSize, List<String> rowDataList) {
for (int i = 0; i < cellSize; i++) {
XWPFTableCell cell = row.getCell(i);
cell = cell == null ? row.createCell() : row.getCell(i);
if (i < rowDataList.size()) {
PoiWordUtils.copyCellAndSetValue(flagCell, cell, rowDataList.get(i));
} else {
// 数据不满整行时,添加空列
PoiWordUtils.copyCellAndSetValue(flagCell, cell, "");
}
}
}
/**
* 根据模板cell 添加重复行
*
* @param startCell 模板列的开始位置
* @param endCell 模板列的结束位置
* @param currentRow 创建的新行
* @param repeatFlagRow 模板列所在的行
* @param rowDataList 每行的数据
*/
private void addRowRepeat(int startCell, int endCell, XWPFTableRow currentRow, XWPFTableRow repeatFlagRow, List<String> rowDataList) {
int cellSize = repeatFlagRow.getTableCells().size();
for (int i = 0; i < cellSize; i++) {
XWPFTableCell cell = currentRow.getCell(i);
cell = cell == null ? currentRow.createCell() : currentRow.getCell(i);
int flagCellIndex = i % (endCell - startCell + 1);
XWPFTableCell repeatFlagCell = repeatFlagRow.getCell(flagCellIndex);
if (i < rowDataList.size()) {
PoiWordUtils.copyCellAndSetValue(repeatFlagCell, cell, rowDataList.get(i));
} else {
// 数据不满整行时,添加空列
PoiWordUtils.copyCellAndSetValue(repeatFlagCell, cell, "");
}
}
}
/**
* 复制段落
*
* @param sourcePar 原段落
* @param targetPar
* @param texts
*/
private void copyParagraph(XWPFParagraph sourcePar, XWPFParagraph targetPar, String... texts) {
targetPar.setAlignment(sourcePar.getAlignment());
targetPar.setVerticalAlignment(sourcePar.getVerticalAlignment());
// 设置布局
targetPar.setAlignment(sourcePar.getAlignment());
targetPar.setVerticalAlignment(sourcePar.getVerticalAlignment());
if (texts != null && texts.length > 0) {
String[] arr = texts;
XWPFRun xwpfRun = sourcePar.getRuns().isEmpty() ? sourcePar.getRuns().get(0) : null;
for (int i = 0, len = texts.length; i < len; i++) {
String text = arr[i];
XWPFRun run = targetPar.createRun();
if (xwpfRun != null) {
String fontFamily = xwpfRun.getFontFamily();
run.setText(text);
run.setFontFamily(fontFamily);
int fontSize = xwpfRun.getFontSize();
run.setFontSize((fontSize == -1) ? DEFAULT_FONT_SIZE : fontSize);
run.setBold(xwpfRun.isBold());
run.setItalic(xwpfRun.isItalic());
} else {
run.setFontFamily("仿宋_GB2312");
int fontSize = -1;
run.setFontSize((fontSize == -1) ? DEFAULT_FONT_SIZE : fontSize);
run.setBold(false);
run.setItalic(false);
}
}
}
}
public void setParamMap(Map<String, Object> paramMap) {
this.paramMap = paramMap;
}
}
FreeMarkerUtil类
package com.midea.dmr.cont.ctr;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.midea.dmr.common.exception.ParamValidationException;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.logging.Logger;
/**
* freemarker工具类
*/
public class FreeMarkerUtil {
private static final Logger LOG = Logger.getLogger(FreeMarkerUtil.class.getName());
private static final String ENCODE = "UTF-8";
/**
* freeMarker渲染
*
* @param data
* @param templateFile
* @return
* @throws
*/
public static String freeMarkerRender(Map<String, Object> data, byte[] templateFile) throws ParamValidationException {
Writer writer = new StringWriter();
try {
Configuration configuration = initConfig();
Template template = getTemplate(configuration, templateFile);
template.process(data, writer);
writer.flush();
return writer.toString();
} catch (Exception e) {
LOG.info("freeMarker渲染异常:" + e.getMessage());
throw new ParamValidationException("freeMarker渲染异常");
} finally {
try {
writer.close();
} catch (IOException ioe) {
LOG.info("关闭文件流异常:" + ioe.getMessage());
}
}
}
/**
* 模板转换为pdf(使用默认页眉页脚)
*
* @param templateFile
* @return
* @throws
*/
public static byte[] html2Pdf(String templateFile) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = null;
try {
document = new Document(PageSize.A4, 90, 90, 60, 60);
PdfWriter writer = PdfWriter.getInstance(document, baos);
PDFBuilder builder = new PDFBuilder();
writer.setPageEvent(builder);
document.open();
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider();
LOG.info("html2Pdf.parseXHtml,开始");
com.itextpdf.tool.xml.XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(templateFile.getBytes(ENCODE)), null, Charset.forName(ENCODE), fontImp);
LOG.info("html2Pdf.parseXHtml,结束");
document.close();
baos.flush();
baos.close();
} catch (Exception e) {
LOG.info("转换电子合同异常:" + e.getMessage());
throw new Exception(e);
}
return baos.toByteArray();
}
/**
* 模板转换为pdf(使用默认页眉页脚)
*
* @param templateFile
* @return
* @throws
*/
public static byte[] html2PdfNew(String templateFile) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = null;
try {
document = new Document(PageSize.A4, 90, 90, 60, 60);
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font font = new Font(baseFont);
Paragraph p = new Paragraph();
p.setFont(font);
PdfWriter writer = PdfWriter.getInstance(document, baos);
PDFBuilder builder = new PDFBuilder();
writer.setPageEvent(builder);
document.open();
document.add(p);
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider();
LOG.info("html2Pdf1.parseXHtml,开始");
com.itextpdf.tool.xml.XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(templateFile.getBytes(ENCODE)), null, Charset.forName(ENCODE), fontImp);
LOG.info("html2Pdf1.parseXHtml,结束");
document.close();
baos.flush();
baos.close();
} catch (Exception e) {
LOG.info("转换电子合同异常1:" + e.getMessage());
throw new Exception(e);
}
return baos.toByteArray();
}
/**
* 模板转换为pdf(使用自定义页眉页脚)
*
* @param templateFile
* @param builder
* @return
* @throws
*/
public static byte[] html2Pdf(String templateFile, PDFBuilder builder) throws ParamValidationException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
Document document = new Document(PageSize.A4, 90, 90, 60, 60);
PdfWriter writer = PdfWriter.getInstance(document, baos);
writer.setPageEvent(builder);
document.open();
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider();
com.itextpdf.tool.xml.XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(templateFile.getBytes()), null, Charset.forName(ENCODE), fontImp);
document.close();
baos.flush();
baos.close();
} catch (Exception e) {
LOG.info("转换电子合同异常:" + e.getMessage());
throw new ParamValidationException("转换电子合同异常");
}
return baos.toByteArray();
}
/**
* 模板参数初始化
*
* @return
*/
public static Configuration initConfig() {
Configuration configuration = new Configuration();
configuration.setDefaultEncoding(ENCODE);
return configuration;
}
/**
* 获取模板
*
* @param configuration
* @return
* @throws
*/
public static Template getTemplate(Configuration configuration, byte[] templateFile) throws ParamValidationException {
StringTemplateLoader stl = new StringTemplateLoader();
stl.putTemplate("template", new String(templateFile));
configuration.setTemplateLoader(stl);
try {
return configuration.getTemplate("template");
} catch (Exception e) {
LOG.info("获取模板异常:" + e.getMessage());
throw new ParamValidationException("获取模板异常");
}
}
}
ImageEntity类
package com.midea.dmr.cont.ctr;
/**
* Create by IntelliJ Idea 2018.2
* <p>
* 图片实体对象
*
* @author: qyp
* Date: 2019-10-26 21:52
*/
public class ImageEntity {
/**
* 图片宽度
*/
private int width = 400;
/**
* 图片高度
*/
private int height = 300;
/**
* 图片地址
*/
private String url;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
ImageUtils类
package com.midea.dmr.cont.ctr;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
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;
/**
* Create by IntelliJ Idea 2018.2
*
* @author: qyp
* Date: 2019-10-26 21:55
*/
public class ImageUtils {
/**
* 图片类型枚举
*/
enum ImageType {
/**
* 支持四种类型 JPG/JPEG, GIT, BMP, PNG
*/
JPG("JPG", XWPFDocument.PICTURE_TYPE_JPEG),
JPEG("JPEG", XWPFDocument.PICTURE_TYPE_JPEG),
PNG("PNG", XWPFDocument.PICTURE_TYPE_PNG)
;
private String name;
private Integer typeId;
ImageType(String name, Integer type) {
this.name = name;
this.typeId = type;
}
public String getName() {
return name;
}
public Integer getTypeId() {
return typeId;
}
}
public static void createPicture(XWPFRun run, String blipId, int id, int width, int height) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
CTInline inline = run.getCTR().addNewDrawing().addNewInline();
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>";
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch(XmlException xe) {
xe.printStackTrace();
}
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("Picture " + id);
docPr.setDescr("Generated");
}
}
MapperUtils类
package com.midea.dmr.cont.ctr;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
public class MapperUtils {
private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
private static MapperFacade mapper = null;
static {
mapper = mapperFactory.getMapperFacade();
}
public static MapperFacade getMapper() {
return mapper;
}
public static void main(String[] args) {
}
}
PDFBuilder类
package com.midea.dmr.cont.ctr;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
/**
* 设置页眉页脚处理类
*/
public class PDFBuilder extends PdfPageEventHelper {
// 页眉
private String header = " 2020年V1.0版";
// 页脚
private String footer = "";
// 字体大小
private int presentFontSize = 9;
// 纸张大小
private Rectangle pageSize = PageSize.A4;
// 模板
private PdfTemplate pdfTemplate;
// 基础字体对象
private BaseFont baseFont = null;
// 利用基础字体生成的字体对象,一般用于生成中文文字
private Font headerFont = null;
private Font footerFont = null;
public PDFBuilder() {
}
public PDFBuilder(String header, int presentFontSize, Rectangle pageSize) {
this.header = header;
this.presentFontSize = presentFontSize;
this.pageSize = pageSize;
}
public PDFBuilder(String header, String footer, int presentFontSize, Rectangle pageSize) {
this.header = header;
this.footer = footer;
this.presentFontSize = presentFontSize;
this.pageSize = pageSize;
}
/**
* 文档打开时初始化
*
* @param writer
* @param document
*/
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
// 设置边框长宽
pdfTemplate = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
try {
if (baseFont == null) {
baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
}
// 设置字体
if (headerFont == null) {
headerFont = new Font(baseFont, presentFontSize, Font.UNDERLINE);// 数据体字体
}
if (footerFont == null) {
footerFont = new Font(baseFont, presentFontSize, Font.NORMAL);// 数据体字体
}
} catch (Exception e) {
// LogUtil.error("初始化异常:", e);
// throw new ServiceException("初始化异常");
}
}
/**
* 每页关闭写入页眉页脚
*
* @param writer
* @param document
*/
@Override
public void onEndPage(PdfWriter writer, Document document) {
try {
if (baseFont == null) {
// baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
baseFont = BaseFont.createFont();
}
if (footerFont == null) {
// 数据体字体
footerFont = new Font(baseFont, presentFontSize, Font.NORMAL);
}
float right = 505.0f;
float top = 782.0f;
float rightMargin = 90.0f;
float leftMargin = 90.0f;
float left = 90.0f;
float bottom = 60.0f;
if (document != null) {
right = document.right();
top = document.top();
rightMargin = document.rightMargin();
leftMargin = document.leftMargin();
left = document.left();
bottom = document.bottom();
}
// 1.写入页眉
ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_RIGHT, new Phrase(header, headerFont), right, top + 20, 0);
// 2.写入前半部分的 第 X页/共
String foot1 = "";
int align;
// if (footer.isEmpty()) {
if (org.apache.commons.lang.StringUtils.isBlank(this.footer)) {
int pageS = writer.getPageNumber();
foot1 = " " + pageS + " /";
align = Element.ALIGN_CENTER;
} else {
foot1 = this.footer;
align = Element.ALIGN_LEFT;
}
Phrase phrase = new Phrase(foot1, footerFont);
TabSettings tabSettings = new TabSettings();
// 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
float len = baseFont.getWidthPoint(foot1, presentFontSize);
// 4.拿到当前的PdfContentByte
PdfContentByte cb = writer.getDirectContent();
// 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
ColumnText.showTextAligned(cb, align, phrase, (rightMargin + right + leftMargin - left - len) / 2.0F + 20F, bottom - 20, 0);
// 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
// len , y 轴和之前的保持一致,底边界-20
cb.addTemplate(pdfTemplate, (rightMargin + right + leftMargin - left) / 2.0F + 20F, bottom - 20); // 调节模版显示的位置
} catch (Exception e) {
// LogUtil.error("系统异常:", e);
System.err.println(e.getMessage());
return;
}
}
/**
* 文档关闭时写入页眉页脚
*
* @param writer
* @param document
*/
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
// 关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕。
pdfTemplate.beginText();
pdfTemplate.setFontAndSize(baseFont, presentFontSize);// 生成的模版的字体、颜色
String foot2 = "";
// if (footer.isEmpty()) {
if (org.apache.commons.lang.StringUtils.isBlank(footer)) {
foot2 = " " + (writer.getPageNumber()) + " ";
}
pdfTemplate.showText(foot2);// 模版显示的内容
pdfTemplate.endText();
pdfTemplate.closePath();
}
}
PDFUtil类
package com.midea.dmr.cont.ctr;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
//import com.midea.jr.ecr.common.log.util.LogUtil;
public class PDFUtil {
/**
* 获取PDDocument对象
*
* @param bytes
* @return
*/
public static PDDocument getPDDocument(byte[] bytes) {
PDDocument pdf = null;
try {
pdf = PDDocument.load(bytes);
return pdf;
} catch (Exception e) {
//LogUtil.error("", e);
}
return null;
}
/**
* 获取PDDocument对象
*
* @param file
* @return
*/
public static PDDocument getPDDocument(File file) {
PDDocument pdf = null;
try {
pdf = PDDocument.load(file);
return pdf;
} catch (Exception e) {
//LogUtil.error("", e);
}
return null;
}
/**
* 获取PDDocument对象
*
* @param fileInputStream
* @return
*/
public static PDDocument getPDDocument(FileInputStream fileInputStream) {
PDDocument pdf = null;
try {
pdf = PDDocument.load(fileInputStream);
return pdf;
} catch (Exception e) {
//LogUtil.error("", e);
}
return null;
}
/**
* 获取PDDocument对象
*
* @param pdfFilePath
* @return
*/
public static PDDocument getPDDocument(String pdfFilePath) {
try {
File file = new File(pdfFilePath);
if (file.exists()) {
throw new Exception("路径" + pdfFilePath + "文件不存在");
}
if (!file.isFile()) {
throw new Exception("路径" + pdfFilePath + "不是文件");
}
if (!file.canRead()) {
throw new Exception("文件" + pdfFilePath + "无法读取");
}
return getPDDocument(file);
} catch (Exception e) {
//LogUtil.error("", e);
}
return null;
}
/**
* 自己设置压缩质量来把图片压缩成byte[]
*
* @param image
* 压缩源图片
* @param quality
* 压缩质量,在0-1之间,
* @return 返回的字节数组
*/
public static byte[] bufferedImageTobytes(BufferedImage image, float quality) {
// 如果图片空,返回空
if (image == null) {
return null;
}
// 得到指定Format图片的writer
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");// 得到迭代器
ImageWriter writer = iter.next(); // 得到writer
// 得到指定writer的输出参数设置(ImageWriteParam )
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩
iwp.setCompressionQuality(quality); // 设置压缩质量参数
iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
ColorModel colorModel = ColorModel.getRGBdefault();
// 指定压缩时使用的色彩模式
iwp.setDestinationType(
new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
// 开始打包图片,写入byte[]
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 取得内存输出流
IIOImage iIamge = new IIOImage(image, null, null);
byte[] bytes = null;
try {
// 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput
// 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput
writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream));
writer.write(null, iIamge, iwp);
bytes = byteArrayOutputStream.toByteArray();
} catch (IOException e) {
//LogUtil.error("", e);
}
return bytes;
}
/**
* 向pdf表单填充数据
*
* @param fields
* @param map
* @throws IOException
* @throws DocumentException
*/
public static void fillData(AcroFields fields, Map<String, Object> map) throws IOException, DocumentException {
List<String> keys = new ArrayList<String>();
Map<String, AcroFields.Item> formFields = fields.getFields();
for (String key : map.keySet()) {
if (formFields.containsKey(key)) {
String value = String.valueOf(map.get(key));
fields.setField(key,value/*,true*/); // 为字段赋值,注意字段名称是区分大小写的
keys.add(key);
}
}
Iterator<String> itemsKey = formFields.keySet().iterator();
while (itemsKey.hasNext()) {
String itemKey = itemsKey.next();
if (!keys.contains(itemKey)) {
fields.setField(itemKey, " ");
}
}
}
/**
* itext生成pdf
*
* @param map
* @param file
* @return
*/
public static byte[] generatePDF(Map<String, Object> map, byte[] file) {
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(file);
PdfStamper ps = new PdfStamper(reader, bos);
/* 使用中文字体 */
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();
fontList.add(bf);
/* 取出报表模板中的所有字段 */
AcroFields fields = ps.getAcroFields();
fields.setSubstitutionFonts(fontList);
fillData(fields, map);
/* 必须要调用这个,否则文档不会生成的 如果为false那么生成的PDF文件还能编辑,一定要设为true */
ps.setFormFlattening(true);
ps.close();
return bos.toByteArray();
} catch (Exception e) {
//LogUtil.error("", e);
}
return null;
}
/**
* 给pdf文件添加水印
* @param InPdfFile
* @param markImagePath
* @return
*/
public static byte[] addPdfMark(byte[] InPdfFile, byte[] markImagePath) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes());
PdfStamper stamp = new PdfStamper(reader, bos);
Image img = Image.getInstance(markImagePath);// 插入水印
int pageSize = reader.getNumberOfPages();// 原pdf文件的总页数
for(int i = 1; i <= pageSize; i++) {
float pageWidth = reader.getPageSize(i).getWidth();
float pageHeight = reader.getPageSize(i).getHeight();
PdfContentByte under = stamp.getUnderContent(i); //水印在文本之下
// PdfGState gs = new PdfGState();
// gs.setFillOpacity(0.8f);// 设置透明度
// under.setGState(gs);
float per =(pageWidth/img.getWidth()) <(pageHeight/img.getHeight())?(pageWidth/img.getWidth()):(pageHeight/img.getHeight());
img.scalePercent(per*100);//依照比例缩放
img.scaleAbsolute(pageWidth,pageHeight);//自定义大小
img.setAbsolutePosition((pageWidth-img.getWidth())/2, (pageHeight-img.getHeight())/2);//图片坐标--居中
under.addImage(img);
}
stamp.close();
return bos.toByteArray();
}
catch(Exception e){
//LogUtil.error("", e);
}
return null;
}
/**
* 给pdf文件添加水印 -cfca用
* @param InPdfFile
* @param markImagePath
* @return
*/
public static byte[] addPdfMarkToCfca(byte[] InPdfFile, byte[] markImagePath) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// try (ByteArrayOutputStream bos = new ByteArrayOutputStream();){
PdfReader reader = new PdfReader(InPdfFile, "PDF".getBytes());
PdfStamper stamp = new PdfStamper(reader, bos);
Image img = Image.getInstance(markImagePath);// 插入水印
int pageSize = reader.getNumberOfPages();// 原pdf文件的总页数
for(int i = 1; i <= pageSize; i++) {
float pageWidth = reader.getPageSize(i).getWidth();
float pageHeight = reader.getPageSize(i).getHeight();
PdfContentByte under = stamp.getUnderContent(i); //水印在文本之下
// PdfGState gs = new PdfGState();
// gs.setFillOpacity(0.8f);// 设置透明度
// under.setGState(gs);
// img.scalePercent(50);//依照比例缩放
float per =(pageWidth/img.getWidth()) <(pageHeight/img.getHeight())?(pageWidth/img.getWidth()):(pageHeight/img.getHeight());
img.scalePercent(per*100);//依照比例缩放
//img.scaleAbsolute(pageWidth,pageHeight);//自定义大小
img.setAbsolutePosition(0, 0);//图片坐标--居中
under.addImage(img);
}
stamp.close();
return bos.toByteArray();
}
catch(Exception e){
//LogUtil.error("", e);
}
return null;
}
}
PoiWordUtils类
package com.midea.dmr.cont.ctr;
import org.apache.poi.xwpf.usermodel.*;
import java.util.List;
import java.util.Map;
/**
* Create by IntelliJ Idea 2018.2
*
* @author: qyp
* Date: 2019-10-26 2:12
*/
public class PoiWordUtils {
/**
* 占位符第一个字符
*/
public static final String PREFIX_FIRST = "$";
/**
* 占位符第二个字符
*/
public static final String PREFIX_SECOND = "{";
/**
* 占位符的前缀
*/
public static final String PLACEHOLDER_PREFIX = PREFIX_FIRST + PREFIX_SECOND;
/**
* 占位符后缀
*/
public static final String PLACEHOLDER_END = "}";
/**
* 表格中需要动态添加行的独特标记
*/
public static final String addRowText = "tbAddRow:";
public static final String addRowRepeatText = "tbAddRowRepeat:";
/**
* 表格中占位符的开头 ${tbAddRow: 例如${tbAddRow:tb1}
*/
public static final String addRowFlag = PLACEHOLDER_PREFIX + addRowText;
/**
* 表格中占位符的开头 ${tbAddRowRepeat: 例如 ${tbAddRowRepeat:0,2,0,1} 第0行到第2行,第0列到第1列 为模板样式
*/
public static final String addRowRepeatFlag = PLACEHOLDER_PREFIX + addRowRepeatText;
/**
* 重复矩阵的分隔符 比如:${tbAddRowRepeat:0,2,0,1} 分隔符为 ,
*/
public static final String tbRepeatMatrixSeparator = ",";
/**
* 占位符的后缀
*/
public static final String PLACEHOLDER_SUFFIX = "}";
/**
* 图片占位符的前缀
*/
public static final String PICTURE_PREFIX = PLACEHOLDER_PREFIX + "image:";
/**
* 判断当前行是不是标志表格中需要添加行
*
* @param row
* @return
*/
public static boolean isAddRow(XWPFTableRow row) {
return isDynRow(row, addRowFlag);
}
/**
* 添加重复模板动态行(以多行为模板)
* @param row
* @return
*/
public static boolean isAddRowRepeat(XWPFTableRow row) {
return isDynRow(row, addRowRepeatFlag);
}
private static boolean isDynRow(XWPFTableRow row, String dynFlag) {
if (row == null) {
return false;
}
List<XWPFTableCell> tableCells = row.getTableCells();
if (tableCells != null) {
XWPFTableCell cell = tableCells.get(0);
if (cell != null) {
String text = cell.getText();
if (text != null && text.startsWith(dynFlag)) {
return true;
}
}
}
return false;
}
/**
* 从参数map中获取占位符对应的值
*
* @param paramMap
* @param key
* @return
*/
public static Object getValueByPlaceholder(Map<String, Object> paramMap, String key) {
if (paramMap != null) {
if (key != null) {
return paramMap.get(getKeyFromPlaceholder(key));
}
}
return null;
}
/**
* 后去占位符的重复行列矩阵
* @param key 占位符
* @return {0,2,0,1}
*/
public static String getTbRepeatMatrix(String key) {
//Assert.assertNotNull("占位符为空", key);
String $1 = key.replaceAll("\\" + PREFIX_FIRST + "\\" + PREFIX_SECOND + addRowRepeatText + "(.*)" + "\\" + PLACEHOLDER_SUFFIX, "$1");
return $1;
}
/**
* 从占位符中获取key
*
* @return
*/
public static String getKeyFromPlaceholder(String placeholder) {
// return Optional.ofNullable(placeholder).map(p -> p.replaceAll("[\\$\\{\\}]", "")).get();
return placeholder.replaceAll("[\\$\\{\\}]", "");
}
public static void main(String[] args) {
String s = "${aa}";
s = s.replaceAll(PLACEHOLDER_PREFIX + PLACEHOLDER_SUFFIX , "");
System.out.println(s);
// String keyFromPlaceholder = getKeyFromPlaceholder("${tbAddRow:tb1}");
// System.out.println(keyFromPlaceholder);
}
/**
* 复制列的样式,并且设置值
* @param sourceCell
* @param targetCell
* @param text
*/
public static void copyCellAndSetValue(XWPFTableCell sourceCell, XWPFTableCell targetCell, String text) {
//段落属性
List<XWPFParagraph> sourceCellParagraphs = sourceCell.getParagraphs();
if (sourceCellParagraphs == null || sourceCellParagraphs.size() <= 0) {
return;
}
XWPFParagraph sourcePar = sourceCellParagraphs.get(0);
XWPFParagraph targetPar = targetCell.getParagraphs().get(0);
// 设置段落的样式
targetPar.getCTP().setPPr(sourcePar.getCTP().getPPr());
List<XWPFRun> sourceParRuns = sourcePar.getRuns();
if (sourceParRuns != null && sourceParRuns.size() > 0) {
// 如果当前cell中有run
List<XWPFRun> runs = targetPar.getRuns();
// Optional.ofNullable(runs).ifPresent(rs -> rs.stream().forEach(r -> r.setText("", 0)));
if (runs != null && runs.size() > 0) {
runs.get(0).setText(text, 0);
} else {
XWPFRun cellR = targetPar.createRun();
cellR.setText(text, 0);
// 设置列的样式位模板的样式
targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
}
setTypeface(sourcePar, targetPar);
} else {
targetCell.setText(text);
}
}
/**
* 复制字体
*/
private static void setTypeface(XWPFParagraph sourcePar, XWPFParagraph targetPar) {
XWPFRun sourceRun = sourcePar.getRuns().get(0);
String fontFamily = sourceRun.getFontFamily();
int fontSize = sourceRun.getFontSize();
// String color = sourceRun.getColor();
// String fontName = sourceRun.getFontName();
boolean bold = sourceRun.isBold();
boolean italic = sourceRun.isItalic();
// int kerning = sourceRun.getKerning();
// String style = sourcePar.getStyle();
UnderlinePatterns underline = sourceRun.getUnderline();
List<XWPFRun> runs = targetPar.getRuns();
if(runs.isEmpty()){
return;
}
XWPFRun targetRun = targetPar.getRuns().get(0);
targetRun.setFontFamily(fontFamily);
// targetRun.setFontSize(fontSize == -1 ? 10 : fontSize);
targetRun.setBold(bold);
// targetRun.setColor(color);
targetRun.setItalic(italic);
// targetRun.setKerning(kerning);
targetRun.setUnderline(underline);
//targetRun.setFontSize(fontSize);
}
/**
* 判断文本中时候包含$
* @param text 文本
* @return 包含返回true,不包含返回false
*/
public static boolean checkText(String text){
boolean check = false;
if(text.indexOf(PLACEHOLDER_PREFIX)!= -1){
check = true;
}
return check;
}
/**
* 获得占位符替换的正则表达式
* @return
*/
public static String getPlaceholderReg(String text) {
return "\\" + PREFIX_FIRST + "\\" + PREFIX_SECOND + text + "\\" + PLACEHOLDER_SUFFIX;
}
public static String getDocKey(String mapKey) {
return PLACEHOLDER_PREFIX + mapKey + PLACEHOLDER_SUFFIX;
}
/**
* 判断当前占位符是不是一个图片占位符
* @param text
* @return
*/
public static boolean isPicture(String text) {
return text.startsWith(PICTURE_PREFIX);
}
/**
* 删除一行的列
* @param row
*/
public static void removeCells(XWPFTableRow row) {
int size = row.getTableCells().size();
try {
for (int i = 0; i < size; i++) {
// row.removeCell(i);
}
} catch (Exception e) {
}
}
}