zoukankan      html  css  js  c++  java
  • 【easyexcel】1.实时下载导出报表

    实时下载导出报表

    ====================================================================================

    1.修改总览

     

    1.pom.xml

    <!-- 阿里巴巴easyexcel start-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>${easyexcel.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>cglib</groupId>
                        <artifactId>cglib</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>2.2</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>${poi.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>${poi.version}</version>
            </dependency>
            <!-- 阿里巴巴easyexcel end-->
    View Code

    2.controller

    package com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.controller;
    
    
    import com.alibaba.fastjson.JSON;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.dto.ReportDTO;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.enums.ReportEnum;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.exception.ReportException;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.query.DUQuery;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.service.ReportService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletResponse;
    import javax.validation.Valid;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.OutputStream;
    import java.net.URLEncoder;
    
    @Slf4j
    @Validated
    @RestController
    @RequestMapping("/xlsx/downloadAndUpload")
    public class XlsxDownloadAndUploadController {
    
    
        @Resource
        private ReportService reportService;
    
        /**
         * 实时下载  xlsx文件
         * 将根据查询条件实时查询到的数据  通过 xlsx文件导出
         * @param query 导出查询条件
         * @return
         */
        @RequestMapping(value = "/rtDownload", method = {RequestMethod.GET})
        public void rtDownload(HttpServletResponse response, @Valid DUQuery query) {
            OutputStream outputStream = null;
            FileInputStream inputStream =null;
            File file = null;
            try {
    
                ReportDTO dto = new ReportDTO();
                dto.setReportEnum(ReportEnum.RT_REPORT);
                dto.setRequestParams(JSON.toJSONString(query));
                file = reportService.generateReport(dto);
    
    
    
                response.setContentType("mutipart/form-data");
                response.setCharacterEncoding("utf-8");
                response.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(file.getName(), "utf-8"));
                outputStream = response.getOutputStream();
    
    
                inputStream = new FileInputStream(file);
                byte[] b = new byte[1024];
                int length = 0;
                while ((length = inputStream.read(b)) != -1) {
                    outputStream.write(b, 0, length);
                }
                outputStream.flush();
    
    
            } catch (Exception e) {
                log.error("导出业务报表发生错误:", e);
                throw new ReportException("导出业务报表发生错误!");
            }finally{
                reportService.close(outputStream,inputStream);
                reportService.delFile(file);
            }
        }
    
    }
    View Code

    3.报表service

    package com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.service.impl;
    
    import com.alibaba.excel.EasyExcel;
    import com.alibaba.excel.ExcelWriter;
    import com.alibaba.excel.write.metadata.WriteSheet;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.context.ReportGenerateContext;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.dto.ReportDTO;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.enums.ReportEnum;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.exception.ReportException;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.handler.AbstractReportHandler;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.service.ReportService;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.utils.XlsxCellWidthUtil;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.utils.XlsxCellWriteUtil;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.utils.XlsxHeadUtil;
    import com.sxd.swapping.utils.serialNum.SerialNumHelper;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.Properties;
    
    /**
     * 业务报表Service
     *
     * 报表导出的 核心逻辑在这里
     *
     * 1.边读边写 解决FullGC问题
     * 2.集成多种业务报表   不同的报表类型可以在ReportEnum中以不同枚举定义  定义入参class  出参class  报表名称 等关键信息
     * 3.单元格支持超过15位长的纯数字串不会显示成E+问题
     * 4.generateReport()  生成临时File,支持【实时导出】  和 【上传远程服务器得到可直接下载的URL 暂未实现】
     */
    @Slf4j
    @Service
    public class ReportServiceImpl implements ReportService {
    
    
        @Resource
        private ReportGenerateContext reportGenerateContext;
    
        /**
         * 生成报表临时文件
         * @param reportDTO
         * @return
         */
        @Override
        public File generateReport(ReportDTO reportDTO) {
            ReportEnum reportEnum = reportDTO.getReportEnum();
            if (reportEnum == null) {
                throw new ReportException("报表类型必传!");
            }
    
            if (StringUtils.isBlank(reportDTO.getRequestParams())) {
                throw new ReportException("报表入参数据必传!");
            }
    
    
    
            //1.获取临时文件路径[需定义自定义报表枚举]
            String filePath = getFilePath(reportEnum.getTempFileName());
    
    
    
    
            //2.初始化xlsx文件对象 [需定义自定义表头工具]
            ExcelWriter excelWriter = EasyExcel
                    .write(filePath, reportEnum.getReportClass())
    //                .registerWriteHandler(new XlsxCellFontUtil())       //默认情况不用显式设置,除非业务有需求
    //                .registerWriteHandler(XlsxCellStyleUtil.getCellStyleStrategy())  //默认情况不用显式设置,除非业务有需求
                    .registerWriteHandler(new XlsxCellWidthUtil())      //一般情况下可以不用设置,除非表头没正常生成
                    .registerWriteHandler(new XlsxCellWriteUtil())      //如果导出数据中,有超过15位的数字串,则需要设置
                    .head(XlsxHeadUtil.getHeadByReportEnum(reportEnum)) //一般情况可以不用设置,除非表头没正常生成
                    .build();
            WriteSheet writeSheet = EasyExcel.writerSheet(reportEnum.getDesc()).build();
            reportDTO.setExcelWriter(excelWriter);
            reportDTO.setWriteSheet(writeSheet);
    
    
    
            //3.获取报表handler完成xlsx文件生成[需定义自定义handler并加入上下文]
            AbstractReportHandler reportHandler = reportGenerateContext.getReportHandler(reportEnum);
            reportHandler.generateReport(reportDTO);
    
    
    
            //4.关闭easyxlsx写入器
            excelWriter.finish();
    
    
            return new File(filePath);
        }
    
        /**
         * 根据文件名获取文件路径
         * @param tempFileName
         * @return
         */
        @Override
        public String getFilePath(String tempFileName) {
            Properties properties = System.getProperties();
            String path = properties.getProperty("user.dir");
            if (properties.getProperty("os.name").toLowerCase().contains("win")) {
                path += "\";
            } else {
                path += "/";
            }
            path += String.format(tempFileName, SerialNumHelper.generateRecordId());
    
            log.info("DownloadServiceImpl#getFilePath={}" , path);
            return path;
        }
    
        /**
         * 删除临时文件
         * @param file
         */
        @Override
        public void delFile(File file) {
            if (file != null && file.exists()) {
                try {
                    file.delete();
                }catch (Exception e) {
                    log.error("删除临时文件失败:", e);
                }
            }
        }
    
        /**
         * 关闭资源
         * @param outputStream
         * @param inputStream
         */
        @Override
        public void close(OutputStream outputStream, InputStream inputStream) {
            closeOutStream(outputStream);
            cloaseInputStream(inputStream);
        }
    
        @Override
        public void closeOutStream(OutputStream outputStream) {
            if(outputStream !=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("关闭输出流失败:", e);
                }
            }
        }
    
        @Override
        public void cloaseInputStream(InputStream inputStream) {
            if(inputStream != null ){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("关闭输入流失败:", e);
                }
            }
        }
    }
    View Code

    4.报表枚举ReportEnum

    package com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.enums;
    
    
    import com.fasterxml.jackson.annotation.JsonCreator;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.query.DUQuery;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.vo.RTReportVO;
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    import java.util.Arrays;
    import java.util.Objects;
    
    @AllArgsConstructor
    @Getter
    public enum  ReportEnum {
    
        /** 枚举项 */
        RT_REPORT(1, "实时导出报表", RTReportVO.class, DUQuery.class,"实时导出报表-%s.xlsx"),
    
        ;
    
        /***/
        private Integer value;
    
        /**报表描述*/
        private String desc;
    
        /**导出模板*/
        private Class reportClass;
    
        /**业务入参*/
        private Class requestParams;
    
        /**报表文件名称*/
        private String tempFileName;
    
    
    
        @JsonCreator
        public static ReportEnum valueOf(Integer value) {
            return Arrays.stream(ReportEnum.values())
                    .filter(e -> Objects.equals(e.value, value)).findFirst()
                    .orElseThrow(() -> new RuntimeException("ReportEnum value=" + value + " not exists!"));
        }
    }
    View Code

    5.业务枚举DUStatusEnum

    package com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.enums;
    
    import com.fasterxml.jackson.annotation.JsonCreator;
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    import java.util.Arrays;
    import java.util.Objects;
    
    @AllArgsConstructor
    @Getter
    public enum DUStatusEnum {
    
    
    
        WAIT(0,"等待处理"),
    
        SUCCESS(1,"成功"),
    
        FAIL(-1, "失败")
        ;
    
        /***/
        private Integer value;
    
        /**报表描述*/
        private String desc;
    
    
        @JsonCreator
        public static DUStatusEnum valueOf(Integer value) {
            return Arrays.stream(DUStatusEnum.values())
                    .filter(e -> Objects.equals(e.value, value)).findFirst()
                    .orElseThrow(() -> new RuntimeException("DUStatusEnum value=" + value + " not exists!"));
        }
    
    }
    View Code

    6.报表上下文ReportGenerateContext

    package com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.context;
    
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.enums.ReportEnum;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.handler.AbstractReportHandler;
    import com.sxd.swapping.downloadAndUpload.xlsxDownloadAndUpload.handler.RTReportHandler;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 报表生成上下文
     */
    @Component
    public class ReportGenerateContext implements ApplicationContextAware {
    
        private Map<ReportEnum, AbstractReportHandler> reportHandlerMap;
    
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (reportHandlerMap == null) {
                reportHandlerMap = new HashMap<>();
                reportHandlerMap.put(ReportEnum.RT_REPORT,applicationContext.getBean(RTReportHandler.class));
            }
        }
    
    
        public AbstractReportHandler getReportHandler(ReportEnum reportEnum){
            return reportHandlerMap.get(reportEnum);
        }
    }
    View Code

    请求实时下载:

    http://localhost:9666/xlsx/downloadAndUpload/rtDownload

    生成报表结果展示:

  • 相关阅读:
    luogu P2852 [USACO06DEC]Milk Patterns G
    FZOJ 4267 树上统计
    CF1303G Sum of Prefix Sums
    luogu P5311 [Ynoi2011]成都七中
    luogu P5306 [COCI2019] Transport
    SP34096 DIVCNTK
    luogu P5325 【模板】Min_25筛
    luogu P1742 最小圆覆盖
    求两直线交点坐标
    1098: 复合函数求值(函数专题)
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/14823458.html
Copyright © 2011-2022 走看看