一.概念:
1.場(chǎng)景需求
????????將一些數(shù)據(jù)庫(kù)信息導(dǎo)出為Excel表格
????????將Excel表格數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫(kù)
? ? ? ? 大量數(shù)據(jù)的導(dǎo)入導(dǎo)出操作
常?的解決?案為: Apache POI 與阿?巴巴 easyExcel
?2.Apache POI介紹
?官?:https://poi.apache.org/
?模塊
POI存在的問題:? ? ? ? java解析,生成Excel比較有名的框架有 POI ,JXL,但他們有一個(gè)嚴(yán)重的問題,就是 非常消耗內(nèi)存, 也就是說數(shù)據(jù)量比較大的情況下有的時(shí)候會(huì)出現(xiàn)OOM(全稱“Out Of Memory”,翻譯成中文就是“內(nèi)存用完了”? )的問題。但 是POI 有?套 SAX 模式的 API 可以?定程度的解決?些內(nèi)存溢出的問題,但是依舊沒有完全的解決內(nèi)存消耗過?的問題OOM詳細(xì)解析什么是OOM,為什么會(huì)OOM及一些解決方法_Qi_Meng6的博客-CSDN博客_oom
?3.Excel表格 03 與 07 版本區(qū)別
07+版本:理論上沒有限制,但實(shí)際?持?數(shù)為:1048576,并且后綴為.xlsx
?二:POI操作Excel寫
?先第?件事情,我們需要?jiǎng)?chuàng)建項(xiàng)?導(dǎo)?對(duì)應(yīng)的 Maven ,這?我們需要演示 03 版本和 07+ 版本,所以兩個(gè)依賴都需要導(dǎo)?
?1.導(dǎo)依賴
<dependencies>
<!-- 03 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.1</version>
</dependency>
<!-- 07 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.1</version>
</dependency>
</dependencies>
2.寫?
?接下來我們完成通過POI寫?Excel表格數(shù)據(jù)的操作,那么?先我們要知道寫?個(gè)表
格需要的步驟:1.創(chuàng)建工作簿: Workbook2.創(chuàng)建工作表:sheet3.創(chuàng)建行:Row4.創(chuàng)建列(單元格):Cell5.具體數(shù)據(jù)寫入
?1.03版本測(cè)試:
簡(jiǎn)單寫入? (練習(xí)一下即可)
public class ExcelWriteDemo {
public static void main(String[] args) throws IOException {
new ExcelWriteDemo().writeExcel03();
}
public void writeExcel03() throws IOException {
// 1. 創(chuàng)建工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
// 2.創(chuàng)建工作表
HSSFSheet sheet = workbook.createSheet("03版本測(cè)試");
// 3.創(chuàng)建行 (創(chuàng)建第一行)
HSSFRow row1 = sheet.createRow(0);
// 創(chuàng)建單元格 (1,1)
HSSFCell cell11 = row1.createCell(0);
cell11.setCellValue("商品ID");
// 創(chuàng)建第一行第二列
HSSFCell cell12 = row1.createCell(1);
cell12.setCellValue("商品名稱");
// 創(chuàng)建第二行
HSSFRow row2 = sheet.createRow(1);
HSSFCell cell21 = row2.createCell(0);
cell21.setCellValue("a1");
HSSFCell cell22 = row2.createCell(1);
cell22.setCellValue("精品鼠標(biāo)");
// 生成一張表 -- IO流
FileOutputStream outputStream = new FileOutputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\03版本測(cè)試.xls");
// 寫入文件
workbook.write(outputStream);
// 關(guān)流 (養(yǎng)成良好習(xí)慣)
outputStream.close();
System.out.println("文件寫入完畢!");
}
}

