在日常开发中,Excel 的导入导出是非常常见的需求,尤其在管理系统中更是必不可少的功能。本文将基于实际项目代码,介绍三种不同的 Excel 导入导出实现方式,包括使用 EasyPOI 工具、自定义 POI 操作以及结合模板的 Excel 生成方式,并对它们的优缺点进行分析对比。
一、使用 EasyPOI 实现 Excel 操作
EasyPOI 是一款基于 POI 封装的 Excel 处理工具,它简化了 Excel 的导入导出代码,使开发更加高效。
1.1 导出功能实现
/**
* 数据导出接口
*/
@GetMapping("/exportExcel")
public Result exportExcel(PersonListQuery query) {
// 1. 获取要导出的人员数据列表
List<PersonListVO> personListvo = personService.exportExcel(query);
// 2. 设置导出参数
ExportParams exportParams = new ExportParams("人员数据报表","人员数据");
exportParams.setStyle(ExcelExportStylerColorImpl.class);
// 3. 生成Excel工作簿
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, PersonListVO.class, personListvo);
String fileName = System.currentTimeMillis()+".xls";
String filePath = Paths.get(excelPath, fileName).toString();
// 4. 确保存储目录存在
File file = new File(excelPath);
if (!file.exists()) {
file.mkdirs();
}
try{
// 5. 写入文件
ByteArrayOutputStream out = new ByteArrayOutputStream();
workbook.write(out);
byte[] excelBytes = out.toByteArray();
Files.write(Paths.get(filePath), excelBytes);
// 6. 关闭资源
out.close();
workbook.close();
}catch (Exception e){
e.printStackTrace();
return Result.error("导出失败");
}
return Result.ok().put("data",fileName);
}
1.3 EasyPOI 方式优缺点
优点:
- 代码简洁,开发效率高
- 注解驱动,配置灵活
- 支持复杂表头、图片等复杂场景
- 自带样式美化功能
缺点:
- 额外引入第三方依赖
- 对于非常复杂的 Excel 模板支持不够灵活
二、基于 POI 的自定义 Excel 工具类
当需要更精细的控制 Excel 格式时,可以直接使用 Apache POI 进行自定义开发,封装成工具类使用。
public class ExcelUtil {
public static String ExpPersonInfo(List<PersonVO> info, String path){
POIFSFileSystem fs = null;
int headRow = 2;// 数据起始行(跳过前2行表头)
String descfile = null;
try {
// 1. 复制模板文件
String srcfile = path + "personInfo.xls";// 源模板文件路径
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String dateStr = format.format(date);
descfile = dateStr + ".xls";
FileInputStream fis = new FileInputStream(srcfile);
FileOutputStream fos = new FileOutputStream(path+descfile);
byte [] buffer = new byte[1024*4];
while(fis.read(buffer) != -1){
fos.write(buffer);
}
fis.close();
fos.close();
// 2. 打开新创建的文件并写入数据
fs = new POIFSFileSystem(new FileInputStream(path + descfile));
fos = new FileOutputStream(path + descfile);
HSSFWorkbook wb1 = new HSSFWorkbook(fs);
HSSFSheet sheet = wb1.getSheetAt(0);
// 3. 创建单元格样式
HSSFCellStyle style = wb1.createCellStyle();
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);
// 4. 写入数据
int size = info.size();
for(int i = 0;i < size;i++){
int col = 0;
PersonVO p = info.get(i);
HSSFRow row = sheet.createRow(i+headRow);
HSSFCell cell = row.createCell(col++);
cell.setCellStyle(style);
cell.setCellValue(p.getPersonId());
cell = row.createCell(col++);
cell.setCellStyle(style);
cell.setCellValue(p.getCommunityName());
// 其他列...
}
// 5. 保存并关闭
wb1.write(fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return descfile;
}
}
2.1 自定义工具类优缺点
优点:
- 完全自定义,灵活性高
- 可以精确控制 Excel 的每一个单元格
- 可以结合模板生成复杂格式的 Excel
缺点:
- 代码量大,开发效率低
- 需要手动处理样式、边框等细节
- 需注意资源关闭,否则可能导致内存泄漏
三、基于 POI 的通用导入实现
对于 Excel 导入,也可以直接使用 POI 实现通用的解析方案,适用于各种复杂结构的 Excel。
/**
* 数据导入操作
*/
@PostMapping("/parsefile/{fileName}")
public Result parsefile(@PathVariable("fileName") String fileName, HttpSession session){
User user = (User) session.getAttribute("user");
POIFSFileSystem fs = null;
HSSFWorkbook wb = null;
try {
// 1. 读取Excel文件
String basePath = excel + fileName;
fs = new POIFSFileSystem(new FileInputStream(basePath));
wb = new HSSFWorkbook(fs);
} catch (Exception e) {
e.printStackTrace();
}
// 2. 解析Excel内容到二维数组
HSSFSheet sheet = wb.getSheetAt(0);
Object[][] data = null;
int r = sheet.getLastRowNum()+1;
int c = sheet.getRow(0).getLastCellNum();
int headRow = 2;
data = new Object[r - headRow][c];
for (int i = headRow; i < r; i++) {
HSSFRow row = sheet.getRow(i);
for (int j = 0; j < c; j++) {
HSSFCell cell = null;
try {
cell = row.getCell(j);
DataFormatter dataFormater = new DataFormatter();
String a = dataFormater.formatCellValue(cell);
data[i - headRow][j] = a;
} catch (Exception e) {
data[i-headRow][j] = "";
// 特殊处理第一列
if(j==0){
try {
double d = cell.getNumericCellValue();
data[i - headRow][j] = (int)d + "";
}catch(Exception ex){
data[i-headRow][j] = "";
}
}
}
}
}
// 3. 处理解析后的数据并保存到数据库
int row = data.length;
String errinfo = "";
headRow = 3;
for (int i = 0; i < row; i++) {
Person single = new Person();
single.setPersonId(0);
single.setState(1);
single.setFaceUrl("");
try {
int col=1;
String communityName = data[i][col++].toString();
QueryWrapper<Community> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("community_name", communityName);
Community community = this.communityService.getOne(queryWrapper);
if( community == null){
errinfo += "Excel文件第" + (i + headRow) + "行小区名称不存在!";
return Result.ok().put("status", "fail").put("data", errinfo);
}
single.setCommunityId(community.getCommunityId());
single.setTermName(data[i][col++].toString());
single.setHouseNo(data[i][col++].toString());
single.setUserName(data[i][col++].toString());
// 设置其他字段...
this.personService.save(single);
} catch (Exception e) {
e.printStackTrace();
}
}
return Result.ok().put("status", "success").put("data","数据导入完成!");
}
3.1 通用 POI 导入优缺点
优点:
- 可以处理各种复杂格式的 Excel
- 对 Excel 结构的控制更加精细
- 适合导入格式不固定的场景
缺点:
- 代码复杂,需要处理各种异常情况
- 解析逻辑与业务逻辑混合,可读性差
- 开发和维护成本高
四、三种方式的对比与选择建议
实现方式 | 开发效率 | 灵活性 | 适用场景 | 依赖 |
---|---|---|---|---|
EasyPOI | 高 | 中 | 大部分常规导入导出场景 | 需引入 EasyPOI 依赖 |
自定义 POI 工具类 | 中 | 高 | 需要精确控制 Excel 格式,结合模板 | 仅需 POI 依赖 |
通用 POI 导入 | 低 | 高 | 复杂 Excel 结构,格式不固定 | 仅需 POI 依赖 |
选择建议:
- 对于大多数常规的 Excel 导入导出需求,优先选择 EasyPOI,开发效率最高
- 当需要使用模板生成复杂格式 Excel 时,可以采用自定义 POI 工具类的方式
- 当 Excel 格式复杂且不固定,或者有特殊解析需求时,才考虑使用通用 POI 导入方式
- 导入导出功能较多的项目,建议封装统一的工具类或服务,避免代码重复
五、文件上传通用处理
无论采用哪种导入方式,都需要先处理文件上传,以下是一个通用的文件上传实现:
@PostMapping("/excelUpload")
public Result excelUpload(@RequestParam("uploadExcel") MultipartFile file) throws Exception {
if(file.getOriginalFilename().equals("")){
return Result.error("没有选中要上传的文件");
}else {
// 生成唯一文件名
String picName = UUID.randomUUID().toString();
String oriName = file.getOriginalFilename();
String extName = oriName.substring(oriName.lastIndexOf("."));
String newFileName = picName + extName;
// 保存文件
File targetFile = new File(excel, newFileName);
file.transferTo(targetFile);
return Result.ok().put("data",newFileName);
}
}
六、总结
Excel 导入导出是 Java 开发中的常见功能,选择合适的实现方式可以大大提高开发效率。EasyPOI 作为封装完善的工具,能够满足大部分需求;而当遇到复杂场景时,直接使用 POI 进行自定义开发则更加灵活。在实际项目中,应根据具体需求选择合适的实现方式,同时注意代码的可维护性和资源的正确释放。