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的顺序问题

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

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

         首先谈一下今天发生的一件开心的事,本着一颗android的心我被分配到了PB组,身在曹营心在汉啊!好吧,今天要记录和分享的是Java利用POI导入导出Excel中的数据.下面POI包的下载地 ...

  2. Java POI导入导出Excel

    1.异常java.lang.NoClassDefFoundError: org/apache/poi/UnsupportedFileFormatException 解决方法: 使用的poi的相关jar ...

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

    Apache POI项目的使命是创造和保持java API操纵各种文件格式基于Office Open XML标准(OOXML)和微软的OLE复合文档格式(OLE2)2.总之,你可以读写Excel文件使 ...

  4. POI导入导出excel(附工具类)

    关于POI导出excel的功能我在前面的文章已经写过了,POI导出excel的三种方式 , 导出表格数据到excel并下载(HSSFWorkbook版) ,本篇文章主要是将导入导出功能进一步地封装,在 ...

  5. POI导入导出Excel(HSSF格式,User Model方式)

    1.POI说明 Apache POI是Apache软件基金会的开源代码库, POI提供对Microsoft Office格式档案读和写的功能. POI支持的格式: HSSF - 提供读写Microso ...

  6. SpringMvc 使用poi导入导出Excel

    Util类 package com.common.util; public class ExportUtil { private XSSFWorkbook wb = null; private XSS ...

  7. poi 导入导出excel

    import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; i ...

  8. java poi 导入导出Excel xsl xslx

    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import  ...

  9. 导入导出Excel工具类ExcelUtil

    前言 前段时间做的分布式集成平台项目中,许多模块都用到了导入导出Excel的功能,于是决定封装一个ExcelUtil类,专门用来处理Excel的导入和导出 本项目的持久化层用的是JPA(底层用hibe ...

  10. 导入导出Excel的Java工具类ExcelUtil

    在编写ExcelUtil之前,在网上查了一些资料.java中用来处理Excel的第三方开源项目主要就是POI和JXL.poi功能强大,但是比较耗资源,对于大数据量的导入导出性能不是太好:jxl功能简单 ...

随机推荐

  1. 开源PaaS平台:Cloudify

    Cloudify是gigaspaces公司推出的基于java的paas平台. refer to :http://timeson.iteye.com/blog/1699730

  2. js正则表达式常见规则整理

    验证数字的正则表达式集 验证数字:^[0-9]*$ 验证n位的数字:^\d{n}$ 验证至少n位数字:^\d{n,}$ 验证m-n位的数字:^\d{m,n}$ 验证零和非零开头的数字:^(0|[1-9 ...

  3. json格式示例

    案例一: {key:value,key:value} class Person{ String firstname = "张"; String lastname = "三 ...

  4. Leetcode844.Backspace String Compare比较含退格的字符串

    给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果. # 代表退格字符. 示例 1: 输入:S = "ab#c", T = " ...

  5. Leetcode709.To Lower Case转换成小写字母

    实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串. 示例 1: 输入: "Hello" 输出: & ...

  6. (转载)怎样解决SQL Server内存不断增加问题

    在启用sqlserver服务后,发现进程sqlservr.exe的内存使用量从开始的100多MB持续增加,很快就高达1G以上,造成机器运行缓慢.卡机,严重影响使用.sql server 在查询大数据量 ...

  7. 阿里工程师开发了一款免费工具,提升Kubernetes应用开发效率

    对于使用了Kubernetes作为应用运行环境的开发者而言,在同一个集群中我们可以使用命名空间(Namespace)快速创建多套隔离环境,在相同命名空间下,服务间使用Service的内部DNS域名进行 ...

  8. 【codeforces Manthan, Codefest 17 C】Helga Hufflepuff's Cup

    [链接]h在这里写链接 [题意]     k是最高级别的分数,最高界别的分数最多只能有x个.     1<=k<=m;     和k相邻的点的分数只能小于k;     n个点的树,问你每个 ...

  9. Linux常用命令4 帮助命令

    1.帮助命令:man 命令英文原意:manual 命令所在路径:/usr/bin/man    执行权限:所有用户 语法:man [命令或配置文件] 功能描述:获得命令或者配置文件的帮助信息 例如:m ...

  10. VUE中的style 样式处理的Scope (<style scope>)

    在VUE组件中,为了让样式私有化,不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块. 但是这样的话,就会导致无法修改其他第三方组件样式,或者是内嵌的样式,解决方案 ...