若依框架Excel导出源码解析

入口

 	/**
     * 导出接收人列表
     */
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(Wxpusher wxpusher) {
        List<Wxpusher> list = wxpusherService.selectWxpusherList(wxpusher);
        // 工具的泛型接口,创建专用工具实例
        ExcelUtil<Wxpusher> util = new ExcelUtil<Wxpusher>(Wxpusher.class);
        // 传入需要打印的 数据集合 和 工作表名称
        return util.exportExcel(list, "接收人数据");
    }

Excel工具

泛型构造器

public class ExcelUtil<T>{
 	/**
     * 实体对象
     */
    public Class<T> clazz;

    public ExcelUtil(Class<T> clazz)
    {
        this.clazz = clazz;
    }
}

导出方法

	/**
     * 对list数据源将其里面的数据导入到excel表单
     *
     * @param list 导出数据集合
     * @param sheetName 工作表的名称
     * @return 结果
     */
    public AjaxResult exportExcel(List<T> list, String sheetName)
    {
        return exportExcel(list, sheetName, StringUtils.EMPTY); // 导出 Excel 文件
    }
    
     /**
     * 对list数据源将其里面的数据导入到excel表单
     *
     * @param list 导出数据集合
     * @param sheetName 工作表的名称
     * @param title 标题
     * @return 结果
     */
    public AjaxResult exportExcel(List<T> list, String sheetName, String title)
    {
        this.init(list, sheetName, title, Type.EXPORT);
        return exportExcel();
    }

初始化


	private List<T> list;     // 数据集合
	private String sheetName; // 工作表名
	private Type type;        // 导出类型
	private String title;     // 标题
	
 	public void init(List<T> list, String sheetName, String title, Type type)
    {
        if (list == null)
        {
            list = new ArrayList<T>(); // 防空
        }
        this.list = list;
        this.sheetName = sheetName;
        this.type = type;
        this.title = title;
        createExcelField(); // 创建字段
        createWorkbook();   // 创建工作本
        createTitle();      // 创建标题
    }

反射获取字段

	private List<Object[]> fields; // 注解列表
	private short maxHeight;       // 最大高度
	

	/**
     * 得到所有定义字段
     */
    private void createExcelField()
    {
        this.fields = getFields(); // 获取字段
        // 根据注解中的sort字段大小进行排序
        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
        this.maxHeight = getRowHeight(); // 根据注解获取最大行高
    }

    /**
     * 获取字段注解信息
     */
    public List<Object[]> getFields()
    {
        List<Object[]> fields = new ArrayList<Object[]>();
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); // 反射获取超类的字段
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));                 // 反射获取当前类的字段
        for (Field field : tempFields)
        {
            // 单注解
            if (field.isAnnotationPresent(Excel.class)) // 有 @Excel 注解的
            {
                Excel attr = field.getAnnotation(Excel.class);
                // 匹配注解中的字段(类型)
                if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
                {
                    field.setAccessible(true);
                    fields.add(new Object[] { field, attr });
                }
            }

            // 多注解
            if (field.isAnnotationPresent(Excels.class))
            {
                Excels attrs = field.getAnnotation(Excels.class);
                Excel[] excels = attrs.value();
                for (Excel attr : excels)
                {
                    if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
                    {
                        field.setAccessible(true);
                        fields.add(new Object[] { field, attr });
                    }
                }
            }
        }
        return fields;
    }
    
     /**
     * 根据注解获取最大行高
     */
    public short getRowHeight()
    {
        double maxHeight = 0;
        for (Object[] os : this.fields)
        {
            Excel excel = (Excel) os[1];
            // 取注解中的最大行高作为行高
            maxHeight = Math.max(maxHeight, excel.height());
        }
        return (short) (maxHeight * 20);
    }

创建工作本

  	/**
     * 创建一个工作簿
     */
    public void createWorkbook()
    {
        this.wb = new SXSSFWorkbook(500); // 创建缓存为500行的工作本
        this.sheet = wb.createSheet();         // 为工作本创建工作表
        wb.setSheetName(0, sheetName);  // 设置表名
        this.styles = createStyles(wb);        // 创建样式
    }

