import com.aliyun.oss.ClientConfiguration; import com.aliyun.oss.ClientException; import com.aliyun.oss.OSSClient; import com.aliyun.oss.OSSException; import com.aliyun.oss.model.*; import com.xw.cn.jujiaoweb.utils.UUIDUtil; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class OSSMultipartUploadUtil { private static final String ACCESS_ID = "***********************************"; private static final String ACCESS_KEY = "***********************************"; private static final String OSS_ENDPOINT = "***********************************"; private static final long PART_SIZE = 5 * 1024 * 1024L; // 每一個Part的大小,最小爲5MB private static final int CONCURRENCIES = 2; // 上傳Part的併發線程數。 private static final String partUrl = "***********************************"; private static String bucketName = "*****"; // 須要存儲的bucketName private static String picLocation = "bigFile/"; // 圖片保存路徑 /** * 分段上傳大文件,經過Multipart的方式上傳一個大文件,要上傳文件的大小必須大於一個Part容許的最小大小,即5MB。 * @throws OSSException * @throws ClientException * @throws InterruptedException */ public static String uploadBigFile(MultipartFile file, String fileTypeName) throws OSSException, ClientException, InterruptedException { long begin = System.currentTimeMillis(); ClientConfiguration config = new ClientConfiguration(); OSSClient client = new OSSClient(OSS_ENDPOINT, ACCESS_ID, ACCESS_KEY, config); String key = String.format("%s%s.%s",picLocation,UUIDUtil.getUUID(),fileTypeName); int partCount = calPartCount(file.getSize()); if (partCount <= 1) { throw new IllegalArgumentException("要上傳文件的大小必須大於一個Part的字節數:" + PART_SIZE); } String uploadId = initMultipartUpload(client,bucketName, key); ExecutorService pool = Executors.newFixedThreadPool(CONCURRENCIES); List<PartETag> eTags = Collections.synchronizedList(new ArrayList<PartETag>()); for (int i = 0; i < partCount; i++) { long start = PART_SIZE * i; long curPartSize = PART_SIZE < file.getSize() - start ? PART_SIZE : file.getSize() - start; pool.execute(new UploadPartThread(client,bucketName, key,file, uploadId, i + 1, PART_SIZE * i, curPartSize,eTags)); } pool.shutdown(); while (!pool.isTerminated()) { pool.awaitTermination(5, TimeUnit.SECONDS); } if (eTags.size() != partCount) { throw new IllegalStateException("Multipart上傳失敗,有Part未上傳成功。"); } completeMultipartUpload(client,bucketName, key, uploadId, eTags); String fileUrl = String.format("%s%s",partUrl,key); long end = System.currentTimeMillis(); System.out.println(end - begin); return fileUrl; } // 根據文件的大小和每一個Part的大小計算須要劃分的Part個數。 private static int calPartCount(long length) { int partCount = (int) (length / PART_SIZE); if (length % PART_SIZE != 0) { partCount++; } return partCount; } // 初始化一個Multi-part upload請求。 private static String initMultipartUpload(OSSClient client,String bucketName, String key) throws OSSException, ClientException { InitiateMultipartUploadRequest initUploadRequest = new InitiateMultipartUploadRequest(bucketName, key); InitiateMultipartUploadResult initResult = client.initiateMultipartUpload(initUploadRequest); String uploadId = initResult.getUploadId(); return uploadId; } // 完成一個multi-part請求。 private static void completeMultipartUpload(OSSClient client,String bucketName, String key, String uploadId, List<PartETag> eTags) throws OSSException, ClientException { // 爲part按partnumber排序 Collections.sort(eTags, new Comparator<PartETag>() { public int compare(PartETag arg0, PartETag arg1) { PartETag part1 = arg0; PartETag part2 = arg1; return part1.getPartNumber() - part2.getPartNumber(); } }); CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, key, uploadId, eTags); client.completeMultipartUpload(completeMultipartUploadRequest); } private static class UploadPartThread implements Runnable { private MultipartFile file; private String bucket; private String object; private long start; private long size; private List<PartETag> eTags; private int partId; private OSSClient client; private String uploadId; UploadPartThread(OSSClient client,String bucket, String object,MultipartFile file, String uploadId, int partId, long start,long partSize, List<PartETag> eTags) { this.file = file; this.bucket = bucket; this.object = object; this.start = start; this.size = partSize; this.eTags = eTags; this.partId = partId; this.client = client; this.uploadId = uploadId; } @Override public void run() { InputStream in = null; try { in = file.getInputStream(); in.skip(start); UploadPartRequest uploadPartRequest = new UploadPartRequest(); uploadPartRequest.setBucketName(bucket); uploadPartRequest.setKey(object); uploadPartRequest.setUploadId(uploadId); uploadPartRequest.setInputStream(in); uploadPartRequest.setPartSize(size); uploadPartRequest.setPartNumber(partId); UploadPartResult uploadPartResult = client.uploadPart(uploadPartRequest); eTags.add(uploadPartResult.getPartETag()); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) try { in.close(); } catch (Exception e) { } } } } }