poi导入/导出

1 前言

大家可能对阿里的easypoi比较熟悉,简简单单的一两行代码就能够进行导入和导出的操作。但是平时在很多地方,我们还是用到了Apache的poi。所以这里做一个简单的记录。

有关easypoi使用文章:CSDN

2 基本功能

结构:

HSSF - 提供读写Excel格式文档的功能

XSSF - 提供读写ExcelOOXML格式档案的功能

HWPF - 提供Word格式档案的功能

HSLF - 提供读写PowerPoint格式文档的功能

HDGF - 提供Visio格式档案的功能

注意:Apache的poi存在一个很严重的问题就是非常的耗内存,poi有一套SAX模式虽然可以在一定程度上可以解决一些内存溢出的问题,但依然会有一些缺陷。07版本的Excel解压缩和解压后的存储都是在内存中完成的,内存消耗很大。而easyExcel就不会出现内存溢出的问题。

想要搞清楚poi对Excel表格中从操作,我们需要先搞清楚其中的四个对象:

//创建一个工作簿(07版本的)
XSSFWorkbook workbook = new XSSFWorkbook();

//创建一个工作表
XSSFSheet sheet = workbook.createSheet();

//创建一个行
XSSFRow row = sheet.createRow(0);

//创建一个单元格
XSSFCell cell = row.createCell(0);

先创建一个工作簿(也就是一个Excel表格)

然后根据excel去创建一个工作表 (就是excel表格中的sheet1,,sheet2)

然后根据表格去创建一个行

最后根据行去创建列

这样我们就可以确定我们的一个坐标

注意:当我们大文件写入HSSF(03版)时

缺点:最多只能处理65536行,否则会抛出异常

优点:过程中写入缓存,不操作磁盘,最后一次性操作缓存,速度快

当我们大文件写入XSSF(07版)时

缺点:写数据时速度非常快,非常耗内存,也会发生内存溢出

优点:可以写入较大的数据

3 代码演示

 相关准备

导入相关依赖:

        <!--xls(03)-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>

        <!--xlsx(07)-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <!--日期格式化工具-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.5</version>
        </dependency>

数据库插入数据:

 3.1 导出数据

我们演示将这些数据读出来放入excel表格中:

代码如下:

@Controller
@Slf4j
public class RestController {

    @Resource
    private UserMapper userMapper;

    @PostMapping("/get")
    public void getUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.like("name", "张");
        List<User> users = userMapper.selectList(queryWrapper);
        System.out.println("******"+users);

        //定义表格名称并且指定编码格式
        String encode = URLEncoder.encode("导出文件" + ".xlsx", "utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + encode);


        OutputStream outputStream = response.getOutputStream();
        List<List<String>> listStrings = new ArrayList<>();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        users.forEach(user->{
            List<String> list1 = new ArrayList<>();
            list1.add(String.valueOf(user.getId()));
            list1.add(user.getName());
            list1.add(format.format(user.getCreateTime()));
            list1.add(user.getUniqueId());
            list1.add(user.getNotice());
            listStrings.add(list1);
        });

        log.info("将要导出的数据:"+listStrings);

        //创建一个工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();

        //创建一个工作表
        XSSFSheet sheet = workbook.createSheet();
        //表头在第一行 将表头中的数据循环放入第一行的表头中
        XSSFRow row = sheet.createRow(0);
        String[] heads = headNames();

        //填充表头数据
        for (int i = 0; i < headNames().length; i++) {
            XSSFCell cell = row.createCell(i);
            cell.setCellValue(heads[i]);
        }

        //填充实际数据
        if (CollectionUtils.isNotEmpty(listStrings)){
            for (int i = 0; i < listStrings.size(); i++) {
                //表头数据上面已经填充过了,然后从第二行开始填充
                XSSFRow row1 = sheet.createRow(i + 1);
                XSSFCell cell = row1.createCell(0);
                cell.setCellValue(i+1);
                //将user对象中的值填充到表格中
                List<String> list = listStrings.get(i);
                for (int j = 0; j < list.size(); j++) {
                    XSSFCell cell1 = row1.createCell(j + 1);
                    cell1.setCellValue(list.get(j));
                }

            }

        }
        //将产生的workbook对象放入输出流中
        workbook.write(outputStream);
        //刷新流
        outputStream.flush();
        //关闭流
        outputStream.close();

    }

