[alibaba/easyexcel]请提供数据套用模板后上传OSS的最佳方案

2024-05-24 472 views
7

建议描述 现有需求,数据导出到Excel,并且上传到OSS,进行存储以待用户选择合适时间进行下载

   那么遇到的问题就是,没有找到合适的方法,调用API上传到OSS

   所以请提供一个这样的最佳方案的代码

回答

2

有两种方案:

  • 挂载oss到本地(linux)这样和本地写文件一样
  • 输出文件到本地路径(或者内存ByteArrayOutputStream),然后打开文件流到oss
4

请问如何将导出的文件导出至指定位置,或者说直接将ExcelWriter这个输出流对接到oss(直接导入oss文件服务器)

9

请问如何将导出的文件导出至指定位置,或者说直接将ExcelWriter这个输出流对接到oss(直接导入oss文件服务器)

第一种:把oss挂载到服务器,比如挂载到 /yourOssMountPath目录下,那么,输出的代码就是:

//这里只是提示是一个文件路径
File outputFile = new File("/yourOssMountPath/yourDir/yourExcelFileName.xlsx");
EasyExcel.write(outputFile, DemoData.class).sheet("模板").doWrite(data());

第二种的话,流转换一下就好了

//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourExcelFileName>", new ByteArrayInputStream(bos.toByteArray()));
6

谢谢大佬,但是第二种方法 会报异常 SaveContextServletOutputStream转换为java.io.ByteArrayOutputStream 而且用的导出是阿里云ExcelWriter这个类

3

谢谢大佬,但是第二种方法 会报异常 SaveContextServletOutputStream转换为java.io.ByteArrayOutputStream 而且用的导出是阿里云ExcelWriter这个类

我测试了输出到ByteArrayOutputStream没有问题2.1.3,没有看到报错 ExcelWriter这个类不能直接新建,要通过EasyExcel这个工厂类来创建

1

大佬,可是 response 里面拿到的是ServletOutputStream,转换ByteArrayOutputStream, 会报错的。。。

1

大佬,可是 response 里面拿到的是ServletOutputStream,转换ByteArrayOutputStream, 会报错的。。。

不兼容类型强转当然会报错…… 如果你只是web应用不需要输出到oss或者response是oss SDK的响应的话 EasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(data());

2

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

6

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

这里是阿里云官方oss的demo简单上传oss的简单完整demo

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "<yourObjectName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourDir>/<yourExcelFileName>.xlsx", new ByteArrayInputStream(bos.toByteArray()));

// 关闭OSSClient。
ossClient.shutdown();

这个文件就被放到http://<yourBucketName>.oss-cn-hangzhou.aliyuncs.com/<yourDir>/<yourExcelFileName>.xlsx 把这个路径发送给前端,前端访问这个路径就可以获取生成的excel文件, 或者利用OSS SDK/HTTP读取这个文件输出到response.getOutputStream(),就可以做文件下载了

3

问题已解决,感谢大佬!

5

大佬,EasyExcel的背景颜色设置可以支持RBG吗???

2

RGB #FF0000

1

RGB #FF0000

优先使用百度搜索解决方案比较好 目前easyExcel使用的时POI写入,POI设置背景颜色的方法是

style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());

IndexedColors的枚举数量是有限的

excel颜色 如果想支持自定义RGB的话,请查看这篇文章

            //自定义RGB
            HSSFPalette customPalette = workbook.getCustomPalette();
            //这里的setColorAtIndex方法需要的参数是(short index, byte red, byte green, byte blue)
            //这里的short我们直接用Java给我们提供的,我看有些人用的是自定义的short那个会有问题的
            customPalette.setColorAtIndex(IndexedColors.LIGHT_YELLOW.getIndex(), (byte) 255,
                    (byte) 230, (byte) 153);

但是这样会覆盖掉原先的颜色,自行取舍

7

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

这里是阿里云官方oss的demo简单上传oss的简单完整demo

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "<yourObjectName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourDir>/<yourExcelFileName>.xlsx", new ByteArrayInputStream(bos.toByteArray()));

// 关闭OSSClient。
ossClient.shutdown();

这个文件就被放到http://<yourBucketName>.oss-cn-hangzhou.aliyuncs.com/<yourDir>/<yourExcelFileName>.xlsx 把这个路径发送给前端,前端访问这个路径就可以获取生成的excel文件, 或者利用OSS SDK/HTTP读取这个文件输出到response.getOutputStream(),就可以做文件下载了

怎么定义这个文件的大小,多大才算大,50M 以内?

2

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

