目录
一、 引入依赖
<!--Xlsx导入导出--> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.7</version> </dependency>
二、 创建简单类
public class ExcelDictDTO { /** @ExcelProperty("id")的值要和表格中的表头一致 @ExcelIgnore 表示忽略这个字段不进行读写 */ @ExcelProperty("id") private Long id; @ExcelProperty("上级id") private Long parentId; @ExcelProperty("名称") private String name; @ExcelProperty("值") private Integer value; @ExcelProperty("编码") private String dictCode; }
读
三、编写监听器(读取数据并保存到数据库的操作)
@Slf4j @NoArgsConstructor public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> { /** * 每隔5条存储数据库,最好不超过3000条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 5; List<ExcelDictDTO> list = new ArrayList(); private DictMapper dictMapper; /** 传入mapper对象 */ public ExcelDictDTOListener(DictMapper dictMapper) { this.dictMapper = dictMapper; } /** *遍历每一行的记录,若数据达到BATCH_COUNT的值就调用数据库存储方法 * @param data * @param context */ @Override public void invoke(ExcelDictDTO data, AnalysisContext context) { log.info("解析到一条记录: {}", data); list.add(data); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易内存不足或溢出 if (list.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list list.clear(); } } /** *当数据不这足以达到BATCH_COUNT值就最后再调用一次数据库存储方法 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 saveData(); log.info("所有数据解析完成!"); } /** * 将list的数据存储到数据库 */ private void saveData() { log.info("{}条数据,开始存储数据库!", list.size()); //批量插入 dictMapper.insertBatch(list); log.info("存储数据库成功!"); }
四、mapper创建批量新增sql
void insertBatch(List<ExcelDictDTO> list);
<insert id="insertBatch"> insert into dict ( id , parent_id , name , value , dict_code ) values <foreach collection="list" item="item" index="index" separator=","> ( #{item.id} , #{item.parentId} , #{item.name} , #{item.value} , #{item.dictCode} ) </foreach> </insert>
五、service创建批量新增的方法接口并实现
void importData(InputStream inputStream);
/** 开启事务出现Exception异常就会回滚数据 默认RuntimeException异常回滚 @param inputStream */ @Transactional(rollbackFor = {Exception.class}) @Override public void importData(InputStream inputStream) { // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 doRead:执行读取操作 EasyExcel.read(inputStream, ExcelDictDTO.class, new ExcelDictDTOListener(baseMapper)).sheet().doRead(); log.info("导入成功"); }
六、controller编写前端调用接口
@Resource private DictService dictService; @ApiOperation("Excel批量导入数据字典") @PostMapping("/import") public ReturnJson batchImport( @ApiParam(value = "Excel文件", required = true) @RequestParam("file") MultipartFile file) { try { InputStream inputStream = file.getInputStream(); dictService.importData(inputStream); return ReturnJson.ok().message("批量导入成功"); } catch (Exception e) { throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e); } }
写
七、service添加写入接口并实现
List<ExcelDictDTO> listDictData();
@Override public List<ExcelDictDTO> listDictData() { List<Dict> dictList = baseMapper.selectList(null); //创建ExcelDictDTO列表,将Dict列表转换成ExcelDictDTO列表 ArrayList<ExcelDictDTO> excelDictDTOList = new ArrayList<>(dictList.size()); dictList.forEach(dict -> { ExcelDictDTO excelDictDTO = new ExcelDictDTO(); //dict的数据拷贝到excelDictDTO BeanUtils.copyProperties(dict, excelDictDTO); //将拷贝好的数据添加到列表 excelDictDTOList.add(excelDictDTO); }); return excelDictDTOList; }
八、controller 编写前端调用接口
@ApiOperation("Excel数据的导出") @GetMapping("/export") public void export(HttpServletResponse response) { try { // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 String fileName = URLEncoder.encode("下载数据字典", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), ExcelDictDTO.class).sheet("数据字典").doWrite(dictService.listDictData()); } catch (IOException e) { throw new BusinessException(EXPORT_DATA_ERROR, e); } }
九、测试
根据自己的实际来编写测试用例或其他方法测试