POI 导入、导出Excel

POI,全称Apache POI,是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。项目地址:Apache POI - the Java API for Microsoft Documents

1 导入

使用form表单(enctype="multipart/form-data")上传excel文件,后台接收MultipartFile文件格式。

读取excel

    private static final String EXCEL_XLS = "xls";
    private static final String EXCEL_XLSX = "xlsx";

    /**
     * 判断Excel的版本,获取Workbook
     * @param in
     * @param file
     * @return
     * @throws IOException
     */
    public static Workbook getWorkbok(InputStream in, MultipartFile file) throws IOException {
        Workbook wb = null;
        if(file.getOriginalFilename().endsWith(EXCEL_XLS)){     //Excel 2003
            wb = new HSSFWorkbook(in);
        }else if(file.getOriginalFilename().endsWith(EXCEL_XLSX)){    // Excel 2007/2010
            wb = new XSSFWorkbook(in);
        }
        return wb;
    }

    /**
     * 判断文件是否是excel
     * @throws Exception
     */
    public static void checkExcelVaild(MultipartFile file) throws Exception{
        if(ToolUtil.isEmpty(file)){
            throw new Exception("文件不存在");
        }
        if(!((file.getOriginalFilename().endsWith(EXCEL_XLS) || file.getOriginalFilename().endsWith(EXCEL_XLSX)))){
            throw new Exception("文件不是Excel");
        }
    }

    /**
     * 读取Excel,兼容 Excel 2003/2007/2010     * @param excelFile   * @param sheetIndex  从第几个sheet开始遍历     * @param dataRowIndex  从第几行开始遍历     * @throws Exception
     */
    public static List<Map<String, Object>> parseExcelObject(MultipartFile excelFile, int sheetIndex, int dataRowIndex) {

        List<Map<String,Object>> lists = new ArrayList<>();
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // 同时支持Excel 2003、2007
            FileInputStream is = (FileInputStream) excelFile.getInputStream(); // 文件流
            checkExcelVaild(excelFile);
            Workbook workbook = getWorkbok(is,excelFile);
            //Workbook workbook = WorkbookFactory.create(is); // 这种方式 Excel2003/2007/2010都是可以处理的

            /**
             * 设置当前excel中sheet的下标:sheetIndex
             */
            if(sheetIndex >= 0 && sheetIndex < workbook.getNumberOfSheets())
            {
                for (; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++)
                {

                    int rowSize = 0;
                    Sheet sheet = workbook.getSheetAt(sheetIndex);
                    for(int rowIndex = dataRowIndex; rowIndex <= sheet.getLastRowNum(); rowIndex++)
                    {
                        Row row = sheet.getRow(rowIndex);
                        if(row == null)
                            continue;
                        int tempRowSize = row.getLastCellNum();
                        if(tempRowSize > rowSize)
                            rowSize = tempRowSize;

                        Map<String, Object> maps = new HashMap<String, Object>();
                        String rowValue = "";
                        for(short columnIndex = 0; columnIndex < row.getLastCellNum(); columnIndex++)
                        {
                            Cell cell = row.getCell(columnIndex);
                            if(ToolUtil.isEmpty(cell))
                                continue;
                            int cellType = cell.getCellType();

                            String cellValue = "";
                            switch (cellType)
                            {
                                case Cell.CELL_TYPE_STRING:        // 文本
                                    cellValue = cell.getRichStringCellValue().getString().trim();
                                    break;
                                case Cell.CELL_TYPE_NUMERIC:    // 数字、日期
                                    if (DateUtil.isCellDateFormatted(cell)) {
                                        cellValue = fmt.format(cell.getDateCellValue());
                                    } else {
                                        cell.setCellType(Cell.CELL_TYPE_STRING);
                                        cellValue = String.valueOf(cell.getRichStringCellValue().getString());
                                    }
                                    break;
                                case Cell.CELL_TYPE_BOOLEAN:    // 布尔型
                                    cellValue = String.valueOf(cell.getBooleanCellValue());
                                    break;
                                case Cell.CELL_TYPE_BLANK: // 空白
                                    cellValue = cell.getStringCellValue();
                                    break;
                                case Cell.CELL_TYPE_ERROR: // 错误
                                    cellValue = "";
                                    break;
                                case Cell.CELL_TYPE_FORMULA:    // 公式
                                    // 得到对应单元格的公式
                                    //cellValue = cell.getCellFormula() + "#";
                                    // 得到对应单元格的字符串
                                    cell.setCellType(Cell.CELL_TYPE_STRING);
                                    cellValue = String.valueOf(cell.getRichStringCellValue().getString());
                                    break;
                                default:
                                    cellValue = "";
                            }
                            //  保存数据
                            if (columnIndex == 0)
                            {
                                 maps.put("name", cellValue);
                            }                  // ......其他逻辑......
                        }
                        lists.add(maps);
                    }
                }
            }

            is.close();   //关闭文件流

        } catch (Exception e) {
            e.printStackTrace();
        } finally{

        }
        return lists;
    }

