POI之EXCEL的import整理

本文详细介绍了如何使用Java实现从Excel批量导入黑名单数据至数据库的过程,包括文件上传、解析、数据验证、入库及结果反馈等关键步骤。

public UserImportResultVo importFromFile(HttpServletRequest request, BlacklistPo po) throws ServiceException {
/**
 * 1.保存上传文件到服务器
 */
//获取项目在容器中的实际发布运行的根路径
String basePath = request.getSession().getServletContext().getRealPath("/");//获取服务器Session路径
//根据前端的key值获取文件名
MultipartHttpServletRequest multipartHttpservletRequest = (MultipartHttpServletRequest) request;
MultipartFile file = multipartHttpservletRequest.getFile("fileImport");
String origName = file.getOriginalFilename();
//截取后缀来检查
String ext = FilenameUtils.getExtension(origName).toLowerCase();
SystemLogUtils.Debug("上传的导入文件:" + origName);
if (!("xls".equals(ext) || "xlsx".equals(ext))) {
      throw new ServiceException("请选择要导入的excel文件");
}
//构建导入文件保存路径
String datePath = DateConstants.DATE_FORMAT_NUM_SHORT().format(new Date());
path = path + "upload/" + user.getEntId() + "/blacklistImport/" + datePath;
//导入文件路径不存在就生成
File dir = new File(path);
if (!dir.exists()) {
    dir.mkdirs();
}
//构建导入文件新的名称
String fileName = user.getEntId() + "_" + DateConstants.DATE_FORMAT_NUM().format(new Date()) + new Random().nextInt(10) + "." + ext;
String destPath = path + "/" + fileName;
//新建文件
File destFile = new File(destPath);
try {
     //复制文件到新目录
     file.transferTo(destFile);
      } catch (IllegalStateException | IOException e) {
         e.printStackTrace();
         throw new ServiceException("上传文件失败");
      }
/**
* 2.解析excel,添加名单到库,返回导入结果及结果文件路径
*/
        try {
            //本地文件测试
            //path = path + "upload/" + user.getEntId();
            //String fileName = "7766114_blacklist_data.xlsx";
            //String destPath = path + "/" + fileName;
 
            resultVo = parseExcel(destPath, po, request, user);

        } catch (ServiceException e) {
            throw new ServiceException(e.getMessage());
        }

        return resultVo;
}