创建行

    /**
     * 创建写入数据到Sheet
     */
    public void writeSheet()
    {
        // 取出一共有多少个sheet.
        int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
        for (int index = 0; index < sheetNo; index++)
        {
            createSheet(sheetNo, index);

            // 产生一行
            Row row = sheet.createRow(rownum);
            int column = 0;
            // 写入各个字段的列头名称
            for (Object[] os : fields)
            {
                Excel excel = (Excel) os[1];
                this.createCell(excel, row, column++); // 创建单元格
            }
            if (Type.EXPORT.equals(type))
            {
                fillExcelData(index, row);
                addStatisticsRow();
            }
        }
    }

后续很繁杂就不看了,不难,有兴趣去研究一下

响应回前端

生成的Excel文件已经导出到项目指定的文件目录下,返回前端的是文件名

    /**
     * 对list数据源将其里面的数据导入到excel表单
     *
     * @return 结果
     */
    public AjaxResult exportExcel()
    {
        OutputStream out = null;
        try
        {
            writeSheet();                                          // 写入数据到工作表
            String filename = encodingFilename(sheetName);         // 拼接生成文件名
            out = new FileOutputStream(getAbsoluteFile(filename)); // 创建文件输出流
            wb.write(out);                                         // 把文件导出到指定的绝对路径下
            return AjaxResult.success(filename);                   // 返回文件名
        }
        catch (Exception e)
        {
            log.error("导出Excel异常{}", e.getMessage());
            throw new UtilException("导出Excel失败,请联系网站管理员!");
        }
        finally
        {
            IOUtils.closeQuietly(wb);
            IOUtils.closeQuietly(out);
        }
    }

前端拿到文件名,再去跳转到下载接口

// 导出数据
exportExcel: function (formId) {
    table.set();
    $.modal.confirm("确定导出所有" + table.options.modalName + "吗?", function () {
        var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;
        var params = $("#" + table.options.id).bootstrapTable('getOptions');
        var dataParam = $("#" + currentId).serializeArray();
        dataParam.push({"name": "orderByColumn", "value": params.sortName});
        dataParam.push({"name": "isAsc", "value": params.sortOrder});
        $.modal.loading("正在导出数据,请稍候...");
        $.post(table.options.exportUrl, dataParam, function (result) {
            if (result.code == web_status.SUCCESS) {
            	// 跳转到下载链接
                window.location.href = ctx + "common/download?fileName=" + encodeURI(result.msg) + "&delete=" + true;
            } else if (result.code == web_status.WARNING) {
                $.modal.alertWarning(result.msg)
            } else {
                $.modal.alertError(result.msg);
            }
            $.modal.closeLoading();
        });
    });
},

下载接口

    /**
     * 通用下载请求
     *
     * @param fileName 文件名称
     * @param delete 是否删除
     */
    @GetMapping("/download")
    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
    {
        try
        {
            if (!FileUtils.checkAllowDownload(fileName)) // 检查是否允许下载
            {
                throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
            }
            // 生成下载文件名
            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
            String filePath = RuoYiConfig.getDownloadPath() + fileName; // 文件的绝对路径

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 设置响应类型
            FileUtils.setAttachmentResponseHeader(response, realFileName);     // 下载文件名重新编码
            FileUtils.writeBytes(filePath, response.getOutputStream());        // 用 response 对象的输出流写出字节流
            if (delete) // 完事儿删除文件
            {
                FileUtils.deleteFile(filePath);
            }
        }
        catch (Exception e)
        {
            log.error("下载文件失败", e);
        }
    }

具体写出方法

    /**
     * echoo mark 输出指定文件的byte数组
     *
     * @param filePath 文件路径
     * @param os 输出流
     * @return
     */
    public static void writeBytes(String filePath, OutputStream os) throws IOException
    {
        FileInputStream fis = null;
        try
        {
            File file = new File(filePath);
            if (!file.exists())
            {
                throw new FileNotFoundException(filePath);
            }
            fis = new FileInputStream(file); // 读取文件
            byte[] b = new byte[1024];       // 缓存字节数组
            int length;                      // 临时变量:读取长度
            while ((length = fis.read(b)) > 0) // 没读取完
            {
                os.write(b, 0, length);   // 写出
            }
        }
        catch (IOException e)
        {
            throw e;
        }
        finally
        {
            IOUtils.close(os);
            IOUtils.close(fis);
        }
    }
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值