XWPFDocument document = null;
document = new XWPFDocument(POIXMLDocument.openPackage(mdlepath));
这种方法读取docx文档,修改后另存为另一个文档
FileOutputStream outputStream = new FileOutputStream(tempPath);
document.write(outputStream);
outputStream.close();
然后这个文档就可以使用勒。是不是很简单,是不是很方便。但是,这个代码我是在网上找的,这个代码有个巨坑无比的地方。
我在操作一个word的时候,调用了一个copyTable方法。这个方法的作用就是复制某一个表格到指定位置。中间使用了一个document.setTable(pos,table)方法。这个方法有个巨坑的点,其中table是我需要复制的表格。再执行完这个代码之后,doc.getTable()这个函数的返回值正确,没有问题,逐行遍历表格也没有问题。但是在操作这个表格的时候发现了问题。使用逐行操作表格会无效。究其原因我猜测是因为引用问题。POI在操作table的时候并不能像List一样。new 一个对象就新分配一个空间。POI在操作很多东西的时候并不能新分配一个对象,而没有引用。所以就导致我的setTable方法传入参数的table,永远是同一个table。我是怎么知道的呢,是因为我每次把这个table的某一个单元格setText("i="+i)会发现复制的几个表格里,最后一个表格输出了很多个i=.......在逐个遍历表格赋值的时候,会造成每次修改的表格都是同一个。并不能修改到复制出来的表格。解决办法就是必须把这个文件另存为,再打开。这是背景。
那么我就需要调用两次上面的代码。而且第二次调用的docx文件是第一次的输出文件。
这个东西我是要挂载在服务器上的,我肯定是要删除掉的。那么坑就来了。
我第一次生成的文件叫temp1,第二次生成的文件叫temp2.
我执行这一段代码:
out1.getFD().valid();
out2.getFD().valid();
输出结果为false和false。然后我删除文件。输出删除结果,均为true。然后我打开文件夹,发现temp
,删除了temp2没删除。我心态崩掉了。然后我file(temp1).exists();发现结果为false。就是说我删除成功而且检查删除后文件已经不存在了。然后我debug,发现删除那句话并没有执行,却返回true。没删除掉exists却返回false。然后我怀疑是文件占用或者是别的原因,我就怀疑是这个封装方法出了问题。
解决办法:
try (FileInputStream argIS = new FileInputStream(mdlepath);XWPFDocument document = new XWPFDocument(argIS)){
//这里面的代码就是操作整个document的具体操作了。
//不需要关闭 FileInputStream 会自动关闭
}
我换了一种方法读取docx文件,而且写在try()中间.就不会出现占用或者流未关闭的问题了。
解决办法是看的官方例程http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/examples/
public static void copyTable(XWPFDocument doc, Integer mdlIndex, Integer startPos, Integer copysiz, List titlelist,XWPFParagraph sourse) throws Exception {
if (mdlIndex == null || mdlIndex >= doc.getTables().size() || mdlIndex < 0) {
return;
}
XWPFTable table = doc.getTables().get(mdlIndex);
// Copying a existing table
CTTbl ctTbl = CTTbl.Factory.newInstance(); // Create a new CTTbl for the new table
ctTbl.set(table.getCTTbl()); // Copy the template table's CTTbl
// Create a new table using the CTTbl upon.0
XWPFTable table2 = new XWPFTable(ctTbl, doc);//这个table2是个引用类型,放到循环里也不会改变他引用的对象是他的模板table,这是个坑;
for (int i = 0; i < copysiz; i++) {
//创建表之前先创建头
XWPFParagraph paragraph = doc.createParagraph();
paragraph.getCTP().setPPr(sourse.getCTP().getPPr());
// paragraph.setPageBreak(true);
// paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun xwpfRun = paragraph.createRun();
xwpfRun.setFontSize(18);//设置字体大小
xwpfRun.setBold(true);
xwpfRun.setText("表-" + titlelist.get(i+1));
paragraph.setPageBreak(true);//分页符
//创建表并且修改表
doc.createTable(); // Create a empty table in the document
// 这里有一个坑,必须重新打开该文件这个这个替换掉的table才能修改。不然改不了。或者在创建table2的时候就把数据加上
doc.setTable(doc.getTables().size() - 1, table2);
}
}
首先有例程http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExample.java
这个例程有两个坑爹的地方:
1.图表不能设置的东西很多。比如:我想生成这样的图表:
我不能设置没有表头,官方有个类似的方法没有用。不生效。我想设置是否标出数据大小,比如2,7,11,5啥的,没有。我想设置样式,也没有。
解决办法,,我创建模板压,创建完之后修改数据就完事了。把表头设置为空字符串,看起来就和没有差不多。
List chartList = document.getCharts();
XWPFChart chart = chartList.get(0);
String[] categories = (String[]) barChartMap.get("categories");
Integer[] value = (Integer[]) barChartMap.get("value");
setBarData(chart, categories, value);
private static void setBarData(XWPFChart chart, String[] categories, Integer[] values1) {
final List data = chart.getChartSeries();
final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);
final int numOfPoints = categories.length;
final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
final XDDFDataSource> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
final XDDFNumericalDataSource extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);
XDDFChartData.Series series1 = bar.getSeries().get(0);
series1.replaceData(categoriesData, valuesData);
series1.setTitle("123", chart.setSheetTitle("123", 0));
bar.setBarDirection(BarDirection.COL);
chart.plot(bar);
solidFillSeries(bar, 0, PresetColor.GRAY);
chart.setTitleText(""); // https://stackoverflow.com/questions/30532612
chart.setAutoTitleDeleted(true);
chart.setTitleOverlay(false);
//改变颜色
}
private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) {
//改变柱状图的第index的颜色
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
XDDFChartData.Series series = data.getSeries().get(index);
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setFillProperties(fill);
series.setShapeProperties(properties);
}
类似√×这样的特殊字符。有的甚至要输出一些奇奇怪怪的东西。
思路有两个:
1.直接在java里打出来,然后添加到word里面
2.在word里生成特殊字符。
方法1,我试过是可以的。
方法2 这里附上解决办法和思路:poi插入word 2007 Wingdings字符。可行,可能以后会出现版本问题。那篇帖子挺老的了。
还有一点心得:如果你的POI版本比较新,比如说我使用的是POI 4.1.0版本的,百度上面差到的资料是很少的,而且百度辣鸡,用谷歌能查到一些,最好的地方是去官方文档里去寻找答案。或者到国外的开发者论坛:https://stackoverflow.com/经常是可以搜到的。
下面是一些用到的代码:
/**
* 替换段落文本
*
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeText(XWPFDocument document, Map textMap) {
//获取段落集合
List paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
if (checkText(text)) {
List runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
Object ob = changeValue(run.toString(), textMap);
//System.out.println("段落:" + run.toString());
if (ob instanceof String) {
if(textMap.containsKey(run.toString())){
run.setText((String) ob, 0);
}
}
}
}
}
}
public static void changePic(XWPFDocument document, Map textMap) throws Exception{
//获取段落集合
List paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
if (checkText(text)) {
List runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
Object ob = changeValue(run.toString(), textMap);
//System.out.println("段落:" + run.toString());
if (ob instanceof String) {
if(textMap.containsKey(run.toString())){
run.setText("", 0);
try(FileInputStream is=new FileInputStream((String)ob)){
run.addPicture(is,XWPFDocument.PICTURE_TYPE_PNG,(String)ob, Units.toEMU(50),Units.toEMU(50));
}
}
}
}
}
}
}
public static boolean checkText(String text) {
boolean check = false;
if (text.indexOf("$") != -1) {
check = true;
}
return check;
}
public static void changeTableText(XWPFDocument document, Map data) {
List tableList = document.getTables();
//循环所有需要进行替换的文本,进行替换
for (int i = 0; i < tableList.size(); i++) {
XWPFTable table = tableList.get(i);
if (checkText(table.getText())) {
List rows = table.getRows();
System.out.println("简单表格替换:" + rows);
//遍历表格,并替换模板
eachTable(document, rows, data);
}
}
}
public static void changeTablePic(XWPFDocument document, Map pic) throws Exception{
List tableList = document.getTables();
//循环所有需要进行替换的文本,进行替换
for (int i = 0; i < tableList.size(); i++) {
XWPFTable table = tableList.get(i);
if (checkText(table.getText())) {
List rows = table.getRows();
System.out.println("简单表格替换:" + rows);
//遍历表格,并替换模板
eachTablePic(document, rows, pic);
}
}
}
public static void eachTablePic(XWPFDocument document, List rows, Map pic) throws Exception{
for (XWPFTableRow row : rows) {
List cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if (checkText(cell.getText())) {
//System.out.println("cell:" + cell.getText());
List paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List runs = paragraph.getRuns();
for (XWPFRun run : runs) {
Object ob = changeValue(run.toString(), pic);
if (ob instanceof String) {
System.out.println("run:"+"'"+run.toString()+"'");
if(pic.containsKey(run.toString())){
System.out.println("run:"+run.toString()+"替换为"+(String)ob);
run.setText("", 0);
try(FileInputStream is=new FileInputStream((String)ob)){
run.addPicture(is,XWPFDocument.PICTURE_TYPE_PNG,(String)ob,Units.toEMU(50),Units.toEMU(100));
}
}
else{
System.out.println("'"+run.toString()+"'不匹配");
}
}
}
}
}
}
}
}
public static Object changeValue(String value, Map textMap) {
Set> textSets = textMap.entrySet();
Object valu = "";
for (Map.Entry textSet : textSets) {
//匹配模板与替换值 格式${key}
String key = textSet.getKey();
if (value.indexOf(key) != -1) {
valu = textSet.getValue();
}
}
return valu;
}
public static void eachTable(XWPFDocument document, List rows, Map textMap) {
for (XWPFTableRow row : rows) {
List cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if (checkText(cell.getText())) {
//System.out.println("cell:" + cell.getText());
List paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List runs = paragraph.getRuns();
for (XWPFRun run : runs) {
Object ob = changeValue(run.toString(), textMap);
if (ob instanceof String) {
System.out.println("run:"+"'"+run.toString()+"'");
if(textMap.containsKey(run.toString())){
System.out.println("run:"+run.toString()+"替换为"+(String)ob);
run.setText((String) ob, 0);
}
else{
System.out.println("'"+run.toString()+"'不匹配");
}
}
}
}
}
}
}
}
public static void insertTable(XWPFTable table, List tableList, List daList, Integer type) {
if (2 == type) {
//创建行和创建需要的列
for (int i = 0; i < daList.size() - 1; i++) {
//添加一个新行
// XWPFTableRow row = table.insertNewTableRow(1 + i);
XWPFTableRow row = table.getRow(1);
copy(table, row, i + 1);
// for (int k = 0; k < daList.get(i).length; k++) {
// row.createCell();
// }
}
System.out.println("插入表格数据");
//创建行,根据需要插入的数据添加新行,不处理表头
for (int i = 0; i < daList.size(); i++) {
List cells = table.getRow(i + 1).getTableCells();
for (int j = 0; j < cells.size(); j++) {
XWPFTableCell cell02 = cells.get(j);
cell02.setText(daList.get(i)[j]);
}
}
} else if (4 == type) {
//插入表头下面第一行的数据
for (int i = 0; i < tableList.size(); i++) {
XWPFTableRow row = table.createRow();
List cells = row.getTableCells();
cells.get(0).setText(tableList.get(i));
}
}
}
/**
* 复制两行
*
* @param table
* @param sourceRow
* @param rowIndex
*/
public static void copy(XWPFTable table, XWPFTableRow sourceRow, int rowIndex) {
//在表格指定位置新增一行
XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);
//复制行属性
targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
List cellList = sourceRow.getTableCells();
if (null == cellList) {
return;
}
//复制列及其属性和内容
XWPFTableCell targetCell = null;
for (XWPFTableCell sourceCell : cellList) {
targetCell = targetRow.addNewTableCell();
//列属性
targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
//段落属性
if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {
targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());
if (sourceCell.getParagraphs().get(0).getRuns() != null && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {
XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
cellR.setText(sourceCell.getText());
cellR.setBold(sourceCell.getParagraphs().get(0).getRuns().get(0).isBold());
} else {
targetCell.setText(sourceCell.getText());
}
} else {
targetCell.setText(sourceCell.getText());
}
}
}
/**
* 合并行
* @param table
* @param col
* @param fromRow
* @param toRow
*/
public static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) {
for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
CTVMerge vmerge = CTVMerge.Factory.newInstance();
if (rowIndex == fromRow) {
vmerge.setVal(STMerge.RESTART);
} else {
vmerge.setVal(STMerge.CONTINUE);
}
XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
CTTcPr tcPr = cell.getCTTc().getTcPr();
if (tcPr != null) {
tcPr.setVMerge(vmerge);
} else {
tcPr = CTTcPr.Factory.newInstance();
tcPr.setVMerge(vmerge);
cell.getCTTc().setTcPr(tcPr);
}
}
}
/**
* 合并列
*
* @param table
* @param row
* @param fromCell
* @param toCell
*/
public 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);
//cellCount为表格总列数
int cellCount = table.getRow(row).getTableCells().size();
Integer width = (toCell - fromCell + 1) / cellCount * table.getCTTbl().getTblPr().getTblW().getW().intValue();
cell.getCTTc().getTcPr().addNewTcW().setW(BigInteger.valueOf(width));
} else {
// Cells which join (merge) the first one, are set with CONTINUE
cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
}
}
}