EasyExcel 生成文件并上传OSS

4,675 阅读2分钟

这是我参与更文挑战的第19天,活动详情查看: 更文挑战

前言

EasyExcel是生成Excel的一个利器,本文想解决的问题是当生成Excel时间过长,同步下载文件老超时的问题。 既然同步总是超时,那么我们就要将生成Excel的方法改为异步的,每当用户点击对应按钮时,发送mq给处理程序,将对应的数据放入Excel中后上传到OSS中,分成两步就是生成和分片上传。

使用到的包

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.10</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.2</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.0.0</version>
        </dependency>

hutool是用来操作文件的。

使用EasyExcel生成Excel

第一步中需要注意一点,我们要将Excel保存在本地临时文件中,因为如果直接流模式向OSS那边传递的话会大量的耗费内存 参见:github.com/alibaba/eas…

        ExcelWriter excelWriter = null;
        String fileName = "test.xlsx";
        try {
            //创建文件
            FileUtil.touch(fileName);
            excelWriter = EasyExcel.write(fileName, User.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("用户名单").build();
            List<User> userList = new ArrayList<>();
            userList.add(new User(1, "wlz"));
            userList.add(new User(2, "lin"));
            userList.add(new User(3, "shi"));
            userList.add(new User(4, "ying"));
            userList.add(new User(5, "di"));
            excelWriter.write(userList, writeSheet);
        } catch (Exception e) {

        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }

分片上传OSS

上传时最好使用OSS的分片上传,帮助大文件进行快速上传。

        InputStream inputStream = null;
        OSS ossClient = null;
        try {
            File file = new File(fileName);
            String fileAddress = "test.xlsx";
            ossClient = new OSSClientBuilder().build("region", "secretId", "secretKey");
            //创建InitiateMultipartuploadRequest对象。
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest("bucketName", fileAddress);//初始化分片
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            //返回uploadId,它是分片上传事件的唯一标识,您可以根据这个ID来发起相关的操作,如取消分片上传、查询分片上传等。
            String uploadId = upresult.getUploadId();
            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
            List<PartETag> partETags = new ArrayList<>();
            //计算文件有多少个分片。
            //单个分片大小2MB
            long partSize = 2 * 1024 * 1024L;// "<localFile>”本地要上传的文件
            long fileLength = file.length();
            int partCount = (int) (fileLength / partSize);
            if (fileLength % partSize != 0) {
                partCount++;
            }
            //遍历分片上传。
            for (int i = 0; i < partCount; i++) {
                long startPos = i * partSize;
                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;

                inputStream = new FileInputStream(fileName);

                //跳过已经上传的分片。
                inputStream.skip(startPos);
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName("bucketName");
                uploadPartRequest.setKey(fileAddress);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(inputStream);

                //设置分片大小。除了最后一个分片没有大小限制,其他的分片最小为100KB。uploadPartRequest.setPartsize(curPartSize);
                // 设置分片号。每一个上传的分片都有一个分片号,取值范围是1 ~10000,如果超出这个范围,oSS将返回InvalidArgument的错误码。
                uploadPartRequest.setPartNumber(i + 1);

                //每个分片不需要按顺序上传,甚至可以在不同客户端上传,oSS会按照分片号排序组成完整的文件。
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);


                //每次上传分片之后,0SS的返回结果会包含一个PartETag。PartETag将被保存到partETags中
                partETags.add(uploadPartResult.getPartETag());
            }
            //创建CompleteMultipartUploadRequest对象。
            //在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每 个分片的有效性。当所有的数据分片验证通过后,OSS将 把这些分片组合成个完整的文 件。
            CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest("", fileAddress, uploadId, partETags);


            // 完成上传。
            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);


        } catch (Exception e) {
        }
        finally {
            try {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
                if(file!=null){
                    //使用Hutool的方法删掉文件
                    file.delete();
                }
            } catch (Exception e) {

            }
        }

总结

将大任务分成小点,各个突破,才是我们编程的不二法门。