POI优化读取EXCEL方式
本文适用于EXCEL表格的表头与当前实体类字段对应的方式
1.构建与excel对应的实体类
public class SysUser implements Serializable {
private static final long serialVersionUID=1L;
/**
* 测试字段,一会演示用,后面会提到
*/
private String testStr1;
/**
* 测试字段,一会演示用,会面会提到
*/
private String testStr2;
/**
* id
*/
private Integer id;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String passWord;
/**
* 邮箱
*/
private String email;
/**
* 昵称
*/
private String nickName;
/**
* 备注信息
*/
private String note;
/**
* 创建时间
*/
private Date createTime;
/**
* 最后登录时间
*/
private Date loginTime;
/**
* 帐号启用状态:0->禁用;1->启用
*/
private Integer status;
2. 简单展示当前优化后的代码,具体业务处理由个人进行处理
/**
* 大家主要关注对excel读取的处理即可
*/
public CommonResult batchImport(MultipartFile file) {
//获取当前文件流
String fileName = file.getOriginalFilename();
//对当前excel格式做判断,我这里只对2007版本的做了判断
if (!fileName.matches("^.+\\.(?i)(xlsx)$")) {
return CommonResult.failed("请上传excel2007版本及以上的xlsx文件");
}
try {
//根据当前文件流获取到XSSFWorkbook 对象
XSSFWorkbook xssf = new XSSFWorkbook(file.getInputStream());
//获取所有sheet表
int numberOfSheets = xssf.getNumberOfSheets();
//创建读取数据存储集合
List<SysUser> sysUserList = new ArrayList<>();
//遍历所有sheet表
for (int i = 0; i < numberOfSheets; i++) {
//获取当前sheet表
XSSFSheet sheet = xssf.getSheetAt(i);
//获得所有的行数
int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();
//对当前所有行数遍历,获取每行数据
for (int j = 0; j < physicalNumberOfRows; j++) {
//因excel 第一行为0,所以跳过第一行,因为第一行是表头,大家可根据实际情况选择
if (j == 0) {
continue;
}
//获取当前行XSSFRow对象
XSSFRow row = sheet.getRow(j);
//这里是我以表头来确定单元格的数量,进行后续遍历
int physicalNumberOfCells = sheet.getRow(0).getPhysicalNumberOfCells();
//创建当前对象
SysUser sysUser = new SysUser();
//通过Java反射,获取当前对象所有对象属性
Field[] f = SysUser.getClass().getDeclaredFields();
//遍历当前行所有单元格
for (int k = 0; k < physicalNumberOfCells; k++) {
//当前单元格数据
String stringCellValue = "";
//获取当前单元格XSSFCell对象
XSSFCell cell = row.getCell(k);
//对当前单元格进行非null处理
if (cell != null) {
//设置当前单元格类型,建议均为string类型(文本类型),方便处理
cell.setCellType(Cell.CELL_TYPE_STRING);
//对当前单元格赋值
stringCellValue = cell.getStringCellValue();
}
//关键地方,此时对应当前对象(k+2代表,我需要跳过当前对象的前2个属性,就是上面testStr1和testStr2,对后面的属性赋值)
String attributeName = f[k + 2].getName();
//因赋值原因,我需要对象id进行转大写,如:id ——> Id
String methodName = attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1);
//根据反射机制,拼接set,如:setId
Method setMethod = SysUser.getClass().getMethod("set" + methodName, String.class);
//此时进行赋值操作
setMethod.invoke(SysUser, stringCellValue);
}
//添加到集合中
sysUserList.add(SysUser);
}
}
return CommonResult.success(null, "上传文件成功");
} catch (Exception e) {
e.printStackTrace();
return CommonResult.failed("上传文件格式错误或文件数据有误,请联系管理员");
}
}
此方式要比通过row.getCell(0),row.getCell(1)赋值方式减少大量的重复代码,当然也需要注意的是要与实体类一一对应
3. 以下为excel 的表头
id | 用户名 | 密码 | 邮箱 | 昵称 | 备注信息 |
---|
此时也可看出代码中k+2的处理就是跳过实体类前2个属性,从而进行做到赋值操作,这里一但不对应,就会出现绑定数据错误,要多多注意。