一、前言 今天小編帶大家一起整合一下easyExcel,之所以用這個,是因為easyExcel性能比較好,不會報OOM! 市面上常見的導入導出Excel分為三種: hutool easyExcel poi hutool和easyExcel都是對poi的封裝,使用起來更加方便! 如果想使用poi和hu ...
一、前言
今天小編帶大家一起整合一下easyExcel
,之所以用這個,是因為easyExcel
性能比較好,不會報OOM
!
市面上常見的導入導出Excel分為三種:
- hutool
- easyExcel
- poi
hutool
和easyExcel
都是對poi
的封裝,使用起來更加方便!
如果想使用poi
和hutool
導出的可以看一下小編的之前寫的文章:
使用POI+hutool導入Excel
使用POI把查詢到的數據表數據導出到Excel中,一個表一個sheet
導出的話看一下這篇,下麵主要以導入來展開介紹!
EasyExcel導出Excel表格到瀏覽器,並通過Postman測試導出Excel
二、導入依賴
小編這裡是3.0.X
版本的,版本不同可能導致部分有出入,如果大家版本是3.1.X
,可以去官方文檔看看有不一樣的!
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
三、實體類
這裡可以自帶的轉換器:
- @DateTimeFormat("yyyy年MM月dd日HH時mm分ss秒")
- LocalDateTimeStringConverter
或者自定義轉化器:
實現:implements Converter<T>
具體文檔:官方文檔
@ExcelProperty
參數註意:
這裡不建議 index 和 name 同時用,要麼一個對象只用index,要麼一個對象只用name去匹配
用名字去匹配,這裡需要註意,如果名字重覆,會導致只有一個欄位讀取到數據
/**
* @author wangzhenjun
* @date 2022/12/2 15:52
*/
@Data
public class Test {
@TableId
private Integer id;
@ExcelProperty(index = 0)
private String name;
@ExcelProperty(index = 1)
private Integer age;
@ExcelProperty(index = 2,converter = LocalDateTimeStringConverter.class)
private LocalDateTime time;
}
四、編寫監聽器
註意點:
這個監聽器一定不要是單例的,被spring管理預設為單例,如果要使用@Component
,一定要加上:
@Scope("prototype")
,這樣在創建完後spring不會進行管理,每次都會是新bean!
不加@Component
在導入時要進行new ImportDataListener
!
小編這裡不想new了直接這樣寫!!如果不想這樣,可以使用構造器set進行使用!
BATCH_COUNT
:數據閾值,超過了就會清理list,在之前可以進行保存到資料庫中,方便記憶體回收,防治OOM
!
這裡保存到資料庫中一般使用批量保存
,不要解析到一行就去保存資料庫中,這樣數據量大會給資料庫增加IO,導致掛掉!這裡小編使用ServiceImpl
的saveBatch()
方法,也可以自己寫一下,像小編這樣寫,會出現迴圈依賴,加上@Lazy
就行!
/**
* @author wangzhenjun
* @date 2022/12/2 15:38
*/
@Slf4j
@Component
// 每次bean都是新的,不要單例
@Scope("prototype")
public class ImportDataListener implements ReadListener<Test> {
@Autowired
@Lazy
private TestService testService;
/**
* 每隔5條存儲資料庫,實際使用中可以100條,然後清理list ,方便記憶體回收
*/
private static final int BATCH_COUNT = 100;
/**
* 緩存的數據
*/
private List<Test> importExcelDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 這個每一條數據解析都會來調用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(Test data, AnalysisContext context) {
log.info("解析到一條數據:{}", JSON.toJSONString(data));
importExcelDataList.add(data);
// 達到BATCH_COUNT了,需要去存儲一次資料庫,防止數據幾萬條數據在記憶體,容易OOM
if (importExcelDataList.size() >= BATCH_COUNT) {
saveData();
// 存儲完成清理 list
importExcelDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有數據解析完成了 都會來調用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 這裡也要保存數據,確保最後遺留的數據也存儲到資料庫
saveData();
log.info("所有數據解析完成!");
}
/**
* 加上存儲資料庫
*/
private void saveData() {
log.info("{}條數據,開始存儲資料庫!", importExcelDataList.size());
testService.saveBatch(importExcelDataList);
log.info("存儲資料庫成功!");
}
}
五、Controller
/**
* @author wangzhenjun
* @date 2022/10/26 16:51
*/
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private TestService testService;
@PostMapping("/import")
public Result importExcel(@RequestBody MultipartFile multipartFile){
testService.importExcel(multipartFile);
return Result.success("ok");
}
}
六、Service
/**
* @author wangzhenjun
* @date 2022/10/26 16:55
*/
public interface TestService extends IService<Test> {
void importExcel(MultipartFile multipartFile);
}
七、ServiceImpl
/**
* @author wangzhenjun
* @date 2022/10/26 16:56
*/
@Service
public class TestServiceImpl extends ServiceImpl<TestDbMapper, Test> implements TestService{
@Autowired
private ImportDataListener importDataListener;
@SneakyThrows
@Override
public void importExcel(MultipartFile multipartFile) {
InputStream inputStream = multipartFile.getInputStream();
// 這裡 需要指定讀用哪個class去讀,然後讀取第一個sheet 文件流會自動關閉
EasyExcel.read(inputStream, Test.class, importDataListener).sheet().doRead();
}
}
八、Mapper
/**
* @author wangzhenjun
* @date 2022/10/26 17:07
*/
public interface TestDbMapper extends BaseMapper<Test> {
}
九、測試
準備Excel數據:
postman上傳:
控制台列印:
資料庫查看:
完美搞定!!
十、總結
這樣就完成了easyExcel批量導入Excel到資料庫,還是有很多要註意的點:
- 自定義轉換器
- 監聽器不要單例
- 保存資料庫採用批量
- 版本差距
如果對你有幫助,還請不要吝嗇您的發財小手,你的一鍵三連是我寫作的動力,謝謝大家哈!!
可以看下小編的微信公眾號,文章首發看,歡迎關註,一起交流哈!!