Excel 文件数据导入数据库

首先说明下读写Excel三种常用的技术:
  1. POI : 效率高,操作相对JXL复杂,支持公式,宏,图像图表,一些企业应用上会比较实用.能够修饰单元格属性.字体 数字 日期操作.
  2. FASTEXCEL: 不可操作样式,推荐简单的导入,速度快.
  3. JXL : 效率低,简单.部分支持.能够修饰单元格属性,但没有POI强大.同样支持字体 数字 日期操作.

本次演示的是使用POI进行导入

为了快速搭建使用SpringBoot,先导入相关Jar包.

<!-- POI -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.8</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-codec</artifactId>
                    <groupId>commons-codec</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.8</version>
        </dependency>
        .....省略相关数据库驱动.

大体流程 :

1.前端页面文件提交按钮,把需要导入的Excel文件提交上去.
2.后端处理器接收后对文件进行读取,并分析信息.然后把文件中的每一行封装为一个对象,添加进入list集合中.
3.(可省略)把封装好的list集合存入缓存中(Redis),把提取出来的数据相应给前端页面,给操作者检查.其中数据包含分析数据,提示哪里可能出现遗漏数据.当操作者缺认后,点击添加,则将缓存中数据取出对应存入数据库中.
最关键的一步还是在提取数据环节(这里可能会遇到空指针异常 , 就需要处理.),需要保证精确的提取出数据,防止遗漏.

上代码(关键部分代: 提取数据)

    /**
 * 处理Excel文件数据,打包成List对象集合
 * @param file Excel数据文件
 * @return
 */
