import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.model.PartETag;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSErrorCode;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CompleteMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadResult;
import com.aliyun.oss.model.ObjectMetadata;
/**
* @Description: 使用普通方式上傳小文件,使用Multipart上傳方式進行多線程分段上傳較大文件
* @author: zrk
* @time: 2015年3月30日 上午10:45:12
*/
public class OSSUploadFile implements Callable{
private static final Logger logger = LoggerFactory
.getLogger(OSSUploadFile.class);
//外層線程池
public static ExecutorService uploadMainPool = null;
static{
uploadMainPool = Executors.newFixedThreadPool(Constant.CONCURRENT_FILE_NUMBER,new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread s = Executors.defaultThreadFactory().newThread(r);
s.setDaemon(true);
return s;
}
});
}
//內層線程池
private ExecutorService pool ;
private MultipartFile sourcePath;//原文件路徑
private String bucketName;//bucketName
private String key;//雲端存儲路徑
/**
* oss上傳 支持斷點續傳
* @param sourcePath 源文件路徑
* @param bucketName bucketName
* @param key 存儲key -在oss的存儲路徑
*/
public OSSUploadFile(MultipartFile sourcePath,String bucketName,String key) {
//實例化單文件上次線程池
pool = Executors.newFixedThreadPool(Constant.SINGLE_FILE_CONCURRENT_THREADS);
this.sourcePath = sourcePath;
this.bucketName = bucketName;
this.key = key;
}
/**
* 執行當前線程
* @return
*/
@SuppressWarnings("finally")
public Integer uploadFile() {
Integer r = Global.ERROR;
//向uploadMainPool中submit當前線程
Future<Integer> result = uploadMainPool.submit(this);
try {
r=result.get();
} catch (ExecutionException e) {
e.printStackTrace();
} finally{
return r;
}
}
/**
* oss上傳
* @param sourcePath 源文件路徑
* @param bucketName bucketName
* @param key 存儲key 存儲路徑
* @return Integer
*/
@Override
public Integer call(){
OSSClient client = OssUtil.getOSSClient();
//File uploadFile = new File(sourcePath);
/*if (!sourcePath.exists()){
return Global.FILE_NOT_FOUND_ERROR;
}*/
int result = Global.ERROR;
key = key.contains("\\\\")?key.replaceAll("\\\\", "/"):key.contains("\\")?key.replaceAll("\\", "/"):key;
// 准備Bucket
result = ensureBucket(client,bucketName);
if(result == Global.ERROR )return result;
// 使用multipart的方式上傳文件
result = uploadBigFile(client, bucketName, key, sourcePath);
pool = null;
return result;
}
// 通過Multipart的方式上傳一個大文件
private int uploadBigFile(OSSClient client, String bucketName, String key,
MultipartFile uploadFile) {
//自定義的每個上傳分塊大小
Integer partSize = Constant.UPLOAD_PART_SIZE;
//需要上傳的文件分塊數
int partCount = calPartCount(uploadFile,partSize);
//文件的MD5值
String fileDM5Str = "";
String uploadId = "";
//序列化的文件路徑(與上傳文件同路徑使用.up.temp后綴)
String serializationFilePath =File.separator+ "tmp"+File.separator+"vide.mp4"+".up.temp";
boolean isSerializationFile = false;
//子線程池的線程對象封裝類(用於序列化的)
UploadPartObj uploadPartObj = null;
//獲取文件MD5值
fileDM5Str = MD5Util.getFileMD5(uploadFile);
//若存在上傳失敗留下的序列化文件則反序列化對象
if(new File(serializationFilePath).exists()){
uploadPartObj = (UploadPartObj)ObjectSerializableUtil.deserialization(serializationFilePath);
isSerializationFile = true;
}
//序列化文件不存在,分配分塊給子線程池線程對象
if(uploadPartObj==null||!isSerializationFile){
uploadPartObj = new UploadPartObj();
try {
//初始化MultipartUpload 返回uploadId
uploadId = initMultipartUpload(client, bucketName, key,fileDM5Str);
} catch (Exception e) {
e.printStackTrace();
return Global.OSS_SUBMIT_ERROR;
}
for (int i = 0; i < partCount ; i++) {
long start = partSize * i;
long curPartSize = partSize < uploadFile.getSize() - start ?
partSize : uploadFile.getSize() - start;
//構造上傳線程,UploadPartThread是執行每個分塊上傳任務的線程
uploadPartObj.getUploadPartThreads().add(new UploadPartThread(client, bucketName, key,uploadFile, uploadId, i + 1,partSize * i, curPartSize));
}
}
try {
int i = 0;
//upload方法提交分塊上傳線程至子線程池上傳,while循環用於上傳失敗重復上傳,Constant.RETRY定義重復次數
while (upload(uploadPartObj,serializationFilePath).isResult()==false) {
if(++i == Constant.RETRY)break;
}
} catch (Exception e) {
e.printStackTrace();
return Global.THREAD_ERROR;
}
if(!uploadPartObj.isResult()){
return Global.NETWORK_ERROR;
}
try {
//完成一個multi-part請求。
completeMultipartUpload(client, bucketName, key, uploadPartObj);
} catch (Exception e) {
e.printStackTrace();
logger.error("multi-part請求失敗!!");
ObjectSerializableUtil.serialization(uploadPartObj,serializationFilePath);
return Global.OSS_SUBMIT_ERROR;
}
return Global.SUCCESS;
}
/**
* 多線程上傳單個文件
* @param uploadPartObj
* @param serializationFilePath
* @return
*/
private UploadPartObj upload(UploadPartObj uploadPartObj,String serializationFilePath){
try {
uploadPartObj.setResult(true);
//向子線程池中submit單個文件所有分塊上傳線程
for (int i=0;i<uploadPartObj.getUploadPartThreads().size();i++) {
if(uploadPartObj.getUploadPartThreads().get(i).getMyPartETag()==null)
pool.submit(uploadPartObj.getUploadPartThreads().get(i));
}
//shutdown子線程池,池內所上傳任務執行結束后停止當前線程池
pool.shutdown();
while (!pool.isTerminated()) {
//循環檢查線程池,同時在此序列化uploadPartObj
ObjectSerializableUtil.serialization(uploadPartObj,serializationFilePath);
pool.awaitTermination(Constant.SERIALIZATION_TIME, TimeUnit.SECONDS);
}
//判斷上傳結果
for (UploadPartThread uploadPartThread: uploadPartObj.getUploadPartThreads()) {
if(uploadPartThread.getMyPartETag()==null)
uploadPartObj.setResult(false);
}
//上傳成功 刪除序列化文件
if (uploadPartObj.isResult()==true)
ObjectSerializableUtil.delSerlzFile(serializationFilePath);
} catch (Exception e) {
logger.error("多線程上傳單個文件異常!!");
}
return uploadPartObj;
}
// 根據文件的大小和每個Part的大小計算需要划分的Part個數。
private static int calPartCount(MultipartFile f,Integer partSize) {
int partCount = (int) (f.getSize() / partSize);
if (f.getSize() % partSize != 0){
partCount++;
}
return partCount;
}
// 創建Bucket
private int ensureBucket(OSSClient client, String bucketName){
try {
// 創建bucket
client.createBucket(bucketName);
//設置bucket的訪問權限,public-read-write權限
client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
} catch (OSSException e) {
e.printStackTrace();
return Global.ERROR;
} catch (ClientException e) {
if (!OSSErrorCode.BUCKET_ALREADY_EXISTS.equals(e.getErrorCode())) {
// 如果Bucket已經存在,則忽略
}else{
e.printStackTrace();
return Global.ERROR;
}
}
return Global.SUCCESS;
}
// 初始化一個Multi-part upload請求。
private static String initMultipartUpload(OSSClient client,String bucketName, String key,String fileDM5Str) throws OSSException,ClientException{
String uploadId=null;
try{
ObjectMetadata objectMetadata =new ObjectMetadata();
objectMetadata.getUserMetadata().put(Global.X_OSS_META_MY_MD5,fileDM5Str);
InitiateMultipartUploadRequest initUploadRequest = new InitiateMultipartUploadRequest(bucketName, key, objectMetadata);
InitiateMultipartUploadResult initResult = client.initiateMultipartUpload(initUploadRequest);
uploadId = initResult.getUploadId();
System.err.println(uploadId);
}catch (Exception e) {
logger.error("初始化Multi-part upload請求失敗!!");
}
return uploadId;
}
// 完成一個multi-part請求。
private static void completeMultipartUpload(OSSClient client, String bucketName, String key,UploadPartObj uploadPartObj){
List<PartETag> eTags = new ArrayList<PartETag>();
for (UploadPartThread uploadPartThread : uploadPartObj.getUploadPartThreads()) {
eTags.add(new PartETag(uploadPartThread.getMyPartETag().getPartNumber(),uploadPartThread.getMyPartETag().geteTag()));
}
//為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();
}
});
try{
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, key, uploadPartObj.getUploadPartThreads().get(0).getUploadId(), eTags);
System.err.println(uploadPartObj.getUploadPartThreads().get(0).getUploadId());
client.completeMultipartUpload(completeMultipartUploadRequest);
}catch (Exception e) {
logger.error("合並上傳失敗!!");
}
}
}
這里是主程序,用的文件流是MultipartFile,下面是主程序需要用到的一些類和方法。
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import org.springframework.web.multipart.MultipartFile;
public class MD5Util {
public static String getFileMD5(MultipartFile file) {
/* if (!file.exists() || !file.isFile()) {
return null;
} */
MessageDigest digest = null;
InputStream in = null;
byte buffer[] = new byte[1024];
int len;
try {
digest = MessageDigest.getInstance(“MD5”);
//in = new FileInputStream(file);
in=file.getInputStream();
while ((len = in.read(buffer, 0, 1024)) != -1) {
digest.update(buffer, 0, len);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
return null;
}
BigInteger bigInt = new BigInteger(1, digest.digest());
return bigInt.toString(16);
}
}
import java.io.Serializable;
import com.aliyun.oss.model.PartETag;
/**
* @Description: 封裝PartETag 用於序列化
* @author: zrk
* @time: 2015年4月1日 上午10:52:50
*/
public class MyPartETag implements Serializable {
private static final long serialVersionUID = 1L;
private int partNumber;
private String eTag;
public MyPartETag(PartETag partETag ) {
super();
this.partNumber = partETag.getPartNumber();
this.eTag = partETag.getETag();
}
public int getPartNumber() {
return partNumber;
}
public void setPartNumber(int partNumber) {
this.partNumber = partNumber;
}
public String geteTag() {
return eTag;
}
public void seteTag(String eTag) {
this.eTag = eTag;
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectSerializableUtil {
public static void serialization (Object object, String serializationFilePath) {
File file = new File(serializationFilePath);
if (!new File(file.getParent()).exists())
new File(file.getParent()).mkdirs();
if (file.exists())
file.delete();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(object);
oos.close();
} catch (IOException e) {
e.printStackTrace();
try {if (oos!=null)oos.close();} catch (IOException e1) {e1.printStackTrace();}
file.delete();
}
}
public static Object deserialization (String serializationFilePath) {
File file = new File(serializationFilePath);
if (!file.exists())
return null;
else {
}
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Object object = ois.readObject();
ois.close();
file.delete();
return object;
} catch (Exception e) {
return null;
}
}
public static boolean delSerlzFile(String serializationFilePath) {
File file = new File(serializationFilePath);
if (file.exists())
return file.delete();
return true;
}
}
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 單個文件的上傳線程集合
* @Description: TODO
* @author: zrk
* @time: 2015年5月6日 下午1:56:54
*/
public class UploadPartObj implements Serializable{
private static final long serialVersionUID = 1L;
List<UploadPartThread> uploadPartThreads = Collections.synchronizedList(new ArrayList<UploadPartThread>());
boolean result = true;
public List<UploadPartThread> getUploadPartThreads() {
return uploadPartThreads;
}
public void setUploadPartThreads(List<UploadPartThread> uploadPartThreads) {
this.uploadPartThreads = uploadPartThreads;
}
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
}
import java.io.InputStream;
import java.io.Serializable;
import java.util.concurrent.Callable;
import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.model.UploadPartResult;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.UploadPartRequest;
/**
* @Description: 上傳每個part的線程類 可序列化 用於上傳的斷點續傳
* @author: zrk
* @time: 2015年4月1日 上午10:35:34
*/
public class UploadPartThread implements Callable ,Serializable {
private static final long serialVersionUID = 1L;
private MultipartFile uploadFile;
private String bucket;
private String object;
private long start;
private long size;
private int partId;
private String uploadId;
private MyPartETag myPartETag;
public UploadPartThread(OSSClient client,String bucket, String object,
MultipartFile uploadFile,String uploadId, int partId,
long start, long partSize) {
this.uploadFile = uploadFile;
this.bucket = bucket;
this.object = object;
this.start = start;
this.size = partSize;
this.partId = partId;
this.uploadId = uploadId;
}
@SuppressWarnings("finally")
@Override
public UploadPartThread call() {
InputStream in = null;
try {
//in = new FileInputStream(uploadFile);
in=uploadFile.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);
//MyPartETag是對uploadPartResult.getPartETag()的返回值PartETag的封裝,主要是為了能序列化PartETag,MyPartETag僅比PartETag多實現了Serializable接口
UploadPartResult uploadPartResult = OssUtil.getOSSClient().uploadPart(uploadPartRequest);
myPartETag = new MyPartETag(uploadPartResult.getPartETag());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null){
try {
in.close();
} catch (final Exception e) {
}
}
return this;
}
}
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
public MyPartETag getMyPartETag() {
return myPartETag;
}
public void setMyPartETag(MyPartETag myPartETag) {
this.myPartETag = myPartETag;
}
}
下面的代碼是獲取oss對象和簡單上傳小文件及一個單線程的分片斷點續傳。
import java.io.FileInputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CompleteMultipartUploadRequest;
import com.aliyun.oss.model.CompleteMultipartUploadResult;
import com.aliyun.oss.model.InitiateMultipartUploadRequest;
import com.aliyun.oss.model.InitiateMultipartUploadResult;
import com.aliyun.oss.model.ListMultipartUploadsRequest;
import com.aliyun.oss.model.ListPartsRequest;
import com.aliyun.oss.model.MultipartUpload;
import com.aliyun.oss.model.MultipartUploadListing;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PartETag;
import com.aliyun.oss.model.PartListing;
import com.aliyun.oss.model.PartSummary;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.UploadPartRequest;
import com.aliyun.oss.model.UploadPartResult;
public class OssUtil {
// 阿里雲API的內或外網域名
private static String ENDPOINT;
// 阿里雲API的密鑰Access Key ID
private static String ACCESS_KEY_ID;
// 阿里雲API的密鑰Access Key Secret
private static String ACCESS_KEY_SECRET;
// init static datas
static {
ResourceBundle bundle = PropertyResourceBundle.getBundle("oss");
ENDPOINT = bundle.getString("endpoint").trim();
int a = ENDPOINT.length();
System.err.println("a=" + a);
ACCESS_KEY_ID = bundle.getString("accessKeyId").trim();
int b = ACCESS_KEY_ID.length();
System.err.println("b=" + b);
ACCESS_KEY_SECRET = bundle.getString("accessKeySecret").trim();
int c = ACCESS_KEY_SECRET.length();
System.err.println("c=" + c);
}
/**
* 獲取阿里雲OSS客戶端對象
* */
public static OSSClient getOSSClient() {
OSSClient ocClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID,
ACCESS_KEY_SECRET);
return ocClient;
}
/**
* 上傳圖片至OSS
*
* @param ossClient
* oss連接
* @param file
* 上傳文件(文件全路徑如:D:\\image\\cake.jpg)
* @param bucketName
* 存儲空間
* @param folder
* 模擬文件夾名 如"qj_nanjing/"
* @return String 返回的唯一MD5數字簽名
* */
public static String uploadObject2OSS(OSSClient ossClient,
MultipartFile file, String bucketName, String folder,
String fileName) {
String resultStr = null;
try {
// 以輸入流的形式上傳文件
// InputStream is = new FileInputStream(file);
// 文件名
// String fileName = file.getOriginalFilename();
// 文件大小
// Long fileSize = file.length();
// 創建上傳Object的Metadata
ObjectMetadata metadata = new ObjectMetadata();
// 上傳的文件的長度
metadata.setContentLength(file.getSize());
// 指定該Object被下載時的網頁的緩存行為
metadata.setCacheControl("no-cache");
// 指定該Object下設置Header
metadata.setHeader("Pragma", "no-cache");
// 指定該Object被下載時的內容編碼格式
metadata.setContentEncoding("utf-8");
// 文件的MIME,定義文件的類型及網頁編碼,決定瀏覽器將以什么形式、什么編碼讀取文件。如果用戶沒有指定則根據Key或文件名的擴展名生成,
// 如果沒有擴展名則填默認值application/octet-stream
// metadata.setContentType(getContentType(fileName));
// 指定該Object被下載時的名稱(指示MINME用戶代理如何顯示附加的文件,打開或下載,及文件名稱)
// metadata.setContentDisposition("filename/filesize=" + fileName
// + "/" + fileSize + "Byte.");
// 上傳文件 (上傳文件流的形式)
PutObjectResult putResult = ossClient.putObject(bucketName, folder
+ fileName, file.getInputStream(), metadata);
// 解析結果
resultStr = putResult.getETag();
} catch (Exception e) {
e.printStackTrace();
}
return resultStr;
}
/**
* 通過文件名判斷並獲取OSS服務文件上傳時文件的contentType
*
* @param fileName
* 文件名
* @return 文件的contentType
*/
public static String getContentType(String fileName) {
// 文件的后綴名
String fileExtension = fileName.substring(fileName.lastIndexOf("."));
if (".bmp".equalsIgnoreCase(fileExtension)) {
return "image/bmp";
}
if (".gif".equalsIgnoreCase(fileExtension)) {
return "image/gif";
}
if (".jpeg".equalsIgnoreCase(fileExtension)
|| ".jpg".equalsIgnoreCase(fileExtension)
|| ".png".equalsIgnoreCase(fileExtension)) {
return "image/jpeg";
}
if (".html".equalsIgnoreCase(fileExtension)) {
return "text/html";
}
if (".txt".equalsIgnoreCase(fileExtension)) {
return "text/plain";
}
if (".vsd".equalsIgnoreCase(fileExtension)) {
return "application/vnd.visio";
}
if (".ppt".equalsIgnoreCase(fileExtension)
|| "pptx".equalsIgnoreCase(fileExtension)) {
return "application/vnd.ms-powerpoint";
}
if (".doc".equalsIgnoreCase(fileExtension)
|| "docx".equalsIgnoreCase(fileExtension)) {
return "application/msword";
}
if (".xml".equalsIgnoreCase(fileExtension)) {
return "text/xml";
}
// 默認返回類型
return "image/jpeg";
}
/**
* 獲得url鏈接
*
* @param key
* @return
*/
public static String getUrl(String key) {
// 設置URL過期時間為10年 3600l* 1000*24*365*10
Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24
* 365 * 10);
// 生成URL
// 初始化OSSClient
OSSClient ossClient = OssUtil.getOSSClient();
URL url = ossClient.generatePresignedUrl("fsg-video", key, expiration);
if (url != null) {
return url.toString();
}
return null;
}
/**
* 斷點續傳
*
* @param key
* @return
*/
public static String multipartUploadObject(String bucketName, String key,
MultipartFile partFile) {
String tag = null;
String uploadid = null;
int j = 0;
// 初始化一個OSSClient
OSSClient client = getOSSClient();
ListMultipartUploadsRequest lmur = new ListMultipartUploadsRequest(
bucketName);
// 獲取Bucket內所有上傳事件
MultipartUploadListing listing = client.listMultipartUploads(lmur);
// 新建一個List保存每個分塊上傳后的ETag和PartNumber
List<PartETag> partETags = new ArrayList<PartETag>();
// 遍歷所有上傳事件 設置UploadId
for (MultipartUpload multipartUpload : listing.getMultipartUploads()) {
if (multipartUpload.getKey().equals(key)) {
uploadid = multipartUpload.getUploadId();
break;
}
}
if (StringUtils.isEmpty(uploadid)) {
// 開始Multipart Upload,InitiateMultipartUploadRequest
// 來指定上傳Object的名字和所屬Bucke
InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(
bucketName, key);
InitiateMultipartUploadResult initiateMultipartUploadResult = client
.initiateMultipartUpload(initiateMultipartUploadRequest);
uploadid = initiateMultipartUploadResult.getUploadId();
} else {
ListPartsRequest listPartsRequest = new ListPartsRequest(
bucketName, key, uploadid);
// listParts 方法獲取某個上傳事件所有已上傳的塊
PartListing partListing = client.listParts(listPartsRequest);
// 遍歷所有Part
for (PartSummary part : partListing.getParts()) {
partETags
.add(new PartETag(part.getPartNumber(), part.getETag()));
j++;
}
}
// 設置每塊為 5M(最小支持5M)
final int partSize = 1024 * 1024 * 10;
try {
// 計算分塊數目
int partCount = (int) (partFile.getSize() / partSize);
if (partFile.getSize() % partSize != 0) {
partCount++;
}
for (int i = j; i < partCount; i++) {
// 獲取文件流
FileInputStream fis;
fis = (FileInputStream) partFile.getInputStream();
// 跳到每個分塊的開頭
long skipBytes = partSize * i;
fis.skip(skipBytes);
// 計算每個分塊的大小
long size = partSize < partFile.getSize() - skipBytes ? partSize
: partFile.getSize() - skipBytes;
// 創建UploadPartRequest,上傳分塊
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(key);
uploadPartRequest.setUploadId(uploadid);
uploadPartRequest.setInputStream(fis);
uploadPartRequest.setPartSize(size);
uploadPartRequest.setPartNumber(i + 1);
UploadPartResult uploadPartResult = client
.uploadPart(uploadPartRequest);
// 將返回的PartETag保存到List中。
partETags.add(uploadPartResult.getPartETag());
// 關閉文件
fis.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
bucketName, key, uploadid, partETags);
// 完成分塊上傳
CompleteMultipartUploadResult completeMultipartUploadResult = client
.completeMultipartUpload(completeMultipartUploadRequest);
// 打印Object的ETag(返回的ETag不是md5.具體是什么不詳)
tag = completeMultipartUploadResult.getETag();
return tag;
}
}
上傳完成了在說一下我在項目中遇見的問題吧,應為這個是分片上傳的所以要等分片上傳完了才能把分片合成一個完整的視頻,這樣坑就來了,本來上傳一個500多M的視頻就要不少時間在加上傳完后還要合並碎片也要不少時間,這樣就會導致這個接口超時,自己在本地測試的時候並不會報超時,但部署到線上就會出現這個問題,后來發現是負載均衡的問題,因為是用的阿里雲的一站式解決方案,后來也沒有什么好的解決方案,我們只好不經過負載均衡了直接訪問的,這樣才解決了這一問題。
好了下面給出轉碼的代碼
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.mts.model.v20140618.SubmitJobsRequest;
import com.aliyuncs.mts.model.v20140618.SubmitJobsResponse;
import com.aliyuncs.profile.DefaultProfile;
public class OSSMTSUtil {
private static final String MTS_REGION = “cn-beijing”;
private static final String OSS_REGION = “oss-cn-beijing”;
private static final String mtsEndpoint = "mts.cn-beijing.aliyuncs.com";
private static String waterMarkFilePath = "";// 水印圖片的key
private static String accessKeyId = "";
private static String accessKeySecret = "";
private static String pipelineId = "";// 轉碼管道ID
private static String transcodeTemplateId = "S00000001-200030";// 預制模板MP4高清
// private static String waterMarkTemplateId = "";//自定義水印模板ID
private static String Bucket = ""; // 存儲空間名
private static DefaultAcsClient aliyunClient;
private static final Logger logger = LoggerFactory
.getLogger(OSSMTSUtil.class);
static {
//添加多地區
try {
DefaultProfile.addEndpoint(MTS_REGION, MTS_REGION, "Mts", mtsEndpoint);
} catch (ClientException e) {
logger.error("多地區添加失敗!!");
e.printStackTrace();
}
//獲取轉碼連接對象
aliyunClient = new DefaultAcsClient(DefaultProfile.getProfile(
MTS_REGION, accessKeyId, accessKeySecret));
}
/*
*
*
*
*/
//提交轉碼作業
public static String submitTranscodeJob(OSSFileDO inputFile,
OSSFileDO watermarkFile,String MTSFlieName) {
/*JSONObject waterMarkConfig = new JSONObject();
waterMarkConfig.put("InputFile", watermarkFile.toJson());
waterMarkConfig.put("WaterMarkTemplateId", waterMarkTemplateId);
JSONArray waterMarkConfigArray = new JSONArray();
waterMarkConfigArray.add(waterMarkConfig);*/
JSONObject jobConfig = new JSONObject();
jobConfig.put("OutputObject", MTSFlieName);
jobConfig.put("TemplateId", transcodeTemplateId);
// jobConfig.put("WaterMarks", waterMarkConfigArray);
JSONArray jobConfigArray = new JSONArray();
jobConfigArray.add(jobConfig);
SubmitJobsRequest request = new SubmitJobsRequest();
request.setInput(inputFile.toJson().toJSONString());
request.setOutputBucket(Bucket);
request.setOutputs(jobConfigArray.toJSONString());
request.setPipelineId(pipelineId);
request.setOutputLocation(OSS_REGION);
Integer outputJobCount = 1;
SubmitJobsResponse response = null;
try {
//發送轉碼請求
response = aliyunClient.getAcsResponse(request);
if (response.getJobResultList().size() != outputJobCount) {
throw new RuntimeException("SubmitJobsRequest Size failed");
}
return response.getJobResultList().get(0).getJob().getJobId();
} catch (ServerException e) {
logger.error("轉碼請求提交失敗!!");
throw new RuntimeException("submitTranscodeJob Server failed");
} catch (ClientException e) {
logger.error("轉碼請求提交失敗!!");
throw new RuntimeException("submitTranscodeJob Client failed");
}
}
}
import com.alibaba.fastjson.JSONObject;
public class OSSFileDO {
public void setBucket(String bucket) {
this.bucket = bucket;
}
public void setObject(String object) {
this.object = object;
}
public void setLocation(String location) {
this.location = location;
}
public String toJsonString(){
return toJson().toJSONString();
}
public JSONObject toJson(){
JSONObject jsonObject = new JSONObject();
jsonObject.put("Bucket", bucket);
jsonObject.put("Location", location);
jsonObject.put("Object", object);
return jsonObject;
}
public OSSFileDO(){
}
public OSSFileDO(String location, String bucket, String object){
this.location = location;
this.bucket = bucket;
this.object = object;
}
private String location;
private String bucket;
private String object;
}