这里是阿里云官方oss的demo简单上传oss的简单完整demo

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "<yourObjectName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourDir>/<yourExcelFileName>.xlsx", new ByteArrayInputStream(bos.toByteArray()));

// 关闭OSSClient。
ossClient.shutdown();

这个文件就被放到http://<yourBucketName>.oss-cn-hangzhou.aliyuncs.com/<yourDir>/<yourExcelFileName>.xlsx 把这个路径发送给前端,前端访问这个路径就可以获取生成的excel文件, 或者利用OSS SDK/HTTP读取这个文件输出到response.getOutputStream(),就可以做文件下载了

怎么定义这个文件的大小,多大才算大,50M 以内?

根据你业务来评估的,如果你导出的数据是固定行数,或者不会超出一定限度的话,直接输出就可以,如果是根据业务量增长的话,最好是异步处理。

2

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

这里是阿里云官方oss的demo简单上传oss的简单完整demo

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "<yourObjectName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourDir>/<yourExcelFileName>.xlsx", new ByteArrayInputStream(bos.toByteArray()));

// 关闭OSSClient。
ossClient.shutdown();

这个文件就被放到http://<yourBucketName>.oss-cn-hangzhou.aliyuncs.com/<yourDir>/<yourExcelFileName>.xlsx 把这个路径发送给前端,前端访问这个路径就可以获取生成的excel文件, 或者利用OSS SDK/HTTP读取这个文件输出到response.getOutputStream(),就可以做文件下载了

怎么定义这个文件的大小,多大才算大,50M 以内?

根据你业务来评估的,如果你导出的数据是固定行数,或者不会超出一定限度的话,直接输出就可以,如果是根据业务量增长的话,最好是异步处理。

目前导出 30W+,同步输出大概 4 分钟左右,文件大小 40M左右。所以现在考虑异步上传到 OSS,想采取输出流的方案,但是看到你的 demo 代码有一句注释,"//这里只是输出到内存中,大文件不要这么做",只是好奇衡量大文件的标准是啥?看jvm 设置的内存大小占比吗?

5

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

这里是阿里云官方oss的demo简单上传oss的简单完整demo

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "<yourObjectName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourDir>/<yourExcelFileName>.xlsx", new ByteArrayInputStream(bos.toByteArray()));

// 关闭OSSClient。
ossClient.shutdown();

这个文件就被放到http://<yourBucketName>.oss-cn-hangzhou.aliyuncs.com/<yourDir>/<yourExcelFileName>.xlsx 把这个路径发送给前端,前端访问这个路径就可以获取生成的excel文件, 或者利用OSS SDK/HTTP读取这个文件输出到response.getOutputStream(),就可以做文件下载了

怎么定义这个文件的大小,多大才算大,50M 以内?

根据你业务来评估的,如果你导出的数据是固定行数,或者不会超出一定限度的话,直接输出就可以,如果是根据业务量增长的话,最好是异步处理。

目前导出 30W+,同步输出大概 4 分钟左右,文件大小 40M左右。所以现在考虑异步上传到 OSS,想采取输出流的方案,但是看到你的 demo 代码有一句注释,"//这里只是输出到内存中,大文件不要这么做",只是好奇衡量大文件的标准是啥?看jvm 设置的内存大小占比吗?

bos输出的流会存储在内存里,内存紧张的时候这种操作可能会引起频繁GC的……,4分钟的确应该异步处理的

9

这个需求是,用户点导出的时候,给这个导出的文件(未生成),给放到Oss里面去, 大佬可以教下我怎么做吗? (原来有个想法是,先生成到linux某个文件夹,然后在读取这个文件,存入oss后再删掉,但是发现好像导出没法指定路径)

这里是阿里云官方oss的demo简单上传oss的简单完整demo

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
// <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "<yourObjectName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourDir>/<yourExcelFileName>.xlsx", new ByteArrayInputStream(bos.toByteArray()));

// 关闭OSSClient。
ossClient.shutdown();

这个文件就被放到http://<yourBucketName>.oss-cn-hangzhou.aliyuncs.com/<yourDir>/<yourExcelFileName>.xlsx 把这个路径发送给前端,前端访问这个路径就可以获取生成的excel文件, 或者利用OSS SDK/HTTP读取这个文件输出到response.getOutputStream(),就可以做文件下载了

怎么定义这个文件的大小,多大才算大,50M 以内?

根据你业务来评估的,如果你导出的数据是固定行数,或者不会超出一定限度的话,直接输出就可以,如果是根据业务量增长的话,最好是异步处理。

