通用异步线程下载zip包导出excel文件

通用异步线程下载zip包导出excel文件

前言:页面点击下载按钮(批量导出excel文件,并且压缩成zip包格式导出),使用异步线程进行 查询数据、封装excel、导出下载 过程。

  • 文件导出模板通用类

提取一个抽象类,泛型 继承于 导出参数模型基础类,以便于不同类型的文件导出,只需要改变入参类型(需要继承基础模型类)即可。生成通用抽象方法,生成入参、查询参数、生成文件、下载文件、导入外系统(DFS)等...

/**
 * 文件导出模板通用类
 *
 * @author Hang.W
 * @date 2019-08-26 16:18
 */
@Slf4j
public abstract class AbstractDownloadTemplate<T extends MctProdBaseReqDTO> {

	/** dfs 工具类 */
    @Autowired
    private DfsFileDealUtils dfsFileDealUtils;

	/** 下载中心 */
    @Autowired
    private MctProdReserveDownloadManager mctProdReserveDownloadManager;

    /**
     * 生成导出文件参数,并记录下载
	 *
     * @param request
     * @return
     */
    public abstract MctCoreDownloadTaskInsertReqDTO insertRecord(T request);

    /**
     * 查询数据
	 *
     * @param request
     * @return
     */
    public abstract Object queryDate(T request) throws Exception;

    /**
     * 生成文件
	 *
     * @param o
     * @return
     */
    public abstract byte[] generateFile(T request, Object o, Object oj) throws Exception;

    /**
     * 下载方法
     * @param request
     * @param fileType
     */
    public void download(T request, MctCoreDownloadTaskInsertReqDTO downloadTaskInsertReqDTO,
                         String fileType) {
        DownLoadThread<T> downLoadThread = new DownLoadThread<>(this, request,
            downloadTaskInsertReqDTO, fileType, null);
        ThreadPoolUtils.execute(downLoadThread);
    }

    /**
     * 下载方法
	 *
     * @param request
     * @param fileType
     */
    public void download(T request, MctCoreDownloadTaskInsertReqDTO downloadTaskInsertReqDTO,
                         String fileType, Object o) {
        DownLoadThread<T> downLoadThread = new DownLoadThread<>(this, request,
            downloadTaskInsertReqDTO, fileType, o);
        ThreadPoolUtils.execute(downLoadThread);
    }

    /**
     * 完成文件上传外网
	 *
     * @param t 请求数据
     * @param fileFormat 文件格式
     */
    public void finishDownload(T t, MctCoreDownloadTaskInsertReqDTO downloadTaskInsertReqDTO,
                               String fileFormat, Object o) {
        try {
            byte[] fileByte = generateFile(t, queryDate(t), o);
            String filePath = dfsFileDealUtils.uploadFileByBytes(fileByte, fileFormat);
            if (filePath != null) {
                downloadTaskInsertReqDTO.setFileFullPath(MctProdConstant.DFS_HTTP_PATH + filePath);
                downloadTaskInsertReqDTO
                    .setStatus(MctCoreFileDownloadTaskStatusEnum.SUCCESS.getCode());
                downloadTaskInsertReqDTO.setUpdatedAt(new Date());
                mctProdReserveDownloadManager.initOrUpdateDownloadTask(downloadTaskInsertReqDTO);
            } else {
                downloadTaskInsertReqDTO
                    .setStatus(MctCoreFileDownloadTaskStatusEnum.FAILURE.getCode());
                downloadTaskInsertReqDTO.setUpdatedAt(new Date());
                mctProdReserveDownloadManager.initOrUpdateDownloadTask(downloadTaskInsertReqDTO);
            }
        } catch (Exception e) {
            log.info("文件上传外网异常,原因:{}", downloadTaskInsertReqDTO, e);
            downloadTaskInsertReqDTO.setStatus(MctCoreFileDownloadTaskStatusEnum.FAILURE.getCode());
            downloadTaskInsertReqDTO.setUpdatedAt(new Date());
            mctProdReserveDownloadManager.initOrUpdateDownloadTask(downloadTaskInsertReqDTO);
        }
    }
	
}
  • 具体文件下载类,继承于通用模板下载类
  1. 继承于上边通用模板下载类,重写生成入参、生成文件方法。
  2. 入参MctProdExportStoreReqDTO 门户导出类,泛型继承于 基础模型类。
  3. generateFile()生成excel文件方法中,POI创建HSSFWorkbook,excel,包括合并单元格,字体颜色等,最终生成导入zip包中
/**
 * 门户信息导出Excel表格zip包格式
 *
 * @author Hang.W
 * @date 2019-08-26 16:24
 */