控制层

/**
 * 导入excel
 *
 * @param multipartFile
 * @return
 */
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
@ResponseBody
public void importExcel(@RequestParam("file") MultipartFile multipartFile) {
    if (multipartFile == null) {
          throw new Exception("excel文件请求参数错误");
    }
    List<Map<String, Object>> list = ExcelUtil.parseExcelObject(multipartFile, 0, 0); // 这里只解析第一个sheet,从第一行开始
    for(Map<String, Object> map : list){
        System.out.println(map.getString("name"));
    }
}

1 导出

如果你想看到下载弹框提示,如下图,那么就需要使用form表单提交方式,请求后台接口。接下来会解释为什么。

写入excel

public static XSSFWorkbook createExcelObject(List<ExcelObject> list) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // 第一步,创建一个webbook文件,对应一个excel文件
            XSSFWorkbook wb = new XSSFWorkbook();
            // 第二部,在excel中添加一个sheet工作簿,参数为该工作簿名字,不写为默认;
            XSSFSheet sheet = wb.createSheet("sheet1");
            // 第三部,做sheet中添加表头第0行,注意老版本poi对excel的行数列数有限制short
            XSSFRow row = sheet.createRow((int) 0);

            // 第四部,设置单元格样式
            XSSFCellStyle style = wb.createCellStyle();
            style.setAlignment(HorizontalAlignment.CENTER);//创建一个居中格式
            // 生成字体
            Font font = wb.createFont();
            font.setFontHeightInPoints((short) 12);
            font.setBold(true);
            // 把字体应用到当前的样式
            style.setFont(font);

            // 第五部,设置好表头内容
            XSSFCell cell = row.createCell(0);
            cell.setCelSPUue("name");
            cell.setCellStyle(style)

            // 第六部,写入实体数据 实际应用中这些数据应该是从数据库中得到
            for (int i = 0; i < list.size(); i++) {
                // 每次新建一行然后在新行中插入list中的数据对象,有点繁琐,也许有更好的封装方法,留待后看
                row = sheet.createRow((int) i + 1);
                row.createCell((int) 0).setCellValue(list.get(i).getName());
            }

            return wb;

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        return null;
    }    

  控制层

/**
 * 导出商品信息
 *
 * @param request
 * @param response
 * @throws Exception
 */
@RequestMapping(value = "/downExcel",method = RequestMethod.POST)
@ResponseBody
public void downExcel(HttpServletRequest request, HttpServletResponse response){

    List<ExcelObject> list; // 查询出来的数据

    // 正确代码顺序
    //FileInputStream fs=new FileInputStream(excel);
    //XSSFWorkbook workbook = new XSSFWorkbook(fs);
    //FileOutputStream out=new FileOutputStream(excel);
    //workbook.write(out);

    XSSFWorkbook wb = ExcelUtil.createExcelObject(list);
    if (wb == null)
        throw new Exception("excel文件解析异常");

    try {
        // 设置输出的格式
        response.reset();// 清空输出流
        response.setHeader("Content-Disposition", "attachment; filename=" + new String(("excel.xlsx").getBytes(), "iso-8859-1"));// 设定输出文件头
        response.setContentType("application/x-download;charset=GBK");// 定义输出类型

        //创建输出流
        OutputStream outputStream = response.getOutputStream();

        wb.write(outputStream);
        outputStream.close();
    }catch (Exception e){
        e.printStackTrace();
    }
}

3 疑难解答

1、为什么一定要form表单请求,才会出现下载弹框?而ajax请求方式却不会出现

因为,导出excel,在通过后台生成excel文件,并且以文件流的形式传递给前端,而ajax接收的返回数据类型只能是:字符串、xml。所以ajax处理不了返回的文件流。而浏览器可以处理。

  2、注意,导出时的代码顺序,否则报错NotOfficeXmlFileException?

假如,你直接先把输入流,输出流建立好了以后,再创建新对象,就会报错。错误信息为: org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException: No valid entries or contents found, this is not a valid OOXML (Office Open XML) file。

导出->控制层代码,已经给出了正确的顺序。

欢迎大家评论与交流,加油!!

【参考】

  1. https://blog.csdn.net/phil_jing/article/details/78307819
  2. https://www.cnblogs.com/xbq8080/p/7344258.html    ajax请求导出excel的问题
  3. https://blog.csdn.net/anlian523/article/details/72268347    XSSFWorkbook的顺序问题

原文地址:https://www.cnblogs.com/pan1042/p/10710900.html

时间: 2024-10-11 05:45:18

POI 导入、导出Excel的相关文章

