阿里Oss物件儲存服務基本工具整合
阿新 • • 發佈:2018-11-08
一、引言
阿里的oss物件儲存伺服器,提供了儲存空間管理,檔案上傳下載,檔案管理,音訊與影象處理等常用操作,基本滿足中小企業對於檔案處理的需求,但官方提供的Api介面都是簡版,demo級別的,並不適合直接使用,故在下在工作之餘,對其常用Api進行封裝,整合為OssUtils工具類。
二、Oss基本配置
阿里官網推舉用子access_key_id和access_key_secrt,而不採用全域性配置
/** * 物件儲存Oss工具類 * * @author sunyiran * @date 2018-11-07 */ @Slf4j public class OssUtils { /** * 連線URL */ private static final String ENDPOINT = "XXXX"; /** * 例項ID */ private static final String ACCESS_KEY_ID = "XXXX"; /** * 例項金鑰 */ private static final String ACCESS_KEY_SECRET = "XXXX"; /** * 預設儲存空間 */ private static final String DEFAULT_BUCKETNAME = "syr-test"; /** * 預設圖片格式 */ private static final String DEFAULT_IMAGE_TYPE = "png"; /** * 預設壓縮比例 */ private static final int DEFAULT_SCALE = 10; /** * 預設水印文字 */ private static final String DEFAULT_CONTENT = "我的水印"; /** * 連線例項 */ private static final OSSClient OSS_CLIENT; private static final String SUCCESS = "success"; private static final String FAILED = "failed"; static { // 建立ClientConfiguration例項,按照您的需要修改預設引數。 ClientConfiguration conf = new ClientConfiguration(); // 關閉CNAME選項。 conf.setSupportCname(false); OSS_CLIENT = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf); } }
三、管理儲存空間
採用不同的儲存空間可以講檔案分類別儲存,它具有建立,列舉,獲取詳情,刪除等操作。
/** * 儲存空間管理工具 */ public static class BucketUtils { /** * 建立新的儲存空間 * * @param bucketName */ public static String createBucket(String bucketName) { CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); // 設定儲存空間的許可權為公共讀,預設是私有。 createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead); // 設定儲存空間的儲存型別為低頻訪問型別,預設是標準型別。 createBucketRequest.setStorageClass(StorageClass.IA); try { OSS_CLIENT.createBucket(createBucketRequest); return SUCCESS; } catch (OSSException e) { log.error(e.getMessage()); return FAILED; } } /** * 列舉儲存空間 * * @param bucketPrefix */ public static List<Bucket> listBucket(String bucketPrefix) { ListBucketsRequest listBucketsRequest = new ListBucketsRequest(); // 列舉指定字首的儲存空間。 if (StringUtils.isNotBlank(bucketPrefix)) { listBucketsRequest.setPrefix(bucketPrefix); } try { return OSS_CLIENT.listBuckets(listBucketsRequest).getBucketList(); } catch (OSSException e) { log.error(e.getMessage()); return null; } } /** * 獲取儲存空間資訊 * * @param bucketName */ public static Map getBucketInfo(String bucketName) { //判斷空間是否存在 boolean exists = OSS_CLIENT.doesBucketExist(bucketName); if (!exists) { return null; } // 儲存空間的資訊包括地域(Region或Location)、建立日期(CreationDate)、擁有者(Owner)、許可權(Grants)等。 Map<String, Object> result = new HashMap<>(4); BucketInfo info = OSS_CLIENT.getBucketInfo(bucketName); // 獲取地域。 result.put("location", info.getBucket().getLocation()); // 獲取建立日期。 result.put("createTime", new SimpleDateFormat("yyyy-MM-dd HH:ss").format(info.getBucket().getCreationDate())); // 獲取擁有者資訊。 result.put("owner", info.getBucket().getOwner()); // 獲取許可權資訊。';; AccessControlList acl = OSS_CLIENT.getBucketAcl(bucketName); result.put("authority", acl.toString()); return result; } /** * 刪除儲存空間 * * @param bucketName */ public static boolean deleteBucket(String bucketName) { //判斷空間是否存在 boolean exists = OSS_CLIENT.doesBucketExist(bucketName); if (!exists) { return false; } // 刪除儲存空間。 OSS_CLIENT.deleteBucket(bucketName); return true; } }
四、檔案上傳
阿里提供了流傳輸,分片傳輸,斷點續傳,帶進度條的等上傳操作
/** * 檔案上傳工具 */ public static class UploadUtils { /** * 預設上傳 * * @param file * @return * @throws IOException */ public static String simpleUpload(MultipartFile file) { try { return upload(file, DEFAULT_BUCKETNAME); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 自定義儲存空間上傳配置 * * @param file * @return * @throws IOException */ public static String upload(MultipartFile file, String bucketName) throws IOException { String putName = file.getOriginalFilename() + "_" + UUID.randomUUID().toString(); // 上傳檔案流。 PutObjectResult putObject = OSS_CLIENT.putObject(bucketName, putName, file.getInputStream()); String errorResponseAsString = putObject.getResponse().getErrorResponseAsString(); if (StringUtils.isNotBlank(errorResponseAsString)) { return errorResponseAsString; } System.out.println(errorResponseAsString); return putName; } /** * 合併檔案(主要用於文字物件) * * @param bucketName * @param contentType * @param content * @return */ public static String mergeContent(String bucketName, String contentType, InputStream... content) { ObjectMetadata meta = new ObjectMetadata(); // 指定上傳的內容型別。 meta.setContentType(contentType); //設定檔名 String fileName = UUID.randomUUID().toString(); AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, fileName, content[0], meta); AppendObjectResult objectResult = null; try { for (int i = 0; i < content.length; i++) { if (i == 0) { appendObjectRequest.setPosition(0L); objectResult = OSS_CLIENT.appendObject(appendObjectRequest); } else { appendObjectRequest.setPosition(objectResult.getNextPosition()); appendObjectRequest.setInputStream(content[i]); OSS_CLIENT.appendObject(appendObjectRequest); } } return fileName; } catch (OSSException e) { log.error(e.getMessage()); return FAILED; } } /** * 分片上傳 * * @param bucketName * @param file * @return * @throws IOException */ public static String shardUpload(String bucketName, MultipartFile file) throws IOException { //設定檔名 String putName = file.getOriginalFilename() + "_" + UUID.randomUUID().toString(); /* 步驟1:初始化一個分片上傳事件。 */ InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, putName); InitiateMultipartUploadResult result = OSS_CLIENT.initiateMultipartUpload(request); // 返回uploadId,它是分片上傳事件的唯一標識,您可以根據這個ID來發起相關的操作,如取消分片上傳、查詢分片上傳等。 String uploadId = result.getUploadId(); /* 步驟2:上傳分片。 */ // partETags是PartETag的集合。PartETag由分片的ETag和分片號組成。 List<PartETag> partETags = new ArrayList<>(); // 計算檔案有多少個分片。 final long partSize = 1024 * 1024L; long fileLength = file.getSize(); 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 instep = file.getInputStream(); // 跳過已經上傳的分片。 instep.skip(startPos); UploadPartRequest uploadPartRequest = new UploadPartRequest(); uploadPartRequest.setBucketName(bucketName); uploadPartRequest.setKey(putName); uploadPartRequest.setUploadId(uploadId); uploadPartRequest.setInputStream(instep); // 設定分片大小。除了最後一個分片沒有大小限制,其他的分片最小為100KB。 uploadPartRequest.setPartSize(curPartSize); // 設定分片號。每一個上傳的分片都有一個分片號,取值範圍是1~10000,如果超出這個範圍,OSS將返回InvalidArgument的錯誤碼。 uploadPartRequest.setPartNumber(i + 1); // 每個分片不需要按順序上傳,甚至可以在不同客戶端上傳,OSS會按照分片號排序組成完整的檔案。 UploadPartResult uploadPartResult = OSS_CLIENT.uploadPart(uploadPartRequest); // 每次上傳分片之後,OSS的返回結果會包含一個PartETag。PartETag將被儲存到partETags中。 partETags.add(uploadPartResult.getPartETag()); } /* 步驟3:完成分片上傳。 */ // 排序。partETags必須按分片號升序排列。 partETags.sort(Comparator.comparingInt(PartETag::getPartNumber)); // 在執行該操作時,需要提供所有有效的partETags。OSS收到提交的partETags後,會逐一驗證每個分片的有效性。當所有的資料分片驗證通過後,OSS將把這些分片組合成一個完整的檔案。 CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, putName, uploadId, partETags); OSS_CLIENT.completeMultipartUpload(completeMultipartUploadRequest); return putName; } /** * 帶進度條上傳 * * @param bucketName * @param file * @return */ public static String uploadWithProgress(String bucketName, MultipartFile file) throws IOException { String putName = file.getOriginalFilename() + "_" + UUID.randomUUID().toString(); try { OSS_CLIENT.putObject(new PutObjectRequest(bucketName, putName, file.getInputStream()).withProgressListener(new PutObjectProgressListener())); return putName; } catch (OSSException e) { log.error(e.getMessage()); return FAILED; } } }
五、檔案下載
/**
* 檔案下載工具類
*/
public static class DownloadUtils {
/**
* 預設下載
*
* @param fileUrl
* @return
*/
public static byte[] simpleDownload(String fileUrl) {
try {
download(DEFAULT_BUCKETNAME, fileUrl);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static byte[] download(String bucketName, String fileUrl) throws IOException {
// ossObject包含檔案所在的儲存空間名稱、檔名稱、檔案元資訊以及一個輸入流。
OSSObject ossObject = OSS_CLIENT.getObject(bucketName, fileUrl);
return ossObjectToByte(ossObject);
}
}
六、檔案管理
/**
* 檔案管理
*/
public static class FileManager {
/**
* 判斷檔案是否存在
*
* @param bucketName
* @param fileUrl
* @return
*/
public static boolean isExist(String bucketName, String fileUrl) {
// 判斷檔案是否存在。
return OSS_CLIENT.doesObjectExist(bucketName, fileUrl);
}
/**
* 獲取檔案資訊
*
* @param bucketName
* @param fileUrl
* @return
*/
public static Map getFileInfo(String bucketName, String fileUrl) {
// 獲取檔案元資訊。
ObjectMetadata metadata = OSS_CLIENT.getObjectMetadata(bucketName, fileUrl);
return metadata.getRawMetadata();
}
/**
* 獲取指定字首的檔案
*
* @param bucketName
* @param filePrefix
* @return
*/
public static List<OSSObjectSummary> listFile(String bucketName, String filePrefix) {
// 列舉包含指定字首的檔案。預設列舉100個檔案。
ObjectListing objectListing = OSS_CLIENT.listObjects(new ListObjectsRequest(bucketName).withPrefix(filePrefix));
return objectListing.getObjectSummaries();
}
/**
* 刪除檔案
*
* @param bucketName
* @param fileUrl
* @return
*/
public static String delete(String bucketName, String fileUrl) {
// 刪除檔案。
try {
OSS_CLIENT.deleteObject(bucketName, fileUrl);
return SUCCESS;
} catch (OSSException e) {
log.error(e.getMessage());
return FAILED;
}
}
}
七、圖片處理
/**
* 圖片處理工具類
*/
public static class ImageUtils {
public static void test() {
// // 縮放
// String style = "image/resize,m_fixed,w_100,h_100";
// GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-resize.jpg"));
//// 水印
// style = "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ";
// request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-watermark.jpg"));
//// 格式轉換
// style = "image/format,png";
// request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-format.png"));
//// 獲取圖片資訊
// style = "image/info";
// request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-info.txt"));
//// 關閉OSSClient。
// ossClient.shutdown();
}
/**
* 圖片等比例縮放
*
* @param scale
* @param bucketName
* @param fileUrl
* @return
*/
public static byte[] resize(int scale, String bucketName, String fileUrl) {
// 縮放
String style = "image/resize,p_" + scale;
GetObjectRequest request = new GetObjectRequest(bucketName, fileUrl);
request.setProcess(style);
OSSObject object = OSS_CLIENT.getObject(request);
return ossObjectToByte(object);
}
/**
* 新增水印
*
* @param content
* @param bucketName
* @param fileUrl
* @return
*/
public static byte[] waterMark(String content, String bucketName, String fileUrl) {
// 水印
String style = null;
try {
style = "image/watermark,text_" + Base64.getEncoder().encodeToString(content.getBytes("utf8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
GetObjectRequest request = new GetObjectRequest(bucketName, fileUrl);
request.setProcess(style);
OSSObject object = OSS_CLIENT.getObject(request);
return ossObjectToByte(object);
}
}
附本地圖片處理方案:
/**
* 等比例壓縮圖片
*
* @param scale 縮放比例
* @param targetPath 被處理圖片路徑
* @param path 處理後圖片存放路徑
* @return
* @throws IOException
*/
public static File changeImgSize(double scale, String targetPath, String path) throws IOException {
BufferedImage img = ImageIO.read(getInputStream(targetPath));
int w = (int) (img.getWidth() * scale);
int h = (int) (img.getHeight() * scale);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_USHORT_555_RGB);
image.getGraphics().drawImage(img, 0, 0, w, h, null);
File destFile = new File(getPath(path));
FileOutputStream out = new FileOutputStream(destFile);
// 可以正常實現bmp、png、gif轉jpg
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
return destFile;
}
八、使用用例
/**
* @author sunyiran
* @date 2018-11-07
*/
@RestController("/file")
public class FileController {
/**
* 檔案下載
* @param fileUrl
* @return
*/
@PostMapping("/download")
public static ResponseEntity<byte[]> download(String fileUrl) {
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", "test.jpg"));
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
byte[] download = OssUtils.DownloadUtils.simpleDownload(fileUrl);
if (download == null) {
return null;
}
return ResponseEntity.ok().headers(headers)
.contentLength(download.length).contentType(MediaType.parseMediaType("application/octet-stream"))
.body(download);
}
/**
* 上傳檔案
*
* @param file
* @return
*/
@PostMapping("/upload")
public static String upload(MultipartFile file) {
String fileUrl = OssUtils.UploadUtils.simpleUpload(file);
return fileUrl;
}
}
九、工具類下載路徑: