java实现导入导出Excel文件

2020-02-26  本文已影响0人  范er_er

导包

第一步从导包开始,关于这个Excel表,已经有了一套现成的依赖包:

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.6</version>
        </dependency>

这个也是我在网上找的依赖,各种帖子中的依赖版本不同,反正这个3.6是我目前看到的最高版本。至于有没有更新的不确定,反正这个可以使用。然后好多帖子引用了几个依赖,但是反正我实测,导入导出这一个依赖就能搞定。

导入Excel文件工具类

这个分两个,一个是导入工具,一个是导出工具
大概说一下工作原理:导入就是把Excel文件解析,一个单元格一个单元格的转化成想要的数据。有的转成数组,有的转成map,我反正直接转成想要的对象了。
我也看了一些技术贴的做法,有的简单有的麻烦,反正大体过程是一样的。接下来上代码(因为涉及到公司数据格式,所以对象用User来代替):

    /**
     * 检验文件是否有效
     * 
     * @param file
     * @throws Exception
     */
    public static void checkFile(MultipartFile file) throws Exception {
        // 判断文件是否存在
        if (null == file) {
            throw new FileNotFoundException("文件不存在!");
        }
        // 获得文件名
        String fileName = file.getOriginalFilename();
        // 判断文件是否是excel文件
        if (!fileName.endsWith("xls") && !fileName.endsWith("xlsx")) {
            throw new IOException(fileName + "不是excel文件");
        }
    }

上面这个方法单纯的为了判断一个文件是否是Excel文件。毕竟文件格式不对整个解析都不能继续。


    /**
     * 获取workbook
     * 
     * @param file
     * @return
     */
    public static Workbook getWorkBook(MultipartFile file) {
        // 获得文件名
        String fileName = file.getOriginalFilename();
        // 创建Workbook工作薄对象,表示整个excel
        Workbook workbook = null;
        try {
            // 获取excel文件的io流
            InputStream is = file.getInputStream();
            // 根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象
            if (fileName.endsWith("xls")) {
                // 2003
                workbook = new HSSFWorkbook(is);
            } else if (fileName.endsWith("xlsx")) {
                // 2007
                workbook = new XSSFWorkbook(is);
            }
        } catch (IOException e) {

        }
        return workbook;
    }

这个方法是为了获取文件的workbook实现类对象。因为Excel文件分为xls和xlsx两种格式,所以要做个判断。
其实这两个方法写在一起,或者说这个三个方法写在一起都可以,但是我还是分开写了,这样每个类干什么的就会很清楚的知道了。


    /**
     * 获取解析后的文件内容
     * 
     * @return
     */
    public static List<User> readExcel(MultipartFile file) {
        List<User> list = new ArrayList<User>();
        try {
            checkFile(file);
            // 获得Workbook工作薄对象
            Workbook workbook = getWorkBook(file);
            int sheetSize = workbook.getNumberOfSheets();
            for (int i = 0; i < sheetSize; i++) {// 遍历sheet页
                // 获取第一个张表
                Sheet sheet = workbook.getSheetAt(0);
                // 获取每行中的字段
                for (int j = 0; j <= sheet.getLastRowNum(); j++) {
                    Row row = sheet.getRow(j); // 获取行
                    if (row == null) {//略过空行
                        continue;
                    }else{
                    // 获取单元格中的值并存到对象中
                    User user = new User();
                    user.setFullName(row.getCell(0).getStringCellValue());
                    user.setPassword(row.getCell(1).getStringCellValue());
                    user.setUsername(row.getCell(2).getStringCellValue());
                    list.add(user);
                    }
                }
            }
        } catch (Exception e) {
            throw new Exception("Excel导入失败!");
        }
        return list;
    }

最后这个方法是把workbook对象转化成自己想要的。注解写的很清楚,首先遍历页,然后遍历行,每一行在拆分,每行第一个单元格下标是0,依次顺序往后。这个顺序注意,我反正是表格和实体对应着一个个取出来set进去的。尤其是如果一行十几个甚至很多的数据,千万别写反了就行。
demo中用的user来做例子,所以只有三列,但是实际上肯定比这个要麻烦的。最后把一行一行解析的对象放入list中返回。
因为这个get的过程肯定要针对具体情况来写,所以我直接一步到位set进对象里,我看很多教程都是放到map中,然后在map集合遍历取出放到对象中,具体要怎么做都可以。
反正这个方法得到的结果集就是我们解析exc文件获取到的想要的结果集。

数据格式问题:

但是这个是很空洞的情况,真正解析起来各种数据是不同的,最简单的比方,一个时间日期格式也用String类型接收,就会从日期变成小数,解析都不好解析的那种。
同理,如果是数字类型的格子,也没必要先换成string接收再转回数字。
我们可以用set方法先设置好某个格子是什么数据类型的。
例如:row.getCell(1).setCellType(Cell.CELL_TYPE_NUMERIC);
上面的代码就是设置第二个格子(因为从0开始,所以1是第二个格子)是数值类型的。
poi类有很多不同常量的定义:

image

这个设置和获取要配对,比如设置布尔类型,然后用string类型获取就会报错:

Cannot get a text value from a numeric cell

这个错就是不能从一个数值类型获取string。

判空问题

这个我感觉应该也是很常见的一个需求,我们要判断excel文件中某些必填字段是否为空,如果是则直接返回前端而不浪费时间。
其实我提出来这个是因为我在这里遇到了一个小小的坑,我以为取出来如果是null或者如果是“”则为空。
但是实际上如果格子里面没有内容,在取的过程中就会报错!因为你把一个blank(空)格式的格子用别的类型来获取了!
所以这里的非空判断要做一点小小的修改:

row.getCell(k) == null 

直接用getCell来判断,没有下一步的获取内容。

导出Excel文件工具类

这个导入导出用的都是这一个依赖,所以就不多说了。直接说操作:
导入的原理就是把对象集合以Excel表格的形式导出。
大体的操作流程也差不多,就是设置文件格式,设置表头,然后往里循环添加数据。下面是完整的代码例子(为了防止公司数据泄露所以用user举例):

public static HSSFWorkbook getHSSFWorkbook(List<User> list){

        // 第一步,创建一个HSSFWorkbook,对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();

        // 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet();

        // 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);

        // 第四步,创建单元格,并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();

        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式

        HSSFCell cell1 = row.createCell(0);
        cell1.setCellValue("日期");
        cell1.setCellStyle(style);

        HSSFCell cell2 = row.createCell(1);
        cell2.setCellValue("昵称");
        cell2.setCellStyle(style);

        HSSFCell cell3 = row.createCell(2);
        cell3.setCellValue("名称");
        cell3.setCellStyle(style);

        HSSFCell cell4 = row.createCell(3);
        cell4.setCellValue("年龄");
        cell4.setCellStyle(style);

        HSSFCell cell5 = row.createCell(4);
        cell5.setCellValue("体重");
        cell5.setCellStyle(style);

        HSSFCell cell6 = row.createCell(5);
        cell6.setCellValue("爱好");
        cell6.setCellStyle(style);

        HSSFCell cell7 = row.createCell(6);
        cell7.setCellValue("工作");
        cell7.setCellStyle(style);

        HSSFCell cell8 = row.createCell(7);
        cell8.setCellValue("家庭住址");
        cell8.setCellStyle(style);

        HSSFCell cell9 = row.createCell(8);
        cell9.setCellValue("婚恋状态");
        cell9.setCellStyle(style);

        HSSFCell cell10 = row.createCell(9);
        cell10.setCellValue("工作单位");
        cell10.setCellStyle(style);

        HSSFCell cell11 = row.createCell(10);
        cell11.setCellValue("性别");
        cell11.setCellStyle(style);

        HSSFCell cell12 = row.createCell(11);
        cell12.setCellValue("是否是新用户");
        cell12.setCellStyle(style);

        HSSFCell cell13 = row.createCell(12);
        cell13.setCellValue("密码");
        cell13.setCellStyle(style);

        //创建内容
        for(int i=0;i<list.size();i++){
           //第一行是表头,第二行开始插数据
            row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
            row.createCell(1).setCellValue(list.get(i).getNick());
            row.createCell(2).setCellValue(list.get(i).getName());
            //插入的数据是数字
            Cell cella = row.createCell(3);
            cella.setCellType(Cell.CELL_TYPE_NUMERIC);
            cella.setCellValue(list.get(i).getAge());
            Cell cellb = row.createCell(4);
            cellb.setCellType(Cell.CELL_TYPE_NUMERIC);
            cellb.setCellValue(list.get(i).getWeight().doubleValue());
            Cell cellc = row.createCell(5);
            //别问我为啥爱好是double,我就是测试数据类型
            cellc.setCellType(Cell.CELL_TYPE_NUMERIC);
            cellc.setCellValue(list.get(i).getLike().doubleValue());
            row.createCell(6).setCellValue(list.get(i).getWork());
            row.createCell(7).setCellValue(list.get(i).getAddress());
            row.createCell(8).setCellValue(list.get(i).getLoveStatus());
            row.createCell(9).setCellValue(list.get(i).getWorkAddress());
            row.createCell(10).setCellValue(list.get(i).getSex());
            Cell celld = row.createCell(11);
            celld.setCellType(Cell.CELL_TYPE_NUMERIC);
            celld.setCellValue(list.get(i).getIsNew()==null?0: list.get(i).getIsNew().intValue());
            row.createCell(12).setCellValue(list.get(i).getPassword());

        }
        return wb;
    }

如上,一个数据导出到Excel文件完成。不过这个还只是数据格式,而不是一个真真实实可打开的xls文件。
因为我们的项目是前后端分离的,也不要求我在服务器生成一个文件啥的,主要还是把数据发给前端,所以还有个发送给前端的过程(最简化操作,一点业务逻辑没写,根据实际情况添加):

 public void export(HttpServletResponse response) {
        //excel文件名
        String fileName = "测试一号.xls";
        //创建HSSFWorkbook,别问我list哪来的,我哪知道你数据哪来的
        HSSFWorkbook wb = getHSSFWorkbook(list);
        //响应到客户端
        try {
            this.setResponseHeader(response, fileName);
            OutputStream os = response.getOutputStream();
            wb.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
}

上一篇下一篇

猜你喜欢

热点阅读