目前导出 30W+,同步输出大概 4 分钟左右,文件大小 40M左右。所以现在考虑异步上传到 OSS,想采取输出流的方案,但是看到你的 demo 代码有一句注释,"//这里只是输出到内存中,大文件不要这么做",只是好奇衡量大文件的标准是啥?看jvm 设置的内存大小占比吗?

bos输出的流会存储在内存里,内存紧张的时候这种操作可能会引起频繁GC的……,4分钟的确应该异步处理的 那这样的话先临时写到服务器本地,再上传文件流,这样应该可以避免GC 吧?而且上传成功后如何通知前端获取这个文件 url?有什么比较好的方式,提供一个接口让前端轮询?

6

那这样的话先临时写到服务器本地,再上传文件流,这样应该可以避免GC 吧?而且上传成功后如何通知前端获取这个文件 url?有什么比较好的方式,提供一个接口让前端轮询?

把bos换成FileOutputStream就可以了,文件找个临时路径,生成结束之后删除这个文件,至于url请参考上面的阿里云是oss实现,url写到异步任务的列表里即可

6

那这样的话先临时写到服务器本地,再上传文件流,这样应该可以避免GC 吧?而且上传成功后如何通知前端获取这个文件 url?有什么比较好的方式,提供一个接口让前端轮询?

把bos换成FileOutputStream就可以了,文件找个临时路径,生成结束之后删除这个文件,至于url请参考上面的阿里云是oss实现,url写到异步任务的列表里即可

你好,我也碰到这个问题了,除了写临时文件的方案,还有更好解决办法吗? 写磁盘的话又多了两次IO操作,处理时间和系统资源占用上都不是很好的办法。

7

那这样的话先临时写到服务器本地,再上传文件流,这样应该可以避免GC 吧?而且上传成功后如何通知前端获取这个文件 url?有什么比较好的方式,提供一个接口让前端轮询?

把bos换成FileOutputStream就可以了,文件找个临时路径,生成结束之后删除这个文件,至于url请参考上面的阿里云是oss实现,url写到异步任务的列表里即可

你好,我也碰到这个问题了,除了写临时文件的方案,还有更好解决办法吗? 写磁盘的话又多了两次IO操作,处理时间和系统资源占用上都不是很好的办法。

还有一种方案就是@pdkst 说的:挂载oss到本地(linux)这样和本地写文件一样,就避免了两次 IO 操作

0

请问如何将导出的文件导出至指定位置,或者说直接将ExcelWriter这个输出流对接到oss(直接导入oss文件服务器)

第一种:把oss挂载到服务器,比如挂载到 /yourOssMountPath目录下,那么,输出的代码就是:

//这里只是提示是一个文件路径
File outputFile = new File("/yourOssMountPath/yourDir/yourExcelFileName.xlsx");
EasyExcel.write(outputFile, DemoData.class).sheet("模板").doWrite(data());

第二种的话,流转换一下就好了

//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourExcelFileName>", new ByteArrayInputStream(bos.toByteArray()));

请问大佬我使用第二种输出流的方式创建excel,但是用下面这种写法,生成的文件打不开,我debug显示输出流没有写入值,不知道有没有遇到这种情况?

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ExcelWriter  excelWriter = EasyExcel.write(baos,Demo.class).build();
WriteSheet allSheet = EasyExcel.writerSheet(0, "总体概览").build();
excelWriter.write(data(), allSheet);
4

请问如何将导出的文件导出至指定位置,或者说直接将ExcelWriter这个输出流对接到oss(直接导入oss文件服务器)

第一种:把oss挂载到服务器,比如挂载到 /yourOssMountPath目录下,那么,输出的代码就是:

//这里只是提示是一个文件路径
File outputFile = new File("/yourOssMountPath/yourDir/yourExcelFileName.xlsx");
EasyExcel.write(outputFile, DemoData.class).sheet("模板").doWrite(data());

第二种的话,流转换一下就好了

//这里只是输出到内存中,大文件不要这么做
ByteArrayOutputStream bos = new ByteArrayOutputStream();
EasyExcel.write(bos, DemoData.class).sheet("模板").doWrite(data());
//ossClient请参照oss的SDK,这里以aliyunOss为例
ossClient.putObject("<yourBucketName>", "<yourExcelFileName>", new ByteArrayInputStream(bos.toByteArray()));

请问大佬我使用第二种输出流的方式创建excel,但是用下面这种写法,生成的文件打不开,我debug显示输出流没有写入值,不知道有没有遇到这种情况?

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ExcelWriter  excelWriter = EasyExcel.write(baos,Demo.class).build();
WriteSheet allSheet = EasyExcel.writerSheet(0, "总体概览").build();
excelWriter.write(data(), allSheet);

一般打不开都是数据为null,试试转换nullemptyList