工具类-阿里云oss
private static String accessId;
private static String accessKey;
private static String endpoint;
private static String endpointInternal;
private static String bucket;
private static Integer expiredSeconds;
private static String environment;
@Value("${aliyun.oss.accessId}")
public void setAccessId(String accessId){
this.accessId = accessId;
}
@Value("${aliyun.oss.accessKey}")
public void setAccessKey(String accessKey){
this.accessKey = accessKey;
}
@Value("${aliyun.oss.endpoint}")
public void setEndpoint(String endpoint){
this.endpoint = endpoint;
}
@Value("${aliyun.oss.endpointInternal}")
public void setEndpointInternal(String endpointInternal){
this.endpointInternal = endpointInternal;
}
@Value("${aliyun.oss.bucket}")
public void setBucket(String bucket){
this.bucket = bucket;
}
@Value("${aliyun.oss.expiredSeconds}")
public void setExpiredSeconds(Integer expiredSeconds){
this.expiredSeconds = expiredSeconds;
}
@Value("${virtual.environment}")
public void setEnvironment(String environment){
this.environment = environment;
}
private static final String process = "imm/previewdoc,copy_0";
private static final int DEFAULT_PARALLELISM = 5;
/**
* 上传并返回访问的url
* @param file
* @param objectName
* @return
*/
public static String uploadOss (MultipartFile file, String objectName){
if(file == null||objectName == null||"".equals(objectName)){
return null;
}
final long partSize = 1 * 1024 * 1024L*10; // 1MB
long fileLength = file.getSize();
if(fileLength>partSize){
return uploadOssBigFile(file,objectName);
}else{
return uploadOssSmallFile(file,objectName);
}
}
public static String uploadOssSmallFile(MultipartFile file, String objectName){
System.out.println("开始普通上传");
if(file == null||objectName == null||"".equals(objectName)){
return null;
}
String point=endpoint;
if(environment.equals("prod")){
point = endpointInternal;
}
OSS ossClient = new OSSClientBuilder().build("http://"+point, accessId, accessKey);
try{
String name = file.getOriginalFilename();
//ObjectMetadata metadata = new ObjectMetadata();
//metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//metadata.setHeader("Content-Type","image/jpeg");
// 上传文件流。
InputStream inputStream = file.getInputStream();
// if(name.indexOf(".")!=-1){
// ossClient.putObject(bucket, objectName, inputStream);
// }else{
// ossClient.putObject(bucket, objectName, inputStream,metadata);
// }
ossClient.putObject(bucket, objectName, inputStream);
//返回url
return "https://"+bucket+"."+endpoint+"/"+objectName;
}catch (Exception e){
e.printStackTrace();
throw new SjException(ErrorStateEnum.UPLOAD_ERROR);
}finally {
// 关闭OSSClient
if(ossClient != null){
ossClient.shutdown();
}
}
}
/**
* 上传并返回访问的url
* @param file
* @param objectName
* @return
*/
public static String uploadOssBigFile (MultipartFile file, String objectName){
System.out.println("开始分片上传");
if(file == null||objectName == null||"".equals(objectName)){
return null;
}
String point=endpoint;
if(environment.equals("prod")){
point = endpointInternal;
}
OSS ossClient = new OSSClientBuilder().build("http://"+point, accessId, accessKey);
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucket, objectName);
try{
String name = file.getOriginalFilename();
String prefix = name.substring(name.lastIndexOf("."),name.length());
if(".mp4".equals(prefix)){
// 如果需要在初始化分片时设置文件存储类型,请参考以下示例代码。
ObjectMetadata metadata = new ObjectMetadata();
//metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
metadata.setHeader("Content-Type","video/mp4");
request.setObjectMetadata(metadata);
}
// 初始化分片。
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
// 返回uploadId,它是分片上传事件的唯一标识,您可以根据这个uploadId发起相关的操作,如取消分片上传、查询分片上传等。
String uploadId = upresult.getUploadId();
// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
//List<PartETag> partETags = new ArrayList<PartETag>();
// 计算文件有多少个分片。
final long partSize = 1 * 1024 * 512; // 1MB
long fileLength = file.getSize();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
// 使用线程池遍历分片上传。
List<Future<PartETag>> tmpList = Collections.synchronizedList(new ArrayList<>(partCount));
ExecutorService executorService = Executors.newFixedThreadPool(DEFAULT_PARALLELISM);
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
InputStream instream = file.getInputStream();
//多线程处理
tmpList.add(executorService.submit(new PartUploader(bucket,instream,startPos,curPartSize,i+1,uploadId,objectName,ossClient)));
// 跳过已经上传的分片。
// instream.skip(startPos);
// UploadPartRequest uploadPartRequest = new UploadPartRequest();
// uploadPartRequest.setBucketName(bucket);
// uploadPartRequest.setKey(objectName);
// uploadPartRequest.setUploadId(uploadId);
// uploadPartRequest.setInputStream(instream);
// // 设置分片大小。除了最后一个分片没有大小限制,其他的分片最小为100 KB。
// uploadPartRequest.setPartSize(curPartSize);
// // 设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出这个范围,OSS将返回InvalidArgument的错误码。
// uploadPartRequest.setPartNumber( i + 1);
// // 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
// UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
// // 每次上传分片之后,OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
// partETags.add(uploadPartResult.getPartETag());
}
//关闭线程池
executorService.shutdown();
while (!executorService.isTerminated()){
try {
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error(e.getMessage());
}
}
List<PartETag> partETags = Collections.synchronizedList(new ArrayList<PartETag>());
for (Future<PartETag> aTmpList : tmpList) {
if (aTmpList.isDone()) {
partETags.add(aTmpList.get());
}
}
System.out.println(partETags.size());
if(partETags.size()!=partCount){
throw new IllegalStateException("文件的某些部分上传失败!");
}else {
System.out.println("成功上传文件"+file.getName());
}
// 创建CompleteMultipartUploadRequest对象。
// 在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucket, objectName, uploadId, partETags);
// 如果需要在完成文件上传的同时设置文件访问权限,请参考以下示例代码。
// completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
// 完成上传。
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//返回url
return "https://"+bucket+"."+endpoint+"/"+objectName;
}catch (Exception e){
e.printStackTrace();
throw new SjException(ErrorStateEnum.UPLOAD_ERROR);
}finally {
// 关闭OSSClient
if(ossClient != null){
ossClient.shutdown();
}
}
}
/**
* 删除单个阿里云文件
* @param objectName
*/
public static void deleteOss(String objectName){
// if(objectName ==null||"".equals(objectName)){
// return;
// }
// // 创建OSSClient实例
// OSSClient ossClient = new OSSClient(endpoint, accessId, accessKey);
// // 删除文件
// ossClient.deleteObject(bucket, objectName);
// // 关闭OSSClient
// ossClient.shutdown();
}
/**
* 批量删除阿里云文件
* @param keys
* @return
*/
public static int deleteBatchOss(List<String> keys){
// if(keys == null||keys.size()==0){
// return 0;
// }
// // 创建OSSClient实例
// OSSClient ossClient = new OSSClient(endpoint, accessId, accessKey);
// // 删除文件
// DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucket).withKeys(keys));
// List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
// // 关闭OSSClient
// ossClient.shutdown();
// return deletedObjects.size();
return 0;
}
/**
* 阿里云上传获取签名
* @param dir
* @return
*/
public static OssPolicy getOssPolicy(String dir){
long expireEndTime = System.currentTimeMillis() + expiredSeconds*1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
OSS ossClient = new OSSClientBuilder().build("http://"+endpoint, accessId, accessKey);
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = new byte[0];
try {
binaryData = postPolicy.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
OssPolicy policy = new OssPolicy();
policy.setAccessId(accessId);
policy.setHost("https://" + bucket+"."+endpoint);
policy.setDir(dir);//dir为备课本编码(阿里云oss文件夹名称)
policy.setExpire(String.valueOf(expireEndTime / 1000));
policy.setPolicy(encodedPolicy);
policy.setSignature(postSignature);
return policy;
}
/**
* 阿里云单个文件文件流下载
* @param filename
* @param response
* @param request
*/
public static void downloadOss(String filename, HttpServletResponse response, HttpServletRequest request){
if(filename == null){
return;
}
try{
String[] filenames = filename.split("/");
System.out.println(filenames[filenames.length-1]);
response.reset();
response.setCharacterEncoding("utf-8");
response.setHeader("Accept-Ranges", "bytes");
if(StringUtils.contains(request.getHeader("User-Agent"),"Firefox")){
response.setHeader("Content-Disposition","attachment;"+ "filename="+ new
String(filenames[filenames.length-1].getBytes("UTF-8"),"ISO8859-1"));
}else{
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filenames[filenames.length-1],"UTF8"));
}
//response.setHeader("Content-Disposition", "attachment; filename=" + filenames[filenames.length-1]);
response.setCharacterEncoding("UTF-8");
ServletOutputStream out = response.getOutputStream();
OSS ossClient = new OSSClientBuilder().build("http://"+endpoint, accessId, accessKey);
// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
OSSObject ossObject = ossClient.getObject(bucket, filename);
InputStream inputStream = ossObject.getObjectContent();
int bytesRead = 0;
// 向压缩文件中输出数据
while((bytesRead=inputStream.read())!=-1){
out.write(bytesRead);
}
inputStream.close();
out.close();
// 关闭OSSClient。
ossClient.shutdown();
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 预览文件
* @param objectName
*
*/
public static String previewOss(String objectName){
if(objectName == null){
return null;
}
try{
OSS ossClient = new OSSClientBuilder().build("http://"+endpoint, accessId, accessKey);
GetObjectRequest getObjectRequest = new GetObjectRequest(bucket,objectName);
getObjectRequest.setProcess(process);
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket,objectName, HttpMethod.GET);
request.setProcess(process);
request.setExpiration(new Date(new Date().getTime()+1000*60*30));//30分钟
URL url = ossClient.generatePresignedUrl(request);
System.out.println(url.toString());
return url.toString();
}catch (Exception e) {
e.printStackTrace();
return null;
}
}
//拼接阿里云oss完整url
public static String getUrl(String objectName){
return "https://"+bucket+"."+endpoint+"/"+objectName;
}
public class PutObjectProgressListener implements ProgressListener {
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
@Override
public void progressChanged(ProgressEvent progressEvent) {
long bytes = progressEvent.getBytes();
ProgressEventType eventType = progressEvent.getEventType();
switch (eventType) {
case TRANSFER_STARTED_EVENT:
System.out.println("Start to upload......");
break;
case REQUEST_CONTENT_LENGTH_EVENT:
this.totalBytes = bytes;
System.out.println(this.totalBytes + " bytes in total will be uploaded to OSS");
break;
case REQUEST_BYTE_TRANSFER_EVENT:
this.bytesWritten += bytes;
if (this.totalBytes != -1) {
int percent = (int)(this.bytesWritten * 100.0 / this.totalBytes);
System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
} else {
System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
System.out.println("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
break;
case TRANSFER_FAILED_EVENT:
System.out.println("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
break;
default:
break;
}
}
public boolean isSucceed() {
return succeed;
}
// public static void main(String[] args) {
// // Endpoint以杭州为例,其它Region请按实际情况填写。
// String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
// String accessKeyId = "<yourAccessKeyId>";
// String accessKeySecret = "<yourAccessKeySecret>";
// String bucketName = "<yourBucketName>";
// String objectName = "<yourObjectName>";
//
// // 创建OSSClient实例。
// OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
//
// try {
// // 上传文件的同时指定了进度条参数。
// ossClient.putObject(new PutObjectRequest(bucketName, objectName, new File("<yourLocalFile>")).
// <PutObjectRequest>withProgressListener(new PutObjectProgressListener()));
//
// } catch (Exception e) {
// e.printStackTrace();
// }
// // 关闭OSSClient。
// ossClient.shutdown();
// }
}
private static class PartUploader implements Callable<PartETag> {
private String bucketName;
private InputStream inputStream;
private long startPos;
private long partSize;
private int partNumber;
private String uploadId;
private String key;
private OSS ossClient;
public PartUploader(String bucketName,InputStream inputStream,long startPos,long partSize,int partNumber,String uploadId,String key,OSS ossClient){
this.bucketName = bucketName;
this.startPos = startPos;
this.inputStream = inputStream;
this.partNumber = partNumber;
this.uploadId = uploadId;
this.partSize = partSize;
this.key = key;
this.ossClient = ossClient;
}
public PartETag call() {
System.out.println("...........start"+partNumber);
PartETag partETag = null;
InputStream is = inputStream;
try{
//跳过已经上传的分片
is.skip(startPos);
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(key);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setInputStream(is);
//设置分片大小。除了最后一个分片没有大小限制,其他分片最小为100KB
uploadPartRequest.setPartSize(partSize);
//设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出这个范围,OSS将返回InvalidArgum的错误码
uploadPartRequest.setPartNumber(partNumber);
//每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会根据分片号排序组成完整的文件。
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//每次上传分片之后,OSS的返回结果会包含一个PartETag。PartETag将被保存到PartETags中。
partETag = uploadPartResult.getPartETag();
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
System.out.println("...........end"+partNumber);
return partETag;
}
}
/**
* 导出压缩包,按模块分文件夹存放文件
* @param zips
* @param fileName
* @param request
* @param response
*/
public static void downloadFilesZip(List<FilesZip> zips,String fileName, HttpServletRequest request, HttpServletResponse response){
OSS ossClient = new OSSClientBuilder().build("http://"+endpoint, accessId, accessKey);
try{
File zipFile = File.createTempFile(fileName, ".zip");
fileName = fileName+".zip";
FileOutputStream f = new FileOutputStream(zipFile);
/**
* 作用是为任何OutputStream产生校验和
* 第一个参数是制定产生校验和的输出流,第二个参数是指定Checksum的类型 (Adler32(较快)和CRC32两种)
*/
CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());
// 用于将数据压缩成Zip文件格式
ZipOutputStream zos = new ZipOutputStream(csum);
String rootPath = request.getSession().getServletContext().getRealPath("/");
for(FilesZip zip : zips){
File temDir = new File(rootPath + "/" + zip.getName());
if(!temDir.exists()){
temDir.mkdirs();
}
for(String key : zip.getKeys()){
OSSObject ossObject = ossClient.getObject(bucket, key);
// 读去Object内容 返回
InputStream inputStream = ossObject.getObjectContent();
String[] keyNames = key.split("/");
FileOutputStream outputStream = new FileOutputStream(temDir.getAbsolutePath()+"/"+keyNames[keyNames.length-1]);
int bytesRead = 0;
// 向压缩文件中输出数据
while((bytesRead=inputStream.read())!=-1){
outputStream.write(bytesRead);
}
inputStream.close();
outputStream.close();
}
compress(temDir,zos,zip.getName(),true);
File[] listFiles = temDir.listFiles();
for (int i = 0; i < listFiles.length; i++) {
listFiles[i].delete();
}
temDir.delete();
}
zos.close();
response.reset();
response.setHeader("Accept-Ranges", "bytes");
// response.addHeader("Content-Length", String.valueOf(zipFile.length()));
if(StringUtils.contains(request.getHeader("User-Agent"),"Firefox")){
response.setHeader("Content-Disposition","attachment;"+ "filename="+ new
String(fileName.getBytes("UTF-8"),"ISO8859-1"));
}else{
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName,"UTF-8"));
}
response.setCharacterEncoding("UTF-8");
FileInputStream inputStream = new FileInputStream(zipFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch;
while ((ch = inputStream.read()) != -1) {
out.write(ch);
}
byte[] bytes = out.toByteArray();
response.setHeader("Content-Length", String.valueOf(bytes.length));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
// 关闭流
bos.write(bytes);
bos.close();
out.close();
// 删除临时文件
zipFile.delete();
}catch (Exception ex){
log.error(ex.getMessage());
}finally {
// 关闭OSSClient
if(ossClient != null){
ossClient.shutdown();
}
}
}
@Data
public static class FilesZip {
private String name;
private List<String> keys;
}
private static void compress(File sourceFile, ZipOutputStream zos, String
name,boolean keepDirStructure) throws Exception{
byte[] buf = new byte[1024];
if(sourceFile.isFile()){
zos.putNextEntry(new ZipEntry(name));
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = in.read(buf)) != -1){
zos.write(buf, 0, len);
}
zos.closeEntry();
in.close();
}else {
File[] listFiles = sourceFile.listFiles();
if(listFiles == null || listFiles.length == 0){
if(keepDirStructure){
// 空文件夹的处理
zos.putNextEntry(new ZipEntry(name + "/"));
// 没有文件,不需要文件的copy
zos.closeEntry();
}
}else {
for (File file : listFiles) {
if (keepDirStructure) {
// 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
compress(file, zos, name + "/" + file.getName(),keepDirStructure);
}else {
compress(file, zos, file.getName(),keepDirStructure);
}
}
}
}
}