easypoi导出word修改样式
easyPoi是 POI 工具类,Excel的快速导入导出,Excel模板导出,Word模板导出,可以仅仅5行代码就可以完成Excel的导入导出,修改导出格式简单粗暴,快速有效(摘自码云https://gitee.com/lemur/easypoi)
对于简单的导出,只需要对象封装map里面,在模板上用{{}}表达式写出对象,就可以导出了,网上有很多教程,这里就不在赘述了。本文主要是讲如何通过Java代码来动态的修改样式。一般我们的word模板字段不是很多,只需要封装对象就可以了
HashMap<String, Object> map = new HashMap<String, Object>(4);
//单个对象
map.put("id", "1231313");
map.put("name", "A某某");
map.put("age", "34");
map.put("phone", "18787674333");
return map;
//easypoi通用导出word
XWPFDocument s = WordExportUtil.exportWord07("/" + templateFile, map);
导出的模板如下,这样模板字段是什么样式的,比如加粗倾斜宋体等,导出的结果就是什么样式的,只需要调整模板的样式就可以了。
对于导出内容比较多的word,通常可以利用list进行遍历导出,这样如果修改其中某些字段的样式,那就变得比较复杂了,在网上找了很久,发现这方面的资料还是比较少的,而且都没有达到理想中的效果。
经过一天的摸索与努力,终于实现了修改所有遍历的字段的样式,这样后来者如果再遇到这类问题,就不需要花费过多的时间和精力了,也算是发扬下当代互联网人的精神吧。
word导出要求遍历的字段全部采用仿宋,小四字体,网上很容易搜到了一种方法,经过整理下过程如下
调用easypoi会返回一个XWPFDocument的对象,获取表table,行row,空格子cell,每一个段落paragraph,然后获取run对象就可以修改样式了。
//获取table
XWPFTable sourceTable = s.getTables().get(0);
//获取row
XWPFTableRow sourceRow = sourceTable.getRow(3);
//获取cell
XWPFTableCell sourceCell = sourceRow.getCell(0);
//获取每一行
XWPFParagraph sourcePara = sourceCell.getParagraphs().get(0);
//获取每一个run对象
XWPFRun sourceRun = sourcePara.getRuns().get(0);
// 设置列宽
sourceCell .setWidth(String.valueOf(sourceRow.getCell(0).getWidth()));
sourceCell .setWidthType(sourceRow.getCell(0).getWidthType());
// 设置垂直对齐方式
sourceCell .setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
// 设置水平对齐方式
sourcePara .setAlignment(ParagraphAlignment.CENTER);
//修改字体的样式大小,内容,颜色等等
sourceRun.setFontSize(12);
sourceRun.setBold(true);
sourceRun.setText("舜发于畎亩之中");
sourceRun.setCapitalized(true);
sourceRun.setColor("BED4F1");
sourceRun.setDoubleStrikethrough(true);
sourceRun.setEmbossed(true);
sourceRun.setFontFamily("仿宋", XWPFRun.FontCharRange.cs);
sourceRun.setFontSize(12);
sourceRun.setImprinted(true);
sourceRun.setItalic(true);
sourceRun.setShadow(true);
sourceRun.setStrikeThrough(true);
代码只是修改某一个空格子的样式,如果可以,那我就循环判断修改任何一个空格子了。我以为这样就可以了,但也只是我以为,也不会花费一天之久了,其中多少次想放弃呢。
上述代码的确可以去修改遍历list字体的大小,颜色,倾斜,加粗等。顺便说下,仿宋小四,是12号。但是不可以修改为仿宋的字体格式。接下来就是踩坑排错的过程了。首先 sourceRun.setFontFamily("仿宋");这个方法可以单个参数“宋体”,也可以两个参数 cellRun.setFontFamily("仿宋", XWPFRun.FontCharRange.eastAsia);试了下,也不行。第二个参数是个枚举类,每种类型都试了也不行。全都写上也不行。放弃之心+20。无奈,只能继续百度了。
网上又看到一个动态修改word字体样式的内容,也是差不多再深挖四层,就不贴思维导图了,看下代码就知道了,大致代码如下
//获取fonts对象
CTFonts tmpFonts = sourceRun.getCTR().getRPr().getRFonts();
//设置字体
tmpFonts.setEastAsia("仿宋");
当然了,试了下还是不行,放弃之心+20,老规矩吧这几个有的全部设置为仿宋了
tmpFonts.setAscii("仿宋");
tmpFonts.setEastAsia("仿宋");
tmpFonts.setHAnsi("仿宋");
tmpFonts.setCs("仿宋");
还是不行,放弃之心+20,然后看到了 asciiTheme 等theme,这个是不是也要设置为仿宋呢?
<w:rFonts w:ascii="仿宋" w:hAnsi="仿宋" w:cs="仿宋" w:eastAsia="仿宋" w:asciiTheme="" w:cstheme="" w:eastAsiaTheme="" w:hAnsiTheme=""/>
试了下代码只有 tmpFonts0.isSetAsciiTheme();和 tmpFonts.unsetAsciiTheme();也没有参数,返回布尔类型,那就没办法设置了。放弃之心+10.就在偶然之间发现了一些不是遍历出来的字段的内容为
<w:rFonts w:hint="eastAsia" w:ascii="仿宋" w:hAnsi="仿宋" w:eastAsia="仿宋" w:cs="Arial"/>
竟然不一样。感觉胜利女神已经在朝我挥手了。突然想起了在名侦探柯南中,小兰推理那集,工藤提到过福尔摩斯的一句话
首先要把一切不可能的结论都排除,那其余的,不管多么离奇,难以置信,也必然是无可辩驳的事实。或许剩下的是几种解释,如果这样,那就要一一地加以证实,直到最后只剩下一种具有充分根据证明的解释。
一旦你排除了所有不可能的事实外,那么剩下的,不管多么不可思议,那就是事实的真相。
当我们排除一系列错误以后,那么真相已经离我们很近了。既然真相已经出现,剩下的只有向真相去靠拢了。
//真相永远只有一个(名侦探柯南)
CTFonts tmpFonts = sourceRun.getCTR().getRPr().getRFonts();
//真相的tmpFonts0
CTFonts tmpFonts0 = sourceRun0.getCTR().getRPr().getRFonts();
String fontFamily0 = sourceRun0.getFontFamily();
System.out.println(tmpFonts0);
//未曾从网上看到过setHint,核心代码
tmpFonts.setHint(tmpFonts0.getHint());
tmpFonts.setAscii(fontFamily0);
tmpFonts.setEastAsia(fontFamily0);
tmpFonts.setHAnsi(fontFamily0);
tmpFonts.setCs("Arial");
System.out.println("~~~~~~~~~~~这是真相~~~~~~~~~~~~~~~~~");
System.out.println(tmpFonts);
System.out.println(tmpFonts0.isSetAsciiTheme());
System.out.println(tmpFonts0.getAsciiTheme());
System.out.println("~~~~~~~~~~~这是我们的结果~~~~~~~~~~~~~~~~~");
System.out.println(tmpFonts.isSetAsciiTheme());
System.out.println(tmpFonts.getAsciiTheme());
//也未曾看到过类似的代码,全凭借推理
tmpFonts.unsetAsciiTheme();
tmpFonts.unsetEastAsiaTheme();
tmpFonts.unsetHAnsiTheme();
System.out.println("~~~~~~~~~~这是按照真相修改后的结果~~~~~~~~~~~~~~~~~~");
System.out.println(tmpFonts.isSetAsciiTheme());
System.out.println(tmpFonts.getAsciiTheme());
sourceRun.setFontSize(sourceRun0.getFontSize());
/**
* ~~~~~~~~~~~这是真相~~~~~~~~~~~~~~~~~
* false
* null
* ~~~~~~~~~~~这是我们的结果~~~~~~~~~~~~~~~~~
* true
* null
* ~~~~~~~~~~这是按照真相修改后的结果~~~~~~~~~~~~~~~~~~
* false
* null
*/
此时要注意下,我们从其他渠道获得的easypoi的jar包可能不全,我原有的就是不全的,还是从码云上拷一份吧,这是easypoi导出word的全部
<!-- easypoi -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.2.0</version>
</dependency>
<!-- Word 需要使用 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.3</version>
<optional>true</optional>
</dependency>
验证遍历后的结果中的一个字段可以,那么就可以循环去修改样式了
/**
* 修改月报的样式
* @param sourceTable
* @param tmpFonts0
* @param fontFamily0
*/
public static void changeMonthStyle(XWPFTable sourceTable, CTFonts tmpFonts0, String fontFamily0) {
// List list = (List)listMap.get("debtList");
//获取table
// final int size = list.size();
//获取所有的行数
int size = sourceTable.getRows().size();
//从第三行开始遍历修改样式
for (int i = 3; i < size; i++) {
//获取每一行
XWPFTableRow row = sourceTable.getRow(i);
// 设置行高
// row.setHeight(600);
// 获取每一个空格子
List<XWPFTableCell> cellList = row.getTableCells();
//获取每一行空格的总个数
final int cellSize = cellList.size();
//进行循环遍历修改每一个空格的样式,标题行不修改样式
for (int j = 0; j < cellSize && cellSize > 1; j++) {
//获取每一个空格
XWPFTableCell cell = row.getCell(j);
// 设置列宽
// cell.setWidth(String.valueOf(sourceRow.getCell(j).getWidth()));
// cell.setWidthType(sourceRow.getCell(j).getWidthType());
// 设置垂直对齐方式
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
//获取空格子里面的每一个行
XWPFParagraph cellPara = cell.getParagraphs().get(0);
// 设置水平对齐方式
// cellPara.setAlignment(ParagraphAlignment.CENTER);
XWPFRun cellRun = cellPara.getRuns().get(0);
System.out.println(cellRun.getText(0));
String text = cellRun.getText(0);
cellRun.setFontSize(12);
//全网独一份,根据模板的样式设置总的样式
CTFonts tmpFonts = cellRun.getCTR().getRPr().getRFonts();
tmpFonts.setHint(tmpFonts0.getHint());
tmpFonts.setAscii(fontFamily0);
tmpFonts.setEastAsia(fontFamily0);
tmpFonts.setHAnsi(fontFamily0);
tmpFonts.setCs("Arial");
tmpFonts.unsetAsciiTheme();
tmpFonts.unsetEastAsiaTheme();
tmpFonts.unsetHAnsiTheme();
if (text.equals("资产总计") || text.equals("负债合计") ||
text.equals("所有者权益合计") || text.equals("负债和所有者权益总计") ||
text.equals("净利润") || text.equals("经营活动产生的现金流量净额") ||
text.equals("经营活动产生的现金流量净额") || text.equals("筹资活动产生的现金流量净额") ||
text.equals("现金及现金等价物净增加额") || text.equals("年末现金及现金等价物余额")
) {
//字体加粗第0列1列2列3列
cellRun.setBold(true);
row.getCell(j + 1).getParagraphs().get(0).getRuns().get(0).setBold(true);
row.getCell(j + 2).getParagraphs().get(0).getRuns().get(0).setBold(true);
row.getCell(j + 3).getParagraphs().get(0).getRuns().get(0).setBold(true);
}
}
}
}
到此,样式修改就完成了 。
有时候有些事,总是想放弃,却又一步一步走了下来。就在突然间灵光一现,答案就在眼前不远处。知识的积累同样如此,可能在很长的一段时间没有感觉到进步,可能是因为还没有到达质变的点,或在下一瞬间,就会突飞猛进,走上人生巅峰!共勉!
参考文章如下: