思路:工作簿(流) -> 工作单 -> 行 -> 列
sheet,row,cell的index都是从0开始的
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itcast</groupId>
<artifactId>poi_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--2003或以下-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<!--2007或以上-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<!--2007或以上-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
#实现导出excel、导入(读取)excel
导入(读取)excel
package cn.itcast.poi;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/**
* 演示Excel的读取
* 1)读取工作簿
* 2)读取工作单(表)
* 3)读取行
* 4)读取列(单元格)
*
*
*/
public class Demo1 {
/**
* 低版本(2003)
*/
@Test
public void test1() throws Exception {
//1. 读取工作簿
HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream("d:/上传货物模板2.xls"));
//2. 读取工作表
//wb.getSheetAt(0) 通过索引获取
HSSFSheet sheet = wb.getSheet("货物表");
//3.读取第一行
HSSFRow row = sheet.getRow(0);
//4.读取列及数据
System.out.println(row.getCell(1).getStringCellValue());
System.out.println(row.getCell(2).getStringCellValue());
System.out.println(row.getCell(3).getStringCellValue());
}
/**
* 高版本(2007)
*/
@Test
public void test2() throws Exception {
//1. 读取工作簿
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream("d:/上传货物模板2.xlsx"));
//2. 读取工作表
//wb.getSheetAt(0) 通过索引获取
XSSFSheet sheet = wb.getSheet("货物表");
//3.读取第一行
XSSFRow row = sheet.getRow(0);
//4.读取列及数据
// 加入当前行列的数据不是字符串,得先转换
// row.getCell(0).setCellType(CellType.STRING);
System.out.println(row.getCell(1).getStringCellValue());
System.out.println(row.getCell(2).getStringCellValue());
System.out.println(row.getCell(3).getStringCellValue());
}
/**
* 高版本(2007) - 遍历行
*/
@Test
public void test3() throws Exception {
//1. 读取工作簿
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream("d:/上传货物模板2.xlsx"));
//2. 读取工作表
//wb.getSheetAt(0) 通过索引获取
XSSFSheet sheet = wb.getSheet("货物表");
//3.遍历行
//3.1 获取总行数
int rowNums = sheet.getPhysicalNumberOfRows();
//3.2 遍历行
for(int i=0;i<rowNums;i++){
XSSFRow row = sheet.getRow(i);
//4.读取列及数据
System.out.print(row.getCell(1).getStringCellValue()+"\t");
System.out.print(row.getCell(2).getStringCellValue()+"\t");
XSSFCell cell = row.getCell(3);
//判断列的类型
if(cell.getCellType() == CellType.NUMERIC) {
System.out.println(row.getCell(3).getNumericCellValue());
}else if(cell.getCellType() == CellType.STRING){
System.out.println(row.getCell(3).getStringCellValue());
}
}
}
}
导出excxel
package cn.itcast.poi;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
* 演示Excel的生成
* 1)创建工作簿
* 2)创建工作单(表)
* 3)创建行
* 4)创建列(单元格)
* 5)把工作簿写出(硬盘/网页等)
*
*
*/
public class Demo2 {
/**
* 低版本(2003)
*/
@Test
public void test1() throws Exception {
//1. 创建工作簿
HSSFWorkbook wb = new HSSFWorkbook();
//2. 创建工作表
HSSFSheet sheet = wb.createSheet("货物表");
//3.创建一行
HSSFRow row = sheet.createRow(0);
//4.创建列及写入数据
row.createCell(0).setCellValue("姓名");
row.createCell(1).setCellValue("年龄");
row.createCell(2).setCellValue("班级");
//5.把工作簿写出硬盘中
wb.write(new FileOutputStream("d:/test.xls"));
}
/**
* 高版本(2007)
*/
@Test
public void test2() throws Exception {
//1. 创建工作簿
XSSFWorkbook wb = new XSSFWorkbook();
//2. 创建工作表
XSSFSheet sheet = wb.createSheet("货物表");
//3.创建一行
XSSFRow row = sheet.createRow(0);
//4.创建列及写入数据
row.createCell(0).setCellValue("姓名");
row.createCell(1).setCellValue("年龄");
row.createCell(2).setCellValue("班级");
//5.把工作簿写出硬盘中
wb.write(new FileOutputStream("d:/test.xlsx"));
}
}
扩展
##自定义表头格式的导出
/**
* 导出出货表
* 1)URL:http://localhost:8080/cargo/contract/printExcel.do
* 2)参数:inputDate=2020-04
* 3)返回: 输出流(相当于文件下载)
*/
@RequestMapping("/printExcel")
public void printExcel(String inputDate) throws IOException {
//1.创建工作簿
Workbook wb = new XSSFWorkbook();
//2.创建工作表
Sheet sheet = wb.createSheet("出货表");
//3.创建行
///3.1 创建标题行
Row titleRow = sheet.createRow(0);
//设置行高
titleRow.setHeightInPoints(36); //磅
//设置列宽
/**
* 参数一:列索引
*/
sheet.setColumnWidth(0,6*256); // 6*256:代表6个字符数
sheet.setColumnWidth(1,26*256); // 6*256:代表6个字符数
sheet.setColumnWidth(2,11*256); // 6*256:代表6个字符数
sheet.setColumnWidth(3,26*256); // 6*256:代表6个字符数
sheet.setColumnWidth(4,11*256); // 6*256:代表6个字符数
sheet.setColumnWidth(5,11*256); // 6*256:代表6个字符数
sheet.setColumnWidth(6,11*256); // 6*256:代表6个字符数
sheet.setColumnWidth(7,11*256); // 6*256:代表6个字符数
sheet.setColumnWidth(8,11*256); // 6*256:代表6个字符数
// 1)合并单元格:addMergedRegion
/**
* 参数一: 起始行
* 参数二: 结束行
* 参数三: 起始列
* 参数四: 结束列
*/
sheet.addMergedRegion(new CellRangeAddress(0,0,1,8));
//2)设置标题内容
Cell cell = titleRow.createCell(1);
//3)标题内容: inputDate=2020-04或2020-10
String title = inputDate.replace("-0","年").replace("-","年")+"月份出货表";
//设置标题样式
cell.setCellStyle(bigTitle(wb));
cell.setCellValue(title);
//3.2 创建表格头部
Row tableRow = sheet.createRow(1);
//设置行高
tableRow.setHeightInPoints(26);
//客户 订单号 货号 数量 工厂 工厂交期 船期 贸易条款
String[] tableHeaders = {"客户","订单号","货号","数量","工厂","工厂交期","船期","贸易条款"};
for(int i=0;i<tableHeaders.length;i++){
Cell cell1 = tableRow.createCell(i + 1);
//设置列的样式
cell1.setCellStyle(title(wb));
cell1.setCellValue(tableHeaders[i]);
}
//4.出货表的内容
//1)读取后台数据
List<ContractProductVo> list = contractProductService.findByShipTime(inputDate,getLoginCompanyId());
if(list!=null && list.size()>0){
for(int i=0;i<list.size();i++){
//逐行生成
Row row = sheet.createRow(i+2);
row.setHeightInPoints(24);
//列的内容
ContractProductVo vo = list.get(i);
Cell cell2 = null;
if(vo.getCustomName()!=null){
cell2 = row.createCell(1);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getCustomName());
}
if(vo.getContractNo()!=null){
cell2 = row.createCell(2);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getContractNo());
}
if(vo.getProductNo()!=null){
cell2 = row.createCell(3);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getProductNo());
}
if(vo.getCnumber()!=null){
cell2 = row.createCell(4);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getCnumber());
}
if(vo.getFactoryName()!=null){
cell2 = row.createCell(5);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getFactoryName());
}
if(vo.getDeliveryPeriod()!=null){
cell2 = row.createCell(6);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getDeliveryPeriod());
}
if(vo.getShipTime()!=null){
cell2 = row.createCell(7);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getShipTime());
}
if(vo.getTradeTerms()!=null){
cell2 = row.createCell(8);
cell2.setCellStyle(text(wb));
cell2.setCellValue(vo.getTradeTerms());
}
}
}
//5.给用户下载出货表
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
wb.write(outputStream);
new DownloadUtil().download(outputStream,response,"出货表.xlsx");
}
//大标题的样式
public CellStyle bigTitle(Workbook wb){
CellStyle style = wb.createCellStyle();
Font font = wb.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short)16);
font.setBold(true);//字体加粗
style.setFont(font);
style.setAlignment(HorizontalAlignment.CENTER); //横向居中
style.setVerticalAlignment(VerticalAlignment.CENTER); //纵向居中
return style;
}
//小标题的样式
public CellStyle title(Workbook wb){
CellStyle style = wb.createCellStyle();
Font font = wb.createFont();
font.setFontName("黑体");
font.setFontHeightInPoints((short)12);
style.setFont(font);
style.setAlignment(HorizontalAlignment.CENTER); //横向居中
style.setVerticalAlignment(VerticalAlignment.CENTER); //纵向居中
style.setBorderTop(BorderStyle.THIN); //上细线
style.setBorderBottom(BorderStyle.THIN); //下细线
style.setBorderLeft(BorderStyle.THIN); //左细线
style.setBorderRight(BorderStyle.THIN); //右细线
return style;
}
//文字样式
public CellStyle text(Workbook wb){
CellStyle style = wb.createCellStyle();
Font font = wb.createFont();
font.setFontName("Times New Roman");
font.setFontHeightInPoints((short)10);
style.setFont(font);
style.setAlignment(HorizontalAlignment.LEFT); //横向居左
style.setVerticalAlignment(VerticalAlignment.CENTER); //纵向居中
style.setBorderTop(BorderStyle.THIN); //上细线
style.setBorderBottom(BorderStyle.THIN); //下细线
style.setBorderLeft(BorderStyle.THIN); //左细线
style.setBorderRight(BorderStyle.THIN); //右细线
return style;
}
使用模板方式导出
确定表头格式。如下:
/**
* 使用模块方式进行出货的Excel导出
* 1)URL:http://localhost:8080/cargo/contract/printExcel.do
* 2) 参数:inputDate=2020-04 船期
* 3)返回:文件下载(文件流)
*/
@RequestMapping("/printExcel")
public void printExcel(String inputDate) throws Exception {
//1.读取模板文件的工作簿
//1)读取模块文件:
//ServletContext.getRealPath():获取项目下的文件路径
//ServletContext.getResourceAsStream(): 获取项目下的文件的输入流
InputStream inputStream = session.getServletContext().getResourceAsStream(""template/template.xls");
//2)把文件读取成工作簿
HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
//2.获取第一张工作单
HSSFSheet sheet = workbook.getSheetAt(0);
//3.获取行
//4.创建列,设置内容
//3.1 获取标题行
HSSFRow titleRow = sheet.getRow(0);
//1)获取列(第二列)
HSSFCell cell = titleRow.getCell(1);
//2)设置内容
//2020-02 -> 2020年2
//2020-12 -> 2020年12
String title = inputDate.replaceAll("-0","年").replaceAll("-","年")+"月份出货表";
cell.setCellValue(title);
//先把内容行的列的样式提取获取出来
CellStyle[] cellStyles = new CellStyle[8];
HSSFRow row = sheet.getRow(2);
for(int i=0;i<8;i++){
cellStyles[i] = row.getCell(i+1).getCellStyle();
}
//3.2 创建内容行
//1)获取内容
List<ContractProductVo> list = contractProductService.findByShipTime(inputDate,getLoginCompanyId());
if(list!=null && list.size()>0){
//2)创建行
for(int i=0;i<list.size();i++){
ContractProductVo ContractProductVo = list.get(i);
HSSFRow contentRow = sheet.createRow(i+2);
//设置行高
contentRow.setHeightInPoints(24);
HSSFCell contentCell = null;
//3)创建列
//客户
contentCell = contentRow.createCell(1);
if(ContractProductVo.getCustomName()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[0]);
contentCell.setCellValue(ContractProductVo.getCustomName());
}
//订单号
contentCell = contentRow.createCell(2);
if(ContractProductVo.getContractNo()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[1]);
contentCell.setCellValue(ContractProductVo.getContractNo());
}
//货号
contentCell = contentRow.createCell(3);
if(ContractProductVo.getProductNo()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[2]);
contentCell.setCellValue(ContractProductVo.getProductNo());
}
//数量
contentCell = contentRow.createCell(4);
if(ContractProductVo.getCnumber()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[3]);
contentCell.setCellValue(ContractProductVo.getCnumber());
}
//工厂
contentCell = contentRow.createCell(5);
if(ContractProductVo.getFactoryName()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[4]);
contentCell.setCellValue(ContractProductVo.getFactoryName());
}
//交货日期
contentCell = contentRow.createCell(6);
if(ContractProductVo.getDeliveryPeriod()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[5]);
contentCell.setCellValue(ContractProductVo.getDeliveryPeriod());
}
//船期
contentCell = contentRow.createCell(7);
if(ContractProductVo.getShipTime()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[6]);
contentCell.setCellValue(ContractProductVo.getShipTime());
}
//贸易条款
contentCell = contentRow.createCell(8);
if(ContractProductVo.getTradeTerms()!=null) {
//4)列的样式
contentCell.setCellStyle(cellStyles[7]);
contentCell.setCellValue(ContractProductVo.getTradeTerms());
}
}
}
//5.把工作簿(Excel的内容)返回给response响应(用户可以下载)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//5.1 把Excel的内容设置到ByteArrayOutputStream流中
workbook.write(outputStream);
/**
* 参数一:ByteArrayOutputStream:需要下载的内容
* 参数二:HttpServletResponse:响应对象
* 参数三:returnName:下载的文件名称
*/
//5.2 下载(把流写给response)
new DownloadUtil().download(outputStream,response,"出货表.xls");
}
百万数据POI操作
我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数据的支持如下:
-
Excel 2003:在POI中使用HSSF对象时,excel 2003最多只允许存储65536条数据,一般用来处理较少的数据量。这时对于百万级别数据,Excel肯定容纳不了。
-
Excel 2007:当POI升级到XSSF对象时,它可以直接支持excel2007以上版本,因为它采用ooxml格式。这时excel可以支持1048576条数据,单个sheet表就支持近百万条数据。但实际运行时还可能存在问题,原因是执行POI报表所产生的行对象,单元格对象,字体对象,他们都不会销毁,这就导致OOM的风险
使用 SXSSFWorkbook
-
处理大数据量excel报表生成的:将已经使用过的内存元素,即使删除(poi4采用)或者保存到本地磁盘(poi3)
-
使用条件:
(1) 不支持模板打印
(2)不支持太多的样式对象(不超过64000个)
实现
模拟百万数据的导出
这里把导出的工作簿对象换为了SXSSF, 以及查询的每一条数据遍历6000次导出:
/**
* 百万数据导出--出货的Excel导出
* 1)URL:http://localhost:8080/cargo/contract/printExcel.do
* 2) 参数:inputDate=2020-04 船期
* 3)返回:文件下载(文件流)
*/
@RequestMapping("/printExcel")
public void printExcel(String inputDate) throws Exception {
//1.创建工作簿
SXSSFWorkbook workbook = new SXSSFWorkbook();
//2.创建工作单
Sheet sheet = workbook.createSheet("出货表");
//3.创建行
//4.创建列,设置内容
//3.1 创建标题行
Row titleRow = sheet.createRow(0);
//设置行高
titleRow.setHeightInPoints(36); // 磅
//设置列的宽度:setColumnWidth
/**
* 参数一:列的索引
* 参数二:列宽度值(字符数*256=磅)
*/
sheet.setColumnWidth(1,26*256);
sheet.setColumnWidth(2,11*256);
sheet.setColumnWidth(3,26*256);
sheet.setColumnWidth(4,29*256);
sheet.setColumnWidth(5,11*256);
sheet.setColumnWidth(6,11*256);
sheet.setColumnWidth(7,11*256);
sheet.setColumnWidth(8,11*256);
//1)创建列(第二列)
Cell cell = titleRow.createCell(1);
//设置列的样式
//cell.setCellStyle(bigTitle(workbook));
//2)合并列:addMergedRegion()
//CellRangeAddress: 起始行号 结束行号 起始列号 结束列号
sheet.addMergedRegion(new CellRangeAddress(0,0,1,8));
//3)设置内容
//2020-02 -> 2020年2
//2020-12 -> 2020年12
String title = inputDate.replaceAll("-0","年").replaceAll("-","年")+"月份出货表";
cell.setCellValue(title);
//3.2 创建表头行
//1)定义表头内容数组:客户 订单号 货号 数量 工厂 工厂交期 船期 贸易条款
String[] headerNames = {"客户","订单号","货号","数量","工厂","工厂交期","船期","贸易条款"};
//2)创建行
Row headerRow = sheet.createRow(1);
//设置行高
headerRow.setHeightInPoints(26);
//3) 创建列
for(int i=0;i<headerNames.length;i++){
Cell headerCell = headerRow.createCell(i+1);
//设置列的样式
headerCell.setCellStyle(title(workbook));
//4)内容
headerCell.setCellValue(headerNames[i]);
}
//3.3 创建内容行
//1)获取内容
List<ContractProductVo> list = contractProductService.findByShipTime(inputDate,getLoginCompanyId());
if(list!=null && list.size()>0){
int index = 2;
for(int j=0;j<=5000;j++) {
//2)创建行
for (int i = 0; i < list.size(); i++) {
ContractProductVo ContractProductVo = list.get(i);
Row contentRow = sheet.createRow(index++);
//设置行高
contentRow.setHeightInPoints(24);
Cell contentCell = null;
//3)创建列
//客户
contentCell = contentRow.createCell(1);
if (ContractProductVo.getCustomName() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getCustomName());
}
//订单号
contentCell = contentRow.createCell(2);
if (ContractProductVo.getContractNo() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getContractNo());
}
//货号
contentCell = contentRow.createCell(3);
if (ContractProductVo.getProductNo() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getProductNo());
}
//数量
contentCell = contentRow.createCell(4);
if (ContractProductVo.getCnumber() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getCnumber());
}
//工厂
contentCell = contentRow.createCell(5);
if (ContractProductVo.getFactoryName() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getFactoryName());
}
//交货日期
contentCell = contentRow.createCell(6);
if (ContractProductVo.getDeliveryPeriod() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getDeliveryPeriod());
}
//船期
contentCell = contentRow.createCell(7);
if (ContractProductVo.getShipTime() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getShipTime());
}
//贸易条款
contentCell = contentRow.createCell(8);
if (ContractProductVo.getTradeTerms() != null) {
//4)列的样式
contentCell.setCellValue(ContractProductVo.getTradeTerms());
}
}
}
}
//5.把工作簿(Excel的内容)返回给response响应(用户可以下载)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//5.1 把Excel的内容设置到ByteArrayOutputStream流中
workbook.write(outputStream);
/**
* 参数一:ByteArrayOutputStream:需要下载的内容
* 参数二:HttpServletResponse:响应对象
* 参数三:returnName:下载的文件名称
*/
//5.2 下载(把流写给response)
new DownloadUtil().download(outputStream,response,"出货表.xlsx");
}
导出报错了,注意:在SXSSF的excel导出中,为了提供导出效率,限制了导出的样式对象不能超过64000个。所以需要注释到上面的样式代码。