接上文,本章介绍下POI的开发流程
不同于Freemarker那样将模板和数据分离的方式,POI是没有模板的,模板和数据是糅合在一起的。
POI的开发流程其实网上教程都比较多了,我这边就将我写好的工具类贴在这里,大家自取
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<!-- poi处理xlsx格式,用于处理word中的表格 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-excelant</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
<!-- poi-tl基于poi的word模板引擎 -->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
package com.shr.service.inspect.util.word;
import com.deepoove.poi.data.MiniTableRenderData;
import com.deepoove.poi.util.TableTools;
import com.shr.service.inspect.entity.task.word.BasicInfoEntity;
import com.shr.service.inspect.entity.task.word.ResultItemEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHeightRule;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
@Slf4j
public class GeneratePoiWord {
@Autowired
private DocUtil docUtil;
private static final int TABLE_WIDTH = 13698;
private static List<TableHeadEntity> pointTableColHeads = new ArrayList<>();
private void initPointTableColHeads()
{
pointTableColHeads.add(TableHeadEntity.builder().title("序号").width(740).build());
pointTableColHeads.add(TableHeadEntity.builder().title("点位名称").width(1058).build());
pointTableColHeads.add(TableHeadEntity.builder().title("设备类型").width(1058).build());
pointTableColHeads.add(TableHeadEntity.builder().title("设备部件").width(1058).build());
pointTableColHeads.add(TableHeadEntity.builder().title("巡检时间").width(1058).build());
pointTableColHeads.add(TableHeadEntity.builder().title("巡检结果").width(1058).build());
pointTableColHeads.add(TableHeadEntity.builder().title("人工确认结果").width(1058).build());
pointTableColHeads.add(TableHeadEntity.builder().title("巡检图片").width(5000).build());
pointTableColHeads.add(TableHeadEntity.builder().title("审核状态").width(1058).build());
}
public void createWordDocument(Map<String, Object> root, File outFile)
{
if (Objects.isNull(root)) {
log.error("--- createWordDocument root is null");
return;
}
log.info("--- createWordDocument start");
// new 空白的文档
XWPFDocument doc = new XWPFDocument();
FileOutputStream out = null;
try {
initPointTableColHeads();
out = new FileOutputStream(outFile);
//将word排版设置成横向
docUtil.setPageSize(doc, 16840, 11907);
XWPFStyles newStyles = doc.createStyles();
String firstTitle = "My Heading 1";
docUtil.createHeadingStyle(newStyles, firstTitle, 1, 52, "000000", "楷体_GB2312");
String secondTitle = "My Heading 2";
docUtil.createHeadingStyle(newStyles, secondTitle, 1, 24, "000000", "楷体_GB2312");
BasicInfoEntity basicInfo = (BasicInfoEntity) root.get("basicInfo");
if (Objects.isNull(basicInfo)) {
log.error("--- createWordDocument basicInfo is null");
return;
}
docUtil.createFirstTitle(doc, firstTitle, basicInfo.getTitle(), true);
docUtil.createSecondTitle(doc, secondTitle, "一、概述", true);
createBaseInfoTable(doc, basicInfo);
docUtil.createSecondTitle(doc, secondTitle, "二、异常点位结果", true);
List<List<ResultItemEntity>> abnormalList = (List) root.get("abnormalList");
if (CollectionUtils.isEmpty(abnormalList)) {
docUtil.createContent(doc, "无", true);
}
else {
int abnormalNum = (int) root.get("abnormalNum");
creatTable(doc, abnormalList, abnormalNum);
}
docUtil.createSecondTitle(doc, secondTitle, "三、失败点位结果", true);
List<List<ResultItemEntity>> failList = (List) root.get("failList");
if (CollectionUtils.isEmpty(failList)) {
docUtil.createContent(doc, "无", true);
}
else {
int failNum = (int) root.get("failNum");
creatTable(doc, failList, failNum);
}
docUtil.createSecondTitle(doc, secondTitle, "四、正常点位结果", true);
List<List<ResultItemEntity>> normalList = (List) root.get("normalList");
if (CollectionUtils.isEmpty(normalList)) {
docUtil.createContent(doc, "无", true);
}
else {
int normalNum = (int) root.get("normalNum");
creatTable(doc, normalList, normalNum);
}
doc.write(out);
out.close();
} catch (Exception e) {
log.error("-- CreateWordDocument error, {}", e.getMessage());
} finally {
try {
if (Objects.nonNull(doc)) {
doc.close();
}
if (Objects.nonNull(out)) {
out.close();
}
} catch (Exception e1) {
}
}
}
private void createBaseInfoTable(XWPFDocument doc, BasicInfoEntity basicInfo)
{
//创建一个表格,并指定宽度
XWPFTable infoTable = doc.createTable(6, 4);
TableTools.widthTable(infoTable, MiniTableRenderData.WIDTH_A4_FULL, 4);
infoTable.getCTTbl().getTblPr().getTblW().setType(STTblWidth.DXA);
infoTable.getCTTbl().getTblPr().getTblW().setW(BigInteger.valueOf(TABLE_WIDTH));
CTJc ctJc = infoTable.getCTTbl().getTblPr().addNewJc();
ctJc.setVal(STJc.CENTER);
List<XWPFTableRow> rows = infoTable.getRows();
for (int i = 0; i < rows.size(); i++) {
XWPFTableRow row = rows.get(i);
//设置每一行的高度和居中
row.getCtRow().addNewTrPr().addNewTrHeight().setVal(BigInteger.valueOf(750));
row.getCtRow().addNewTrPr().addNewTrHeight().setHRule(STHeightRule.AT_LEAST);
row.getCtRow().addNewTrPr().addNewJc().setVal(STJc.CENTER);
//设置每一列的宽度和居中
row.getTableCells().get(0).getCTTc().addNewTcPr().addNewTcW().setType(STTblWidth.DXA);
row.getTableCells().get(0).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(2519));
row.getTableCells().get(0).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);
//设置单元格背景颜色
row.getTableCells().get(0).getCTTc().addNewTcPr().addNewShd().setVal(STShd.CLEAR);
row.getTableCells().get(0).getCTTc().addNewTcPr().addNewShd().setColor("auto");
row.getTableCells().get(0).getCTTc().addNewTcPr().addNewShd().setFill("C5E0B3");
// row.getTableCells().get(0).getCTTc().addNewTcPr().addNewShd().setThemeFill(STThemeColor.ACCENT_6);
// row.getTableCells().get(0).getCTTc().addNewTcPr().addNewShd().setThemeFillTint(intToByteArray(66));
row.getTableCells().get(1).getCTTc().addNewTcPr().addNewTcW().setType(STTblWidth.DXA);
row.getTableCells().get(1).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(4126));
row.getTableCells().get(1).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);
row.getTableCells().get(2).getCTTc().addNewTcPr().addNewTcW().setType(STTblWidth.DXA);
row.getTableCells().get(2).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(2407));
row.getTableCells().get(2).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);
row.getTableCells().get(2).getCTTc().addNewTcPr().addNewShd().setVal(STShd.CLEAR);
row.getTableCells().get(2).getCTTc().addNewTcPr().addNewShd().setColor("auto");
row.getTableCells().get(2).getCTTc().addNewTcPr().addNewShd().setFill("C5E0B3");
// row.getTableCells().get(2).getCTTc().addNewTcPr().addNewShd().setThemeFill(STThemeColor.ACCENT_6);
// row.getTableCells().get(2).getCTTc().addNewTcPr().addNewShd().setThemeFillTint(intToByteArray(66));
row.getTableCells().get(3).getCTTc().addNewTcPr().addNewTcW().setType(STTblWidth.DXA);
row.getTableCells().get(3).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(4646));
row.getTableCells().get(3).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);
}
//将表格的单元格进行合并:从第六行的第二列到第四列进行合并;合并后的单元格,算做此行的第二列
docUtil.mergeCellsHorizontal(infoTable, 5, 1, 3);
//设置第1行数据
docUtil.setTableCell(rows.get(0).getTableCells().get(0), "变电站");
docUtil.setTableCell(rows.get(0).getTableCells().get(1), basicInfo.getUnit());
docUtil.setTableCell(rows.get(0).getTableCells().get(2), "任务名称");
docUtil.setTableCell(rows.get(0).getTableCells().get(3), basicInfo.getTaskName());
//设置第2行数据
docUtil.setTableCell(rows.get(1).getTableCells().get(0), "开始时间");
docUtil.setTableCell(rows.get(1).getTableCells().get(1), basicInfo.getTaskStartTime());
docUtil.setTableCell(rows.get(1).getTableCells().get(2), "结束时间");
docUtil.setTableCell(rows.get(1).getTableCells().get(3), basicInfo.getTaskEndTime());
//设置第3行数据
docUtil.setTableCell(rows.get(2).getTableCells().get(0), "审核人员");
docUtil.setTableCell(rows.get(2).getTableCells().get(1), basicInfo.getAuditor());
docUtil.setTableCell(rows.get(2).getTableCells().get(2), "审核时间");
docUtil.setTableCell(rows.get(2).getTableCells().get(3), basicInfo.getAuditTime());
//设置第4行数据
docUtil.setTableCell(rows.get(3).getTableCells().get(0), "任务巡视点总数");
docUtil.setTableCell(rows.get(3).getTableCells().get(1), basicInfo.getPointTotal() + "");
docUtil.setTableCell(rows.get(3).getTableCells().get(2), "正常巡视点数");
docUtil.setTableCell(rows.get(3).getTableCells().get(3), basicInfo.getNormalNum() + "");
//设置第5行数据
docUtil.setTableCell(rows.get(4).getTableCells().get(0), "告警巡视点数");
docUtil.setTableCell(rows.get(4).getTableCells().get(1), basicInfo.getAlarmNum() + "");
docUtil.setTableCell(rows.get(4).getTableCells().get(2), "失败巡视点数");
docUtil.setTableCell(rows.get(4).getTableCells().get(3), basicInfo.getFailNum() + "");
//设置第5行数据
docUtil.setTableCell(rows.get(5).getTableCells().get(0), "当前天气");
docUtil.setTableCell(rows.get(5).getTableCells().get(1), basicInfo.getMicroclimateData());
}
private void creatTable(XWPFDocument doc, List<List<ResultItemEntity>> listList, int rowsCount)
{
int colCount = 9; //列数
// File file = new File("E:\\11\\image\\pre_image");//File类型可以是文件也可以是文件夹
// File[] files = file.listFiles();
// rowsCount = 3000;//行数
XWPFTable infoTable = doc.createTable(rowsCount + 1, colCount);
TableTools.widthTable(infoTable, MiniTableRenderData.WIDTH_A4_FULL, 4);
infoTable.getCTTbl().getTblPr().getTblW().setType(STTblWidth.DXA);
infoTable.getCTTbl().getTblPr().getTblW().setW(BigInteger.valueOf(TABLE_WIDTH));
CTJc ctJc1 = infoTable.getCTTbl().getTblPr().addNewJc();
ctJc1.setVal(STJc.CENTER);
List<XWPFTableRow> rows = infoTable.getRows();
XWPFTableRow firstRow = rows.get(0);
for (int w = 0; w < pointTableColHeads.size(); w++) {
TableHeadEntity tableHeadEntity = pointTableColHeads.get(w);
firstRow.getTableCells().get(w).getCTTc().addNewTcPr().addNewTcW().setType(STTblWidth.DXA);
firstRow.getTableCells().get(w).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(tableHeadEntity.getWidth()));
firstRow.getTableCells().get(w).getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);
firstRow.getCtRow().addNewTrPr().addNewTrHeight().setVal(BigInteger.valueOf(750));
firstRow.getCtRow().addNewTrPr().addNewTrHeight().setHRule(STHeightRule.AT_LEAST);
firstRow.getCtRow().addNewTrPr().addNewJc().setVal(STJc.CENTER);
docUtil.setPointTableCell(firstRow.getTableCells().get(w), tableHeadEntity.getTitle(), true);
}
int currentRow = 0;
int fromRow = 1;
for (List<ResultItemEntity> list : listList) {
int toRow = fromRow + list.size();
docUtil.mergeCellsVertically(infoTable, 0, fromRow, toRow);
docUtil.mergeCellsVertically(infoTable, 1, fromRow, toRow);
docUtil.mergeCellsVertically(infoTable, 2, fromRow, toRow);
docUtil.mergeCellsVertically(infoTable, 3, fromRow, toRow);
docUtil.mergeCellsVertically(infoTable, 4, fromRow, toRow);
fromRow = toRow;
for (ResultItemEntity resultItemEntity : list) {
currentRow++;
log.info("----" + currentRow);
XWPFTableRow row = rows.get(currentRow);
row.getCtRow().addNewTrPr().addNewTrHeight().setVal(BigInteger.valueOf(750));
row.getCtRow().addNewTrPr().addNewTrHeight().setHRule(STHeightRule.AT_LEAST);
row.getCtRow().addNewTrPr().addNewJc().setVal(STJc.CENTER);
docUtil.setPointTableCell(row.getTableCells().get(0), resultItemEntity.getIndex(), false);
docUtil.setPointTableCell(row.getTableCells().get(1), resultItemEntity.getPointName(), false);
docUtil.setPointTableCell(row.getTableCells().get(2), resultItemEntity.getDeviceType(), false);
docUtil.setPointTableCell(row.getTableCells().get(3), resultItemEntity.getComponentName(), false);
docUtil.setPointTableCell(row.getTableCells().get(4), resultItemEntity.getExecuteTime(), false);
docUtil.setPointTableCell(row.getTableCells().get(5), resultItemEntity.getTaskResult(), false);
docUtil.setPointTableCell(row.getTableCells().get(6), resultItemEntity.getManualConfirmResult(), false);
docUtil.setCellImage(row.getTableCells().get(7), resultItemEntity.getImageUrl());
docUtil.setPointTableCell(row.getTableCells().get(8), resultItemEntity.getAuditStatus(), false);
}
}
}
}
package com.shr.service.inspect.util.word;
import com.shr.service.inspect.entity.common.ConstantInterface;
import com.shr.service.inspect.util.file.FileManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFStyle;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTColor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageSz;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STPageOrientation;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@Component
@Slf4j
public class DocUtil {
@Autowired
private FileManager fileManager;
/**
* 设置纸张大小
*
* @param document doc对象
* @param width 宽
* @param height 长
*/
public void setPageSize(XWPFDocument document, long width, long height)
{
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
CTPageSz pgsz = sectPr.isSetPgSz() ? sectPr.getPgSz() : sectPr.addNewPgSz();
pgsz.setW(BigInteger.valueOf(width));
pgsz.setH(BigInteger.valueOf(height));
pgsz.setOrient(STPageOrientation.LANDSCAPE);
}
/**
* @param styles
* @param strStyleId 标题id
* @param headingLevel 标题级别
* @param pointSize 字体大小(/2)
* @param hexColor 字体颜色
* @param typefaceName 字体名称(默认宋体)
*/
public void createHeadingStyle(XWPFStyles styles, String strStyleId, int headingLevel, int pointSize, String hexColor, String typefaceName)
{
//创建样式
CTStyle ctStyle = CTStyle.Factory.newInstance();
//设置id
ctStyle.setStyleId(strStyleId);
CTString styleName = CTString.Factory.newInstance();
styleName.setVal(strStyleId);
ctStyle.setName(styleName);
CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
indentNumber.setVal(BigInteger.valueOf(headingLevel));
// 数字越低在格式栏中越突出
ctStyle.setUiPriority(indentNumber);
CTOnOff onoffnull = CTOnOff.Factory.newInstance();
ctStyle.setUnhideWhenUsed(onoffnull);
// 样式将显示在“格式”栏中
ctStyle.setQFormat(onoffnull);
// 样式定义给定级别的标题
CTPPr ppr = CTPPr.Factory.newInstance();
ppr.setOutlineLvl(indentNumber);
ctStyle.setPPr(ppr);
XWPFStyle style = new XWPFStyle(ctStyle);
CTHpsMeasure size = CTHpsMeasure.Factory.newInstance();
size.setVal(new BigInteger(String.valueOf(pointSize)));
CTHpsMeasure size2 = CTHpsMeasure.Factory.newInstance();
size2.setVal(new BigInteger(String.valueOf(pointSize)));
CTFonts fonts = CTFonts.Factory.newInstance();
if (typefaceName == null || typefaceName.equals("")) {
typefaceName = "宋体";
}
fonts.setAscii(typefaceName); //字体
fonts.setEastAsia(typefaceName); //中文字体
CTRPr rpr = CTRPr.Factory.newInstance();
rpr.setRFonts(fonts);
rpr.setSz(size);
rpr.setSzCs(size2); //字体大小
CTColor color = CTColor.Factory.newInstance();
color.setVal(hexToBytes(hexColor));
rpr.setColor(color); //字体颜色
style.getCTStyle().setRPr(rpr);
// is a null op if already defined
style.setType(STStyleType.PARAGRAPH);
styles.addStyle(style);
}
public static byte[] hexToBytes(String hexString)
{
HexBinaryAdapter adapter = new HexBinaryAdapter();
byte[] bytes = adapter.unmarshal(hexString);
return bytes;
}
public void setTableCell(XWPFTableCell cell01, String text)
{
int fontSize = 11;
String fontFamily = "楷体_GB2312";
ParagraphAlignment alignment = ParagraphAlignment.LEFT;
boolean isBold = false;
CTP ctP = (cell01.getCTTc().sizeOfPArray() == 0) ? cell01.getCTTc().addNewP() : cell01.getCTTc().getPArray(0);
XWPFParagraph p = cell01.getParagraph(ctP);
XWPFRun headRun0 = p.createRun();
headRun0.setText(" " + text);
headRun0.setFontSize(fontSize);
p.setAlignment(alignment);
headRun0.setFontFamily(fontFamily);
headRun0.setBold(isBold);//是否粗体
}
public void setPointTableCell(XWPFTableCell cell01, String text, boolean isBold)
{
int fontSize = 9;
String fontFamily = "宋体 (正文)";
ParagraphAlignment alignment = ParagraphAlignment.CENTER;
CTP ctP = (cell01.getCTTc().sizeOfPArray() == 0) ? cell01.getCTTc().addNewP() : cell01.getCTTc().getPArray(0);
//单元格内容垂直居中
cell01.getCTTc().addNewTcPr().addNewVAlign().setVal(STVerticalJc.CENTER);
XWPFParagraph p = cell01.getParagraph(ctP);
XWPFRun headRun0 = p.createRun();
headRun0.setText(text);
headRun0.setFontSize(fontSize);
p.setAlignment(alignment);
headRun0.setFontFamily(fontFamily);
headRun0.setBold(isBold);//是否粗体
}
/**
* 合并单元格
*
* @param table 表格对象
* @param beginRowIndex 开始行索引
* @param endRowIndex 结束行索引
* @param colIndex 合并列索引
*/
public void mergeRowCell(XWPFTable table, int beginRowIndex, int endRowIndex, int colIndex)
{
try {
if (beginRowIndex == endRowIndex || beginRowIndex > endRowIndex) {
return;
}
//合并行单元格的第一个单元格
CTVMerge startMerge = CTVMerge.Factory.newInstance();
startMerge.setVal(STMerge.RESTART);
//合并行单元格的第一个单元格之后的单元格
CTVMerge endMerge = CTVMerge.Factory.newInstance();
endMerge.setVal(STMerge.CONTINUE);
table.getRow(beginRowIndex).getCell(colIndex).getCTTc().getTcPr().setVMerge(startMerge);
for (int i = beginRowIndex + 1; i <= endRowIndex; i++) {
table.getRow(i).getCell(colIndex).getCTTc().getTcPr().setVMerge(endMerge);
}
} catch (Exception e) {
log.error("-- mergeRowCell error, {}", e.getMessage());
}
}
/**
* word跨列合并单元格
* table 表单对象
* row 合并行
* fromCell 起始列
* toCell 结束列
*/
public void mergeCellsHorizontal(XWPFTable table, Integer row, Integer fromCell, Integer toCell)
{
try {
for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
if (cellIndex == fromCell) {
// The first merged cell is set with RESTART merge value
cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
}
else {
// Cells which join (merge) the first one, are set with CONTINUE
cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
}
}
} catch (Exception e) {
log.error("--- mergeCellsHorizontal error, {}", e.getMessage());
}
}
/**
* 跨行合并单元格
*
* @param table 表单对象
* @param col 合并列
* @param fromRow 起始行
* @param toRow 结束行
*/
public void mergeCellsVertically(XWPFTable table, Integer col, Integer fromRow, Integer toRow)
{
try {
for (int rowIndex = fromRow; rowIndex < toRow; rowIndex++) {
XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
if (rowIndex == fromRow) {
// The first merged cell is set with RESTART merge value
cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
}
else {
// Cells which join (merge) the first one, are set with CONTINUE
cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
}
}
} catch (Exception e) {
log.error("--- mergeCellsVertically error, {}", e.getMessage());
}
}
/**
* 设置一级标题
*
* @param doc
* @param secondTitle
* @param title
* @param isBold
*/
public void createFirstTitle(XWPFDocument doc, String secondTitle, String title, boolean isBold)
{
try {
XWPFParagraph para = doc.createParagraph();
para.setAlignment(ParagraphAlignment.CENTER); //标题设置水平居中
para.setStyle(secondTitle);
XWPFRun run2 = para.createRun();
run2.setText(title);
run2.setBold(isBold);
} catch (Exception e) {
log.error("--- createFirstTitle error, {}", e.getMessage());
}
}
/**
* 设置二级标题
*
* @param doc
* @param secondTitle
* @param title
* @param isBold
*/
public void createSecondTitle(XWPFDocument doc, String secondTitle, String title, boolean isBold)
{
try {
XWPFParagraph para = doc.createParagraph();
para.createRun().addBreak();
para.setStyle(secondTitle);
XWPFRun run2 = para.createRun();
run2.setText(title);
run2.setBold(isBold);
} catch (Exception e) {
log.error("--- createSecondTitle error, {}", e.getMessage());
}
}
/**
* 设置正文
*
* @param doc
* @param title
* @param isBold
*/
public void createContent(XWPFDocument doc, String title, boolean isBold)
{
try {
XWPFParagraph para = doc.createParagraph();
para.createRun().addBreak();
XWPFRun run2 = para.createRun();
run2.setText(title);
run2.setBold(isBold);
run2.setFontFamily("楷体_GB2312");
} catch (Exception e) {
log.error("--- createSecondTitle error, {}", e.getMessage());
}
}
private void copyFileUsingFileStreams(File source, File dest)
throws IOException
{
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(source);
output = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buf)) > 0) {
output.write(buf, 0, bytesRead);
}
} finally {
input.close();
output.close();
}
}
/**
* 单元格写入图片
*
* @param cell
* @param url
* @throws IOException
*/
public void setCellImage(XWPFTableCell cell, String url)
{
InputStream in = null;
try {
List<XWPFParagraph> paragraphs = cell.getParagraphs();
XWPFParagraph newPara = paragraphs.get(0);
XWPFRun imageCellRunn = newPara.createRun();
newPara.setAlignment(ParagraphAlignment.CENTER);
String newFileName = UUID.randomUUID().toString();
File newFile = File.createTempFile(newFileName, ConstantInterface.PNG_SUFFIX);
if (StringUtils.isBlank(url) || url.split(ConstantInterface.SPACE_SEPARATOR).length != 2) {
return;
}
String[] split = url.split(ConstantInterface.SPACE_SEPARATOR);
String fileName = split[1];
in = fileManager.getFile(split[0], fileName);
int format;
if (url.endsWith(".emf")) {
format = XWPFDocument.PICTURE_TYPE_EMF;
}
else if (url.endsWith(".wmf")) {
format = XWPFDocument.PICTURE_TYPE_WMF;
}
else if (url.endsWith(".pict")) {
format = XWPFDocument.PICTURE_TYPE_PICT;
}
else if (url.endsWith(".jpeg") || url.endsWith(".jpg")) {
format = XWPFDocument.PICTURE_TYPE_JPEG;
}
else if (url.endsWith(".png")) {
format = XWPFDocument.PICTURE_TYPE_PNG;
}
else if (url.endsWith(".dib")) {
format = XWPFDocument.PICTURE_TYPE_DIB;
}
else if (url.endsWith(".gif")) {
format = XWPFDocument.PICTURE_TYPE_GIF;
}
else if (url.endsWith(".tiff")) {
format = XWPFDocument.PICTURE_TYPE_TIFF;
}
else if (url.endsWith(".eps")) {
format = XWPFDocument.PICTURE_TYPE_EPS;
}
else if (url.endsWith(".bmp")) {
format = XWPFDocument.PICTURE_TYPE_BMP;
}
else if (url.endsWith(".wpg")) {
format = XWPFDocument.PICTURE_TYPE_WPG;
}
else {
log.error("Unsupported picture: " + url + ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
return;
}
imageCellRunn.addPicture(in, format, newFile.getName(), Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
} catch (Exception e) {
log.error("--- setCellImage error, {}", e.getMessage());
} finally {
try {
if (Objects.nonNull(in)) {
in.close();
}
} catch (Exception e1) {
}
}
}
/**
* 单元格写入图片
*
* @param cell
* @param file
*/
public void setCellImageFromFile(XWPFTableCell cell, File file)
{
try {
List<XWPFParagraph> paragraphs = cell.getParagraphs();
XWPFParagraph newPara = paragraphs.get(0);
XWPFRun imageCellRunn = newPara.createRun();
newPara.setAlignment(ParagraphAlignment.CENTER);
if (!file.exists()) {
return;
}
String url = file.getPath();
int format;
if (url.endsWith(".emf")) {
format = XWPFDocument.PICTURE_TYPE_EMF;
}
else if (url.endsWith(".wmf")) {
format = XWPFDocument.PICTURE_TYPE_WMF;
}
else if (url.endsWith(".pict")) {
format = XWPFDocument.PICTURE_TYPE_PICT;
}
else if (url.endsWith(".jpeg") || url.endsWith(".jpg")) {
format = XWPFDocument.PICTURE_TYPE_JPEG;
}
else if (url.endsWith(".png")) {
format = XWPFDocument.PICTURE_TYPE_PNG;
}
else if (url.endsWith(".dib")) {
format = XWPFDocument.PICTURE_TYPE_DIB;
}
else if (url.endsWith(".gif")) {
format = XWPFDocument.PICTURE_TYPE_GIF;
}
else if (url.endsWith(".tiff")) {
format = XWPFDocument.PICTURE_TYPE_TIFF;
}
else if (url.endsWith(".eps")) {
format = XWPFDocument.PICTURE_TYPE_EPS;
}
else if (url.endsWith(".bmp")) {
format = XWPFDocument.PICTURE_TYPE_BMP;
}
else if (url.endsWith(".wpg")) {
format = XWPFDocument.PICTURE_TYPE_WPG;
}
else {
log.error("Unsupported picture: " + url + ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg");
return;
}
FileInputStream is = new FileInputStream(url);
imageCellRunn.addPicture(is, format, file.getName(), Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
} catch (Exception e) {
log.error("--- setCellImageFromFile error, {}", e.getMessage());
}
}
}
我总结下POI的优缺点:
先说缺点:
1.需要把数据和模板糅合在一起,两者强关联;
2.POI的文档效果不像Freemarker那么方便,一些单元格合并、单元格底色、页边距这些,都要自己在代码里写死,如果要二次修改,就需要自己在代码里进行修改,查看效果也要通过重复生成新文件来验证,很不方便。
优点:
1.文件小!打开快!这是POI的最大的优势!我做过实验,发现,如果我重复插入相同的图片,POI自身会做优化,生成的文件解析成xml后发现,它会把相同的图片只保存一份,哪怕图片来源于不同的文件,它也会只保存一份,这是非常恐怖的。
下图里,文件名里的数字代表的是塞入的相同图片数量,可以看到,在单张图片size是591KB的情况下,1000张图片的文件是645K,2000张图片是701K,3000张图片是758K,文件大小几乎没有增长。这对于特殊场景的需求,还是有很大优化的。
下图是塞入不同图片的情况,可以看到生成的文件大小也非常的小,而且打开速度也很快。
对于使用Freemarker生成的文件,动辄300M的,多则800M的情况,这是一个很大的优化!