@Slf4j
@Service
public class MctProdExportStoreInfoExcelProcess extends AbstractDownloadTemplate<MctProdExportStoreReqDTO> {

	/** 下载中心表 */
    @Autowired
    private MctCoreDownloadTaskService mctCoreDownloadTaskService;

    @Autowired
    private SequenceUtils sequenceUtils;

    @Autowired
    private MctProdMerchantInfoManager mctProdMerchantInfoManager;

    @Override
    public MctCoreDownloadTaskInsertReqDTO insertRecord(MctProdExportStoreReqDTO reqDTO) {
        MctCoreDownloadTaskInsertReqDTO downloadTaskInsertReqDTO = new MctCoreDownloadTaskInsertReqDTO();
        downloadTaskInsertReqDTO.setMerchantCode(reqDTO.getMerchantCode());
        downloadTaskInsertReqDTO.setFileId(sequenceUtils.getSequenceNo());
        downloadTaskInsertReqDTO.setFileType(MctCoreFileDownloadTypeEnum.MERCHANT_STORE_INFO.getCode());
        downloadTaskInsertReqDTO.setFileName(reqDTO.getMerchantCode() + "_商户门户信息" + ".zip");
        downloadTaskInsertReqDTO.setFileFullPath("");
        downloadTaskInsertReqDTO.setStatus(MctCoreFileDownloadTaskStatusEnum.DOING.getCode());
        downloadTaskInsertReqDTO.setRemark("");
        downloadTaskInsertReqDTO.setCreatedAt(new Date());
        downloadTaskInsertReqDTO.setCreatedBy(reqDTO.getMerchantCode());
        downloadTaskInsertReqDTO.setTraceLogId(reqDTO.getTraceLogId());

        Result<Boolean> response = mctCoreDownloadTaskService.insertDownloadTask(downloadTaskInsertReqDTO);
        if (response.isSuccess() && response.getResult()) {
            return downloadTaskInsertReqDTO;
        } else {
            return null;
        }
    }

    @Override
    public Object queryDate(MctProdExportStoreReqDTO request) throws Exception {
        return null;
    }

