芋道框架下的进销存升级(三):Yudao-ERP2异步导出/导入Excel的设计与实现

接上文《芋道框架下的进销存升级(二):Yudao-ERP2打印模板管理的设计与实现》继续升级,本次升级内容主要是实现Excel高性能异步导出或导入。

先看效果:

Yudao-ERP2异步导出/导入Excel的设计与实现

一、后端改造

1. 新增Excel导出/导入表,用芋道框架自带的代码生成功能生成crud代码

2. 实现异步导出逻辑

① 定义一个线程池

② 定义一个导出excel抽象类

③ 每一个具体的导出业务定义一个handler类且继承抽象类,该handler内实现异步导出业务,生成excel导出文件,更新异步导出任务状态等,最关键一点,该handler使用@Component注解声明为Spring容器管理的Bean。

java 复制代码
@Component
@Slf4j
public class DemoExportHandler extends AbstractAsyncExcelExportHandler{

    @Override
    @Async(ASYNC_EXCEL_THREAD_POOL_TASK_EXECUTOR)
    public void exportExcel(ExcelExportSaveReqVO excelExportSaveReqVO) {
        // 1. 更新状态为处理中
        updateExcelExportStatus(new ExcelExportSaveReqVO(
                excelExportSaveReqVO.getId(),
                ImportExportStatusEnum.PROCESS.getStatus()
                )
        );

        // 2. 导出数据
        String resultFilePath = "";
        int dataNum = 0;
        int status = ImportExportStatusEnum.FAIL.getStatus();
        int fileSize = 0;
        String remark = "";

        try {
            List<Map<String, Object>> exportDataList = new ArrayList();
            if (!exportDataList.isEmpty()) {
                byte[] excelContent = new byte[1024];
                fileSize = excelContent.length;
                resultFilePath = saveExcelFile(excelContent, getDateTimeFileName("导出示例", "xlsx"));
                status = ImportExportStatusEnum.SUCCESS.getStatus();
                dataNum = exportDataList.size();
            }else{
                remark = "没有数据";
            }
        } catch (Exception e) {
            log.error("导出失败", e);
            remark = ExceptionUtil.stacktraceToString(e);
        }

        // 3. 更新状态为处理完成
        updateExcelExportStatus(new ExcelExportSaveReqVO(
                        excelExportSaveReqVO.getId(),
                        status,
                        resultFilePath,
                        fileSize,
                        dataNum,
                        remark
                )
        );
    }

}

④ 定义一个统一的创建异步导出Excel任务的接口,该接口的其中一个入参定义为业务类型,对应参数值为handler的Bean名。

java 复制代码
@Tag(name = "管理后台 - Excel导出")
@RestController
@RequestMapping("/system/excel-export")
@Validated
public class ExcelExportController {

    @Resource
    private ExcelExportService excelExportService;

    @PostMapping("/create")
    @Operation(summary = "创建Excel导出")
    @PreAuthorize("@ss.hasPermission('system:excel-export:create')")
    public CommonResult<Long> createExcelExport(@Valid @RequestBody ExcelExportSaveReqVO createReqVO) {
        return success(excelExportService.createExcelExport(createReqVO));
    }
}
java 复制代码
@Service
@Validated
public class ExcelExportServiceImpl implements ExcelExportService {

    @Resource
    private ExcelExportMapper excelExportMapper;

    @Override
    public Long createExcelExport(ExcelExportSaveReqVO createReqVO) {
        if(!SpringUtil.getApplicationContext().containsBean(createReqVO.getDataType())){
            throw exception(EXCEL_EXPORT_TYPE_NOT_EXISTS);
        }

        // 插入
        ExcelExportDO excelExport = BeanUtils.toBean(createReqVO, ExcelExportDO.class);
        excelExport.setStatus(ImportExportStatusEnum.WAIT_PROCESS.getStatus());
        excelExportMapper.insert(excelExport);

        AbstractAsyncExcelExportHandler asyncExcelExportHandler = SpringUtil.getBean(createReqVO.getDataType());
        createReqVO.setId(excelExport.getId());
        asyncExcelExportHandler.exportExcel(createReqVO);

        // 返回
        return excelExport.getId();
    }

    @Override
    public void updateExcelExport(ExcelExportSaveReqVO updateReqVO) {
        // 校验存在
        validateExcelExportExists(updateReqVO.getId());
        if(updateReqVO.getRemark() != null && updateReqVO.getRemark().length() > ExcelExportSaveReqVO.REMARK_MAX_LENGTH){
            updateReqVO.setRemark(updateReqVO.getRemark().substring(0, ExcelExportSaveReqVO.REMARK_MAX_LENGTH));
        }
        // 更新
        ExcelExportDO updateObj = BeanUtils.toBean(updateReqVO, ExcelExportDO.class);
        excelExportMapper.updateById(updateObj);
    }

