上篇介紹了下EasyExcel的讀寫excel文件的使用,現在利用它來實現項目中的excel文件導出和導入的功能。
現在有一個字典列表,要把里面的數據實現導出和導入。
一、實現導出
既然是整合到項目里,跟之前的練習還是有些區別的。說是導出功能,實際上也算是個下載的操作。
1. 實現后端接口
controller 類中增加導出數據字典的控制器方法。
@Api(value = "數據字典的接口")
@RestController
@RequestMapping("/admin/cmn/dict")
@CrossOrigin
public class DictController {
@Autowired
private DictService dictService;
// 導出數據字典接口
@GetMapping("exportData")
public void exportDict(HttpServletResponse response) {
dictService.exportDictData(response);
}
// 根據id查詢子數據列表
@ApiOperation(value = "根據id查詢子數據列表")
@GetMapping("findChildData/{id}")
public Result findChildData(@PathVariable Long id) {
List<Dict> list = dictService.findChildData(id);
return Result.ok(list);
}
}
這里方法exportDict
中傳參是HttpServletResponse response
,為了方便做下載操作。
然后DictService
接口中增加對應的方法exportDictData
。
public interface DictService extends IService<Dict> {
List<Dict> findChildData(Long id);
void exportDictData(HttpServletResponse response);
}
接着就是到DictServiceImpl
類中實現exportDictData
方法了:
// 導出數據字典接口
@Override
public void exportDictData(HttpServletResponse response) {
try {
// 設置下載信息
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = "dict";
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
// 查詢庫里的數據
List<Dict> dictList = baseMapper.selectList(null);
// Dict 轉成 DictEeVo
List<DictEeVo> dictEeVoList = new ArrayList<>(dictList.size());
for (Dict dict: dictList) {
DictEeVo dictEeVo = new DictEeVo();
BeanUtils.copyProperties(dict, dictEeVo);
dictEeVoList.add(dictEeVo);
}
// 調用方法,進行寫操作,這里使用輸出流
EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("dict").doWrite(dictEeVoList);
} catch (IOException e) {
e.printStackTrace();
}
}
做的事情主要是3件:
- 先設置下載信息
- 查詢庫里的數據
- 使用
EasyExcel.write
方法把查出來的數據寫到excel文件中
另外,Dict
對應的是表里的實體類,DictEeVo
則是excel內容的實體類。
調用EasyExcel.write
的時候要傳入的是DictEeVo
類型,而數據庫查出來的是Dict
,所以有了異步轉換的操作。
2. 實現前端
前端可以很簡單的實現,通過一個<a>
標簽就可以:
<a href="http://localhost:8202/admin/cmn/dict/exportData" target="_blank">
<el-button type="text"> 導出</el-button>
</a>
target="_blank"
是為了打開新的標簽頁。
測試下:
二、實現導入
1. 實現后端接口
繼續增加導入的控制器方法:
// 導入數據字典
@PostMapping("importData")
public Result importDict(MultipartFile file) {
dictService.importDictData(file);
return Result.ok();
}
這里參入是MultipartFile file
用於獲取上傳的文件。
跟上面一樣的套路,一直到實現importDictData
方法。
@Override
public void importDictData(MultipartFile file) {
}
不過目前里面還寫不了,因為需要先去寫一個監聽器。
public class DictListener extends AnalysisEventListener<DictEeVo> {
private DictMapper dictMapper;
public DictListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}
// 一行一行讀取
@Override
public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
// 調用方法,添加到數據庫表里
Dict dict = new Dict();
// dictEeVo 轉換成 dict
BeanUtils.copyProperties(dictEeVo, dict);
dictMapper.insert(dict);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
注意這里面的一個細節,因為在invoke
方法中,一行行讀取后,我需要把這每行的數據添加到數據庫中,那么自然需要用到dictMapper
。
那么我這個監聽器里如何才可以支持傳入dictMapper
呢?其中一個方法就是通過有參構造方法來注入:
private DictMapper dictMapper;
public DictListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}
現在監聽器完成,繼續完成importDictData
方法:
@Override
public void importDictData(MultipartFile file) {
try {
EasyExcel.read(file.getInputStream(), DictEeVo.class, new DictListener(baseMapper)).sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
}
}
new DictListener(baseMapper))
這里在傳入監聽器的時候里面就要帶上dictMapper
,這里放的是baseMapper
也可以。
2. 實現前端整合
添加導入按鈕,綁定@click
調用上傳方法。
<el-button type="text" @click="importData"> 導入</el-button>
點擊導入后跳出對話框,增加友好度。
:multiple
: 表示是否上傳多個文件,這里用單個
*:on-success
: 文件上傳成功會調用的方法:action
:請求的接口路徑
對應里面的方法:
//導入數據字典
importData() {
this.dialogImportVisible = true
},
//上傳成功調用
onUploadSuccess() {
//關閉彈框
this.dialogImportVisible = false
//刷新頁面
this.getDictList(1)
},
准備一份數據測試一下:
上傳成功。
查看數據庫里數據正確。