这是我的第一篇掘金博客,开启掘金写作之路 maven相关依赖
<poi.version>3.17</poi.version>
<fr-pdf.version>2.0.1</fr-pdf.version>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId>
<version>${fr-pdf.version}</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.document</artifactId>
<version>${fr-pdf.version}</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.itext.extension</artifactId>
<version>${fr-pdf.version}</version>
</dependency>
工具类
import com.quantaeye.app.common.util.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WordToPdfUtil {
/**
* @param params
* @param tableIndex word的表格索引
* @param rownum 从第几行开始
* @param createrowindex 以第几行作为创建行
* @return
* @throws Exception
*/
public static boolean export(XWPFDocument xwpfDocument,List<Map<String,String>> params, int tableIndex,int rownum,int
createrowindex) throws Exception{
insertValueToTable(xwpfDocument,params,tableIndex,rownum,createrowindex);
return true;
}
/**
* 循环填充表格内容
* @param xwpfDocument
* @param params
* @param tableIndex
* @throws Exception
*/
public static void insertValueToTable(XWPFDocument xwpfDocument, List<Map<String,String>>
params, int tableIndex,int rownum,int createrowindex) throws Exception {
List<XWPFTable> tableList = xwpfDocument.getTables();
if(tableList.size()<=tableIndex){
throw new Exception("tableIndex对应的表格不存在");
}
XWPFTable table = tableList.get(tableIndex);
List<XWPFTableRow> rows = table.getRows();
if(rows.size()<2){
throw new Exception("tableIndex对应表格应该为2行");
}
//模板的那一行
XWPFTableRow tmpRow = rows.get(rownum);
List<XWPFTableCell> tmpCells = null;
List<XWPFTableCell> cells = null;
XWPFTableCell tmpCell = null;
tmpCells = tmpRow.getTableCells();
table.getCTTbl();
String cellText = null;
String cellTextKey = null;
Map<String,Object> totalMap = null;
for (int i = 0, len = params.size(); i < len; i++) {
Map<String,String> map = params.get(i);
// 创建新的一行
XWPFTableRow row = table.createRow();
//XWPFTableRow row = createRow(table.getCTTbl(),table,createrowindex);
// 获取模板的行高 设置为新一行的行高
row.setHeight(tmpRow.getHeight());
cells = row.getTableCells();
for (int k = 0, klen = cells.size(); k < klen; k++) {
tmpCell = tmpCells.get(k);
XWPFTableCell cell = cells.get(k);
cellText = tmpCell.getText();
if (org.apache.commons.lang.StringUtils.isNotBlank(cellText)) {
//转换为mapkey对应的字段
cellTextKey = cellText.replace("$", "").replace("{", "").replace("}",
"");
if (map.containsKey(cellTextKey)) {
// 填充内容 并且复制模板行的属性
setCellText(tmpCell,cell,map.get(cellTextKey)==null?"":map.get(cellTextKey).toString());
}
}
}
}
// 删除模版行
table.removeRow(rownum);
}
public static XWPFTableRow createRow(CTTbl ctTbl, XWPFTable table, int i){
int sizeCol = ctTbl.sizeOfTrArray() > 0 ? ctTbl.getTrArray(i)
.sizeOfTcArray() : 0;
XWPFTableRow tabRow = new XWPFTableRow(ctTbl.addNewTr(), table);
addColumn(tabRow, sizeCol);
//tableRows.add(tabRow);
return tabRow;
}
public static void addColumn(XWPFTableRow tabRow, int sizeCol) {
if (sizeCol > 0) {
for (int i = 0; i < sizeCol; i++) {
tabRow.createCell();
}
}
}
/**
* 复制模板行的属性
* @param tmpCell
* @param cell
* @param text
* @throws Exception
*/
public static void setCellText(XWPFTableCell tmpCell, XWPFTableCell cell,String text)
throws Exception {
CTTc cttc2 = tmpCell.getCTTc();
CTTcPr ctPr2 = cttc2.getTcPr();
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
if (ctPr2.getTcW() != null) {
ctPr.addNewTcW().setW(ctPr2.getTcW().getW());
}
if (ctPr2.getVAlign() != null) {
ctPr.addNewVAlign().setVal(ctPr2.getVAlign().getVal());
}
if (cttc2.getPList().size() > 0) {
CTP ctp = cttc2.getPList().get(0);
if (ctp.getPPr() != null) {
if (ctp.getPPr().getJc() != null) {
cttc.getPList().get(0).addNewPPr().addNewJc()
.setVal(ctp.getPPr().getJc().getVal());
}
}
}
if (ctPr2.getTcBorders() != null) {
ctPr.setTcBorders(ctPr2.getTcBorders());
}
XWPFParagraph tmpP = tmpCell.getParagraphs().get(0);
XWPFParagraph cellP = cell.getParagraphs().get(0);
XWPFRun tmpR = null;
if (tmpP.getRuns() != null && tmpP.getRuns().size() > 0) {
tmpR = tmpP.getRuns().get(0);
}
XWPFRun cellR = cellP.createRun();
cellR.setText(text);
// 复制字体信息
if (tmpR != null) {
if(!cellR.isBold()){
cellR.setBold(tmpR.isBold());
}
cellR.setItalic(tmpR.isItalic());
cellR.setUnderline(tmpR.getUnderline());
cellR.setColor(tmpR.getColor());
cellR.setTextPosition(tmpR.getTextPosition());
if (tmpR.getFontSize() != 1)
{
cellR.setFontSize(tmpR.getFontSize());
}
if (tmpR.getFontFamily() != null) {
cellR.setFontFamily(tmpR.getFontFamily());
}
if (tmpR.getCTR() != null) {
if (tmpR.getCTR().isSetRPr()) {
CTRPr tmpRPr = tmpR.getCTR().getRPr();
if (tmpRPr.isSetRFonts()) {
CTFonts tmpFonts = tmpRPr.getRFonts();
CTRPr cellRPr = cellR.getCTR().isSetRPr() ? cellR
.getCTR().getRPr() : cellR.getCTR().addNewRPr();
CTFonts cellFonts = cellRPr.isSetRFonts() ? cellRPr
.getRFonts() : cellRPr.addNewRFonts();
cellFonts.setAscii(tmpFonts.getAscii());
cellFonts.setAsciiTheme(tmpFonts.getAsciiTheme());
cellFonts.setCs(tmpFonts.getCs());
cellFonts.setCstheme(tmpFonts.getCstheme());
cellFonts.setEastAsia(tmpFonts.getEastAsia());
cellFonts.setEastAsiaTheme(tmpFonts.getEastAsiaTheme());
cellFonts.setHAnsi(tmpFonts.getHAnsi());
cellFonts.setHAnsiTheme(tmpFonts.getHAnsiTheme());
}
}
}
}
// 复制段落信息
cellP.setAlignment(tmpP.getAlignment());
cellP.setVerticalAlignment(tmpP.getVerticalAlignment());
cellP.setBorderBetween(tmpP.getBorderBetween());
cellP.setBorderBottom(tmpP.getBorderBottom());
cellP.setBorderLeft(tmpP.getBorderLeft());
cellP.setBorderRight(tmpP.getBorderRight());
cellP.setBorderTop(tmpP.getBorderTop());
cellP.setPageBreak(tmpP.isPageBreak());
if (tmpP.getCTP() != null) {
if (tmpP.getCTP().getPPr() != null) {
CTPPr tmpPPr = tmpP.getCTP().getPPr();
CTPPr cellPPr = cellP.getCTP().getPPr() != null ? cellP
.getCTP().getPPr() : cellP.getCTP().addNewPPr();
// 复制段落间距信息
CTSpacing tmpSpacing = tmpPPr.getSpacing();
if (tmpSpacing != null) {
CTSpacing cellSpacing = cellPPr.getSpacing() != null ? cellPPr
.getSpacing() : cellPPr.addNewSpacing();
if (tmpSpacing.getAfter() != null) {
cellSpacing.setAfter(tmpSpacing.getAfter());
}
if (tmpSpacing.getAfterAutospacing() != null) {
cellSpacing.setAfterAutospacing(tmpSpacing
.getAfterAutospacing());
}
if (tmpSpacing.getAfterLines() != null) {
cellSpacing.setAfterLines(tmpSpacing.getAfterLines());
}
if (tmpSpacing.getBefore() != null) {
cellSpacing.setBefore(tmpSpacing.getBefore());
}
if (tmpSpacing.getBeforeAutospacing() != null) {
cellSpacing.setBeforeAutospacing(tmpSpacing
.getBeforeAutospacing());
}
if (tmpSpacing.getBeforeLines() != null) {
cellSpacing.setBeforeLines(tmpSpacing.getBeforeLines());
}
if (tmpSpacing.getLine() != null) {
cellSpacing.setLine(tmpSpacing.getLine());
}
if (tmpSpacing.getLineRule() != null) {
cellSpacing.setLineRule(tmpSpacing.getLineRule());
}
}
// 复制段落缩进信息
CTInd tmpInd = tmpPPr.getInd();
if (tmpInd != null) {
CTInd cellInd = cellPPr.getInd() != null ? cellPPr.getInd()
: cellPPr.addNewInd();
if (tmpInd.getFirstLine() != null) {
cellInd.setFirstLine(tmpInd.getFirstLine());
}
if (tmpInd.getFirstLineChars() != null) {
cellInd.setFirstLineChars(tmpInd.getFirstLineChars());
}
if (tmpInd.getHanging() != null) {
cellInd.setHanging(tmpInd.getHanging());
}
if (tmpInd.getHangingChars() != null) {
cellInd.setHangingChars(tmpInd.getHangingChars());
}
if (tmpInd.getLeft() != null) {
cellInd.setLeft(tmpInd.getLeft());
}
if (tmpInd.getLeftChars() != null) {
cellInd.setLeftChars(tmpInd.getLeftChars());
}
if (tmpInd.getRight() != null) {
cellInd.setRight(tmpInd.getRight());
}
if (tmpInd.getRightChars() != null) {
cellInd.setRightChars(tmpInd.getRightChars());
}
}
}
}
}
/**
* 替换段落里面的变量
*
* @param doc 要替换的文档
* @param params 参数
*/
public static void replaceParams(XWPFDocument doc, Map<String, String> params) {
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
XWPFParagraph paragraph;
while (iterator.hasNext()) {
paragraph = iterator.next();
replaceParam(paragraph, params);
}
}
/**
* 正则匹配字符串
*
* @param str
* @return
*/
public static Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\$\{(.+?)\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
}
/**
* 替换表格里面的变量
*
* @param params 要替换的文档
* @param params 参数
*/
public static void replaceTableParams(XWPFDocument xwpfDocument, Map<String, String> params,int tableIndex) {
List<XWPFTable> tableList = xwpfDocument.getTables();
XWPFTable table =tableList.get(tableIndex);
List<XWPFTableRow> rows;
List<XWPFTableCell> cells;
List<XWPFParagraph> paras;
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if (matcher(table.getText()).find()) {
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
replaceParam(para, params,cell);
}
}
}
}
}
/**
* 替换表格里面的图片变量
*
* @param params 要替换的文档
* @param params 参数
*/
public static void replaceTableImgParams(XWPFDocument xwpfDocument, Map<String, Object> params,int tableIndex) {
List<XWPFTable> tableList = xwpfDocument.getTables();
XWPFTable table =tableList.get(tableIndex);
List<XWPFTableRow> rows;
List<XWPFTableCell> cells;
List<XWPFParagraph> paras;
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if (matcher(table.getText()).find()) {
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
replaceImgParam(para, params);
}
}
}
}
}
/**
* 替换表格里面的图片变量
*
* @param paragraph 要替换的段落
* @param params 参数
*/
public static void replaceImgParam(XWPFParagraph paragraph, Map<String, Object> params) {
List<XWPFRun> runs;
Matcher matcher;
String runText = "";
if (matcher(paragraph.getParagraphText()).find()) {
runs = paragraph.getRuns();
int j = runs.size();
for (int i = 0; i < j; i++) {
runText += runs.get(0).toString();
//保留最后一个段落,在这段落中替换值,保留段落样式
if (!((j - 1) == i)) {
paragraph.removeRun(0);
}
}
matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
String key = matcher.group(1);
Object obj = params.get(key);
if(obj instanceof Map){
Map<String,Object> map = (Map<String,Object>)params.get(key);
byte[] byteArray = (byte[])map.get("byteArray");
String imgFilePath = String.valueOf(map.get("imgFilePath"));
InputStream in = null;
try{
in = new ByteArrayInputStream(byteArray);
runs.get(0).addBreak();
runs.get(0).addPicture(in, getImgFormat(imgFilePath), imgFilePath, Units.toEMU((int)map.get("width")), Units.toEMU((int)map.get("height"))); // 200x200 pixels
runs.get(0).addBreak(BreakType.PAGE);
runText = matcher.replaceFirst("");
}catch(Exception ex){
ex.printStackTrace();
}finally {
try {
if(in != null){
in.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}else if(obj instanceof String || obj instanceof Integer){
runText = matcher.replaceFirst(String.valueOf(obj));
}else if(obj instanceof Date){
runText = matcher.replaceFirst(DateUtil.formatDate((Date)obj,DateUtil.DATETIME));
}else{
runText = matcher.replaceFirst("");
}
}
runs.get(0).setText(runText, 0);
}
}
}
public static final InputStream byte2Input(byte[] buf) {
return new ByteArrayInputStream(buf);
}
public static int getImgFormat(String imgFile){
int format;
if(imgFile.endsWith(".emf")){
format = XWPFDocument.PICTURE_TYPE_EMF;
}
else if(imgFile.endsWith(".wmf")){
format = XWPFDocument.PICTURE_TYPE_WMF;
}
else if(imgFile.endsWith(".pict")){
format = XWPFDocument.PICTURE_TYPE_PICT;
}
else if(imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg")){
format = XWPFDocument.PICTURE_TYPE_JPEG;
}
else if(imgFile.endsWith(".png")) {
format = XWPFDocument.PICTURE_TYPE_PNG;
}
else if(imgFile.endsWith(".dib")){
format = XWPFDocument.PICTURE_TYPE_DIB;
}
else if(imgFile.endsWith(".gif")){
format = XWPFDocument.PICTURE_TYPE_GIF;
}
else if(imgFile.endsWith(".tiff")){
format = XWPFDocument.PICTURE_TYPE_TIFF;
}
else if(imgFile.endsWith(".eps")){
format = XWPFDocument.PICTURE_TYPE_EPS;
}
else if(imgFile.endsWith(".bmp")){
format = XWPFDocument.PICTURE_TYPE_BMP;
}
else{
format = XWPFDocument.PICTURE_TYPE_WPG;
}
return format;
}
/**
* 替换页眉里面的变量
*
* @param params 要替换的文档
* @param params 参数
*/
public static void replaceXWPFHeaderParams(XWPFDocument xwpfDocument, Map<String, String> params) {
List<XWPFHeader> xwpfHeaderList = xwpfDocument.getHeaderList();
Iterator iterator = xwpfHeaderList.iterator();
XWPFParagraph para;
XWPFHeader xwpfHeader;
while (iterator.hasNext()) {
xwpfHeader = (XWPFHeader) iterator.next();
List<XWPFParagraph> xwpfParagraphList = xwpfHeader.getParagraphs();
Iterator iteratorPara = xwpfParagraphList.iterator();
while (iteratorPara.hasNext()){
para = (XWPFParagraph) iteratorPara.next();
replaceParam(para, params);
}
}
}
/**
* 替换段落里面的变量
*
* @param paragraph 要替换的段落
* @param params 参数
*/
public static void replaceParam(XWPFParagraph paragraph, Map<String, String> params,XWPFTableCell cell) {
List<XWPFRun> runs;
Matcher matcher;
String runText = "";
if (matcher(paragraph.getParagraphText()).find()) {
runs = paragraph.getRuns();
int j = runs.size();
for (int i = 0; i < j; i++) {
runText += runs.get(0).toString();
//保留最后一个段落,在这段落中替换值,保留段落样式
if (!((j - 1) == i)) {
paragraph.removeRun(0);
}
}
matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
}
runs.get(0).setText(runText, 0);
}
}
}
/**
* 替换段落里面的变量
*
* @param paragraph 要替换的段落
* @param params 参数
*/
public static void replaceParam(XWPFParagraph paragraph, Map<String, String> params) {
List<XWPFRun> runs;
Matcher matcher;
String runText = "";
if (matcher(paragraph.getParagraphText()).find()) {
runs = paragraph.getRuns();
int j = runs.size();
for (int i = 0; i < j; i++) {
runText += runs.get(0).toString();
//保留最后一个段落,在这段落中替换值,保留段落样式
if (!((j - 1) == i)) {
paragraph.removeRun(0);
}
}
matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
String key = matcher.group(1);
if(key.equals("softwareD") || key.equals("platform") || key.equals("contractSubject")
|| key.equals("dataD")|| key.equals("report")|| key.equals("operationType")
|| key.equals("companyS")|| key.equals("pA")|| key.equals("pW")){
runs.get(0).setFontFamily("Wingdings 2");
}
runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
}
runs.get(0).setText(runText, 0);
}
}
}
private RichTextString fillTextRight(Font font){
RichTextString richTextString = new XSSFRichTextString("\\u25A1");
// 设置字体名称
font.setFontName("Wingdings 2");
richTextString.applyFont(font);
return richTextString;
}
/**
* 将输入流中的数据写入字节数组
*
* @param in
* @return
*/
public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {
byte[] byteArray = null;
try {
int total = in.available();
byteArray = new byte[total];
in.read(byteArray);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (isClose) {
try {
in.close();
} catch (Exception e2) {
e2.getStackTrace();
}
}
}
return byteArray;
}
/**
* 将Object对象里面的属性和值转化成Map对象
*
* @param obj
* @return
* @throws IllegalAccessException
*/
public static Map<String, String> objectToMap(Object obj) throws IllegalAccessException {
Map<String, String> map = new HashMap<>();
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(obj);
if(!StringUtils.isEmpty(value)){
if(value instanceof String || value instanceof Integer){
map.put(fieldName, value.toString());
}else if(value instanceof Date){
map.put(fieldName, DateUtil.formatDate((Date)value,DateUtil.DATETIME));
}
//其它不转换,这里留着扩充使用
}else{
map.put(fieldName, "");
}
}
return map;
}
public static Map<String, Object> objectToMapTwo(Object obj) throws IllegalAccessException {
Map<String, Object> map = new HashMap<>();
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(obj);
map.put(fieldName, value);
}
return map;
}
}
SpringBoot中实现
@ApiOperation("导出PDF")
@RequestMapping(value = "/exportPdf", method = RequestMethod.GET)
public void exportPdfHttpServletResponse response) throws Exception {
BufferedOutputStream outputStream = null;
XWPFDocument doc = null;
try{
ExtFontFactory extFontFactory = new ExtFontFactory();
extFontFactory.registerDirectories();
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("docx/project.docx");
doc = new XWPFDocument(inputStream);
Map<String, String> params = new HashMap<>();
ProjectExportVo editvo = new ProjectExportVo();//获取业务数据,需要自己添加
params = WordToPdfUtil.objectToMap(editvo);
//(1)页眉替换
WordToPdfUtil.replaceXWPFHeaderParams(doc,params);
//(2)替换段落里面的变量
WordToPdfUtil.replaceParams(doc, params);
List<XWPFTable> tableList = doc.getTables();
//(3)表格替换:替换固定表格
WordToPdfUtil.replaceTableParams(doc,params,0);
WordToPdfUtil.replaceTableParams(doc,params,1);
//(4)表格List替换
List<Map<String,String>> mapList = new ArrayList<>();
//mapList = 获取业务数据
WordToPdfUtil.export(doc,mapList,3,1,1);
mapList.clear();
PdfOptions options = PdfOptions.create();
outputStream = new BufferedOutputStream(response.getOutputStream());
PdfConverter.getInstance().convert(doc, outputStream, options);
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment;filename="+UUID.randomUUID()+".pdf");
}catch (Exception ex){
ex.printStackTrace();
log.error("项目pdf文件下载失败. msg={}", ex.getMessage());
}finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (Exception e) {
log.error(e.getMessage());
}
}
if (doc !=null){
try {
doc.close();
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
}
word模板 页眉,正文,固定表格中的 ${projectNo}
动态表格
| 测试1 | 测试2 | 测试3 | 测试4 | 测试5 |
|---|---|---|---|---|
| ${ceshi1} | ${ceshi2} | ${ceshi3} | ${ceshi4} | ${ceshi5} |