lau572
8 months ago
8 changed files with 1766 additions and 0 deletions
File diff suppressed because it is too large
@ -0,0 +1,369 @@ |
|||
package com.zc.business.utils; |
|||
|
|||
import com.aliyuncs.utils.IOUtils; |
|||
import com.google.common.base.Strings; |
|||
import org.apache.poi.openxml4j.opc.OPCPackage; |
|||
import org.apache.poi.ss.util.CellRangeAddress; |
|||
import org.apache.poi.ss.util.CellReference; |
|||
import org.apache.poi.xddf.usermodel.chart.XDDFChartData; |
|||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource; |
|||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory; |
|||
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource; |
|||
import org.apache.poi.xssf.usermodel.XSSFSheet; |
|||
import org.apache.poi.xwpf.usermodel.*; |
|||
import org.apache.xmlbeans.XmlOptions; |
|||
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea; |
|||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import java.io.*; |
|||
import java.math.BigInteger; |
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @author : LCheng |
|||
* @date : 2020-12-10 10:03 |
|||
* description : poi工具 |
|||
*/ |
|||
public class PoiUtil { |
|||
|
|||
public static int headingCount1 = 1; |
|||
public static int headingCount2 = 1; |
|||
|
|||
/** |
|||
* 根据word模板导出 针对图表(柱状图,折线图,饼图等)的处理 |
|||
* |
|||
* @param docChart 图表对象 |
|||
* @param title 图表标题 |
|||
* @param seriesNames 系列名称数组 |
|||
* @return {@link XWPFChart} |
|||
* @author LCheng |
|||
* @date 2020/12/10 11:08 |
|||
*/ |
|||
public static XWPFChart wordExportChar(XWPFChart docChart, String title, String[] seriesNames, XSSFSheet sheet) { |
|||
//获取图表数据对象
|
|||
XDDFChartData chartData = docChart.getChartSeries().get(0); |
|||
|
|||
//word图表均对应一个内置的excel,用于保存图表对应的数据
|
|||
//excel中 第一列第二行开始的数据为分类信息
|
|||
//CellRangeAddress(1, categories.size(), 0, 0) 四个参数依次为 起始行 截止行 起始列 截止列。
|
|||
//根据分类信息的范围创建分类信息的数据源
|
|||
XDDFDataSource catDataSource = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(1,sheet.getLastRowNum(),0,0)); |
|||
//更新数据
|
|||
for (int i = 0; i < seriesNames.length; i++) { |
|||
//excel中各系列对应的数据的范围
|
|||
//根据数据的范围创建值的数据源
|
|||
XDDFNumericalDataSource<Double> valDataSource = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1,sheet.getLastRowNum(),i+1,i+1)); |
|||
//获取图表系列的数据对象
|
|||
XDDFChartData.Series series = chartData.getSeries().get(i); |
|||
//替换系列数据对象中的分类和值
|
|||
series.replaceData(catDataSource, valDataSource); |
|||
//修改系列数据对象中的标题
|
|||
CellReference cellReference = docChart.setSheetTitle(seriesNames[i], 1); |
|||
series.setTitle(seriesNames[i], cellReference); |
|||
} |
|||
//更新图表数据对象
|
|||
docChart.plot(chartData); |
|||
//图表整体的标题 传空值则不替换标题
|
|||
if (!Strings.isNullOrEmpty(title)) { |
|||
docChart.setTitleText(title); |
|||
docChart.setTitleOverlay(false); |
|||
} |
|||
return docChart; |
|||
} |
|||
|
|||
/** |
|||
* 合并docx文件 |
|||
* @param srcDocxs 需要合并的目标docx文件 |
|||
* @param destDocx 合并后的docx输出文件 |
|||
*/ |
|||
public static void mergeDoc(XWPFDocument srcDocxs, XWPFDocument destDocx) { |
|||
|
|||
|
|||
try { |
|||
|
|||
//获取目标文件的CTDocument1对象
|
|||
CTDocument1 ctDocument1 = srcDocxs.getDocument(); |
|||
//获取第一个目标文件的CTBody对象
|
|||
CTBody src1Body = ctDocument1.getBody(); |
|||
|
|||
|
|||
//获取目标文件中的图表
|
|||
List<XWPFChart> relations = srcDocxs.getCharts(); |
|||
//判断是否有图表,没有图表的话,追加到之前的目标文件后面
|
|||
if (relations.size() <= 0) { |
|||
CTBody src2Body = srcDocxs.getDocument().getBody(); |
|||
//获取目标文件中的图片
|
|||
List<XWPFPictureData> allPictures = srcDocxs.getAllPictures(); |
|||
// 记录图片合并前及合并后的ID
|
|||
Map<String,String> map = new HashMap(); |
|||
//遍历图片
|
|||
for (XWPFPictureData picture : allPictures) { |
|||
String before = srcDocxs.getRelationId(picture); |
|||
//将原文档中的图片加入到目标文档中
|
|||
String after = destDocx.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG); |
|||
map.put(before, after); |
|||
} |
|||
//将当前文件的内容追加到之前的目标文件中
|
|||
appendBody(src1Body, src2Body,map); |
|||
} |
|||
//遍历图表,
|
|||
for (XWPFChart chart1 : relations) { |
|||
//是否是word中自带图表
|
|||
if (chart1 instanceof XWPFChart) { // 如果是图表元素
|
|||
XWPFChart chart = destDocx.createChart(5774310, 3076575); |
|||
CTPlotArea plotArea = chart1.getCTChart().getPlotArea(); |
|||
chart.getCTChart().setPlotArea(plotArea); |
|||
chart.getCTChart().setLegend(chart1.getCTChart().getLegend()); |
|||
} |
|||
} |
|||
//关闭流
|
|||
srcDocxs.close(); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 合并chart |
|||
* @param chart 需要合并的目标chart |
|||
* @param destDocx 合并后的docx输出文件 |
|||
*/ |
|||
public static void mergeChart(XWPFChart chart, XWPFDocument destDocx) { |
|||
try { |
|||
|
|||
XWPFChart docxChart = destDocx.createChart(5774310, 3076575); |
|||
CTPlotArea plotArea = chart.getCTChart().getPlotArea(); |
|||
docxChart.getCTChart().setPlotArea(plotArea); |
|||
docxChart.getCTChart().setLegend(chart.getCTChart().getLegend()); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 插入换行符 |
|||
* @param destDocx 合并后的docx输出文件 |
|||
*/ |
|||
public static void createLineBreak(XWPFDocument destDocx) { |
|||
try { |
|||
|
|||
XWPFParagraph paragraph = destDocx.createParagraph(); |
|||
XWPFRun run = paragraph.createRun(); |
|||
run.addBreak(); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 合并文档内容 |
|||
* |
|||
* @param src 目标文档 |
|||
* @param append 要合并的文档 |
|||
* @throws Exception |
|||
*/ |
|||
private static void appendBody(CTBody src, CTBody append,Map<String,String> map) throws Exception { |
|||
XmlOptions optionsOuter = new XmlOptions(); |
|||
optionsOuter.setSaveOuter(); |
|||
//获取目标文件的字符内容
|
|||
String srcString = src.xmlText(); |
|||
//获取目标文件字符的开头
|
|||
String prefix = srcString.substring(0, srcString.indexOf(">") + 1); |
|||
//获取目标文件字符的内容
|
|||
String mainPart = srcString.substring(srcString.indexOf(">") + 1, |
|||
srcString.lastIndexOf("<")); |
|||
//获取目标文件字符的结尾
|
|||
String sufix = srcString.substring(srcString.lastIndexOf("<")); |
|||
//获取需要追加的文件
|
|||
String appendString = append.xmlText(optionsOuter); |
|||
//获取需要追加的文件内容(除去头和尾)
|
|||
String addPart = appendString.substring(appendString.indexOf(">") + 1, |
|||
appendString.lastIndexOf("<")); |
|||
if (map != null && !map.isEmpty()) { |
|||
//对xml字符串中图片ID进行替换
|
|||
for (Map.Entry<String, String> set : map.entrySet()) { |
|||
addPart = addPart.replace(set.getKey(), set.getValue()); |
|||
} |
|||
} |
|||
//将获取到的文件内容合并成为新的CTBody
|
|||
CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart |
|||
+ sufix); |
|||
//将新的CTBody重新设置到目标文件中
|
|||
src.set(makeBody); |
|||
} |
|||
|
|||
public static XWPFParagraph createHeading(XWPFDocument doc, String title) { |
|||
//段落
|
|||
XWPFParagraph paragraph = doc.createParagraph(); |
|||
XWPFRun run = paragraph.createRun(); |
|||
run.setText(title); |
|||
// run.setColor("696969");
|
|||
run.setFontSize(18); |
|||
run.setBold(true);//标题加粗
|
|||
return paragraph; |
|||
} |
|||
|
|||
/** |
|||
* 创建标题1 |
|||
* |
|||
* @param doc |
|||
* @param title |
|||
*/ |
|||
public static void createHeading1(XWPFDocument doc, String title) { |
|||
//段落
|
|||
XWPFParagraph paragraph = doc.createParagraph(); |
|||
XWPFRun run = paragraph.createRun(); |
|||
run.setText(title); |
|||
// run.setColor("696969");
|
|||
run.setFontSize(16); |
|||
run.setBold(true);//标题加粗
|
|||
paragraph.setStyle("Heading1"); |
|||
} |
|||
|
|||
/** |
|||
* 创建标题2 |
|||
* |
|||
* @param doc |
|||
* @param title |
|||
*/ |
|||
public static void createHeading2(XWPFDocument doc, String title) { |
|||
XWPFParagraph paragraph = doc.createParagraph(); |
|||
XWPFRun run = paragraph.createRun(); |
|||
run.setText(title); |
|||
run.setFontSize(14); |
|||
run.setBold(true);//标题加粗
|
|||
paragraph.setStyle("Heading2"); |
|||
} |
|||
|
|||
public static void createTable(XWPFDocument doc) { |
|||
XWPFTable table = doc.createTable(3, 3); |
|||
//列宽自动分割
|
|||
CTTblWidth infoTableWidth = table.getCTTbl().addNewTblPr().addNewTblW(); |
|||
infoTableWidth.setType(STTblWidth.DXA); |
|||
infoTableWidth.setW(BigInteger.valueOf(9072)); |
|||
|
|||
setTableFonts(table.getRow(0).getCell(0), "编号"); |
|||
setTableFonts(table.getRow(0).getCell(1), "问题"); |
|||
setTableFonts(table.getRow(0).getCell(2), "应答"); |
|||
setTableFonts(table.getRow(1).getCell(0), "1"); |
|||
setTableFonts(table.getRow(1).getCell(1), "陈述日期"); |
|||
setTableFonts(table.getRow(1).getCell(2), "2017年02月17日"); |
|||
setTableFonts(table.getRow(2).getCell(0), "2"); |
|||
setTableFonts(table.getRow(2).getCell(1), "PICS序列号"); |
|||
setTableFonts(table.getRow(2).getCell(2), "121313132131"); |
|||
|
|||
} |
|||
|
|||
// word跨列合并单元格
|
|||
public static void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) { |
|||
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); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// word跨行并单元格
|
|||
public static void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) { |
|||
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); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 设置表格中字体 |
|||
* |
|||
* @param cell |
|||
* @param cellText |
|||
*/ |
|||
public static void setTableFonts(XWPFTableCell cell, String cellText) { |
|||
CTP ctp = CTP.Factory.newInstance(); |
|||
XWPFParagraph p = new XWPFParagraph(ctp, cell); |
|||
p.setAlignment(ParagraphAlignment.CENTER); |
|||
XWPFRun run = p.createRun(); |
|||
run.setFontSize(8); |
|||
run.setText(cellText); |
|||
CTRPr rpr = run.getCTR().isSetRPr() ? run.getCTR().getRPr() : run.getCTR().addNewRPr(); |
|||
CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts(); |
|||
fonts.setAscii("仿宋"); |
|||
fonts.setEastAsia("仿宋"); |
|||
fonts.setHAnsi("仿宋"); |
|||
cell.setParagraph(p); |
|||
} |
|||
|
|||
/** |
|||
* 添加描述信息 |
|||
* |
|||
* @param doc |
|||
* @param description |
|||
*/ |
|||
public static void addDescription(XWPFDocument doc, String description) { |
|||
if (StringUtils.isEmpty(description)) { |
|||
return; |
|||
} |
|||
XWPFParagraph title = doc.createParagraph(); |
|||
XWPFRun run = title.createRun(); |
|||
run.setText(description); |
|||
run.setBold(true); |
|||
title.setAlignment(ParagraphAlignment.CENTER); |
|||
} |
|||
|
|||
/** |
|||
* 创建目录 |
|||
* 创建并插入带超链接的目录 |
|||
* @param document |
|||
*/ |
|||
public static void insertTOC2(XWPFDocument document) { |
|||
// 定义 TOC 字段属性
|
|||
CTSimpleField tocField = CTSimpleField.Factory.newInstance(); |
|||
tocField.setInstr("TOC \\h \\z \\t \"Heading1,Heading2\""); // 包含 Heading1 和 Heading2 样式的目录
|
|||
|
|||
// 创建包含 TOC 字段的段落
|
|||
XWPFParagraph tocPara = document.createParagraph(); |
|||
tocPara.getCTP().addNewFldSimple().set(tocField); |
|||
|
|||
// 更新文档字段以计算目录
|
|||
document.enforceUpdateFields(); |
|||
} |
|||
|
|||
/** |
|||
* 创建目录 |
|||
* 创建并插入带超链接的目录 |
|||
* @param document |
|||
*/ |
|||
public static void insertTOC(XWPFDocument document) { |
|||
// 创建目录所在的段落
|
|||
XWPFParagraph tocPara = document.createParagraph(); |
|||
|
|||
|
|||
// 添加 TOC 域代码
|
|||
String tocFieldCode = "TOC \\o \"1-3\" \\h \\z \\u"; |
|||
CTSimpleField tocField = tocPara.getCTP().addNewFldSimple(); |
|||
tocField.setInstr(tocFieldCode); |
|||
tocField.setDirty(STOnOff.TRUE); |
|||
} |
|||
} |
|||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue