前言:学习B站Up主狂神说,视频笔记整理视频链接
POI
常用信息
1、将用户信息导出为excel表格(导出数据…)
2、将Excel表中的信息录入到网站数据库(习题上传…)
开发中经常会设计到excel的处理,如导出Excel,导入Excel到数据库中!操作Excel目前比较流行的就是Apache POI和阿里巴巴的easyExcel !
什么是POI
Excel03与Excel07区别
Excel03行数最多只能到65536
Excel03后缀xlx
Excel07后缀xlsx
快速上手
导入依赖
<!-- 03版 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<!-- 07版 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!-- 日期格式化工具 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.10</version>
</dependency>
文件写出
测试03版本Excel写出
private String PATH="D:\\Wordspase\\POI-EasyExcelStudy\\";
@Test
public void testWrite03() throws Exception {
//创建工作簿
HSSFWorkbook workbook = new HSSFWorkbook();//03版本工作簿
//工作表
HSSFSheet sheet = workbook.createSheet("员工统计表"); //工作表名
//创建一行
Row row1 = sheet.createRow(0);//一行
//单元格
Cell cell = row1.createCell(0);// 坐标(1,1)
cell.setCellValue("员工总数");
//(1,2)
Cell cell1 = row1.createCell(1);
cell1.setCellValue(666);
//第二行
Row row = sheet.createRow(1);
Cell ce1ll = row.createCell(0);
ce1ll.setCellValue("统计时间");
Cell cell2 = row.createCell(1);
String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
cell2.setCellValue(time);
//生成表(IO流) 03版本就是使用xls结尾
FileOutputStream outputStream = new FileOutputStream(PATH + "员工统计表03.xls");
//输出
workbook.write(outputStream);
//关闭流
outputStream.close();
System.out.println("生成完毕");
测试07版本Excel写出
private String PATH="D:\\Wordspase\\POI-EasyExcelStudy\\";
@Test
public void testWrite03() throws Exception {
//创建工作簿
Workbook workbook = new XSSFWorkbook();//07版本工作簿
//工作表
Sheet sheet = workbook.createSheet("员工统计表"); //工作表名
//创建一行
Row row1 = sheet.createRow(0);//一行
//单元格
Cell cell = row1.createCell(0);// 坐标(1,1)
cell.setCellValue("员工总数");
//(1,2)
Cell cell1 = row1.createCell(1);
cell1.setCellValue(666);
//第二行
Row row = sheet.createRow(1);
Cell ce1ll = row.createCell(0);
ce1ll.setCellValue("统计时间");
Cell cell2 = row.createCell(1);
String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
cell2.setCellValue(time);
//生成表(IO流) xlsx
FileOutputStream outputStream = new FileOutputStream(PATH + "员工统计表07.xlsx");
//输出
workbook.write(outputStream);
//关闭流
outputStream.close();
System.out.println("生成完毕");
}
大文件写出说明
大文件写HSSF
缺点︰最多只能处理65536行,否则会抛出异常
优点: 内存中 速度较快
大文件写出XSSF
缺点:速度较慢
优点:可以写出比较大的数据
优化XSSF写出慢问题
优点:可以写非常大的数据量,如100万条甚至更多条,写数据速度快,占用更少的内存
注意:
过程中会产生临时文件,需要湾理临时文件
默认由100条记录被保存在内存中,如果超过这数量,则最前面的数据被写入临时文件如果想自定义内存中数据的数量,可以住用new SXSSFWarkbook(数量)
private String PATH="D:\\Wordspase\\POI-EasyExcelStudy\\";
@Test
public void testWrite07BigDates() throws Exception {
//创建工作簿
Workbook workbook = new SXSSFWorkbook();
//工作表
Sheet sheet = workbook.createSheet("员工统计表"); //工作表名
for (int rowNum =0;rowNum<100000;rowNum++){
Row row = sheet.createRow(rowNum);
for (int cellrow =0;cellrow<10;cellrow++){
Cell cell = row.createCell(cellrow);
cell.setCellValue(cellrow);
}
}
//生成表(IO流) xlsx
FileOutputStream outputStream = new FileOutputStream(PATH + "员工统计表07dates.xlsx");
//输出
workbook.write(outputStream);
//清除临时文件
((SXSSFWorkbook) workbook).dispose();
//关闭流
outputStream.close();
System.out.println("生成完毕");
}
文件读取
03版本文件读取
private String PATH="D:\\Wordspase\\POI-EasyExcelStudy\\";
@Test
public void testRead03() throws Exception {
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH + "员工统计表03.xls");
//创建表
HSSFWorkbook sheets = new HSSFWorkbook(inputStream);
//得到工作簿
HSSFSheet sheetAt = sheets.getSheetAt(0);//第0
//得到行
HSSFRow row = sheetAt.getRow(0);
//得到列
HSSFCell cell = row.getCell(1);
//得到值 字符串类型
// String value = cell.getStringCellValue();
//cell.getNumericCellValue() 浮点数类型
System.out.println(cell.getNumericCellValue());
//关闭流
inputStream.close();
}
获取值的时候一定要注意Excel中的数据类型 否则会报类型异常
07版本文件读取
@Test
public void testRead07() throws Exception {
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH + "员工统计表07.xlsx");
//创建表 07表
Workbook sheets = new XSSFWorkbook(inputStream);
//得到工作簿
Sheet sheetAt = sheets.getSheetAt(0);//第0
//得到行
Row row = sheetAt.getRow(0);
//得到列
Cell cell = row.getCell(1);
//得到值 字符串类型
// String value = cell.getStringCellValue();
//cell.getNumericCellValue() 浮点数类型
System.out.println(cell.getNumericCellValue());
//关闭流
inputStream.close();
}
批量文件读取
我们使用这张03表进行测试
@Test
public void testRead03date() throws Exception {
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH + "员工表.xls");
//创建表
Workbook sheets = new HSSFWorkbook(inputStream);
//得到工作簿
Sheet sheetAt = sheets.getSheetAt(0);//第0
//得到行
Row rowTitle = sheetAt.getRow(0);
if (rowTitle!=null){
//获取列数
int cellCount = rowTitle.getPhysicalNumberOfCells();
for (int cellNum=0;cellNum<cellCount;cellNum++){
Cell cell = rowTitle.getCell(cellNum);
if (cell!=null){
int type = cell.getCellType();//获取类型
String cellValue = cell.getStringCellValue();
System.out.print(cellValue+"|");
}
}
}
//获取表中的内容
int rowNumber = sheetAt.getPhysicalNumberOfRows();//获取所有行数
for (int rowNum = 1;rowNum<rowNumber;rowNum++){
Row rowDate = sheetAt.getRow(rowNum);
if (rowDate!=null){
int cellCount = rowDate.getPhysicalNumberOfCells(); //获取列数
for (int cellNum=0;cellNum<cellCount;cellNum++){
Cell cell = rowDate.getCell(cellNum);//取出单元格
if (cell!=null){
int type = cell.getCellType();//获取类型
String cellValue = "";
//匹配数据类型
switch (type){
case HSSFCell.CELL_TYPE_STRING: //字符串
System.out.println("[String]");
cellValue = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_BOOLEAN: //布尔
System.out.println("[BOOLEAN]");
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_BLANK: //空
System.out.println("[BLANK:]");
break;
case HSSFCell.CELL_TYPE_NUMERIC: //数字(日期,普通数字)
System.out.println("[NUMERIC:]");
if (HSSFDateUtil.isCellDateFormatted(cell)){
//日期
Date date = cell.getDateCellValue();
cellValue = new DateTime(date).toString("yyyy-MM-ss");
}else {
//如果不是日期格式 防止数字过长
System.out.println("转换成字符串输出");
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cellValue = cell.toString();
}
break;
case HSSFCell.CELL_TYPE_ERROR: //数据类型错误
System.out.println("[ERROR]");
break;
}
System.out.println(cellValue);
}
}
}
}
inputStream.close();
}
POI实战-Excel模板下载-导入-导出
controller
@Controller
@RequestMapping("/file")
public class FileController {
//模板存放位置
private String PATH = "D:\\Wordspase\\employee-Information\\";
@Autowired
private FileService fileService;
//下载模板
@ResponseBody
@RequestMapping("/downloadTemplate")
public void downloadTemplate(HttpServletResponse response){
OutputStream out = null;
InputStream in = null;
String fileName= "员工表.xls";
try {
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition","attachment; filename=" + new String(fileName.getBytes("utf-8"), "ISO_8859_1"));
File file = new File(PATH + fileName);
in = new FileInputStream(file);
out = response.getOutputStream();
byte[] tmp = new byte[1024];
while (in.read(tmp) != -1) {
out.write(tmp);
}
out.flush();
in.close();
return ;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("模板下载失败");
}
}
//批量导入员工信息
@RequestMapping("/upload")
public String Fileupload(@RequestParam("file") MultipartFile file, Model model){
if (file.getSize()>0) {
String i = fileService.insertDBByExcel(file);
if (i.equals("ok")){
return "redirect:/employee/allemployee";
}
model.addAttribute("filename",i);
return "addsEmployee";
}else {
model.addAttribute("filename","上传文件为空");
return "addsEmployee";
}
}
//批量导出
@ResponseBody
@RequestMapping("/employeeExcel")
public void employeeExcel(HttpServletResponse response){
fileService.exportToExcel(response);
}
}
Service
public interface FileService {
//批量导入
public String insertDBByExcel(MultipartFile file);
//批量导出
public void exportToExcel(HttpServletResponse response);
}
serviceImpl
@Service
public class FileServiceImpl implements FileService{
@Autowired
private EmployeeService employeeService;
//批量导入
@Override
public String insertDBByExcel(MultipartFile file) {
//获取文件名
String filename = file.getOriginalFilename();
filename = filename.toLowerCase();
if("".equals(filename)){
return "文件名为空!";
}
System.out.println("上传文件名 : "+filename);
//正则表达式校验
if(!filename.matches("^.+\\.(xls)$")) {
return "请上传后缀为.xls的文件";
}
try {
InputStream inputStream = file.getInputStream();
//创建表
Workbook sheets = new HSSFWorkbook(inputStream);
//得到工作簿
Sheet sheetAt = sheets.getSheetAt(0);//第0
int rowNumber = sheetAt.getPhysicalNumberOfRows();//得到所有行
for (int rowNum = 1;rowNum<rowNumber;rowNum++){
//取出每一行
Row rowDate = sheetAt.getRow(rowNum);
if (rowDate != null){
//判断是否为空
//取出一行中的列数
int cellCount = rowDate.getPhysicalNumberOfCells(); //获取列数
//员工表实体类
Employee employee = new Employee();
for (int cellNum=0;cellNum<cellCount;cellNum++){
//便利所有列
Cell cell = rowDate.getCell(cellNum);//取出单元格
if (cell!=null) {
//判断单元格是否为空
String value = typeValue(cell.getCellType(), cell); //单元格数据类型判断
//设置值
switch (cellNum){
case 1:
employee.setName(value);
break;
case 2:
employee.setSex(value);
break;
case 3:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");//注意月份是MM
Date date = simpleDateFormat.parse(value);
employee.setBirth(date);
break;
case 4:
employee.setAddress(value);
break;
case 5:
employee.setPhone(value);
break;
case 6:
employee.setCard(value);
break;
case 7:
employee.setDegree(value);
break;
case 8:
long pid = Long.valueOf(value).longValue();
employee.setPid(pid);
break;
}
}
}
//写入数据库
employeeService.addEmployee(employee);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "ok";
}
//批量导出
@Override
public void exportToExcel(HttpServletResponse response) {
ServletOutputStream out = null;
//创建工作簿
HSSFWorkbook workbook = new HSSFWorkbook();//03版本工作簿
//工作表
Sheet sheet = workbook.createSheet("员工统计表"); //工作表名
//创建一行
Row row1 = sheet.createRow(0);
//设置标题
row1.createCell(0).setCellValue("编号");
row1.createCell(1).setCellValue("名字");
row1.createCell(2).setCellValue("性别");
row1.createCell(3).setCellValue("出生日期");
row1.createCell(4).setCellValue("地址");
row1.createCell(5).setCellValue("手机号");
row1.createCell(6).setCellValue("身份证号");
row1.createCell(7).setCellValue("学历");
row1.createCell(8).setCellValue("职位编号");
//查询全部的员工信息
List<Employee> list = employeeService.queryEmployee(null);
for (int rowNum =0;rowNum<list.size();rowNum++) {
Row row = sheet.createRow(rowNum+1);
Employee employee = list.get(rowNum);
row.createCell(0).setCellValue(employee.getId());
row.createCell(1).setCellValue(employee.getName());
row.createCell(2).setCellValue(employee.getSex());
row.createCell(3).setCellValue(employee.getBirth());
row.createCell(4).setCellValue(employee.getAddress());
row.createCell(5).setCellValue(employee.getPhone());
row.createCell(6).setCellValue(employee.getCard());
row.createCell(7).setCellValue(employee.getDegree());
row.createCell(8).setCellValue(employee.getPid());
}
// 文件名
String fileName = new String("员工统计表.xls");
try {
out = response.getOutputStream();
//获取客户端浏览器类型
response.setHeader("content-disposition", "attachment; filename=\""
+ new String(fileName.toString().getBytes("utf-8"),
"ISO8859_1") + "\"");
workbook.write(out);//写出
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//单元格匹配类型
public String typeValue(int type,Cell cell) {
String cellValue = "";
//匹配数据类型
switch (type) {
case HSSFCell.CELL_TYPE_STRING: //字符串
cellValue = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_BOOLEAN: //布尔
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case HSSFCell.CELL_TYPE_BLANK: //空
break;
case HSSFCell.CELL_TYPE_NUMERIC: //数字(日期,普通数字)
if (HSSFDateUtil.isCellDateFormatted(cell)) {
//日期
Date date = cell.getDateCellValue();
cellValue = new DateTime(date).toString("yyyy-MM-ss");
} else {
//如果不是日期格式 防止数字过长
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cellValue = cell.toString();
}
break;
case HSSFCell.CELL_TYPE_ERROR: //数据类型错误
break;
}
return cellValue;
}
}
EasyExcel
什么是EasyExcel
easyexcel 是一个 JAVA 解析 Excel 工具。Java 解析、生成 Excel 比较有名的框架有 Apache poi、jxl 。但他们都存在一个严重的问题就是 非常的耗内存,poi 有一套 SAX 模式的 API 可以一定程度的解决一些内存溢出的问题,但 POI 还是有一些缺陷,比如 07 版 Excel 解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel 重写了 poi 对 07 版 Excel 的解析,能够原本一个 3M 的 excel 用 POI sax 依然需要 100M 左右内存降低到 KB 级别,并且再大的 excel 不会出现内存溢出,03 版依赖 POI 的 sax 模式。在上层做了模型转换的封装,让使用者更加简单方便。
EasyExcel读取文件的方式
POI读取文件: 100W==>加载到内存中==>全部写入 (可能会引发OOW)
EasyExcel读取文件: 磁盘 一行一行的返回
快速上手
参考文档:https://www.yuque.com/easyexcel/doc/easyexcel文档