最近遇到了一个问题:大数据量导出的时候,性能会大大下降,需要优化excel通用报表导出(是的,没有听错,是通用的导出接口)

于是小编想到了阿里开源了一个excel处理框架,使用简单,节省内存。easyexcel其实去一行行去读数据,逐个去解析,大大减少了占用内存的资源。

esayExcel接口导出下载_excel

这里附上官方文档(其实官方文档是很详细了记录了不同场景,建议先看官方文档了解下):EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com)

关键的问题来了,怎么样去写成一个通用的呢,其实这个小编也是纠结了一小会儿,下面请见详细过程:

1.导入以下依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.0</version>
</dependency>

2.实体类Student

public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    @ExcelProperty("自定义对应列的标题")
    //@ExcelProperty这个注解可以省略,可以通过head来添加列标题,但是要注意,属性的值要和列名相对应
    //如果需要值类型枚举转换,则需要写一个枚举转换类,注解中convertor指定,这里不过多赘述
    //@ExcelProperty(value = "性别(0:女,1:男)",convertor = 枚举转换.class)
    //private GenderType gender;或者是private Integer gender;
    private Integer id;

    @ExcelProperty("自定义对应列的标题")
    private String name;

    @ExcelProperty("自定义对应列的标题")
    private Integer age;

    @ExcelProperty("自定义对应列的标题")
    private String sex;
}

3.大数据导出接口(我的思路是:前端将查询的httpurl、className(全路径)、分页条件(可忽略)传递到后端接口)

分页的情况:按照分页每页去查询,循环外定义好sheet,循环的去使用httpclient查数据,给excel写入数据。注意:在循环外去finish,因为finish是一个excel的结束。(循环的条件当然是分页参数的totalPages啦)

不分页的情况:这个就比较简单了,可以直接参考下面代码,httpclient去调用前端传回的http接口获取到返回值,json进行转换后,写入即可

/**
     *
     * @param request
     * @param response
     * @param <T>
     * @return
     */
    @GetMapping("/bigData-export")
    public <T> String exportBigData(HttpServletRequest request,HttpServletResponse response) {
        try {
            //新建一个临时的file,指定名称和路径
            File excelFile;
            excelFile = new File(System.getProperty("java.io.tmpdir") + File.separator + System.currentTimeMillis() + ".xls");
            excelFile.createNewFile();
            
            //这里是用于显示我们想要的列名,不需要可以忽略
            List<List<String>> headList = new ArrayList();
            List<String> head1 = new ArrayList();
            head1.add("序列号");
            List<String> head2 = new ArrayList();
            head2.add("姓名");
            List<String> head3 = new ArrayList();
            head3.add("年龄");
            List<String> head4 = new ArrayList();
            head4.add("性别");
            headList.add(head1);
            headList.add(head2);
            headList.add(head3);
            headList.add(head4);

            //com.demo.Student权限定名,可以前端动态传递过来,这里先写成定值了
            Class entityClass = Class.forName(“com.demo.Student”);

            List<String> excluteNameList = new ArrayList<>();
            excluteNameList.add("name");
            ExcelWriter excelWriter = EasyExcel.write(excelFile)//传参是File,可以有两个参(File,class)指定了class类型
            .head(headList)//指定每列的标题
            .excludeColumnFiledNames(excluteNameList)//指定不想显示的列名称
            .build();
            WriteSheet writeSheet = EasyExcel.writerSheet(excelFile.getName()).build();

            List<Student> studentList = new ArrayList();
            //这里循环加4条数据
            for (int i = 0;i<4;i++){
                Student stu = new Student().setId(i).setName("张三" + i).setAge(i).setSex("女");
                studentList.add(stu);
            }
            //这里是模仿了后端调用http请求,返回json串,所以进行了一个转换,可以忽略下面两步,直接传studentList
            //实际是前端传递一个url查询的路径,可以拼接查询条件
            //我们通过http调用去请求,如果有分页,可以传回分页参数,后端去循环给excel拼接数据
            String s = JSON.toJSONString(studentList);
            List list = JSON.parseArray(s,entityClass);

            excelWriter.write(list,writeSheet);
            excelWriter.finish();//finish代表我的excel写入完成了
            //下面是用response将excel刷到页面上
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition",
                    "attachment;fileName=" + URLEncoder.encode(excelFile.getName(), "UTF-8"));
            response.flushBuffer();
            BufferedInputStream bis = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(excelFile));
                OutputStream os = response.getOutputStream();
                byte[] buffer = new byte[1024];
                int j = bis.read(buffer);
                while (j != -1) {
                    os.write(buffer, 0, j);
                    j = bis.read(buffer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {

                if (bis != null) {
                    try {
                        bis.close();
                        excelFile.delete();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return "导出成功";
        } catch (Exception busExcep) {
            return busExcep.toString();
        }
    }

注:本文不支持多表联查导出,如果想多表,可以将写入数据格式换成List<List<String>>,easyexcel应该是不支持复杂数据的,小编也尝试过导出类型换成:List<Map<String,Object>>,但是无果,如果有更好的方案,本文会持续更新。

到这里就结束啦,有疑问欢迎大家一起讨论学习,有错误我也会改正的!