产品需求
近期产品提了一个需求,要求我们将查询出来的数据以表格的形式保存在excel和word文档中,excel的单元格有强大的适应性和扩展性,基本无难度,但是word,嗯,要兼容wps word和Microsoft Word,一言难尽。
/**
* 导出word文件
*/
public static XWPFDocument createXWPFDocument(List<Map<String, Object>> data,List<String> fileds) throws Exception {
//创建word文档
XWPFDocument doc = new XWPFDocument();
//创建表头
createTitleParagraph(doc);
//写入数据
if(CollectionUtils.isNotEmpty(data)){
createCell(doc, data,fileds);
}
//返回文档
return doc;
}
/**
* 创建表格的样式标题
*
* @param document
*/
public static void createTitleParagraph(XWPFDocument document) {
//新建一个标题段落对象(就是一段文字)
XWPFParagraph titleParagraph = document.createParagraph();
//样式居中
titleParagraph.setAlignment(ParagraphAlignment.CENTER);
//创建文本对象
XWPFRun titleFun = titleParagraph.createRun();
//设置标题的名字
titleFun.setText("报告报表word文档导出");
//加粗
titleFun.setBold(true);
//设置颜色
titleFun.setColor("000000");
//字体大小
titleFun.setFontSize(20);
//设置字体
titleFun.setFontFamily("Courier");
//换行
titleFun.addBreak();
}
/**
* 创建单元格并存储数据
*
* @param document
*/
public static void createCell(XWPFDocument document, List<Map<String, Object>> data,List<String> fileds) {
XWPFTable infoTable = document.createTable();
//设置单元格表头,这个地方是做了一个汉化表头的处理
List<String> assetHeadTemp = getAssetHeadTemp(fileds);
//设置单元格内字体大小,因为产品需求最多有10列,为了让字体正常显示,所以对字体大小调节
int fontSize = 0;
if(assetHeadTemp.size()>5){
fontSize = 7;
}else {
fontSize = 10;
}
//获取每列的列宽
long columnWidth = new Double(Math.floor(8000/assetHeadTemp.size())).longValue();
//遍历要添加的数据的list
for (int i = 0; i <= data.size() ; i++) {
//为表格添加行
XWPFTableRow newRow = infoTable.insertNewTableRow(i + 1);
//遍历list中的字符串数组
for (int j = 0; j < assetHeadTemp.size(); j++) {
//在新增的行上面创建cell,并设置对齐方式为居中
newRow.createCell().setVerticalAlignment(XWPFTableCell.XWPFVertAlign.BOTH);
//设置单元格样= 式
XWPFTableCell cell = newRow.getCell(j);
// //设置单元格宽度
CTTcPr tcpr = cell.getCTTc().addNewTcPr();
CTTblWidth cellW = tcpr.addNewTcW();
cellW.setType(STTblWidth.DXA);
cellW.setW(BigInteger.valueOf(columnWidth));
//创建段落对象
XWPFParagraph p=cell.addParagraph();
//创建文本对象
XWPFRun run = p.createRun();
//可以换行,可以换行,可以换行,重要的事情说三遍,这个地方很重要
run.addBreak();
if (i == 0) {
run.setText(assetHeadTemp.get(j));
}else {
Map<String, Object> map = data.get(i - 1);
String key = fileds.get(j);
if (map.get(key) == null) {
//给每个cell赋值。
run.setText("");
} else {
run.setText(key.equals(DIMENSION_PREFIX+"_cw_raw_time")?DateUtil.convertTimeToString(Long.parseLong(map.get(key).toString())):map.get(key).toString());
}
}
run.setFontSize(fontSize);
}
}
//删除第一空白行
infoTable.removeRow(0);
//写完数据后调整单元格样式
//设置表格宽
CTTbl table = infoTable.getCTTbl();
CTTblPr pr = table.getTblPr();
CTTblWidth tblW = pr.getTblW();
tblW.setW(BigInteger.valueOf(8000));
tblW.setType(STTblWidth.DXA);
pr.setTblW(tblW);
table.setTblPr(pr);
CTJc jc = pr.addNewJc();
jc.setVal(STJc.LEFT);
pr.setJc(jc);
//使布局固定,不随内容改变宽度,这个非常非常非常重要,如果不固定布局,一个单元格里边的字符长度成百上千的时候,单元格就会放飞自我,就像下边的例图一样,惨不忍睹。另附一张加上下边固定布局之后的代码格式。。
CTTblLayoutType t = pr.isSetTblLayout()?pr.getTblLayout():pr.addNewTblLayout();
t.setType(STTblLayoutType.FIXED);
}
/**
* 翻译表头信息
* @return
*/
private static List<String> getAssetHeadTemp(List<String> fileds){
List<String> assetHeadTemp = new ArrayList<>();
fileds.forEach(field->{
if(field.startsWith(DIMENSION_PREFIX)){
assetHeadTemp.add(LogFieldsEnum.getChinese(field.replace(DIMENSION_PREFIX,""))+"(聚合维度)");
} else {
assetHeadTemp.add(LogFieldsEnum.getChinese(field));
}
});
System.out.println("获得的表头信息是:"+assetHeadTemp);
return assetHeadTemp;
}