【前言】
我們上家公司的存儲系統用的是FastDFS(智能一代雲平台(二十八):對前后端分離和FastDFS的使用的再理解);現在在職的公司用的是阿里雲的OSS(OSS的官方文檔),在工作的時候整理一個上傳OSS文件的工具類,現在與大家分享一下。
【工具類】
1、工具類的代碼:
-
package zhanghan.oss.utils;
-
-
import com.aliyun.oss.ClientException;
-
import com.aliyun.oss.OSSClient;
-
import com.aliyun.oss.OSSException;
-
import com.aliyun.oss.model.ObjectMetadata;
-
import com.aliyun.oss.model.PutObjectResult;
-
import com.fasterxml.jackson.annotation.JsonValue;
-
import org.apache.commons.io.FilenameUtils;
-
import org.apache.commons.lang3.time.DateUtils;
-
import org.springframework.util.StringUtils;
-
import org.springframework.web.multipart.MultipartFile;
-
import zhanghan.oss.exception.OSSCreateBucketRuntimeException;
-
import zhanghan.oss.exception.OSSGeneratePresignedUrlRuntimeException;
-
import zhanghan.oss.exception.OssPutObjectRuntimeException;
-
import java.io.InputStream;
-
import java.net.URL;
-
import java.util.Date;
-
import java.util.UUID;
-
-
/**
-
* OSS上傳工具類-張晗-2017/10/10
-
*/
-
public
class OSSUtil {
-
private
volatile
static OSSClient instance;
-
-
private OSSUtil() {
-
}
-
-
/**
-
* 單例
-
* @return OSS工具類實例
-
*/
-
private static OSSClient getOSSClient() {
-
if (instance ==
null) {
-
synchronized (OSSUtil.class) {
-
if (instance ==
null) {
-
instance =
new OSSClient(OSS_END_POINT, OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET);
-
}
-
}
-
}
-
return instance;
-
}
-
-
//定義日志
-
private
final
static LogUtils logger = LogUtils.getLogger(OSSUtil.class);
-
//OSS 的地址
-
private
final
static String OSS_END_POINT =
"http://oss-cn-qingdao.aliyuncs.com";
-
//OSS 的key值
-
private
final
static String OSS_ACCESS_KEY_ID =
"OSSKEY";
-
//OSS 的secret值
-
private
final
static String OSS_ACCESS_KEY_SECRET =
"OSSSECRET";
-
//OSS 的bucket名字
-
private
final
static String OSS_BUCKET_NAME =
"zhanghan-test";
-
//設置URL過期時間為10年
-
private
final
static Date OSS_URL_EXPIRATION = DateUtils.addDays(
new Date(),
365 *
10);
-
-
//文件路徑的枚舉
-
public
enum FileDirType {
-
ZHANGHAN_TEST(
"test");
-
private String dir;
-
-
FileDirType(String dir) {
-
this.dir = dir;
-
}
-
-
@JsonValue
-
public String getDir() {
-
return dir;
-
}
-
}
-
-
/**
-
* 上傳文件---去除URL中的?后的時間戳
-
* @param file 文件
-
* @param fileDir 上傳到OSS上文件的路徑
-
* @return 文件的訪問地址
-
*/
-
public static String upload(MultipartFile file, FileDirType fileDir) {
-
OSSUtil.createBucket();
-
String fileName = OSSUtil.uploadFile(file, fileDir);
-
String fileOssURL = OSSUtil.getImgUrl(fileName, fileDir);
-
int firstChar = fileOssURL.indexOf(
"?");
-
if (firstChar >
0) {
-
fileOssURL = fileOssURL.substring(
0, firstChar);
-
}
-
return fileOssURL;
-
}
-
-
-
/**
-
* 當Bucket不存在時創建Bucket
-
*
-
* @throws OSSException 異常
-
* @throws ClientException Bucket命名規則:
-
* 1.只能包含小寫字母、數字和短橫線,
-
* 2.必須以小寫字母和數字開頭和結尾
-
* 3.長度在3-63之間
-
*/
-
private static void createBucket() {
-
try {
-
if (!OSSUtil.getOSSClient().doesBucketExist(OSS_BUCKET_NAME)) {
//判斷是否存在該Bucket,不存在時再重新創建
-
OSSUtil.getOSSClient().createBucket(OSS_BUCKET_NAME);
-
}
-
}
catch (Exception e) {
-
logger.error(
"{}",
"創建Bucket失敗,請核對Bucket名稱(規則:只能包含小寫字母、數字和短橫線,必須以小寫字母和數字開頭和結尾,長度在3-63之間)");
-
throw
new OSSCreateBucketRuntimeException(
"創建Bucket失敗,請核對Bucket名稱(規則:只能包含小寫字母、數字和短橫線,必須以小寫字母和數字開頭和結尾,長度在3-63之間)");
-
}
-
}
-
-
-
/**
-
* 上傳到OSS服務器 如果同名文件會覆蓋服務器上的
-
* @param file 文件
-
* @param fileDir 上傳到OSS上文件的路徑
-
* @return 文件的訪問地址
-
*/
-
private static String uploadFile(MultipartFile file, FileDirType fileDir) {
-
String fileName = String.format(
-
"%s.%s",
-
UUID.randomUUID().toString(),
-
FilenameUtils.getExtension(file.getOriginalFilename()));
-
try (InputStream inputStream = file.getInputStream()) {
-
//創建上傳Object的Metadata
-
ObjectMetadata objectMetadata =
new ObjectMetadata();
-
objectMetadata.setContentLength(inputStream.available());
-
objectMetadata.setCacheControl(
"no-cache");
-
objectMetadata.setHeader(
"Pragma",
"no-cache");
-
objectMetadata.setContentType(getContentType(FilenameUtils.getExtension(
"." + file.getOriginalFilename())));
-
objectMetadata.setContentDisposition(
"inline;filename=" + fileName);
-
//上傳文件
-
PutObjectResult putResult = OSSUtil.getOSSClient().putObject(OSS_BUCKET_NAME, fileDir.getDir() + fileName, inputStream, objectMetadata);
-
return fileName;
-
}
catch (Exception e) {
-
logger.error(
"{}",
"上傳文件失敗");
-
throw
new OssPutObjectRuntimeException(
"上傳文件失敗");
-
}
-
}
-
-
-
/**
-
* 獲得文件路徑
-
* @param fileUrl 文件的URL
-
* @param fileDir 文件在OSS上的路徑
-
* @return 文件的路徑
-
*/
-
private static String getImgUrl(String fileUrl, FileDirType fileDir) {
-
if (StringUtils.isEmpty(fileUrl)) {
-
logger.error(
"{}",
"文件地址為空");
-
throw
new RuntimeException(
"文件地址為空");
-
}
-
String[] split = fileUrl.split(
"/");
-
-
//獲取oss圖片URL失敗
-
URL url = OSSUtil.getOSSClient().generatePresignedUrl(OSS_BUCKET_NAME, fileDir.getDir() + split[split.length -
1], OSS_URL_EXPIRATION);
-
if (url ==
null) {
-
logger.error(
"{}",
"獲取oss文件URL失敗");
-
throw
new OSSGeneratePresignedUrlRuntimeException(
"獲取oss文件URL失敗");
-
}
-
return url.toString();
-
}
-
-
/**
-
* 判斷OSS服務文件上傳時文件的contentType
-
*
-
* @param FilenameExtension 文件后綴
-
* @return 后綴
-
*/
-
private static String getContentType(String FilenameExtension) {
-
if (FilenameExtension.equalsIgnoreCase(
"bmp")) {
-
return
"image/bmp";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"gif")) {
-
return
"image/gif";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"jpeg") ||
-
FilenameExtension.equalsIgnoreCase(
"jpg") ||
-
FilenameExtension.equalsIgnoreCase(
"png")) {
-
return
"image/jpeg";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"html")) {
-
return
"text/html";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"txt")) {
-
return
"text/plain";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"vsd")) {
-
return
"application/vnd.visio";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"pptx") ||
-
FilenameExtension.equalsIgnoreCase(
"ppt")) {
-
return
"application/vnd.ms-powerpoint";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"docx") ||
-
FilenameExtension.equalsIgnoreCase(
"doc")) {
-
return
"application/msword";
-
}
-
if (FilenameExtension.equalsIgnoreCase(
"xml")) {
-
return
"text/xml";
-
}
-
return
"image/jpeg";
-
}
-
}
2、調用工具類的代碼:
-
/**
-
* 上傳文件測試
-
* @param multipartFile 待上傳的文件
-
* @return 上傳在OSS文件的訪問路徑
-
* @throws BusinessException 上傳異常
-
*/
-
public String uploadTest(MultipartFile multipartFile) throws BusinessException{
-
try {
-
uploadResult = OSSUtil.upload(multipartFile, OSSUtil.FileDirType.ZHANGHAN_TEST);
-
}
catch (Exception e) {
-
LoggerUtil.logService(LoggerUtil.spManualLoan,
"SPManualLoanServiceImpl-submitLoan",
"call OSSUtil.upload; Exception:" + e.getMessage());
-
throw
new BusinessException(WrongMessageEnum.EXCEPTION_STORE);
-
}
-
return uploadResult;
-
}
3、問題&解決:
(1) 問題:通過URL在瀏覽器中訪問時報如下錯:
(2)解決方案:在阿里雲的控制台上,進入OSS的設置界面,將Bucket的訪問權限由 私有 設置為 公共讀
【總結】
阿里雲現在很多公司都在用,阿里雲穩定,安全,相對來說成本更低;給自己更多思考的是如何讓項目減少成本,以及阿里雲等帶來的商業模式。