背景
今天,飞哥一脸不开心地来找我,我这一看又是有事情了,果不其然,飞哥一脸不岔地对我说:“小米,财务部那边说上次做的报销单下载用word方式不想用了,想用excel的方式导出,你觉得可以不?”,我一听,这都是常态了,已经习以为常了,真是“需求虐我千百遍,我待客户如初恋”~
需求
报销单如上图:
- 题目:报销单
- 报销报销人及申报时间
- 费用类型的表格
- 审核情况的表格
创建excel
// 创建一个Workbook,对应一个Excel文件
HSSFWorkbook wb = new HSSFWorkbook();
创建sheet
// 在Workbook中添加一个sheet,对应Excel文件中的sheet
HSSFSheet reimbursementSheet = wb.createSheet("报销单");
设置样式以及字体样式
// 设置样式以及字体样式
HSSFCellStyle titleStyle = createTitleCellStyle(wb);
HSSFCellStyle headerStyle = createHeadCellStyle(wb);
HSSFCellStyle contentStyle = createContentCellStyle(wb);
AtomicInteger rowNum = new AtomicInteger(NumberUtils.INTEGER_ZERO);
创建标题
rowNum.set(this.firstRowHandler(reimbursementSheet,
titleStyle, rowNum.get(), "报销单"));
private int firstRowHandler(HSSFSheet sheet,
HSSFCellStyle titleStyle, int rowNum, String title) {
HSSFRow row0 = sheet.createRow(rowNum++);
// 设置行高
row0.setHeight((short) 800);
// 样式
HSSFCell c00 = row0.createCell(NumberUtils.INTEGER_ZERO);
c00.setCellValue(title);
c00.setCellStyle(titleStyle);
// 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始)
sheet.addMergedRegion(new CellRangeAddress(
NumberUtils.INTEGER_ZERO, NumberUtils.INTEGER_ZERO,
NumberUtils.INTEGER_ZERO, 4));//标题合并单元格操作,4为总列数
return rowNum;
}
报销人及申报时间
rowNum.set(this.secondRowHandler(
reimbursementSheet, rowNum.get(), wb));
private int secondRowHandler(HSSFSheet sheet, int rowNum,
HSSFWorkbook wb) {
HSSFRow row1 = sheet.createRow(rowNum++);
String[] row_first = {"报销人:", "", "", "申报时间:", ""};
for (int i = NumberUtils.INTEGER_ZERO; i < row_first.length;
i++) {
HSSFCell tempCell = row1.createCell(i);
if (i == NumberUtils.INTEGER_ZERO) {
tempCell.setCellValue(row_first[i] + "李四");
} else if (i == 3) {
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.RIGHT);
tempCell.setCellStyle(cellStyle);
tempCell.setCellValue(row_first[i]+"2022-03-04 03:43");
} else {
tempCell.setCellValue(row_first[i]);
}
}
// 合并
sheet.addMergedRegion(new CellRangeAddress(
NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ONE,
NumberUtils.INTEGER_ZERO, 1));
sheet.addMergedRegion(new CellRangeAddress(
NumberUtils.INTEGER_ONE, NumberUtils.INTEGER_ONE,
3, 4));
return rowNum;
}
费用类型处理
this.typeHandler(reimbursementVO, wb, reimbursementSheet,
headerStyle, contentStyle, rowNum);
private void typeHandler(List list, HSSFWorkbook wb,
HSSFSheet sheet, HSSFCellStyle headerStyle,
HSSFCellStyle contentStyle, AtomicInteger rowNum) {
// 费用类型
list.stream().filter(Objects::nonNull)
.forEach(reimbursementDetailVO -> {
//第三行:费用类型
int expenseTypeNum = rowNum.getAndIncrement();
HSSFRow typeTitleRow = sheet.createRow(expenseTypeNum);
typeTitleRow.setHeight((short) 700);
HSSFCell c30 = typeTitleRow.createCell(NumberUtils.INTEGER_ZERO);
c30.setCellValue("费用类型:费用1");
// 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始)
sheet.addMergedRegion(new CellRangeAddress(expenseTypeNum, expenseTypeNum, NumberUtils.INTEGER_ZERO, 4));
// 内容
int typeNameNum = rowNum.getAndIncrement();
HSSFRow typeNameNumRow = sheet.createRow(typeNameNum);
typeNameNumRow.setHeight((short) 700);
String[] row_third = {"报销项目", "摘要", "费用金额", "发票数量", "费用说明"};
for (int i = NumberUtils.INTEGER_ZERO; i < row_third.length; i++) {
HSSFCell tempCell = typeNameNumRow.createCell(i);
tempCell.setCellValue(row_third[i]);
tempCell.setCellStyle(headerStyle);
}
int typeNum = rowNum.getAndIncrement();
HSSFRow tempRow = sheet.createRow(typeNum);
tempRow.setHeight((short) 500);
// 循环单元格填入数据
for (int j = NumberUtils.INTEGER_ZERO; j < 4; j++) {
HSSFCell tempCell = tempRow.createCell(j);
tempCell.setCellStyle(contentStyle);
tempCell.setCellValue("内容");
}
// 小计
int subTotalNum = rowNum.getAndIncrement();
HSSFRow subtotalNumRow = sheet.createRow(subTotalNum);
String[] subTotalCellValue = {"小计:2000", "", "", "", ""};
for (int i = NumberUtils.INTEGER_ZERO;
i < subTotalCellValue.length; i++) {
HSSFCell tempCell = subtotalNumRow.createCell(i);
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.RIGHT);
tempCell.setCellStyle(cellStyle);
tempCell.setCellValue(subTotalCellValue[i]);
}
//标题合并单元格操作,4为总列数
sheet.addMergedRegion(new CellRangeAddress(subTotalNum,
subTotalNum, NumberUtils.INTEGER_ZERO, 4));
});
// 合计
int totalRowNum = rowNum.getAndIncrement();
HSSFRow totalRow = sheet.createRow(totalRowNum);
String[] totalCellValue = {"合计人民币:2000", "", "", "", ""};
for (int i = NumberUtils.INTEGER_ZERO; i <
totalCellValue.length; i++) {
HSSFCell tempCell = totalRow.createCell(i);
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.RIGHT);
tempCell.setCellStyle(cellStyle);
tempCell.setCellValue(totalCellValue[i]);
}
//标题合并单元格操作,4为总列数
sheet.addMergedRegion(new CellRangeAddress(totalRowNum, totalRowNum, NumberUtils.INTEGER_ZERO, 4));
}
审核情况与费用类型一样,故省略。
表格自适应
为了让表格整体好看一些,不至于拥挤,做了一些表格自适应,代码如下:
setSizeColumn(reimbursementSheet, 5);
private static void setSizeColumn(HSSFSheet sheet,
int columnLength) {
for (int columnNum = 0; columnNum <= columnLength;
columnNum++) {
int columnWidth = sheet.getColumnWidth(columnNum) / 200;
for (int rowNum = 0; rowNum < sheet.getLastRowNum();
rowNum++) {
HSSFRow currentRow; // 当前行未被使用过
if (sheet.getRow(rowNum) == null) {
currentRow = sheet.createRow(rowNum);
} else {
currentRow = sheet.getRow(rowNum);
}
if (currentRow.getCell(columnNum) != null) {
HSSFCell currentCell = currentRow
.getCell(columnNum);
if (currentCell.getCellType() ==
HSSFCell.CELL_TYPE_STRING) {
int length = currentCell.
getStringCellValue().getBytes().length;
if (columnWidth < length) {
columnWidth = length;
}
}
}
}
sheet.setColumnWidth(columnNum, columnWidth * 200);
}
}
excel比word简单点,终于写完了,能交差了,我长长地呼出一口气……
写在最后
好兄弟可以点赞并关注我的公众号“javaAnswer”,全部都是干货。