?2.07版本測(cè)試
// 07 版本測(cè)試
public void writeExcel07() throws IOException {
// 1. 創(chuàng)建工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
// 2.創(chuàng)建工作表
Sheet sheet = workbook.createSheet("07版本測(cè)試");
Row row1 = sheet.createRow(0);
Cell cell11 = row1.createCell(0);
cell11.setCellValue("商品ID");
// 創(chuàng)建表 -- io
FileOutputStream outputStream = new FileOutputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\07版本測(cè)試.xlsx");
workbook.write(outputStream);
outputStream.close();
System.out.println("07 版本測(cè)試完畢!");
}
?有了上邊的基礎(chǔ),這個(gè)也簡(jiǎn)單
?3.實(shí)際對(duì)象分析
?4.批量寫入
那么不管是使? 03 版本還是 07+ 版本,那么我們?cè)趯?shí)際開發(fā)中都會(huì)碰到批量寫?數(shù)據(jù)的操作,尤其是數(shù)據(jù)量?較多的時(shí)候,那么 03 和 07+ 版本處理的?式是不同的
?03版本HSSF:
? ? ? ? 最多支持 65536 行數(shù)據(jù)的寫入,超出會(huì)報(bào)異常。
? ? ? ? 操作行為,先將數(shù)據(jù)放入到緩存中,最后一次寫入磁盤,寫入速度快
07+版本XSSF
????????數(shù)據(jù)的寫入速度會(huì)比較慢,因?yàn)閄SSF是獲取全部?的數(shù)據(jù),因此會(huì)消耗?
?????????可以寫?較?的數(shù)據(jù),?如10W+條數(shù)據(jù)
?測(cè)試: 03測(cè)時(shí)間和數(shù)據(jù)
public class ExcelWriteTimeDemo {
public static void main(String[] args) {
try {
new ExcelWriteTimeDemo().textTime03();
} catch (IOException e) {
e.printStackTrace();
}
}
// 03 版本測(cè)時(shí)間
public void textTime03() throws IOException {
long begin = System.currentTimeMillis();
// 創(chuàng)建工作鋪
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("03測(cè)試");
// 寫入數(shù)據(jù)
for (int rowNum = 0; rowNum < 65536 ; rowNum++) {//行 多一行就不行
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 20; cellNum++) {
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum+1);
}
}
FileOutputStream outputStream = new FileOutputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\03版本測(cè)時(shí)間.xls");
workbook.write(outputStream);
outputStream.close();
long end = System.currentTimeMillis();
System.out.println("所用時(shí)間為:" + (end-begin));
}
}
?07 測(cè)時(shí)間和數(shù)據(jù)
// 07 版本測(cè)時(shí)間
public void textTime07() throws IOException {
long begin = System.currentTimeMillis();
// 創(chuàng)建工作鋪
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("03測(cè)試");
// 寫入數(shù)據(jù)
for (int rowNum = 0; rowNum < 65536 ; rowNum++) {//行 多一行就不行
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 20; cellNum++) {
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum+1);
}
}
FileOutputStream outputStream = new FileOutputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\07版本測(cè)時(shí)間.xlsx");
workbook.write(outputStream);
outputStream.close();
long end = System.currentTimeMillis();
System.out.println("所用時(shí)間為:" + (end-begin));
}
07 比03 慢,但能存數(shù)據(jù)更多
?5.大數(shù)據(jù)寫SXSSF
// 07 大數(shù)據(jù) 版本測(cè)時(shí)間
public void textBigData07() throws IOException {
long begin = System.currentTimeMillis();
// 創(chuàng)建工作鋪
SXSSFWorkbook workbook = new SXSSFWorkbook();
Sheet sheet = workbook.createSheet("03測(cè)試");
// 寫入數(shù)據(jù)
for (int rowNum = 0; rowNum < 65536 ; rowNum++) {//行 多一行就不行
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 20; cellNum++) {
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum+1);
}
}
FileOutputStream outputStream = new FileOutputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\07大數(shù)據(jù)版本測(cè)時(shí)間.xlsx");
workbook.write(outputStream);
outputStream.close();
// 清除臨時(shí)文件
((SXSSFWorkbook) workbook).dispose();
long end = System.currentTimeMillis();
System.out.println("所用時(shí)間為:" + (end-begin));
}
?同樣的數(shù)據(jù)量明顯速度要?于XSSF,
同時(shí)它也可以寫?更多的數(shù)據(jù)
?三:POI讀數(shù)據(jù)
?具體步驟:
? ? ? ? 利用文件流來進(jìn)行讀取
1.獲取工作簿
2.獲取表
3.獲取行
4.獲取單元格
5.讀取數(shù)據(jù)
?03版本簡(jiǎn)單讀?。?/p>
public class ExcelReadDemo {
public static void main(String[] args) throws IOException {
read03();
}
// 讀取Excel
public static void read03() throws IOException {
FileInputStream is = new FileInputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\03版本測(cè)試.xls");
// 獲取工作簿
HSSFWorkbook workbook = new HSSFWorkbook(is);
// 獲取表
HSSFSheet sheet = workbook.getSheetAt(0);
// 獲取行
HSSFRow row1 = sheet.getRow(0);
HSSFCell cell11 = row1.getCell(0);
String value = cell11.getStringCellValue();
is.close();
System.out.println(value);
}
}
07版本簡(jiǎn)單讀取:
// 讀取Excel
public static void read07() throws IOException {
FileInputStream is = new FileInputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\07版本測(cè)時(shí)間.xlsx");
// 獲取工作簿
XSSFWorkbook workbook = new XSSFWorkbook(is);
// 獲取表
Sheet sheet = workbook.getSheetAt(0);
// 獲取行
Row row1 = sheet.getRow(0);
Cell cell11 = row1.getCell(0);
// String value = cell11.getStringCellValue();
double value = cell11.getNumericCellValue();
is.close();
System.out.println(value);
}
?批量數(shù)據(jù)讀取
?
?那么我們想讀取這張表,需要?先讀取標(biāo)題部分,然后再來讀取具體數(shù)據(jù)部分,這
兩步?定是要分開的
public class ExcelReadBigDemo {
public static void main(String[] args) throws IOException {
piLiangReadDemo();
}
// 批量數(shù)據(jù)的讀取
public static void piLiangReadDemo() throws IOException {
FileInputStream inputStream = new FileInputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\批量數(shù)據(jù)讀取測(cè)試.xls");
// 創(chuàng)建工作簿
HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
HSSFSheet sheet = workbook.getSheetAt(0);
// 讀取第一行的數(shù)據(jù)
HSSFRow title = sheet.getRow(0);
if(title != null){
// 獲取單元格的數(shù)量
int numberOfCells = title.getPhysicalNumberOfCells();
System.out.println("單元格的數(shù)量為:" + numberOfCells);
for (int i = 0; i < numberOfCells; i++) {
// 獲取所有單元格
HSSFCell cell = title.getCell(i);
if(cell != null){
String value = cell.getStringCellValue();
System.out.print(value + "|");
}
}
System.out.println();
}
// 獲取標(biāo)題以下的數(shù)據(jù)
int rowNum = sheet.getPhysicalNumberOfRows();
for (int i = 0; i < rowNum; i++) {
Row row = sheet.getRow(i);
if(row != null){
int cellNum = row.getPhysicalNumberOfCells();
for (int j = 0; j < cellNum; j++) {
Cell cell = row.getCell(j);
if(cell != null){
CellType cellType = cell.getCellType();
String cellVal = "";
switch (cellType){
case STRING: //字符串
cellVal = cell.getStringCellValue();
System.out.println("字符串類型");
break;
case NUMERIC://數(shù)值類型
// 判斷是否為日期
if(DateUtil.isCellDateFormatted(cell)){
System.out.println("日期類型");
Date date = cell.getDateCellValue();
cellVal = new SimpleDateFormat("yyyy-MM-dd").format(date);
}else {
cellVal = cell.toString();
System.out.println("數(shù)值類型");
}
break;
case BLANK:
System.out.println("空白類型");
case BOOLEAN:
cellVal = String.valueOf(cell.getBooleanCellValue());
System.out.println("布爾類型");
break;
case ERROR:
System.out.println("錯(cuò)誤格式");
break;
}
System.out.println(cellVal);
}
}
}
}
inputStream.close();
}
}
?以上寫代碼太復(fù)雜,可以找工具類,直接復(fù)制粘貼
?四:Excel操作--EasyExcel
?1.概述:
總結(jié):快速、簡(jiǎn)單避免 OOM 的 Java 處理 Excel ?具
?注意:這個(gè)?具操作?法官??檔提供的?常詳細(xì),甚?連不通的需求如何寫的代
碼都有對(duì)應(yīng)案例,所以這?我們只講?下基礎(chǔ)的使?寫?和讀取的操作,剩下的請(qǐng)參考官??檔
?2.具體操作:
1.引入依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.10</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
?簡(jiǎn)單的寫數(shù)據(jù)
/**
* @author Zzhenhua
* @project kuang-poi
* @date 2023/1/13 15:05
* @description TODO
*/
public class EasyDemo {
public static void main(String[] args) {
new EasyDemo().simpleWrite();
}
private List<DemoData> data() {
List<DemoData> list = ListUtils.newArrayList();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setString("字符串" + i);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
/**
* 最簡(jiǎn)單的寫
* <p>
* 1. 創(chuàng)建excel對(duì)應(yīng)的實(shí)體對(duì)象 參照{(diào)@link DemoData}
* <p>
* 2. 直接寫即可
*/
public void simpleWrite() {
// 注意 simpleWrite在數(shù)據(jù)量不大的情況下可以使用(5000以內(nèi),具體也要看實(shí)際情況),數(shù)據(jù)量大參照 重復(fù)多次寫入
// 寫法1 JDK8+
// since: 3.0.0-beta1
// String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
String fileName = "E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\easyExcel.xlsx";
// 這里 需要指定寫用哪個(gè)class去寫,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉
// 如果這里想使用03 則 傳入excelType參數(shù)即可
EasyExcel.write(fileName, DemoData.class)
.sheet("模板")
.doWrite(data());
// // 寫法2
// fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// // 這里 需要指定寫用哪個(gè)class去寫,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉
// // 如果這里想使用03 則 傳入excelType參數(shù)即可
// EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
//
// // 寫法3
// fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// // 這里 需要指定寫用哪個(gè)class去寫
// try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
// WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// excelWriter.write(data(), writeSheet);
// }
}
}
@Data
@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
@ExcelProperty("字符串標(biāo)題")
private String string;
@ExcelProperty("日期標(biāo)題")
private Date date;
@ExcelProperty("數(shù)字標(biāo)題")
private Double doubleData;
/**
* 忽略這個(gè)字段
*/
@ExcelIgnore
private String ignore;
}
?簡(jiǎn)單的讀
package com.hua.easyexcel;
import com.alibaba.excel.EasyExcel;
import com.hua.pojo.DemoData;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
public class EasyExcelImportMain {
public static void main(String[] args) throws Exception {
// 創(chuàng)建一個(gè)輸入流,將 Excel 文件讀取出來
InputStream inputStream = new FileInputStream(
"E:\\java課\\數(shù)據(jù)導(dǎo)入導(dǎo)出\\練習(xí)\\excelPOi\\easyExcel.xlsx");
List<DemoData> tmpList = EasyExcel.read(inputStream)
// 設(shè)置與Excel表映射的類
.head(DemoData.class)
// 設(shè)置sheet,默認(rèn)讀取第一個(gè)
.sheet()
// 設(shè)置標(biāo)題所在行數(shù)
.headRowNumber(1)
// 異步讀取
.doReadSync();
for (DemoData tmpDate : tmpList) {
System.out.println(tmpDate);
}
}
}
案例給前端返回excel數(shù)據(jù)
?文章來源地址http://www.zghlxwxcb.cn/news/detail-548019.html
@GetMapping("/hotel/export")
public void export(HttpServletResponse response) throws IOException {
//獲取需要導(dǎo)出的數(shù)據(jù)
List<Hotel> hotels = hotelService.find();
//excel文件名
final String FILENAME = "酒店信息";
//sheetName
final String SHEETNAME = "酒店信息表";
//獲取model對(duì)象類
Class hotel = Hotel.class;
try {
//表頭樣式策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//設(shè)置頭居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//內(nèi)容策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//設(shè)置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
//初始化表格樣式
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
// response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 這里URLEncoder.encode可以防止中文亂碼 當(dāng)然和easyexcel沒有關(guān)系
String fileName = URLEncoder.encode(FILENAME, "UTF-8").replaceAll("\\+", "%20");
//響應(yīng)首部 Access-Control-Expose-Headers 就是控制“暴露”的開關(guān),它列出了哪些首部可以作為響應(yīng)的一部分暴露給外部。
//此處設(shè)置了開放Content-Disposition,前端可獲取該響應(yīng)參數(shù)獲取文件名稱
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
// 這里需要設(shè)置不關(guān)閉流
EasyExcel.write(response.getOutputStream(), hotel).autoCloseStream(Boolean.FALSE)
.registerWriteHandler(horizontalCellStyleStrategy).sheet(SHEETNAME).doWrite(hotels);
} catch (IOException e) { //下載失敗情況的處理
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap<>();
map.put("status", "failure");
map.put("message", "下載文件失敗" + e.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
}
最后postman測(cè)試返回?cái)?shù)據(jù)
?
?文章來源:http://www.zghlxwxcb.cn/news/detail-548019.html
?
完成!?
?
?
到了這里,關(guān)于數(shù)據(jù)導(dǎo)入導(dǎo)出(POI以及easyExcel)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!