1. 背景
最近在做项目的时候有一个需求就是将生成的zip直接上传到oss中。查了很多资料以后发现普遍都是将zip先放在本地目录,然后再上传到oss中。这样其实有一个问题就是你生成的zip要么自己每次手动清理,要么就是上传到oss以后再用代码清理掉存放在本地的zip。
那么怎么直接上传到oss呢?本篇将告诉你无需本地存储。直接将生成的zip上传到oss中。返回下载链接给前端。让前端自己下载。
2. 步骤分析
那么我们要拆分一下我们要干嘛?
- 组装zip文件中的每一个文件
- 将每个文件放进zip中
- 将zip上传到oss
3. 实现
3.1. 生成zip文件
/**
* 创建json的zip文件
*
* @param listMap 数据集
* @return oss路径
*/
public static String createJsonFile(Map<String, List<I18nDTO>> listMap) {
ByteArrayOutputStream zipos = new ByteArrayOutputStream(61858764);//设置大小为60M
ZipOutputStream zos = new ZipOutputStream(zipos);//创建压缩流,初始化一个输出流缓存区
// 创建多个ByteArrayInputStream作为示例
listMap.forEach((key, value) -> {
try {
JSONObject jsonObject = new JSONObject();
ByteArrayOutputStream os = new ByteArrayOutputStream(61858764);//设置大小为60M
for (I18nDTO i18nDTO : value) {
jsonObject.put(i18nDTO.getFieldsCode(), i18nDTO.getLanguageValue());
}
//创建一个压缩文件里的名称
ZipEntry zipEntry = new ZipEntry(key + ".json");
String s = JsonFormatTool.formatJson(jsonObject.toString());
os.write(s.getBytes());
zos.putNextEntry(zipEntry);
os.writeTo(zos);
zos.closeEntry();
os.close();
} catch (IOException e) {
}
});
try {
zos.close();//注意关闭流的顺序,在上传oss之前必须关闭流否则下载解压的时候会报“文件末端错误”的问题
zipos.close();
ByteArrayInputStream zipis = new ByteArrayInputStream(zipos.toByteArray());
zipis.close();
} catch (IOException e) {
}
ByteArrayInputStream zipis = new ByteArrayInputStream(zipos.toByteArray());
// 关闭ZipInputStream
String filePath = IdUtils.fastSimpleUUID() + ".zip";
CreateFileUtil.ossUploadByStream(filePath, zipis);
return filePath;
}
3.2. JsonFormatTool 工具
public class JsonFormatTool {
/**
* 单位缩进字符串。
*/
private static String SPACE = " ";
/**
* 返回格式化JSON字符串。
*
* @param json 未格式化的JSON字符串。
* @return 格式化的JSON字符串。
*/
public static String formatJson(String json) {
StringBuilder result = new StringBuilder();
int length = json.length();
int number = 0;
char key = 0;
// 遍历输入字符串。
for (int i = 0; i < length; i++) {
// 1、获取当前字符。
key = json.charAt(i);
// 2、如果当前字符是前方括号、前花括号做如下处理:
if ((key == '[') || (key == '{')) {
// (1)如果前面还有字符,并且字符为“:”,打印:换行和缩进字符字符串。
if ((i - 1 > 0) && (json.charAt(i - 1) == ':')) {
result.append('\n');
result.append(indent(number));
}
// (2)打印:当前字符。
result.append(key);
// (3)前方括号、前花括号,的后面必须换行。打印:换行。
result.append('\n');
// (4)每出现一次前方括号、前花括号;缩进次数增加一次。打印:新行缩进。
number++;
result.append(indent(number));
// (5)进行下一次循环。
continue;
}
// 3、如果当前字符是后方括号、后花括号做如下处理:
if ((key == ']') || (key == '}')) {
// (1)后方括号、后花括号,的前面必须换行。打印:换行。
result.append('\n');
// (2)每出现一次后方括号、后花括号;缩进次数减少一次。打印:缩进。
number--;
result.append(indent(number));
// (3)打印:当前字符。
result.append(key);
// (4)如果当前字符后面还有字符,并且字符不为“,”,打印:换行。
if (((i + 1) < length) && (json.charAt(i + 1) != ',')) {
result.append('\n');
}
// (5)继续下一次循环。
continue;
}
// 4、如果当前字符是逗号。逗号后面换行,并缩进,不改变缩进次数。
if ((key == ',')) {
result.append(key);
result.append('\n');
result.append(indent(number));
continue;
}
// 5、打印:当前字符。
result.append(key);
}
return result.toString();
}
/**
* 返回指定次数的缩进字符串。每一次缩进三个空格,即SPACE。
*
* @param number 缩进次数。
* @return 指定缩进次数的字符串。
*/
private static String indent(int number) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < number; i++) {
result.append(SPACE);
}
return result.toString();
}
}
3.3. 阿里云oss上传
public static void ossUploadByStream(String filePath, InputStream input) {
OSS ossClient = new OSSClientBuilder().build(AliYunConstant.endpoint, AliYunConstant.accessKeyId, AliYunConstant.accessKeySecret);
PutObjectRequest putObjectRequest = new PutObjectRequest(AliYunConstant.bucketName, filePath, input);
ossClient.putObject(putObjectRequest);
ossClient.shutdown();
}
阿里云sdk依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.8.0</version>
</dependency>