    @Override
    public void deleteExcelExport(Long id) {
        // 校验存在
        validateExcelExportExists(id);
        // 删除
        excelExportMapper.deleteById(id);
    }

    @Override
        public void deleteExcelExportListByIds(List<Long> ids) {
        // 删除
        excelExportMapper.deleteByIds(ids);
        }


    private void validateExcelExportExists(Long id) {
        if (excelExportMapper.selectById(id) == null) {
            throw exception(EXCEL_EXPORT_NOT_EXISTS);
        }
    }

    @Override
    public ExcelExportDO getExcelExport(Long id) {
        return excelExportMapper.selectById(id);
    }

    @Override
    public PageResult<ExcelExportDO> getExcelExportPage(ExcelExportPageReqVO pageReqVO) {
        return excelExportMapper.selectPage(pageReqVO);
    }

}

这样便实现了一个简单的,统一的,解耦的,高性能的,异步的导出Excel功能,统一的创建导出任务接口,统一的Excel导出下载页面,不同的业务实现导出只需继承抽象类实现导出逻辑即可。

异步导入Excel同理。

二、前端改造

1. 在业务功能页面,增加"异步导出"按钮,例如采购订单页面如下所示:

javascript 复制代码
<el-button
          type="success"
          plain
          @click="handleAsyncExport"
          :loading="exportLoading"
          v-hasPermi="['erp:purchase-order:export']"
        >
          <Icon icon="ep:download" class="mr-5px" /> 异步导出
        </el-button>
        
 /** 异步导出按钮操作 */
const handleAsyncExport = async () => {
  try {
    // 导出的二次确认
    await message.exportConfirm()
    let filterCondition = ''
    Object.entries(queryParams).forEach((key) => {
      if(queryParamFieldName[key[0]] && key[1] && key[1].length){
        filterCondition += `${queryParamFieldName[key[0]]}:${key[1]};`
      }
    })
    if(filterCondition.length){
      filterCondition = filterCondition.substring(0, filterCondition.length-1)
    }
    // 发起导出
    exportLoading.value = true
    const data = {
      dataType: EXCEL_EXPORT_TYPE.PURCHASE_ORDER,
      filterConditionCode: JSON.stringify(queryParams),
      filterCondition: filterCondition
    } as ExcelExport
    await ExcelExportApi.createExcelExport(data)
    message.success(t('common.exportSuccess'))
  } catch {
  } finally {
    exportLoading.value = false
  }
}       

export enum EXCEL_EXPORT_TYPE {
  PURCHASE_ORDER = 'erpPurchaseOrderExportHandler',
  DEMO = 'demoExportHandler',
}

const queryParams = reactive({
  pageNo: 1,
  pageSize: 10,
  no: undefined,
  supplierId: undefined,
  productId: undefined,
  orderTime: [],
  status: undefined,
  remark: undefined,
  creator: undefined,
  inStatus: undefined,
  returnStatus: undefined
})
const queryParamFieldName = reactive({
  no: '订单单号',
  supplierId: '供应商ID',
  productId: '产品ID',
  orderTime: '订单时间',
  status: '状态',
  remark: '备注',
  creator: '创建人',
  inStatus: '入库数量',
  returnStatus: '退货数量'
})

2. Excel导出下载页面

即用芋道框架自带的代码生成功能生成的Excel导出表的前端代码

src\views\system\excelexport\index.vue

详见源码,地址如下:

https://gitee.com/zkool/yudao-erp2

相关推荐
胡闹541 小时前
【EasyExcel】字段赋值错乱问题
java·开发语言
CodeCraft Studio2 小时前
Excel处理控件Aspose.Cells教程:使用C#在Excel中创建旭日图
c#·excel·aspose·excel旭日图·excel库·excel开发控件·excel api库
断剑zou天涯2 小时前
【算法笔记】AC自动机
java·笔记·算法
张工摆Bug2 小时前
《别再写满屏的if-else了!Spring Boot + 策略模式实战优化》
java
独自归家的兔2 小时前
基于GUI-PLUS 搭配 Java Robot 实现智能桌面操控
java·开发语言·人工智能
用户3721574261352 小时前
Python 实现 PDF 文档压缩:完整指南
java
ew452182 小时前
【JAVA】实现word的DOCX/DOC文档内容替换、套打、支持表格内容替换。
java·开发语言·word
贺今宵2 小时前
装Maven并在idea上配置
java·maven·intellij-idea
qq_12498707532 小时前
基于springboot的幼儿园家校联动小程序的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·spring·微信小程序·小程序