@Transactional
private UserImportResultVo parseExcel(String path, BlacklistPo po, HttpServletRequest request, SsoUserVo user) throws ServiceException {
String entId = user.getEntId();
List<DBObject> failedList = new ArrayList<DBObject>();
UserImportResultVo resultVo = new UserImportResultVo();
List<String> failList = new ArrayList<String>();// 失败记录列表
FileOutputStream fileOut = null; //导入结果输出文件

//构建导入结果返回路径
String resultPath = request.getSession().getServletContext().getRealPath("/");//获取服务器Session路径
String datePath = DateConstants.DATE_FORMAT_NUM_SHORT().format(new Date());
String relativePath = "upload/" + entId + "/blacklistImport/" + datePath + "/result/";
resultPath = resultPath + relativePath;

try {
     File file = new File(path);
     Workbook workbook = null; //多态,两种格式支持。
     if (path.endsWith("xlsx")) {
              workbook = new XSSFWorkbook(file.getPath());
     } else {
              workbook = new HSSFWorkbook(new FileInputStream(file));
     }

Sheet sheet = workbook.getSheetAt(0); // 获得第1个工作薄
int totalNum = 0;
int successNum = 0;
// 加入导入数量限制
int maxRow = sheet.getLastRowNum();
if(maxRow>20001){
      throw new Exception("批量添加导入数量过多,请限制在2万条以内! ");
}
// 创建导出结果标题行
Row hssfRow0 = sheet.getRow(0);
/**
 * 解析excel文件表头对应字段key,返回map
 */
Map<String, Integer> map = BlacklistTitleUtils.parseExcelTitle(hssfRow0);
if (map == null || map.size() == 0) {
       throw new ServiceException("Excel文件表头读取失败,请检查模板是否正确。");
}
// 获取excel文件总列数,新建导出结果的列
int physicalNumberOfCells = hssfRow0.getPhysicalNumberOfCells();
//excel的cell是从0开始算的,所以cell的数量就是下个cell的坐标
hssfRow0.createCell(physicalNumberOfCells).setCellValue("导入结果");
sheet.setColumnWidth(physicalNumberOfCells, 50 * 256);
// 循环行Row,从第1行开始
for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
      Row hssfRow = sheet.getRow(rowNum);
      if (hssfRow == null) {
            continue;
      }

     totalNum++;
     DBObject dbo = new BasicDBObject(); // 新建names数据库插入对象
      /**
       * 从excel这一行中,读取所有字段的值并存入dbo
       */
     for (Map.Entry<String, Integer> entry : map.entrySet()) {
             int cellNum = entry.getValue();
             String key = entry.getKey();
             String value = ExcelUtil.getValue(hssfRow.getCell(cellNum)).trim();
             dbo.put(key, value);
      }
            //固定字段
           dbo.put("entId", entId);
           dbo.put("creatorId", user.getUserId());
           dbo.put("creatorName", user.getUserName());
           dbo.put("createTime", createTime);
     try {
           if (StringUtils.isBlank((String) dbo.get("telPhone"))) {
       //为空抛出异常,然后捕获异常记录失败
                   throw new ServiceException("电话号码不能为空!");
       //或者直接记录失败然后continnue;
      /*String sv = "导入失败:第 " + rowNum + " 行, 添加名单失败!";
                   hssfRow.createCell(physicalNumberOfCells).setCellValue(sv);
                   failList.add(sv);
                   failedList.add(dbo); //记录失败
                   continue;*/
           }
           if (StringUtils.isBlank((String) dbo.get("userName"))) {
                   throw new ServiceException("客户姓名不能为空!");
           }
         
           int success = blacklistDao.addBlacklist(dbo, entId);  //保存名单到数据库。
           if (success == 0) {
               // 添加成功
               successNum++;
               hssfRow.createCell(physicalNumberOfCells).setCellValue("导入成功");
           } else {
                   String sv = "导入失败:第 " + rowNum + " 行, 添加名单失败!";
                   hssfRow.createCell(physicalNumberOfCells).setCellValue(sv);
                   failList.add(sv);
                   failedList.add(dbo); //记录失败
                   continue;
           }
       } catch (ServiceException addE1) {
            String s = "导入失败:第 " + rowNum + " 行, " + addE1.desc;
            hssfRow.createCell(physicalNumberOfCells).setCellValue(s);
            failList.add(s);
            failedList.add(dbo); //记录失败
            continue;
       } catch (Exception addE2) {
            // 失败
            addE2.printStackTrace();
            String s = "导入失败:第 " + rowNum + " 行, 导入失败!";
            failList.add(s);
            hssfRow.createCell(physicalNumberOfCells).setCellValue(s);
            failedList.add(dbo); //记录失败
            continue;
       }
}
//没数据直接返回失败
if (totalNum == 0)
       throw new ServiceException("没有有效数据");
//有导入错误,则生成结果文件返回
       int failNum = totalNum - successNum;
       if (failNum != 0) {
              String resultFileName = entId + "_blacklist_ImportResult" + new Random().nextInt(10) + ".xlsx";
              File dir = new File(resultPath);
              if (!dir.exists()) {
                    dir.mkdirs();
              }

             File destFile = new File(resultPath + resultFileName);
             if (!destFile.exists()) {
                 destFile.createNewFile();
             }
            SystemLogUtils.Debug("上传结果文件保存路径:" + resultPath + resultFileName);
            fileOut = new FileOutputStream(resultPath + resultFileName);
            workbook.write(fileOut);
            fileOut.close();

            resultVo.setResultFilePath(relativePath + resultFileName);
}

            workbook.close();

            resultVo.setTotalNum(totalNum + "");// 总记录条数
            resultVo.setImportSuccessNum(successNum + "");
            resultVo.setImportFailNum(failNum + "");
            resultVo.setFailList(failList);

            return resultVo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("解析excel文件失败,异常:" + e.getMessage());
        }
}


 

