接上文,本章介绍下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 {@Autowiredprivate 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 {@Autowiredprivate 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();//设置idctStyle.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 definedstyle.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 valuecell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);}else {// Cells which join (merge) the first one, are set with CONTINUEcell.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 valuecell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);}else {// Cells which join (merge) the first one, are set with CONTINUEcell.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的情况,这是一个很大的优化!

java word - 2:POI开发流程相关推荐

  1. Java笔记11-软件开发流程设计原则

    今天内容: 1.常用的设计原则 2.常用的设计模式 3.常用的查找算法 4.常用的排序算法 1.常用的设计原则(记住) 1.1软件的开发流程 软件开发授权-投标 -> 100万 1. 编写需求分 ...

  2. java word模板poi生成文件_poi读写word模板 / java生成word文档

    有一word文档表格 形如: 姓名 ${name} 电话 ${tel} 下载包链接:点击进入 从数据库读取记录替换上述变量 import java.io.FileOutputStream; impor ...

  3. java word apache poi 操作word模板。

    apache poi 操作word模板. 操作方式: 1.对于固定格,可以遍历格子然后替换其中指定的值例如在要替换的cell写入${example} 这样格式,遍历到之后替换. 2.对于需要增长的表格 ...

  4. java word模板poi生成文件_利用poi读取word模板文件生成新的word文档

    利用poi读取word模板文件生成新的word文档 利用poi读取word模板文件,并回填逻辑数据,生成并导出需要的word文档源码.解决模板读取异常问题,提供wordUtils工具类(各种功能实现) ...

  5. 理解透彻!java微信公众号开发流程

    01 蚂蚁金服面试题之MySQL 之前的阿里面试题都有做总结,具体面试题内容整理成了文档,本文是针对MySQL系列的,所以下面只展示了自己第一次面试阿里时被吊打问到的一些MySQL难题. 1.请解释关 ...

  6. java word搜索,实战 | Java读取Word,包含表格!

    本文转载自微信公众号「JAVA日知录」,作者单一色调.转载本文请联系JAVA日知录公众号. 不能每天都发鸡汤呀,今天分享一篇开发实战. 业务需求 我们有这样一个需求,需要抽取出WORD文档中的内容,然 ...

  7. JAVA - 使用Apache POI生成word(二) 设置纸张大小、调整纸张方向

    JAVA - 使用Apache POI生成word(二) 设置纸张大小.调整纸张方向 前言 之前开发时,需要将纸张方向由纵向改为横向,查询资料得出只需要设置一下纸张的长度与宽度便可实现相同的效果. 1 ...

  8. java word转html 乱码 poi,java word转html poi

    java word转html poi [2021-01-29 15:50:39]  简介: php去除nbsp的方法:首先创建一个PHP代码示例文件:然后通过"preg_replace(&q ...

  9. java se开发_JAVA_SE基础——3.Java程序的开发流程

    上一篇,写的是JAVA的环境变量的配置,今天我抽空写篇Java程序的开发流程,下面的教程是我结合书本和毕向东老师的视频写下的心的~ 在没有真正写Java程序前,首先需要了解Java程序的开发过程. S ...

最新文章

  1. 关于IT学习的老马私人订制服务
  2. RabbitMQ的五种工作方式详细
  3. js post中服务器500错误信息,node.js - Node Express Post 500(内部服务器错误)jquery-3.4.1.min.js - 堆栈内存溢出...
  4. java 内部类 抽象类_Java 内部类、匿名内部类、抽象类
  5. P_C_Brules
  6. 对话智能新高度:全面解读百度开放域对话模型PLATO
  7. javascript 函数属性prototype(转)
  8. 四年级计算机课程,信息技术(四年级)全部课程PPT课件.ppt
  9. linux 执行sh_linux下执行脚本 sh -x XXX.sh 调试中存在大量/r 的问题
  10. 动态调用object php,PHP动态调用,大家都来谈吧
  11. php 常用文件系统函数,PHP fileperms 文件系统函数
  12. 【python】python 爬虫(python抓取网站的图片)
  13. Android九宫格闪烁,js实现九宫格点击按钮随机三个格子闪烁,发生错误
  14. Spring框架整合多数据源 Mysql+oracle
  15. Pycharm取消双击shift出现搜索框
  16. linux 7- - watch,free,mpstat,vmstat,iostat,pidstat,df,du
  17. linux更改网卡缓存,Linux 网卡驱动学习(四)(缓存描述符 Buffer Description)
  18. 把电脑做成服务器系统,把电脑做成云盘服务器
  19. xp系统如何通过cmd运行命令符查看电脑配置的两种方法
  20. 看C++游戏程序员发展

热门文章

  1. 【智能优化算法】基于蚁狮算法求解多目标问题附Matlab代码
  2. 【GEE】基于MODIS产品的NPP NDVI EVI数据提取
  3. VisualStudio2015安装不上的解决方法_选择对应msi_依然报错继续选择---VisualStudio2015工作笔记001
  4. Ecshop商城系统二次开发视频教程
  5. 分段二次插值例题_二次样条插值[篇].doc
  6. 解决 Windows 10 更新错误代码 0x800f0922
  7. 排序算法(5)快速排序
  8. 判了!国内「最牛删库跑路事件」程序员被判6年,公司损失近十亿
  9. 考Adobe国际认证证书,要多少钱人民币?
  10. 菜鸟基础HTML学习