    @Override
    public byte[] generateFile(MctProdExportStoreReqDTO mctProdExportStoreReqDTO, Object o, Object oj) throws Exception {

        log.info("MctProdMerchantInfoServiceImpl.exportStore 门户信息导出Excel表格, 入参{}", mctProdExportStoreReqDTO);
        Result<List<MctCoreStoreInfoResDTO>> result = mctProdMerchantInfoManager.exportStore(mctProdExportStoreReqDTO);
        log.info("MctProdMerchantInfoServiceImpl.exportStore 门户信息导出Excel表格, 返回{}", result);
        if(!result.isSuccess() || null == result.getResult()) {
            log.error("MctProdMerchantInfoManager.exportStore 调用核心根据商户号merchantCode全量查询门户信息,失败:{}", result);
            throw new MerchantProductBizException(BizErrorCode.EMPTY_QUERY_RESULT, result.getErrorMsg());
        }

        HSSFWorkbook workbook = new HSSFWorkbook();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 压缩输出流
        ZipOutputStream zipOut = new ZipOutputStream(baos);

        try {
            HSSFSheet sheet = workbook.createSheet("门户信息");
            sheet.setColumnWidth(0, 30 * 256);
            sheet.setColumnWidth(1, 30 * 256);
            sheet.setColumnWidth(2, 50 * 256);
            sheet.setColumnWidth(3, 30 * 256);
            sheet.setColumnWidth(4, 30 * 256);
            sheet.setColumnWidth(5, 30 * 256);
            sheet.setColumnWidth(6, 30 * 256);
            sheet.setColumnWidth(7, 50 * 256);
            sheet.setColumnWidth(8, 30 * 256);
            sheet.setColumnWidth(9, 30 * 256);

            // 设置字体颜色
            HSSFFont font = workbook.createFont();
            font.setColor(HSSFColor.RED.index);
            HSSFCellStyle redFontStyle = workbook.createCellStyle();
            redFontStyle.setFont(font);

            HSSFRow row0 = sheet.createRow(0);
            HSSFCell cell0 = row0.createCell(0);
            cell0.setCellValue("填写说明(填写信息时请保留1-5行,删除第6行)");
            cell0.setCellStyle(redFontStyle);
            CellRangeAddress region0 = new CellRangeAddress(0, 0, 0, 9);
            sheet.addMergedRegion(region0);
            HSSFRow row1 = sheet.createRow(1);
            row1.createCell(0).setCellValue("1、红色字体为必填项,请按照标准填写");
            CellRangeAddress region1 = new CellRangeAddress(1, 1, 0, 9);
            sheet.addMergedRegion(region1);
            HSSFRow row2 = sheet.createRow(2);
            row2.createCell(0).setCellValue("2、电话支持手机号和座机两种,只要输入一个即可,固定电话请加区号,如:010-12345678,手机号一般为11位数字");
            CellRangeAddress region2 = new CellRangeAddress(2, 2, 0, 6);
            sheet.addMergedRegion(region2);
            HSSFRow row3 = sheet.createRow(3);
            row3.createCell(0).setCellValue("3、同一商户门户名称/详细地址不可重复");
            CellRangeAddress region3 = new CellRangeAddress(3, 3, 0, 1);
            sheet.addMergedRegion(region3);

            HSSFRow row = sheet.createRow(4);
            HSSFCell cell4_0 = row.createCell(0);
            cell4_0.setCellValue("门户名称");
            cell4_0.setCellStyle(redFontStyle);
            HSSFCell cell4_1 = row.createCell(1);
            cell4_1.setCellValue("门户编号");
            cell4_1.setCellStyle(redFontStyle);
            row.createCell(2).setCellValue("分店名称");
            HSSFCell cell4_3 = row.createCell(3);
            cell4_3.setCellValue("门户属性");
            cell4_3.setCellStyle(redFontStyle);
            HSSFCell cell4_4 = row.createCell(4);
            cell4_4.setCellValue("省份");
            cell4_4.setCellStyle(redFontStyle);
            HSSFCell cell4_5 = row.createCell(5);
            cell4_5.setCellValue("城市");
            cell4_5.setCellStyle(redFontStyle);
            HSSFCell cell4_6 = row.createCell(6);
            cell4_6.setCellValue("区县");
            cell4_6.setCellStyle(redFontStyle);
            HSSFCell cell4_7 = row.createCell(7);
            cell4_7.setCellValue("详细地址");
            cell4_7.setCellStyle(redFontStyle);
            HSSFCell cell4_8 = row.createCell(8);
            cell4_8.setCellValue("联系人");
            cell4_8.setCellStyle(redFontStyle);
            HSSFCell cell4_9 = row.createCell(9);
            cell4_9.setCellValue("电话");
            cell4_9.setCellStyle(redFontStyle);

            int rowCount = 4;
            for (MctCoreStoreInfoResDTO mctCoreStoreInfoResDTO : result.getResult()) {
                rowCount++;
                row = sheet.createRow(rowCount);
                row.createCell(0).setCellValue(mctCoreStoreInfoResDTO.getStoreName());
                row.createCell(1).setCellValue(mctCoreStoreInfoResDTO.getStoreNo());
                row.createCell(2).setCellValue(mctCoreStoreInfoResDTO.getSubStoreName());
                row.createCell(3).setCellValue(mctCoreStoreInfoResDTO.getStoreType());
                row.createCell(4).setCellValue(mctCoreStoreInfoResDTO.getProvinceCode());
                row.createCell(5).setCellValue(mctCoreStoreInfoResDTO.getCityCode());
                row.createCell(6).setCellValue(mctCoreStoreInfoResDTO.getAreaCode());
                row.createCell(7).setCellValue(mctCoreStoreInfoResDTO.getAddress());
                row.createCell(8).setCellValue(mctCoreStoreInfoResDTO.getLinkMan());
                row.createCell(9).setCellValue(mctCoreStoreInfoResDTO.getTelephone());
            }

            // 设置格式是文本
            HSSFCellStyle style = workbook.createCellStyle();
            style.setDataFormat(workbook.createDataFormat().getFormat("yyyy-mm-dd"));
            sheet.setDefaultColumnStyle(0, style);
            sheet.setDefaultColumnStyle(1, style);
            sheet.setDefaultColumnStyle(2, style);
            sheet.setDefaultColumnStyle(3, style);
            sheet.setDefaultColumnStyle(4, style);
            sheet.setDefaultColumnStyle(5, style);
            sheet.setDefaultColumnStyle(6, style);
            sheet.setDefaultColumnStyle(7, style);
            sheet.setDefaultColumnStyle(8, style);
            sheet.setDefaultColumnStyle(9, style);
            log.info("全量导出门户信息zip包开始");
            // 进行压缩存储
            zipOut.setMethod(ZipOutputStream.DEFLATED);
            // 压缩级别值为0-9共10个级别(值越大,表示压缩越厉害)
            zipOut.setLevel(Deflater.BEST_COMPRESSION);
            // 对需要压缩的文件命名
            zipOut.putNextEntry(new ZipEntry("商户门户信息.xls"));
            // 读取要压缩的字节输出流,进行压缩
            workbook.write(zipOut);
            zipOut.flush();

        } catch (IOException e) {
            log.error("全量导出门户信息,写入异常信息:{}, {}", e.getMessage(), e);
            throw new RuntimeException(e);
        } finally {
            workbook.close();
            baos.close();
            zipOut.close();
        }
        log.info("全量导出门户信息zip包完成");
        return baos.toByteArray();
    }

}

 

  • 进行文件导出步骤
  1. 创建interface接口,实现下载文件步骤
  2. 使用具体文件下载类,调用方法,生成下载文件入参,并且调用下载文件方法,开始下载文件