    private String[] headNames(){
        return new String[]{
                "序号",
                "id",
                "姓名",
                "创建时间",
                "分布式id",
                "注意事项"
        };

    }

}

然后我们用postman去进行测试:

 点击这个Send and Download按钮,这时会弹出下载框,

注意:只要中文名称是中文的,文件名称就会乱码(不用惊慌,postman测试导出就是这样的),在浏览器上运行就没有这个问题

 以下是我们的导出的文件

 3.2 导入数据

代码如下:

@PostMapping("/import")
    public void importExcel( @RequestBody MultipartFile file ) throws IOException {
        log.info("excel文件路径名称>>>>>>"+file);
        InputStream inputStream = null;
        try {
             inputStream = file.getInputStream();
        } catch (IOException e) {
            log.info("读取文件出错");
        }
/*        ExcelReader excelReader = new ExcelReader(inputStream,0);
        List<Map<String, Object>> mapList = excelReader.readAll();
        log.info("引用hutool工具类读取数据:"+mapList);*/

        //读取工作簿中第一个表中的内容
        XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
        XSSFSheet sheetAt = workbook.getSheetAt(0);
        //读取表头
        XSSFRow rowTitle = sheetAt.getRow(0);
        if (rowTitle != null ) {
            //该行一共有多少列
            int number = rowTitle.getPhysicalNumberOfCells();
            for (int cellNum = 0; cellNum < number; cellNum++) {
                XSSFCell cell = rowTitle.getCell(cellNum);
                if (cell != null ) {
                    //改列的数据类型
                    CellType cellType = cell.getCellType();
                    String stringCellValue = cell.getStringCellValue();
                    log.info("数值为>>>>>:"+stringCellValue);
                }
            }
        }
        int rowsNum = sheetAt.getPhysicalNumberOfRows();
        for (int rowNum = 1; rowNum < rowsNum; rowNum++) {
            XSSFRow row = sheetAt.getRow(rowNum);
            if (row != null ) {
                int number = rowTitle.getPhysicalNumberOfCells();
                for (int cellNum = 0; cellNum < number; cellNum++) {
                    XSSFCell cell = row.getCell(cellNum);
                    //匹配数据类型
                    if (cell != null ) {
                        CellType cellType = cell.getCellType();
                        String cellValue = "";

                        switch (cellType) {
                            //字符串类型
                            case STRING:
                                cellValue =  cell.getStringCellValue();
                                break;
                                //布尔类型
                            case BOOLEAN:
                                cellValue  =  String.valueOf(cell.getBooleanCellValue());
                                break;
                                //空
                            case BLANK:
                                break;
                                //数字(日期或者普通数字)
                            case NUMERIC:
                                if (HSSFDateUtil.isCellDateFormatted(cell)){
                                    cellValue =  new DateTime(cell.getDateCellValue()).toString("yyyy-MM-dd");
                                }else {
                                    cell.setCellType(CellType.STRING);
                                    cellValue = cell.toString();
                                }
                                break;
                            case ERROR:
                                break;
                        }
                        log.info("数值为>>>>>:"+cellValue);
                    }
                }
            }
        }
        inputStream.close();


    }

但我们可以发现这样导入的数据非常麻烦,所以我们可以用hutol的工具类:

/*        ExcelReader excelReader = new ExcelReader(inputStream,0);
        List<Map<String, Object>> mapList = excelReader.readAll();
        log.info("引用hutool工具类读取数据:"+mapList);*/

可以很轻松的拿到我们想要的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值