关于使用阿里云OSS对象储存上传大视频和转码的一些心得
来源:互联网 发布:php url参数加密 编辑:程序博客网 时间:2024/05/22 00:10
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;//bucketNameprivate 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 */@Overridepublic 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;}// 创建Bucketprivate 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")@Overridepublic 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 IDprivate static String ACCESS_KEY_ID;// 阿里云API的密钥Access Key Secretprivate static String ACCESS_KEY_SECRET;// init static datasstatic { 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 = "";// 水印图片的keyprivate static String accessKeyId = "";private static String accessKeySecret = "";private static String pipelineId = "";// 转码管道IDprivate static String transcodeTemplateId = "S00000001-200030";// 预制模板MP4高清// private static String waterMarkTemplateId = "";//自定义水印模板IDprivate 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;
}
上面注释掉的是加上水印的,各位根据自己的实际情况选择,还有在转码的时候有个坑,就是在提交转码时如果你上次的视频有中文名,转码那边是识别不了的,按阿里的要求转码了就会报接口MD5检测失败,还没有找到什么好的解决办法
- 引用
Ctrl + Q
- 插入链接
Ctrl + L
- 插入代码
Ctrl + K
- 插入图片 `Ctrl +
- 提升标题
Ctrl + H
- 有序列表
Ctrl + O
- 无序列表
Ctrl + U
- 横线
Ctrl + R
- 撤销
Ctrl + Z
- 重做
Ctrl + Y
Markdown及扩展
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ]
使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个链接等,详细语法参考帮助?。
本编辑器支持 Markdown Extra , 扩展了很多好用的功能。具体请参考Github.
表格
Markdown Extra 表格语法:
可以使用冒号来定义对齐方式:
定义列表
- Markdown Extra 定义列表语法:
- 项目1
- 项目2
- 定义 A
- 定义 B
- 项目3
- 定义 C
定义 D
定义D内容
代码块
代码块语法遵循标准markdown代码,例如:
@requires_authorizationdef somefunc(param1='', param2=0): '''A docstring''' if param1 > param2: # interesting print 'Greater' return (param2 - param1 + 1) or Noneclass SomeClass: pass>>> message = '''interpreter... prompt'''
脚注
生成一个脚注1.
目录
用 [TOC]
来生成目录:
- Markdown及扩展
- 表格
- 定义列表
- 代码块
- 脚注
- 目录
- 数学公式
- UML 图
- 离线写博客
- 浏览器兼容
- Markdown及扩展
数学公式
使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com.
- 行内公式,数学公式为:
Γ(n)=(n−1)!∀n∈N 。 - 块级公式:
更多LaTex语法请参考 这儿.
UML 图:
可以渲染序列图:
或者流程图:
- 关于 序列图 语法,参考 这儿,
- 关于 流程图 语法,参考 这儿.
离线写博客
即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。
用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。
博客发表后,本地缓存将被删除。
用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。
注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱。
浏览器兼容
- 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。
- IE9以下不支持
- IE9,10,11存在以下问题
- 不支持离线功能
- IE9不支持文件导入导出
- IE10不支持拖拽文件导入
- 这里是 脚注 的 内容. ↩
- 关于使用阿里云OSS对象储存上传大视频和转码的一些心得
- 阿里云oss的一些使用方法和心得
- 如何使用阿里云OSS储存文件和注意事项
- Java使用阿里云OSS对象存储上传图片
- Java使用阿里云OSS对象存储上传图片
- 自动上传指定文件夹下的所有文件到阿里云oss储存
- 关于阿里云OSS上传以及下载的处理方法
- 阿里云oss对象存储图片上传
- Laravel中上传视频至阿里云对象存储OSS中
- 上传阿里云oss对象型存储 本地文件和上传流上传
- 海康相机接入 sos 流媒体 使用阿里云oss储存 实现实时转发,全天录像,历史回放,视频下载
- 阿里云OSS,搭建自己的云储存
- 阿里OSS对象存储的简单使用
- 阿里云oss云储存错误代码403
- 阿里云的OSS对象存储 java
- ossUploader 阿里云OSS 对象云存储 上传控件
- **关于阿里云oss图片批量上传问题解析**
- 阿里云OSS 上传文件
- qwb去面试 思维
- 对于内部类中super()的疑惑和实验
- struts2+ajax实现页面自动刷新。
- 卡尔曼滤波公式推导
- 大数据架构简述(一):大数据的本质
- 关于使用阿里云OSS对象储存上传大视频和转码的一些心得
- Failed to initialize Monitor Thread:Unable to establish loopback connection
- 268. Missing Number
- 【计算机视觉】从运动中恢复结构SfM-摄像机运动估计
- Spring SimpleUrlHandlerMapping的使用
- 仿微信头像放大图
- 算法谜题121 超级蛋测试
- GCC 源码剖析
- js中正则表达式的使用