public static (打包对象) readExcel(MultipartFile file){

    //============准备工作,相关参数,也可创建一个配置类,来封装一下参数.
    int page = 页数;     //页数 
    int col = 列数;       //列 
    int rows = 0;      //行数
    String msg = "非常流畅,无失误!"; //错误消息
    int num = 0;        //实际处理多少条数据
    int num1= 0;       //完整无跳转处理多少页
    int num2= 0;       //处理到多少页
    List<String> erNum = new ArrayList<>(); //记录哪个点进行跳转,触发自动跳转次数
    List<Shop> list = new ArrayList<>(); //封装后的对象集合
    实体对象 object = null;   // 根据Excel数据创建的实体类
    long endTime = 0;     //结束时间
    long startTime = 0;   //开始时间

    try{
        log.info("即将处理文件:{}",file.getOriginalFilename());
        InputStream is = file.getInputStream(); //获取文件流信息
        Workbook wb = new XSSFWorkbook(is);
        Sheet sheet = null;                     //页对象
        startTime = System.currentTimeMillis(); //计时开始(性能检测)
      //======开始读取===========
        for(int k = 0; k < page; k++){  //循环每一页

            sheet = wb.getSheetAt(k);
            //rows = sheet.getPhysicalNumberOfRows()-1;  //获取物理行数-1 减去标题一栏
            rows = sheet.getLastRowNum();                //最后的行号
            System.out.println("当前页数:"+ (k+1) +" 本页行数:"+ (rows-1));
            num2++;
            //一下两行代码业务需要可添加: 比如可能有跨行的列,多行使用同一个列的情况下,举个例子:广东省下深圳,佛山.....
            String temp = "暂无";         //临时属性变量
            String temp1 = "暂无";        //临时属性变量
            for(int j = 0;j < rows;j++){  //循环每一行

                log.info("当前行数:{}",j);
                //判断是否为空列,空行.解决读取出来的行数与实际有数据的行数不符,如果为空则自动跳过本页,防止空指针异常.并且记录下.
                if(!StringUtils.hasText(sheet.getRow(j).getCell(0).toString()) &&
                   !StringUtils.hasText(sheet.getRow(j).getCell(1).toString()) &&
                   !StringUtils.hasText(sheet.getRow(j).getCell(2).toString()) ||
                    sheet.getRow(j).getCell(2).getCellType() == HSSFCell.CELL_TYPE_BLANK &&  //第3个属性为空
                    sheet.getRow(j).getCell(3).getCellType() == HSSFCell.CELL_TYPE_BLANK){   //第4个属性为空

                    //遇到无数据的行时,自动下一页.
                    log.debug("非正常退出,截止到"+j+"行,遇到空数据,自动下一页!");
                    erNum.add(k+1+"页-"+j+"行");
                    break;
                }

                shop = new Shop();
                for(int i = 0; i < col; i++){  //循环每一列
                    System.out.println(sheet.getRow(j).getCell(i).toString());//getStringCellValue());
                    switch (i){
                        case 0:  //设置属性
                            if(sheet.getRow(j).getCell(i).toString() != null &&
                                    sheet.getRow(j).getCell(i).getCellType() != HSSFCell.CELL_TYPE_BLANK ){  //判断如果有属性的话就把存为临时变量
                                temp = sheet.getRow(j).getCell(i).toString();
                                shop.setProvince(sheet.getRow(j).getCell(i).toString()); //可替换代码(插入属性)
                            }else{                                                 //否则没有的话就用之前的临时变量代替
                                shop.setProvince(temp);
                            }
                            break;
                        case 1: //设置建材属性
                            if(sheet.getRow(j).getCell(i).toString() != null &&
                                    sheet.getRow(j).getCell(i).getCellType() != HSSFCell.CELL_TYPE_BLANK){
                                temp1 = sheet.getRow(j).getCell(i).toString();
                                shop.setBazaar(sheet.getRow(j).getCell(i).toString()); //可替换代码(插入属性)
                            }else{
                                shop.setBazaar(temp1); //可替换代码(插入属性)
                            }
                            break;
                        case 2: //设置属性 
                            shop.setStore(sheet.getRow(j).getCell(i).toString());//可替换代码(插入属性)
                            break;
                        case 3: //设置属性
                            shop.setAddress(sheet.getRow(j).getCell(i).toString());//可替换代码(插入属性)
                            break; 
                        case 4: //设置属性
                            shop.setPhone(sheet.getRow(j).getCell(i).toString()); //可替换代码(插入属性)
                            break;
                        case 5: //设置属性
                            shop.setResult(sheet.getRow(j).getCell(i).toString());//可替换代码(插入属性)
                            break;
                    }
                }
                list.add(shop); //添加一个对象,
                System.out.println("-------------------------------------------------");
                num ++;
                if(( j + 1) == rows){
                    System.out.println("处理完本页数据:截止" + j + "行,即将处理下一页数据!");
                    num1++;
                }
            }
        }
        endTime = System.currentTimeMillis(); //计时结束
    }catch (Exception e){
        log.error("错误 ExcelHandle => readExcel() : {}",e.toString());
        msg = "错误 ExcelHandle => readExcel() : " + e.toString();
    }finally{
        System.out.println("=========================");
        System.out.println("          读取结果");
        System.out.println("=========================");
        System.out.println("实际处理数据条数为:" + num);
        System.out.println("完整无跳转处理页数:"+ num1);
        System.out.println("总共处理页数:"+num2);
        System.out.println("-------------------------");
        System.out.println("自动触发跳转次数:" + erNum.size());
        erNum.stream().forEach(t -> System.out.println(t));
        System.out.println("-------------------------");
        System.out.println("扫描时间:" + (endTime - startTime) + "ms"); //输出程序运行时间
        System.out.println("错误信息:" + msg);

        //封装数据并返回
        analyse = new Analyse();
        analyse.setNum(num);
        analyse.setNum1(num1);
        analyse.setNum2(num2);
        analyse.setErNum(erNum);
        analyse.setMsg(msg);
        analyse.setList(list);
    }
    return analyse;
}

控制台输出结果信息:

提取出后即可以对数据进行持久化操作.如果需要其余代码的,可以在评论区留言.

更多推荐

Excel数据导入数据库(Java)