1.关于Excel版本的一点了解
在项目工作中主要使用两个版本,03版文件名以“.xls”结尾,最大处理行数为65536,07版文件名以“.xlsx”结尾,最大处理行数为1048576。
2.关于Excel的相关概念
工作簿 工作表 行 单元格
3.POI版本使用3.11,创建maven工程方便导入jar包
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11</version>
</dependency>
4.POI操作Excel工作簿的三个实现类(实现接口Workbook)
POI处理不同需求的Excel操作有不同的实现类,03版的xls对应HSSFWorkbook,07版的xlsx对应XSSFWorkbook,大数据量的写操作使用SXSSFWorkbook,大概的区别就是HSSFWorkbook读取的最大行数是65536,读写的速度相对较快,但存在弊端,不能写更多行的数据,这时候XSSFWorkbook登场,但是XSSFWorkbook采用一次性写出数据,如果数据量很大内存又不够,容易造成OOM异常,而SXSSFWorkbook使用了滑动窗口的概念,默认在内存中最多保留100行数据,超过100行的时候,就会把最小索引的行写入到临时文件中,这样就可以尽可能的避免出现OOM异常,大家根据实际需求选择相应的实现类。本次讲解使用HSSFWorkbook
5.HSSFWorkbook常用类与Excel对象的对应关系
HSSFWorkbook 工作簿对象
HSSFSheet 工作表对象
HSSFRow 行对象
HSSFCell 单元格对象
HSSFCellStyle 单元格样式对象
HSSFFont 字体对象
6.生成没有单元格边框的表头
在Excel里面默认的边框线是灰色的,生成没有边框线的单元格的逻辑就是想边框线的颜色改为白色,由于是演示代码,有些冗余代码没有提取出来,大家自行根据需求进行处理。
public static void setSheetHead() {
// 文件路径,03版的文件名以.xls结尾,07版的文件名以.xlsx结尾
String filePath = "/Users/lavined/Desktop/test01.xls";
FileOutputStream os = null;
// 最大列数
int cellNum = 10;
int cellNumTemp = cellNum - 1;
// 工作表名称
String sheetName = "学生信息表";
// 创建工作簿对象
Workbook workbook = new HSSFWorkbook();
// 创建工作表对象
Sheet sheet = workbook.createSheet(sheetName);
// 设置列宽
sheet.setDefaultColumnWidth(13);
// 设置单元格格式
CellStyle cellStyle = workbook.createCellStyle();
// 边框颜色白色
cellStyle.setTopBorderColor(IndexedColors.WHITE.getIndex());
cellStyle.setLeftBorderColor(IndexedColors.WHITE.getIndex());
cellStyle.setRightBorderColor(IndexedColors.WHITE.getIndex());
cellStyle.setBottomBorderColor(IndexedColors.WHITE.getIndex());
// 边框线型
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
// 由于采用无边框样式以后,最后一个单元格的右边框会消失,所以给最后一个单元格的下一个单元格设置样式
CellStyle leftCellStyle = workbook.createCellStyle();
leftCellStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
leftCellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
// 内容居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 设置字体
Font font = workbook.createFont();
font.setBold(true);// 粗体
font.setFontHeightInPoints((short) 14);// 设置字体大小
cellStyle.setFont(font);
// 创建行对象
Row row = sheet.createRow(0);
for (int i = 0; i < cellNum; i++) {
// 创建单元格对象
Cell cell = row.createCell(i);
if (i == 0) {
cell.setCellValue(sheetName);
}
// 设置单元格样式
cell.setCellStyle(cellStyle);
}
row.createCell(cellNum).setCellStyle(leftCellStyle);
// 合并单元格
CellRangeAddress region1 = new CellRangeAddress(0, 0, 0, cellNumTemp);
sheet.addMergedRegion(region1);
// 空一行
sheet.createRow(1);
CellRangeAddress region2 = new CellRangeAddress(1, 1, 0, cellNumTemp);
sheet.addMergedRegion(region2);
// 第二级表头
Row sheetRow2 = sheet.createRow(2);
int lastRemarkCellNum = cellNum - 3;
for (int i = 0; i < cellNum; i++) {
Cell cell = sheetRow2.createCell(i);
if (i == 0) {
cell.setCellValue("班级:三年级一班");
}
if (i == 3) {
cell.setCellValue("人数:10人");
}
if (i == lastRemarkCellNum) {
cell.setCellValue("创建时间:2021-03-01 17:09:47");
}
// 设置单元格样式
cell.setCellStyle(cellStyle);
}
sheetRow2.createCell(cellNum).setCellStyle(leftCellStyle);
// 合并单元格
CellRangeAddress region3 = new CellRangeAddress(2, 2, 0, 2);
sheet.addMergedRegion(region3);
CellRangeAddress region4 = new CellRangeAddress(2, 2, 3, lastRemarkCellNum -1);
sheet.addMergedRegion(region4);
CellRangeAddress region5 = new CellRangeAddress(2, 2, lastRemarkCellNum, cellNumTemp);
sheet.addMergedRegion(region5);
sheet.createRow(3);
CellRangeAddress region6 = new CellRangeAddress(3, 3, 0, cellNumTemp);
sheet.addMergedRegion(region6);
// 以流的方式写出文件
try {
os = new FileOutputStream(filePath);
workbook.write(os);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
代码结果如下:
7.生成带背景色的数据表头
public static void setDataHead(){
String filePath = "/Users/lavined/Desktop/test01.xls";
FileOutputStream os = null;
// 工作表名称
String sheetName = "学生信息表";
// 创建工作簿对象
Workbook workbook = new HSSFWorkbook();
// 创建工作表对象
Sheet sheet = workbook.createSheet(sheetName);
// 设置列宽
sheet.setDefaultColumnWidth(13);
// 设置单元格格式
CellStyle cellStyle = workbook.createCellStyle();
// 内容居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 背景色
cellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
// 边框颜色 黑色
cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
// 边框线型
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
// 数据表头字段
Map<Integer,String> dataHeadMap = new HashMap<>();
dataHeadMap.put(0, "班级");
dataHeadMap.put(1, "姓名");
dataHeadMap.put(2, "性别");
dataHeadMap.put(3, "年龄");
dataHeadMap.put(4, "身高");
dataHeadMap.put(5, "体重");
dataHeadMap.put(6, "家庭地址");
dataHeadMap.put(7, "饭卡余额");
dataHeadMap.put(8, "备注1");
dataHeadMap.put(9, "备注2");
// 报表数据项表头样式
Row row = sheet.createRow(0);
if (dataHeadMap != null) {
for (Map.Entry<Integer, String> headMap : dataHeadMap.entrySet()) {
Cell cell = row.createCell(headMap.getKey());
cell.setCellValue(headMap.getValue());
if (null != cellStyle) {
cell.setCellStyle(cellStyle);
}
}
}
// 以流的方式写出文件
try {
os = new FileOutputStream(filePath);
workbook.write(os);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
代码结果
8.生成数据内容
8.1在生成数据内容的时候,如果是类似数据表头的形式,则可以利用Map<Integer,String>让key的值和列的顺序保持一致,value为单元格内容,参照数据表头的内容;
8.2可以采用反射的方式生成数据内容,定义一个对象并提供set,get方法,属性的类型尽量是字符串类型(在使用反射的时候,如果属性内容为空,则会有默认值,与实际情况不符),对象的属性和Excel列的顺序保持一致。
8.2.1定义对象
public class Student {
private String className;
private String name;
private String sex;
private int age;
private double height;
private double weight;
private String address;
private BigDecimal amount;
private String remark1;
private String remark2;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getRemark1() {
return remark1;
}
public void setRemark1(String remark1) {
this.remark1 = remark1;
}
public String getRemark2() {
return remark2;
}
public void setRemark2(String remark2) {
this.remark2 = remark2;
}
}
8.2.2设置数据公共方法
/**
* 设置单元格内容List
*
* @param sheet 工作表对象
* @param beginRow 数据从第几行开始
* @param dataList 数据集合
* @param dataStyle 数据样式
* @return
*/
public static void setDataList(Sheet sheet, int beginRow, Collection dataList, CellStyle dataStyle) {
if (dataList != null) {
Iterator iterator = dataList.iterator();
while (iterator.hasNext()) {
Row row = sheet.createRow(beginRow);
beginRow++;
Object t = iterator.next();
// 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
Field[] fields = t.getClass().getDeclaredFields();
try {
for (short i = 0; i < fields.length; i++) {
Cell cell = row.createCell(i);
Field field = fields[i];
field.setAccessible(true);
String fieldName = field.getName();
String getMethodName = "get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
Class clazz = t.getClass();
Method method = clazz.getMethod(getMethodName, null);
Object cellValue = method.invoke(t, null);
if (cellValue instanceof BigDecimal) {
DecimalFormat df1 = new DecimalFormat("##,##0.00");
cell.setCellValue(df1.format(cellValue));
} else if (cellValue instanceof Integer) {
cell.setCellValue(Integer.valueOf(cellValue.toString()));
} else if(cellValue instanceof Double){
cell.setCellValue(Double.parseDouble(String.valueOf(cellValue)));
}else {
cell.setCellValue(String.valueOf(cellValue));
}
cell.setCellStyle(dataStyle);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
8.2.3数据表头和数据整体代码
public static void setDataHead(){
String filePath = "/Users/lavined/Desktop/test01.xls";
FileOutputStream os = null;
// 工作表名称
String sheetName = "学生信息表";
// 创建工作簿对象
Workbook workbook = new HSSFWorkbook();
// 创建工作表对象
Sheet sheet = workbook.createSheet(sheetName);
// 设置列宽
sheet.setDefaultColumnWidth(13);
// 设置单元格格式
CellStyle cellStyle = workbook.createCellStyle();
// 内容居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 背景色
cellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
// 边框颜色 黑色
cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
// 边框线型
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
// 数据表头字段
Map<Integer,String> dataHeadMap = new HashMap<>();
dataHeadMap.put(0, "班级");
dataHeadMap.put(1, "姓名");
dataHeadMap.put(2, "性别");
dataHeadMap.put(3, "年龄");
dataHeadMap.put(4, "身高");
dataHeadMap.put(5, "体重");
dataHeadMap.put(6, "家庭地址");
dataHeadMap.put(7, "饭卡余额");
dataHeadMap.put(8, "备注1");
dataHeadMap.put(9, "备注2");
// 报表数据项表头样式
Row row = sheet.createRow(0);
if (dataHeadMap != null) {
for (Map.Entry<Integer, String> headMap : dataHeadMap.entrySet()) {
Cell cell = row.createCell(headMap.getKey());
cell.setCellValue(headMap.getValue());
if (null != cellStyle) {
cell.setCellStyle(cellStyle);
}
}
}
// 数据内容
List dataList = new ArrayList();
Student student = new Student();
student.setClassName("三年级一班");
student.setName("姓名");
student.setSex("男");
student.setAge(10);
student.setHeight(120.3);
student.setWeight(40.2);
student.setAddress("xx省xx市xx县");
student.setAmount(new BigDecimal("1000.3"));
student.setRemark1("备注111111");
student.setRemark2("备注222222");
for (int i = 0; i < 20; i++) {
dataList.add(student);
}
// 数据居中
CellStyle dataCellStyle = workbook.createCellStyle();
dataCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
dataCellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
setDataList(sheet,1,dataList,dataCellStyle);
// 以流的方式写出文件
try {
os = new FileOutputStream(filePath);
workbook.write(os);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
8.2.3结果
9.整体代码(里面有冗余代码,根据需要自行提取方法)
public static void writeToExcel(){
// 文件路径,03版的文件名以.xls结尾,07版的文件名以.xlsx结尾
String filePath = "/Users/lavined/Desktop/test01.xls";
FileOutputStream os = null;
// 最大列数
int cellNum = 10;
int cellNumTemp = cellNum - 1;
// 工作表名称
String sheetName = "学生信息表";
// 创建工作簿对象
Workbook workbook = new HSSFWorkbook();
// 创建工作表对象
Sheet sheet = workbook.createSheet(sheetName);
// 设置列宽
sheet.setDefaultColumnWidth(13);
// 设置单元格格式
CellStyle cellStyle = workbook.createCellStyle();
// 边框颜色白色
cellStyle.setTopBorderColor(IndexedColors.WHITE.getIndex());
cellStyle.setLeftBorderColor(IndexedColors.WHITE.getIndex());
cellStyle.setRightBorderColor(IndexedColors.WHITE.getIndex());
cellStyle.setBottomBorderColor(IndexedColors.WHITE.getIndex());
// 边框线型
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
// 由于采用无边框样式以后,最后一个单元格的右边框会消失,所以给最后一个单元格的下一个单元格设置样式
CellStyle leftCellStyle = workbook.createCellStyle();
leftCellStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
leftCellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
// 内容居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 设置单元格格式
CellStyle cellStyle1 = workbook.createCellStyle();
// 内容居中
cellStyle1.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
// 背景色
cellStyle1.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
cellStyle1.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
// 边框颜色 黑色
cellStyle1.setTopBorderColor(IndexedColors.BLACK.getIndex());
cellStyle1.setLeftBorderColor(IndexedColors.BLACK.getIndex());
cellStyle1.setRightBorderColor(IndexedColors.BLACK.getIndex());
cellStyle1.setBottomBorderColor(IndexedColors.BLACK.getIndex());
// 边框线型
cellStyle1.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
cellStyle1.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
cellStyle1.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
cellStyle1.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
// 设置字体
Font font = workbook.createFont();
font.setBold(true);// 粗体
font.setFontHeightInPoints((short) 14);// 设置字体大小
cellStyle.setFont(font);
// 创建行对象
Row row = sheet.createRow(0);
for (int i = 0; i < cellNum; i++) {
// 创建单元格对象
Cell cell = row.createCell(i);
if (i == 0) {
cell.setCellValue(sheetName);
}
// 设置单元格样式
cell.setCellStyle(cellStyle);
}
row.createCell(cellNum).setCellStyle(leftCellStyle);
// 合并单元格
CellRangeAddress region1 = new CellRangeAddress(0, 0, 0, cellNumTemp);
sheet.addMergedRegion(region1);
// 空一行
sheet.createRow(1);
CellRangeAddress region2 = new CellRangeAddress(1, 1, 0, cellNumTemp);
sheet.addMergedRegion(region2);
// 第二级表头
Row sheetRow2 = sheet.createRow(2);
int lastRemarkCellNum = cellNum - 3;
for (int i = 0; i < cellNum; i++) {
Cell cell = sheetRow2.createCell(i);
if (i == 0) {
cell.setCellValue("班级:三年级一班");
}
if (i == 3) {
cell.setCellValue("人数:10人");
}
if (i == lastRemarkCellNum) {
cell.setCellValue("创建时间:2021-03-01 17:09:47");
}
// 设置单元格样式
cell.setCellStyle(cellStyle);
}
sheetRow2.createCell(cellNum).setCellStyle(leftCellStyle);
// 合并单元格
CellRangeAddress region3 = new CellRangeAddress(2, 2, 0, 2);
sheet.addMergedRegion(region3);
CellRangeAddress region4 = new CellRangeAddress(2, 2, 3, lastRemarkCellNum -1);
sheet.addMergedRegion(region4);
CellRangeAddress region5 = new CellRangeAddress(2, 2, lastRemarkCellNum, cellNumTemp);
sheet.addMergedRegion(region5);
sheet.createRow(3);
CellRangeAddress region6 = new CellRangeAddress(3, 3, 0, cellNumTemp);
sheet.addMergedRegion(region6);
// 数据表头字段
Map<Integer,String> dataHeadMap = new HashMap<>();
dataHeadMap.put(0, "班级");
dataHeadMap.put(1, "姓名");
dataHeadMap.put(2, "性别");
dataHeadMap.put(3, "年龄");
dataHeadMap.put(4, "身高");
dataHeadMap.put(5, "体重");
dataHeadMap.put(6, "家庭地址");
dataHeadMap.put(7, "饭卡余额");
dataHeadMap.put(8, "备注1");
dataHeadMap.put(9, "备注2");
// 报表数据项表头样式
Row row1 = sheet.createRow(4);
if (dataHeadMap != null) {
for (Map.Entry<Integer, String> headMap : dataHeadMap.entrySet()) {
Cell cell = row1.createCell(headMap.getKey());
cell.setCellValue(headMap.getValue());
if (null != cellStyle) {
cell.setCellStyle(cellStyle1);
}
}
}
// 数据内容
List dataList = new ArrayList();
Student student = new Student();
student.setClassName("三年级一班");
student.setName("姓名");
student.setSex("男");
student.setAge(10);
student.setHeight(120.3);
student.setWeight(40.2);
student.setAddress("xx省xx市xx县");
student.setAmount(new BigDecimal("1000.3"));
student.setRemark1("备注111111");
student.setRemark2("备注222222");
for (int i = 0; i < 20; i++) {
dataList.add(student);
}
// 数据居中
CellStyle dataCellStyle = workbook.createCellStyle();
dataCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
dataCellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
setDataList(sheet,5,dataList,dataCellStyle);
// 以流的方式写出文件
try {
os = new FileOutputStream(filePath);
workbook.write(os);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
9.1整体效果
10测试对比
10.1不同版本最大行,最大列
10.1.2超过最大行列则报错
10.2XSSFWorkbook与SXSSFWorkbook效率对比
07版本50万条10秒
07S版本50万条1秒
差别还是有的。