1. 項(xiàng)目背景
唉!本文寫起來都是淚點(diǎn)。不是刻意寫的本文,主要是對(duì)日常用到的文件上傳做了一個(gè)匯總總結(jié),同時(shí)希望可以給用到的小伙伴帶來一點(diǎn)幫助吧。
-
上傳本地,這個(gè)就不水了,基本做技術(shù)的都用到過吧;
-
阿里云OSS,阿里云是業(yè)界巨鱷了吧,用到的人肯定不少吧,不過博主好久不用了,簡(jiǎn)單記錄下;
-
華為云OBS,工作需要,也簡(jiǎn)單記錄下吧;
-
七牛云,個(gè)人網(wǎng)站最開始使用的圖床,目的是為了白嫖10G文件存儲(chǔ)。后來網(wǎng)站了升級(jí)了https域名,七牛云免費(fèi)只支持http,https域名加速是收費(fèi)的。https域名的網(wǎng)站在谷歌上請(qǐng)求圖片時(shí)會(huì)強(qiáng)制升級(jí)為https。
-
又拍云,個(gè)人網(wǎng)站目前在用的圖床,加入了又拍云聯(lián)盟,網(wǎng)站底部掛鏈接,算是推廣合作模式吧(對(duì)我這種不介意的來說就是白嫖)。速度還行,可以去我的網(wǎng)站看一下:笑小楓
還有騰訊云等等云,暫沒用過,就先不整理了,使用都很簡(jiǎn)單,SDK文檔很全,也很簡(jiǎn)單。
2. 上傳思路
分為兩點(diǎn)來說。本文的精華也都在這里了,統(tǒng)一思想。
2.1 前端調(diào)用上傳文件
前端上傳的話,應(yīng)該是我們常用的吧,通過@RequestParam(value = "file") MultipartFile file
接收,然后轉(zhuǎn)為InputStream
or byte[]
or File
,然后調(diào)用上傳就可以了,核心也就在這,很簡(jiǎn)單的,尤其上傳到云服務(wù)器,裝載好配置后,直接調(diào)用SDK接口即可。
2.2 通過url地址上傳網(wǎng)絡(luò)文件
通過url上傳應(yīng)該很少用到吧,使用場(chǎng)景呢,例如爬取文章的時(shí)候,把網(wǎng)絡(luò)圖片上傳到自己的圖床;圖片庫根據(jù)url地址遷移。
說到這,突然想起了一個(gè)問題,大家寫文章的時(shí)候,圖片上傳到圖床后在文章內(nèi)是怎么保存的呢?是全路徑還是怎么保存的?如果加速域名換了,或者換圖床地址了,需要怎么遷移。希望有經(jīng)驗(yàn)的大佬可以留言指導(dǎo)!
3. 上傳到本地
這個(gè)比較簡(jiǎn)單啦,貼下核心代碼吧
- 在yml配置下上傳路徑
file:
local:
maxFileSize: 10485760
imageFilePath: D:/test/image/
docFilePath: D:/test/file/
- 創(chuàng)建配置類,讀取配置文件的參數(shù)
package com.maple.upload.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 上傳本地配置
*
* @author 笑小楓
* @date 2022/7/22
* @see <a >https://www.xiaoxiaofeng.com</a>
*/
@Data
@Configuration
public class LocalFileProperties {
// ---------------本地文件配置 start------------------
/**
* 圖片存儲(chǔ)路徑
*/
@Value("${file.local.imageFilePath}")
private String imageFilePath;
/**
* 文檔存儲(chǔ)路徑
*/
@Value("${file.local.docFilePath}")
private String docFilePath;
/**
* 文件限制大小
*/
@Value("${file.local.maxFileSize}")
private long maxFileSize;
// --------------本地文件配置 end-------------------
}
- 創(chuàng)建上傳下載工具類
package com.maple.upload.util;
import com.maple.upload.properties.LocalFileProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author 笑小楓
* @date 2024/1/10
* @see <a >https://www.xiaoxiaofeng.com</a>
*/
@Slf4j
@Component
@AllArgsConstructor
public class LocalFileUtil {
private final LocalFileProperties fileProperties;
private static final List<String> FILE_TYPE_LIST_IMAGE = Arrays.asList(
"image/png",
"image/jpg",
"image/jpeg",
"image/bmp");
/**
* 上傳圖片
*/
public String uploadImage(MultipartFile file) {
// 檢查圖片類型
String contentType = file.getContentType();
if (!FILE_TYPE_LIST_IMAGE.contains(contentType)) {
throw new RuntimeException("上傳失敗,不允許的文件類型");
}
int size = (int) file.getSize();
if (size > fileProperties.getMaxFileSize()) {
throw new RuntimeException("文件過大");
}
String fileName = file.getOriginalFilename();
//獲取文件后綴
String afterName = StringUtils.substringAfterLast(fileName, ".");
//獲取文件前綴
String prefName = StringUtils.substringBeforeLast(fileName, ".");
//獲取一個(gè)時(shí)間毫秒值作為文件名
fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "_" + prefName + "." + afterName;
File filePath = new File(fileProperties.getImageFilePath(), fileName);
//判斷文件是否已經(jīng)存在
if (filePath.exists()) {
throw new RuntimeException("文件已經(jīng)存在");
}
//判斷文件父目錄是否存在
if (!filePath.getParentFile().exists()) {
filePath.getParentFile().mkdirs();
}
try {
file.transferTo(filePath);
} catch (IOException e) {
log.error("圖片上傳失敗", e);
throw new RuntimeException("圖片上傳失敗");
}
return fileName;
}
/**
* 批量上傳文件
*/
public List<Map<String, Object>> uploadFiles(MultipartFile[] files) {
int size = 0;
for (MultipartFile file : files) {
size = (int) file.getSize() + size;
}
if (size > fileProperties.getMaxFileSize()) {
throw new RuntimeException("文件過大");
}
List<Map<String, Object>> fileInfoList = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
Map<String, Object> map = new HashMap<>();
String fileName = files[i].getOriginalFilename();
//獲取文件后綴
String afterName = StringUtils.substringAfterLast(fileName, ".");
//獲取文件前綴
String prefName = StringUtils.substringBeforeLast(fileName, ".");
String fileServiceName = new SimpleDateFormat("yyyyMMddHHmmss")
.format(new Date()) + i + "_" + prefName + "." + afterName;
File filePath = new File(fileProperties.getDocFilePath(), fileServiceName);
// 判斷文件父目錄是否存在
if (!filePath.getParentFile().exists()) {
filePath.getParentFile().mkdirs();
}
try {
files[i].transferTo(filePath);
} catch (IOException e) {
log.error("文件上傳失敗", e);
throw new RuntimeException("文件上傳失敗");
}
map.put("fileName", fileName);
map.put("filePath", filePath);
map.put("fileServiceName", fileServiceName);
fileInfoList.add(map);
}
return fileInfoList;
}
/**
* 批量刪除文件
*
* @param fileNameArr 服務(wù)端保存的文件的名數(shù)組
*/
public void deleteFile(String[] fileNameArr) {
for (String fileName : fileNameArr) {
String filePath = fileProperties.getDocFilePath() + fileName;
File file = new File(filePath);
if (file.exists()) {
try {
Files.delete(file.toPath());
} catch (IOException e) {
e.printStackTrace();
log.warn("文件刪除失敗", e);
}
} else {
log.warn("文件: {} 刪除失敗,該文件不存在", fileName);
}
}
}
/**
* 下載文件
*/
public void downLoadFile(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
String encodeFileName = URLDecoder.decode(fileName, "UTF-8");
File file = new File(fileProperties.getDocFilePath() + encodeFileName);
// 下載文件
if (!file.exists()) {
throw new RuntimeException("文件不存在!");
}
try (FileInputStream inputStream = new FileInputStream(file);
ServletOutputStream outputStream = response.getOutputStream()) {
response.reset();
//設(shè)置響應(yīng)類型 PDF文件為"application/pdf",WORD文件為:"application/msword", EXCEL文件為:"application/vnd.ms-excel"。
response.setContentType("application/octet-stream;charset=utf-8");
//設(shè)置響應(yīng)的文件名稱,并轉(zhuǎn)換成中文編碼
String afterName = StringUtils.substringAfterLast(fileName, "_");
//保存的文件名,必須和頁面編碼一致,否則亂碼
afterName = response.encodeURL(new String(afterName.getBytes(), StandardCharsets.ISO_8859_1.displayName()));
response.setHeader("Content-type", "application-download");
//attachment作為附件下載;inline客戶端機(jī)器有安裝匹配程序,則直接打開;注意改變配置,清除緩存,否則可能不能看到效果
response.addHeader("Content-Disposition", "attachment;filename=" + afterName);
response.addHeader("filename", afterName);
//將文件讀入響應(yīng)流
int length = 1024;
byte[] buf = new byte[1024];
int readLength = inputStream.read(buf, 0, length);
while (readLength != -1) {
outputStream.write(buf, 0, readLength);
readLength = inputStream.read(buf, 0, length);
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
訪問圖片的話,可以通過重寫WebMvcConfigurer
的addResourceHandlers
方法來實(shí)現(xiàn)。
通過請(qǐng)求/local/images/**
將鏈接虛擬映射到我們配置的localFileProperties.getImageFilePath()
下,文件訪問同理。
詳細(xì)代碼如下
package com.maple.upload.config;
import com.maple.upload.properties.LocalFileProperties;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2024/1/10
*/
@Configuration
@AllArgsConstructor
public class LocalFileConfig implements WebMvcConfigurer {
private final LocalFileProperties localFileProperties;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 重寫方法
// 修改tomcat 虛擬映射
// 定義圖片存放路徑
registry.addResourceHandler("/local/images/**").
addResourceLocations("file:" + localFileProperties.getImageFilePath());
//定義文檔存放路徑
registry.addResourceHandler("/local/doc/**").
addResourceLocations("file:" + localFileProperties.getDocFilePath());
}
}
- controller調(diào)用代碼
package com.maple.upload.controller;
import com.maple.upload.util.LocalFileUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
* 文件相關(guān)操作接口
*
* @author 笑小楓
* @date 2024/1/10
* @see <a >https://www.xiaoxiaofeng.com</a>
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/local")
public class LocalFileController {
private final LocalFileUtil fileUtil;
/**
* 圖片上傳
*/
@PostMapping("/uploadImage")
public String uploadImage(@RequestParam(value = "file") MultipartFile file) {
if (file.isEmpty()) {
throw new RuntimeException("圖片內(nèi)容為空,上傳失敗!");
}
return fileUtil.uploadImage(file);
}
/**
* 文件批量上傳
*/
@PostMapping("/uploadFiles")
public List<Map<String, Object>> uploadFiles(@RequestParam(value = "file") MultipartFile[] files) {
return fileUtil.uploadFiles(files);
}
/**
* 批量刪除文件
*/
@PostMapping("/deleteFiles")
public void deleteFiles(@RequestParam(value = "files") String[] files) {
fileUtil.deleteFile(files);
}
/**
* 文件下載功能
*/
@GetMapping(value = "/download/{fileName:.*}")
public void download(@PathVariable("fileName") String fileName, HttpServletResponse response) {
try {
fileUtil.downLoadFile(response, fileName);
} catch (Exception e) {
log.error("文件下載失敗", e);
}
}
}
調(diào)用上傳圖片的接口,可以看到圖片已經(jīng)上傳成功。
通過請(qǐng)求/local/images/**
將鏈接虛擬映射我們圖片上。
批量上傳,刪除等操作就不一一演示截圖了,代碼已貼,因?yàn)槭窍葘懙膁emo,后寫的文章,獲取代碼片貼的有遺漏,如有遺漏,可以去文章底部查看源碼地址。
4. 上傳阿里云OSS
阿里云OSS官方sdk使用文檔:https://help.aliyun.com/zh/oss/developer-reference/java
阿里云OSS操作指南:https://help.aliyun.com/zh/oss/user-guide
公共云下OSS Region和Endpoint對(duì)照表:https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints
更多公共云下OSS Region和Endpoint對(duì)照,參考上面鏈接
- 引入oss sdk依賴
<!-- 阿里云OSS -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.8.1</version>
</dependency>
- 配置上傳配置信息
file:
oss:
bucketName: mapleBucket
accessKeyId: your ak
secretAccessKey: your sk
endpoint: oss-cn-shanghai.aliyuncs.com
showUrl: cdn地址-file.xiaoxiaofeng.com
- 創(chuàng)建配置類,讀取配置文件的參數(shù)
/*
* Copyright (c) 2018-2999 上海合齊軟件科技科技有限公司 All rights reserved.
*
*
*
* 未經(jīng)允許,不可做商業(yè)用途!
*
* 版權(quán)所有,侵權(quán)必究!
*/
package com.maple.upload.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 阿里云OSS配置
*
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2024/1/10
*/
@Data
@Configuration
public class AliOssProperties {
@Value("${file.oss.bucketName}")
private String bucketName;
@Value("${file.oss.accessKeyId}")
private String accessKeyId;
@Value("${file.oss.secretAccessKey}")
private String secretAccessKey;
@Value("${file.oss.endpoint}")
private String endpoint;
@Value("${file.oss.showUrl}")
private String showUrl;
}
- 上傳工具類
package com.maple.upload.util;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectResult;
import com.maple.upload.properties.AliOssProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
/**
* 阿里云OSS 對(duì)象存儲(chǔ)工具類
* 阿里云OSS官方sdk使用文檔:https://help.aliyun.com/zh/oss/developer-reference/java
* 阿里云OSS操作指南:https://help.aliyun.com/zh/oss/user-guide
*
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2024/1/15
*/
@Slf4j
@Component
@AllArgsConstructor
public class AliOssUtil {
private final AliOssProperties aliOssProperties;
public String uploadFile(MultipartFile file) {
String fileName = file.getOriginalFilename();
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("獲取文件信息失敗");
}
// 組建上傳的文件名稱,命名規(guī)則可自定義更改
String objectKey = FileCommonUtil.setFilePath("xiaoxiaofeng") + FileCommonUtil.setFileName("xxf", fileName.substring(fileName.lastIndexOf(".")));
//構(gòu)造一個(gè)OSS對(duì)象的配置類
OSS ossClient = new OSSClientBuilder().build(aliOssProperties.getEndpoint(), aliOssProperties.getAccessKeyId(), aliOssProperties.getSecretAccessKey());
try (InputStream inputStream = file.getInputStream()) {
log.info(String.format("阿里云OSS上傳開始,原文件名:%s,上傳后的文件名:%s", fileName, objectKey));
PutObjectResult result = ossClient.putObject(aliOssProperties.getBucketName(), objectKey, inputStream);
log.info(String.format("阿里云OSS上傳結(jié)束,文件名:%s,返回結(jié)果:%s", objectKey, result.toString()));
return aliOssProperties.getShowUrl() + objectKey;
} catch (Exception e) {
log.error("調(diào)用阿里云OSS失敗", e);
throw new RuntimeException("調(diào)用阿里云OSS失敗");
}
}
}
因?yàn)槠鶈栴},controller就不貼了。暫時(shí)沒有阿里云oss的資源了,這里就不做測(cè)試,小伙伴在使用過程中如有問題,麻煩留言告訴我下!
5. 上傳華為云OBS
華為云OBS官方sdk使用文檔:https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0101.html
華為云OBS操作指南:https://support.huaweicloud.com/ugobs-obs/obs_41_0002.html
華為云各服務(wù)應(yīng)用區(qū)域和各服務(wù)的終端節(jié)點(diǎn):https://developer.huaweicloud.com/endpoint?OBS
- 引入sdk依賴
<!-- 華為云OBS -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
<version>3.21.8</version>
</dependency>
- 配置上傳配置信息
file:
obs:
bucketName: mapleBucket
accessKey: your ak
secretKey: your sk
endPoint: obs.cn-east-2.myhuaweicloud.com
showUrl: cdn地址-file.xiaoxiaofeng.com
- 創(chuàng)建配置類,讀取配置文件的參數(shù)
package com.maple.upload.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 華為云上傳配置
*
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2024/1/10
*/
@Data
@Configuration
public class HwyObsProperties {
@Value("${file.obs.bucketName}")
private String bucketName;
@Value("${file.obs.accessKey}")
private String accessKey;
@Value("${file.obs.secretKey}")
private String secretKey;
@Value("${file.obs.endPoint}")
private String endPoint;
@Value("${file.obs.showUrl}")
private String showUrl;
}
- 上傳工具類
package com.maple.upload.util;
import com.alibaba.fastjson.JSON;
import com.maple.upload.bean.HwyObsModel;
import com.maple.upload.properties.HwyObsProperties;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.PostSignatureRequest;
import com.obs.services.model.PostSignatureResponse;
import com.obs.services.model.PutObjectResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
/**
* 華為云OBS 對(duì)象存儲(chǔ)工具類
* 華為云OBS官方sdk使用文檔:https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0101.html
* 華為云OBS操作指南:https://support.huaweicloud.com/ugobs-obs/obs_41_0002.html
* 華為云各服務(wù)應(yīng)用區(qū)域和各服務(wù)的終端節(jié)點(diǎn):https://developer.huaweicloud.com/endpoint?OBS
*
* @author 笑小楓
* @date 2022/7/22
* @see <a >https://www.xiaoxiaofeng.com</a>
*/
@Slf4j
@Component
@AllArgsConstructor
public class HwyObsUtil {
private final HwyObsProperties fileProperties;
/**
* 上傳華為云obs文件存儲(chǔ)
*
* @param file 文件
* @return 文件訪問路徑, 如果配置CDN,這里直接返回CDN+文件名(objectKey)
*/
public String uploadFileToObs(MultipartFile file) {
String fileName = file.getOriginalFilename();
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("獲取文件信息失敗");
}
// 文件類型
String fileType = fileName.substring(file.getOriginalFilename().lastIndexOf("."));
// 組建上傳的文件名稱,命名規(guī)則可自定義更改
String objectKey = FileCommonUtil.setFilePath("") + FileCommonUtil.setFileName(null, fileType);
PutObjectResult putObjectResult;
try (InputStream inputStream = file.getInputStream();
ObsClient obsClient = new ObsClient(fileProperties.getAccessKey(), fileProperties.getSecretKey(), fileProperties.getEndPoint())) {
log.info(String.format("華為云obs上傳開始,原文件名:%s,上傳后的文件名:%s", fileName, objectKey));
putObjectResult = obsClient.putObject(fileProperties.getBucketName(), objectKey, inputStream);
log.info(String.format("華為云obs上傳結(jié)束,文件名:%s,返回結(jié)果:%s", objectKey, JSON.toJSONString(putObjectResult)));
} catch (ObsException | IOException e) {
log.error("華為云obs上傳文件失敗", e);
throw new RuntimeException("華為云obs上傳文件失敗,請(qǐng)重試");
}
if (putObjectResult.getStatusCode() == 200) {
return putObjectResult.getObjectUrl();
} else {
throw new RuntimeException("華為云obs上傳文件失敗,請(qǐng)重試");
}
}
/**
* 獲取華為云上傳token,將token返回給前端,然后由前端上傳,這樣文件不占服務(wù)器端帶寬
*
* @param fileName 文件名稱
* @return
*/
public HwyObsModel getObsConfig(String fileName) {
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("The fileName cannot be empty.");
}
String obsToken;
String objectKey = null;
try (ObsClient obsClient = new ObsClient(fileProperties.getAccessKey(), fileProperties.getSecretKey(), fileProperties.getEndPoint())) {
String fileType = fileName.substring(fileName.lastIndexOf("."));
// 組建上傳的文件名稱,命名規(guī)則可自定義更改
objectKey = FileCommonUtil.setFilePath("") + FileCommonUtil.setFileName("", fileType);
PostSignatureRequest request = new PostSignatureRequest();
// 設(shè)置表單上傳請(qǐng)求有效期,單位:秒
request.setExpires(3600);
request.setBucketName(fileProperties.getBucketName());
if (StringUtils.isNotBlank(objectKey)) {
request.setObjectKey(objectKey);
}
PostSignatureResponse response = obsClient.createPostSignature(request);
obsToken = response.getToken();
} catch (ObsException | IOException e) {
log.error("華為云obs上傳文件失敗", e);
throw new RuntimeException("華為云obs上傳文件失敗,請(qǐng)重試");
}
HwyObsModel obsModel = new HwyObsModel();
obsModel.setBucketName(fileProperties.getBucketName());
obsModel.setEndPoint(fileProperties.getEndPoint());
obsModel.setToken(obsToken);
obsModel.setObjectKey(objectKey);
obsModel.setShowUrl(fileProperties.getShowUrl());
return obsModel;
}
}
篇幅問題,不貼controller和測(cè)試截圖了,完整代碼參考文章底部源碼吧,思想明白了,別的都大差不差。
6. 上傳七牛云
七牛云官方sdk:https://developer.qiniu.com/kodo/1239/java
七牛云存儲(chǔ)區(qū)域表鏈接:https://developer.qiniu.com/kodo/1671/region-endpoint-fq
- 引入sdk依賴
<!-- 七牛云 -->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.29</version>
</dependency>
- 配置上傳配置信息
file:
qiniuyun:
bucket: mapleBucket
accessKey: your ak
secretKey: your sk
regionId: z1
showUrl: cdn地址-file.xiaoxiaofeng.com
- 創(chuàng)建配置類,讀取配置文件的參數(shù)
package com.maple.upload.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 七牛云配置
*
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2024/1/10
*/
@Data
@Configuration
public class QiNiuProperties {
@Value("${file.qiniuyun.accessKey}")
private String accessKey;
@Value("${file.qiniuyun.secretKey}")
private String secretKey;
@Value("${file.qiniuyun.bucket}")
private String bucket;
@Value("${file.qiniuyun.regionId}")
private String regionId;
@Value("${file.qiniuyun.showUrl}")
private String showUrl;
}
- 上傳工具類,注意有一個(gè)區(qū)域轉(zhuǎn)換,如后續(xù)有新增,
qiNiuConfig
這里需要調(diào)整一下
package com.maple.upload.util;
import com.maple.upload.properties.QiNiuProperties;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.Objects;
/**
*
* 七牛云 對(duì)象存儲(chǔ)工具類
* 七牛云官方sdk:https://developer.qiniu.com/kodo/1239/java
* 七牛云存儲(chǔ)區(qū)域表鏈接:https://developer.qiniu.com/kodo/1671/region-endpoint-fq
*
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2022/3/24
*/
@Slf4j
@Component
@AllArgsConstructor
public class QiNiuYunUtil {
private final QiNiuProperties qiNiuProperties;
public String uploadFile(MultipartFile file) {
String fileName = file.getOriginalFilename();
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("獲取文件信息失敗");
}
// 組建上傳的文件名稱,命名規(guī)則可自定義更改
String objectKey = FileCommonUtil.setFilePath("xiaoxiaofeng") + FileCommonUtil.setFileName("xxf", fileName.substring(fileName.lastIndexOf(".")));
//構(gòu)造一個(gè)帶指定 Region 對(duì)象的配置類
Configuration cfg = qiNiuConfig(qiNiuProperties.getRegionId());
//...其他參數(shù)參考類注釋
UploadManager uploadManager = new UploadManager(cfg);
try (InputStream inputStream = file.getInputStream()) {
Auth auth = Auth.create(qiNiuProperties.getAccessKey(), qiNiuProperties.getSecretKey());
String upToken = auth.uploadToken(qiNiuProperties.getBucket());
log.info(String.format("七牛云上傳開始,原文件名:%s,上傳后的文件名:%s", fileName, objectKey));
Response response = uploadManager.put(inputStream, objectKey, upToken, null, null);
log.info(String.format("七牛云上傳結(jié)束,文件名:%s,返回結(jié)果:%s", objectKey, response.toString()));
return qiNiuProperties.getShowUrl() + objectKey;
} catch (Exception e) {
log.error("調(diào)用七牛云失敗", e);
throw new RuntimeException("調(diào)用七牛云失敗");
}
}
private static Configuration qiNiuConfig(String zone) {
Region region = null;
if (Objects.equals(zone, "z1")) {
region = Region.huabei();
} else if (Objects.equals(zone, "z0")) {
region = Region.huadong();
} else if (Objects.equals(zone, "z2")) {
region = Region.huanan();
} else if (Objects.equals(zone, "na0")) {
region = Region.beimei();
} else if (Objects.equals(zone, "as0")) {
region = Region.xinjiapo();
}
return new Configuration(region);
}
}
篇幅問題,不貼controller和測(cè)試截圖了,完整代碼參考文章底部源碼吧,思想明白了,別的都大差不差。
7. 上傳又拍云
又拍云客戶端配置:https://help.upyun.com/knowledge-base/quick_start/
又拍云官方sdk:https://github.com/upyun/java-sdk
- 引入sdk依賴
<!-- 又拍云OSS -->
<dependency>
<groupId>com.upyun</groupId>
<artifactId>java-sdk</artifactId>
<version>4.2.3</version>
</dependency>
- 配置上傳配置信息
file:
upy:
bucketName: mapleBucket
userName: 操作用戶名稱
password: 操作用戶密碼
showUrl: cdn地址-file.xiaoxiaofeng.com
- 創(chuàng)建配置類,讀取配置文件的參數(shù)
package com.maple.upload.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 又拍云上傳配置
*
* @author 笑小楓 <https://www.xiaoxiaofeng.com/>
* @date 2024/1/10
*/
@Data
@Configuration
public class UpyOssProperties {
@Value("${file.upy.bucketName}")
private String bucketName;
@Value("${file.upy.userName}")
private String userName;
@Value("${file.upy.password}")
private String password;
/**
* 加速域名
*/
@Value("${file.upy.showUrl}")
private String showUrl;
}
- 上傳工具類
package com.maple.upload.util;
import com.maple.upload.properties.UpyOssProperties;
import com.upyun.RestManager;
import com.upyun.UpException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* 又拍云 對(duì)象存儲(chǔ)工具類
* 又拍云客戶端配置:https://help.upyun.com/knowledge-base/quick_start/
* 又拍云官方sdk:https://github.com/upyun/java-sdk
*
* @author 笑小楓
* @date 2022/7/22
* @see <a >https://www.xiaoxiaofeng.com</a>
*/
@Slf4j
@Component
@AllArgsConstructor
public class UpyOssUtil {
private final UpyOssProperties fileProperties;
/**
* 根據(jù)url上傳文件到又拍云
*/
public String uploadUpy(String url) {
// 組建上傳的文件名稱,命名規(guī)則可自定義更改
String fileName = FileCommonUtil.setFilePath("xiaoxiaofeng") + FileCommonUtil.setFileName("xxf", url.substring(url.lastIndexOf(".")));
RestManager restManager = new RestManager(fileProperties.getBucketName(), fileProperties.getUserName(), fileProperties.getPassword());
URI u = URI.create(url);
try (InputStream inputStream = u.toURL().openStream()) {
byte[] bytes = IOUtils.toByteArray(inputStream);
Response response = restManager.writeFile(fileName, bytes, null);
if (response.isSuccessful()) {
return fileProperties.getShowUrl() + fileName;
}
} catch (IOException | UpException e) {
log.error("又拍云oss上傳文件失敗", e);
}
throw new RuntimeException("又拍云oss上傳文件失敗,請(qǐng)重試");
}
/**
* MultipartFile上傳文件到又拍云
*/
public String uploadUpy(MultipartFile file) {
String fileName = file.getOriginalFilename();
if (StringUtils.isBlank(fileName)) {
throw new RuntimeException("獲取文件信息失敗");
}
// 組建上傳的文件名稱,命名規(guī)則可自定義更改
String objectKey = FileCommonUtil.setFilePath("xiaoxiaofeng") + FileCommonUtil.setFileName("xxf", fileName.substring(fileName.lastIndexOf(".")));
RestManager restManager = new RestManager(fileProperties.getBucketName(), fileProperties.getUserName(), fileProperties.getPassword());
try (InputStream inputStream = file.getInputStream()) {
log.info(String.format("又拍云上傳開始,原文件名:%s,上傳后的文件名:%s", fileName, objectKey));
Response response = restManager.writeFile(objectKey, inputStream, null);
log.info(String.format("又拍云上傳結(jié)束,文件名:%s,返回結(jié)果:%s", objectKey, response.isSuccessful()));
if (response.isSuccessful()) {
return fileProperties.getShowUrl() + objectKey;
}
} catch (IOException | UpException e) {
log.error("又拍云oss上傳文件失敗", e);
}
throw new RuntimeException("又拍云oss上傳文件失敗,請(qǐng)重試");
}
}
篇幅問題,不貼controller和測(cè)試截圖了,完整代碼參考文章底部源碼吧,思想明白了,別的都大差不差。
8. 項(xiàng)目源碼
本文到此就結(jié)束了,如果幫助到你了,幫忙點(diǎn)個(gè)贊??
本文源碼:https://github.com/hack-feng/maple-product/tree/main/maple-file-upload文章來源:http://www.zghlxwxcb.cn/news/detail-834710.html
??我是笑小楓,全網(wǎng)皆可搜的【笑小楓】文章來源地址http://www.zghlxwxcb.cn/news/detail-834710.html
到了這里,關(guān)于SpringBoot集成阿里云OSS、華為云OBS、七牛云、又拍云等上傳案例【附白嫖方案】【附源碼】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!