Java利用POI导入导出Excel中的数据

     首先谈一下今天发生的一件开心的事,本着一颗android的心我被分配到了PB组,身在曹营心在汉啊!好吧,今天要记录和分享的是Java利用POI导入导出Excel中的数据.下面POI包的下载地址http://poi.apache.org/download.html,有兴趣的朋友也可以去看看其中的API.      下面分享一下在对POI进行基本操作时觉得需要注意的两点:       1.POI中针对xlsx/xls是需要create different Workbook instance

poi导入导出excel后记

续上一篇:在springmvc项目中使用poi导入导出excel http://blog.csdn.net/kingson_wu/article/details/38942967 一. 导入时,发现了不少问题,如果是导出excel之后,在里面不删除行,只是简单的修改一些数据的话,则不会出问题,但如果是删除了一些行,或者excel表不是导出的,而是另外的excel文件,里面有很多数据ctrl+a,ctrl+v生成的,那么导入的时候就会出问题,因为里面虽然看起来的数据就那么多,但是有一些数据痕迹.很

基于SSM的POI导入导出Excel实战第二篇-导出EXCEL

业务需求:这里我以产品信息为例,用于POI导入导出Excel实战的操作对象 需求分析:我们要导出的数据格式比较简单,其实就是待导出的表(视图)的数据,如下图所示: 实现思路:A.会发现待导出的数据列表是一个矩阵式的格式,即二维的形式 B.其中的头部id name unit price stock 等字段field是固定不变的,将会充当excel的头部 C.以数据行的角度观察数据列表,会发现每一行每一列的值都是B所指的那些字段一一对应的取值value D.由此可以得出这些数据组织是由每一行数据组成

基于SSM的POI导入导出Excel实战第一篇-SSM框架的整合

业务背景:在JavaWeb应用开发中,经常需要将应用系统中某些业务数据导出到Excel中,又或者需要将这些业务数据先收集到Excel然后一键导入到系统 业务需求:如何用Java实现导入导出Excel 需求分析:目前流行的Java导入导出Excel的框架有POI跟JXL,这两者的优缺点在这里我就不作比较了,感兴趣的童鞋可以自行搜索了解一下; 技术选型:从本文开始,我将分享一下如何基于SSM框架+POI实现Java应用导入导出Excel,数据库采用mysql5.6,应用服务器采用tomcat7 工具

基于SSM的POI导入导出Excel实战尾篇-其余功能实战(mvc三层开发模式体验)

业务需求:前几篇基本已经介绍完毕项目的核心功能,即POI导入导出Excel,为了整个项目的完整性,并让诸位童鞋体验体验企业级javaweb应用mvc三层模式的开发流程,本文将介绍一下项目的其余功能,包括搜索,新增,修改,删除 需求分析:作为程序员,在项目中经常接触的就是CRUD了,本篇博文将整合jquery-easyui框架(版本采用1.5.5.4)异步实现上述几个功能,给项目画上一个完整的句号!当然啦,在刚开始开发时,对于自己开发好的后端接口完全可以用Postman进行模拟(我就是这样做的),

java中使用poi导入导出excel文件_并自定义日期格式

Apache POI项目的使命是创造和保持java API操纵各种文件格式基于Office Open XML标准(OOXML)和微软的OLE复合文档格式(OLE2)2.总之,你可以读写Excel文件使用java.此外,您可以读取和写入MS Word和PowerPoint文件使用java.Apache POI是java Excel解决方案(Excel 97-2008). 需要jar: poi-3.9-20121203.jar 导出 public static void main(String[]

在springmvc项目中使用poi导入导出excel

首先要导入spring相关包,poi,和fileupload包,我是使用maven构建的. 一.导入excel (1)使用spring上传文件 a.前台页面提交 <form name="excelImportForm" action="${pageContext.request.contextPath}/brand/importBrandSort" method="post" onsubmit="return checkImpor

基于SSM的POI导入导出Excel实战第二篇-导入EXCEL

业务需求:上文已经实现了产品信息Excel的导出,接下来将用POI实现Excel导入 需求分析:导入其实是导出的逆过程,数据格式是一样的,均为矩阵式(二维)的数据格式,下面将以导出的模板作为Excel导入时数据填充的文件! 下面就直接进入正文,在阅读正文源码期间如果有相关问题可以加我QQ:1974544863 咨询我 或者加群:583522159 进行技术讨论.下面是我的个人公众号,感兴趣的童鞋可以关注(有干货以及项目实战分享哦) 好了,让我们进入代码实战吧! 在实战之前,介绍一下项目使用的"状

java poi 导入导出Excel xsl xslx

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import o

SpringMvc 使用poi导入导出Excel

controller <pre name="code" class="java"> @ResponseBody @RequestMapping(value = "/chxm/exportAndUpdate") public void exportAndUpdate(@RequestParam(value = "projectId") String projectId, @RequestParam(value = &