/**
 * 异步文件导出类
 *
 * @author Hang.W
 * @date 2019-08-26 16:37
 */
@Service
@Slf4j
public class MctProdMerchantInfoServiceImpl implements MctProdMerchantInfoService {

    @Autowired
    private MctProdExportStoreInfoExcelProcess mctProdExportStoreInfoExcelProcess;

	/**
	 * 导出门户信息
	 */
    @Override
    public Result<Boolean> exportStore(MctProdExportStoreReqDTO mctProdExportStoreReqDTO) {
        MDC.put(Marker.TRACE_LOG_ID, mctProdExportStoreReqDTO.getTraceLogId());
        Result<Boolean> result = new Result<>(Boolean.FALSE);
        try {
            log.info("MctProdMerchantInfoServiceImpl.exportStore 门户信息导出Excel表格, 入参{}", mctProdExportStoreReqDTO);
			// 封装导出excel参数
            MctCoreDownloadTaskInsertReqDTO mctCoreDownloadTaskInsertReqDTO = mctProdExportStoreInfoExcelProcess
                    .insertRecord(mctProdExportStoreReqDTO);

            if (mctCoreDownloadTaskInsertReqDTO != null) {
				// 执行导出excel操作
                mctProdExportStoreInfoExcelProcess.download(mctProdExportStoreReqDTO,
                        mctCoreDownloadTaskInsertReqDTO, "zip");
                result.setResult(Boolean.TRUE);
                log.info("MctProdMerchantInfoServiceImpl.exportStore 门户信息导出Excel表格成功");
            }
        } catch (Exception e) {
            log.error("MctProdMerchantInfoServiceImpl.exportStore 门户信息导出Excel表格, 异常{}", e);
            result = DealExceptionUtil.doExceptionService(e);
        }
        return result;
    }

}
  • 异步线程开始下载文件
  1. 具体文件下载实现类中没有重写通用模板下载方法,所以使用通用模板download方法
  2. 在通用模板下载类中,创建线程,实现先上传,再下载的功能
  3. 线程类构造方法中入参传入,通用模板类,用于不同类型文件对象的下载
/**
 * 异步线程下载
 *
 * @author Hang.W
 * @date 2019-08-26 16:53
 */
public class DownLoadThread<T extends MctProdBaseReqDTO> implements Runnable {

    private AbstractDownloadTemplate<T> abstractDownloadTemplate;

    private MctCoreDownloadTaskInsertReqDTO downloadTaskInsertReqDTO;
	
	private T request;

    private Object o;
	
	private String fileFormat;

    public DownLoadThread(AbstractDownloadTemplate<T> abstractDownloadTemplate, T request,
                          MctCoreDownloadTaskInsertReqDTO downloadTaskInsertReqDTO,
                          String fileFormat, Object o) {
        this.abstractDownloadTemplate = abstractDownloadTemplate;
        this.request = request;
        this.downloadTaskInsertReqDTO = downloadTaskInsertReqDTO;
        this.fileFormat = fileFormat;
        this.o = o;
    }

    @Override
    public void run() {
         abstractDownloadTemplate.finishDownload(request, downloadTaskInsertReqDTO, fileFormat, o);
    }
	
}
  • 具体门户模型类
/**
 * 门户模型类
 *
 * @author Hang.W
 * @date 2019-08-26 17:05
 */
@Getter
@Setter
@ToString
public class MctProdExportStoreReqDTO extends MctProdBaseReqDTO {

	/** 门户号 */
    @NotBlank(message = "门户号不能为空")
    @NotNull(message = "门户号不能为空")
    private String storeCode;

}
  • 总结
  1. 提取通用模板文件下载类
  2. 针对不同的文件对象,例如:(用户信息,产品信息,资金信息等),不同的入参,可以使用同一种类的不同实现来进行功能
  3. 文中包括excel的生成,以及zip的下载

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值