<think>好的,我现在需要帮助用户解决如何使用Apache POI生成Excel文件的问题。用户还希望看到示例代码,并且是用Java写的。首先,我得回忆一下Apache POI的相关知识,特别是关于创建Excel文件的部分。 根据用户提供的引用内容,引用[1]和[2]提到Apache POI可以用于创建、写入和读取Excel文件,尤其是引用[2]指出POI可以写入数据到Excel。引用[5]也提到POI支持Excel文件的读写。此外,引用[4]比较了POI和EasyExcel的内存管理,说明在处理大数据量时POI可能消耗较多内存,但用户的问题主要是生成文件,所以暂时不需要考虑优化,但可能需要提醒用户注意内存问题。 首先,我需要确定用户可能需要的步骤。生成Excel文件通常包括创建Workbook对象,创建Sheet,创建行和单元格,设置单元格的值和样式,最后将文件写入磁盘。 接下来,我应该检查是否需要处理不同版本的Excel文件,比如.xls(HSSF)和.xlsx(XSSF)。根据引用[5],POI支持OOXML和OLE2格式,所以需要区分HSSFWorkbook和XSSFWorkbook。用户可能希望生成较新的.xlsx文件,所以示例代码应该使用XSSF。 然后,单元格样式的设置也是一个重要部分,如字体、颜色、对齐方式等。引用[1]提到本教程包括单元格样式设置,所以示例中需要包含这部分代码。 用户可能需要完整的示例代码,包括导包语句、异常处理以及资源释放(关闭流)。因此,代码中应该使用try-with-resources来自动关闭文件流,确保资源的正确释放。 另外,用户的问题中提到“生成相关问题”,所以回答后需要生成几个相关问题,比如优化方法、处理大数据量、样式设置等,这些可以基于引用中的内容来设计,比如引用[4]提到的内存管理问题,引用[3]中的读取操作,引用[1]中的样式设置。 现在,我需要确保代码的正确性。例如,创建Workbook、Sheet、Row、Cell的步骤是否正确,样式设置是否正确应用。比如,创建Workbook实例时使用XSSFWorkbook,然后创建Sheet,接着创建行和单元格,设置值,应用样式,最后写入文件。 可能需要注意的细节:单元格的索引是从0开始,样式对象需要通过workbook.createCellStyle()创建,字体也是如此。需要确保样式正确关联到单元格。 最后,总结步骤,分点说明,让用户清晰理解。同时,提醒用户处理异常和关闭资源的重要性,可能的大文件处理问题,引用[4]的内容可以作为优化建议放在相关问题里。 现在,我需要将这些思考整理成一个结构化的回答,包含步骤说明、示例代码和相关问题。确保代码语法正确,符合POI 3.5版本的API,因为引用[1]提到基于3.5版本,但用户可能使用较新版本,但基本API应该相似,不过可能需要检查是否有过时的方法。例如,创建Workbook和Sheet的API是否变化不大,通常这些基本操作在版本迭代中保持稳定。 检查示例代码是否有误,比如是否正确处理了异常,是否正确使用了try-with-resources,是否正确创建了单元格样式,比如合并单元格、设置字体加粗等。 总结,回答应包括:步骤说明、示例代码、相关问题,并引用相关的引用内容作为支持。</think>### 如何使用Apache POI生成Excel文件 以下是使用Apache POI生成Excel文件的详细步骤及示例代码: --- #### **步骤说明** 1. **添加依赖** 在Maven项目的`pom.xml`中添加Apache POI依赖: ```xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> ``` 2. **创建Workbook和Sheet** - 使用`XSSFWorkbook`生成`.xlsx`格式文件(或`HSSFWorkbook`生成旧版`.xls`)。 - 通过`createSheet()`方法创建工作表。 3. **填充数据** - 创建行(`Row`)和单元格(`Cell`),通过`setCellValue()`写入数据。 - 合并单元格使用`sheet.addMergedRegion()`。 4. **设置样式** - 定义字体(`Font`)、单元格样式(`CellStyle`),如加粗、居中对齐、背景色等。 - 将样式绑定到单元格。 5. **写入文件** 使用`FileOutputStream`将Workbook保存到本地文件。 --- #### **示例代码** ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileOutputStream; public class ExcelGenerator { public static void main(String[] args) { try (Workbook workbook = new XSSFWorkbook()) { // 1. 创建工作表 Sheet sheet = workbook.createSheet("员工信息"); // 2. 创建标题行并合并单元格 Row titleRow = sheet.createRow(0); titleRow.createCell(0).setCellValue("员工信息表"); sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3)); // 3. 设置标题样式 CellStyle titleStyle = workbook.createCellStyle(); titleStyle.setAlignment(HorizontalAlignment.CENTER); Font titleFont = workbook.createFont(); titleFont.setBold(true); titleFont.setFontHeightInPoints((short) 16); titleStyle.setFont(titleFont); titleRow.getCell(0).setCellStyle(titleStyle); // 4. 添加表头 Row headerRow = sheet.createRow(1); String[] headers = {"姓名", "部门", "工号", "入职日期"}; CellStyle headerStyle = workbook.createCellStyle(); headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headerStyle); } // 5. 填充数据 Row dataRow = sheet.createRow(2); dataRow.createCell(0).setCellValue("张三"); dataRow.createCell(1).setCellValue("技术部"); dataRow.createCell(2).setCellValue("1001"); dataRow.createCell(3).setCellValue("2023-01-15"); // 6. 自动调整列宽 for (int i = 0; i < headers.length; i++) { sheet.autoSizeColumn(i); } // 7. 保存文件 try (FileOutputStream fos = new FileOutputStream("EmployeeData.xlsx")) { workbook.write(fos); System.out.println("Excel文件生成成功!"); } } catch (Exception e) { e.printStackTrace(); } } } ``` --- #### **关键点说明** - **Workbook类型**:`XSSFWorkbook`用于生成`.xlsx`文件,`HSSFWorkbook`用于旧版`.xls`[^5]。 - **资源释放**:使用`try-with-resources`自动关闭流,避免内存泄漏[^4]。 - **性能优化**:处理大数据量时,建议分批次写入或使用`SXSSFWorkbook`流式处理[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值