上篇介绍了下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) },
准备一份数据测试一下:
上传成功。
查看数据库里数据正确。