一.Apache POI
可以通过Apache POI处理excel文件,核心操作是读和写
应用场景
- 银行网银交易明细
- 各种业务系统导出Excel报表
- 批量导入业务数据
使用步骤
1.导入maven坐标
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
2.测试代码(写操作)
public class PoiTest {
/**
* 写操作
* 通过POI创建excel文件并写入文件内容
*/
public static void write() throws IOException {
//在内存中创建一个excel文件XSSFWorkbook表示excel文件
XSSFWorkbook excel = new XSSFWorkbook();
//在excel文件中创建一个sheet页
XSSFSheet sheet = excel.createSheet("info");
//在sheet页中创建行对象,i表示第i+1行
XSSFRow row = sheet.createRow(1);
//在行上创建单元格,并写入内容
row.createCell(1).setCellValue("姓名");
row.createCell(2).setCellValue("城市");
row = sheet.createRow(2);
row.createCell(1).setCellValue("张三");
row.createCell(2).setCellValue("北京");
row = sheet.createRow(3);
row.createCell(1).setCellValue("李四");
row.createCell(2).setCellValue("东京");
//通过输出流将内存中的内容输出到文件中
FileOutputStream fileOutputStream=new FileOutputStream(new File("D:\\info.xlsx"));
excel.write(fileOutputStream);
fileOutputStream.close();
excel.close();
}
public static void main(String[] args) throws Exception {
write();
}
}
3.运行结果(写操作)
4.测试代码(读操作)
public class PoiTest {
/**
* 通过POI读取excel文件中内容
*/
public static void read() throws IOException {
//通过输入流读取一个磁盘中的文件内容;
FileInputStream inputStream = new FileInputStream(new File("D:\\info.xlsx"));
//在内存中创建一个excel文件XSSFWorkbook表示excel文件,并传入输入流
XSSFWorkbook excel=new XSSFWorkbook(inputStream);
//按照sheet页的名称读取
XSSFSheet sheet=excel.getSheetAt(0);
int lastRowNum = sheet.getLastRowNum();//获取有文字的最后一行的行号(从0开始);
for (int i = 1; i < lastRowNum; i++) {
//获取某一行
XSSFRow row=sheet.getRow(i);
if (row==null) continue;
//获取单元格对象
String cellValue=row.getCell(1).getStringCellValue();
String cellValue1=row.getCell(2).getStringCellValue();
System.out.println(cellValue+" "+cellValue1);
}
//关闭输入流
inputStream.close();
//关闭资源
excel.close();
}
public static void main(String[] args) throws Exception {
// write();
read();
}
}
5.运行结果(读操作)
二.导出Excel报表
由于实际业务中可能会有复杂的报表格式,如果直接使用POI进行读取操作十分繁琐,通常是先在windows上对报表格式进行设计,得到一个模版文件,直接读入模版文件进行操作即可
- 设计模版文件
- 查询xx天的数据
- 将查询到的数据写入模版文件
- 通过输出流将excel文件下载到客户端浏览器
实现步骤
- 项目中导入模版文件,在src/main/resources/下新建template目录用来存放模版文件,将模版.xlsx导入
- 编写代码,对指定位置进行填充,写入excel文件中的格式基本是固定的,我认为关键在于传递的参HttpServletResponse response,response.getOutputStream(): 通过调用response对象的getOutputStream()方法,获取到一个Servlet输出流。Servlet输出流是用于向客户端发送数据的输出流,通过这个输出流可以将数据发送到客户端。excel.write(outputStream): 调用excel对象的write()方法,将Excel文件内容写入到之前获取的Servlet输出流中。这会将Excel文件的内容写入到HTTP响应的输出流中,实际上是将Excel文件的字节流发送到客户端浏览器。然后客户端浏览器获得响应后自动开始下载文件.
//通过输出流将excel下载到客户浏览器
ServletOutputStream outputStream = response.getOutputStream();
excel.write(outputStream);
//关闭资源
outputStream.close();
excel.close();
业务层完整代码
/**
* 导出运行数据报表
*
* @param response
*/
@Override
public void exportBusinessData(HttpServletResponse response) {
//查数据库获取营业数据
LocalDate dateBegin = LocalDate.now().minusDays(30);
LocalDate dateEnd = LocalDate.now().minusDays(1);
//将日期转换为详细时间
LocalDateTime dateStartPoint = LocalDateTime.of(dateBegin, LocalTime.MIN);
LocalDateTime dateEndPoint = LocalDateTime.of(dateEnd, LocalTime.MAX);
BusinessDataVO businessData = workspaceService.getBusinessData(dateStartPoint, dateEndPoint);
ClassLoader loader = getClass().getClassLoader();
InputStream stream = loader.getResourceAsStream("template/运营数据报表模板.xlsx");
log.info("读入的输入流stream{}",stream);
//从类路径下边读取资源
InputStream inputStream = ReportServiceImpl.class.getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
// InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
try {
//基于模版文件创建一个新的excel文件
XSSFWorkbook excel=new XSSFWorkbook(inputStream);
XSSFSheet sheet1 = excel.getSheet("Sheet1");
//填充数据,填充时间
sheet1.getRow(1).getCell(1).setCellValue("时间"+dateBegin+"至"+dateEnd);
//获得第四行
XSSFRow row=sheet1.getRow(3);
row.getCell(2).setCellValue(businessData.getTurnover());
row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
row.getCell(6).setCellValue(businessData.getNewUsers());
//获得第五行
row=sheet1.getRow(4);
row.getCell(2).setCellValue(businessData.getValidOrderCount());
row.getCell(4).setCellValue(businessData.getUnitPrice());
//填充明细数据
for (int i=0;i<30;i++){
LocalDate date=dateBegin.plusDays(1);
//查询某一天的数据
workspaceService.getBusinessData(LocalDateTime.of(dateBegin,LocalTime.MIN),
LocalDateTime.of(dateBegin,LocalTime.MAX));
//获取某一行
row = sheet1.getRow(7 + i);
row.getCell(1).setCellValue(date.toString());
row.getCell(2).setCellValue(businessData.getTurnover());
row.getCell(3).setCellValue(businessData.getValidOrderCount());
row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
row.getCell(5).setCellValue(businessData.getUnitPrice());
row.getCell(5).setCellValue(businessData.getNewUsers());
}
//通过输出流将excel下载到客户浏览器
ServletOutputStream outputStream = response.getOutputStream();
excel.write(outputStream);
//关闭资源
outputStream.close();
excel.close();
} catch (IOException e) {
e.printStackTrace();
}
//将查询到的数据写入到Excel文件中
}
实现效果
备注:并不是下载了5个(是我之前测试用的提前下载了4个)