阿里云oss服务器----分片上传文件

一、步骤:

1.配置maven,引入阿里oss服务器提供的相关依赖

2.编写对应的工具类实现对文件分片上传的业务

3.使用junit进行测试

二、maven中引入的依赖如下

<!--阿里云依赖的包-->
		<dependency>
			<groupId>com.aliyun.oss</groupId>
			<artifactId>aliyun-sdk-oss</artifactId>
			<version>3.3.0</version>
		</dependency>

		<dependency>
			<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-core</artifactId>
			<version>3.4.0</version>
		</dependency>
		<dependency>
			<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-ram</artifactId>
			<version>3.0.0</version>
		</dependency>
		<dependency>
			<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-sts</artifactId>
			<version>3.0.0</version>
		</dependency>
		<dependency>
			<groupId>com.aliyun</groupId>
			<artifactId>aliyun-java-sdk-ecs</artifactId>
			<version>4.2.0</version>
		</dependency>

这里可能还需要引入Apache HttpClient ,其maven厂库为:

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.7</version>
</dependency>

三、编写相应的工具类。实现文件的分片上传功能

代码如下:

package com.SCT.weichatprogram.util;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
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;

@Component
public class MutinPartUploadUtil {

    private Logger logger=LoggerFactory.getLogger(MutinPartUploadUtil.class);

    @Value("${aliyunoss.bucketName}")
    private  String bucketName;

    @Value("${aliyunoss.endpoint}")
    private  String endpoint;

    @Value("${aliyunoss.accessKeyId}")
    private  String accessKeyId;

    @Value("${aliyunoss.accessKeySecret}")
    private  String getAccessKeySecret;

    private OSS client=null;

    //用来最后上传成功后,调取对象保存文件名
    private String filelo="";

    private final long partSize=1024*1024*1;

    private  ExecutorService executorService= Executors.newFixedThreadPool(5);
    private List<PartETag> partETagList=Collections.synchronizedList(new ArrayList<PartETag>());//这里考虑集合的线程安全,通过Collections.synchronizedList转为线程安全

    public Boolean sendMutinPart(String key,File message){
        ClientBuilderConfiguration conf=new ClientBuilderConfiguration();
        conf.setIdleConnectionTime(1000);
        client=new OSSClientBuilder().build(endpoint,accessKeyId,getAccessKeySecret,conf);
        try{
            String uploadId=claimUploadId(key);
            File file=message;
            long fileLength=file.length();
            int partCount=(int)(fileLength/partSize);
            if(fileLength%partSize!=0){
                partCount++;
            }
            if(partCount>50000){
                throw new RuntimeException("toal parts count should not excend 10000");
            }
            else{
                logger.info("total parts count "+partCount+"\n");
            }
            logger.info("Begin to upload multiparts to oss form file\n");
            for(int i=0;i<partCount;i++){
                long startPos=i*partSize;
                long curtPartSize=(i+1==partCount)?(fileLength-startPos):partSize;
                //这里运用executor来启动线程,其这里涉及多例模式,运用5个线程,运用有线程池
                executorService.execute(new PartUploader(file,startPos,curtPartSize,i+1,uploadId,key));
            }
            executorService.shutdown();//这里包括三种不同的停止方式,看我的个人博客
            while(!executorService.isTerminated()){//判断是否终止
                executorService.awaitTermination(5,TimeUnit.SECONDS);//解决阻塞的线程,再关闭
            }

            if(partETagList.size()!=partCount){
                throw new IllegalStateException("Upload multiparts fail due to some parts are not finished yet");
            }else{
                logger.info("Succeed to complete multiparts into an object named"+key+"\n");
            }
            listAllPart(uploadId,key);

            //进行oss端整合
            completeMultipartUpload(uploadId,key);

            logger.info("Fetching an object");
            client.getObject(new GetObjectRequest(bucketName,key),new File(filelo));

        } catch(OSSException oe){
            logger.info("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            logger.info("Error Message: " + oe.getErrorMessage());
            logger.info("Error Code:       " + oe.getErrorCode());
            logger.info("Request ID:      " + oe.getRequestId());
            logger.info("Host ID:           " + oe.getHostId());
        } catch(ClientException ce){
            logger.info("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            logger.info("Error Message: " + ce.getMessage());
//                shutUpload();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            /*
             * Do not forget to shut down the client finally to release all allocated resources.
             */
            if (client != null) {
                client.shutdown();
            }
        }
        return true;
    }


    private String claimUploadId(String key){
        InitiateMultipartUploadRequest request=new InitiateMultipartUploadRequest(bucketName,key);
        InitiateMultipartUploadResult result=client.initiateMultipartUpload(request);
        return result.getUploadId();
    }
    //进行上传后,调用oss接口监听查看自己的提交碎片记录,条数
    private void listAllPart(String uploadId,String key){
        logger.info("Listing all parts..");
        ListPartsRequest listPartsRequest=new ListPartsRequest(bucketName,key,uploadId);
        PartListing partListing=client.listParts(listPartsRequest);
        int partCount=partListing.getParts().size();
        for(int i=0;i<partCount;i++){
            PartSummary partSummary=partListing.getParts().get(i);
            logger.info("\tpart#"+partSummary.getPartNumber()+",ETag="+partSummary.getETag());
        }
    }

    private void completeMultipartUpload(String uploadId,String key){
        //进行集合排序,整合
        Collections.sort(partETagList, new Comparator<PartETag>() {
            @Override
            public int compare(PartETag p1, PartETag p2) {
                return p1.getPartNumber() - p2.getPartNumber();
            }
        });
        logger.info("completing to upload multiparts\n");
        //请求碎片的整合操作
        CompleteMultipartUploadRequest completeMultipartUploadRequest=
                new CompleteMultipartUploadRequest(bucketName,key,uploadId,partETagList);
        client.completeMultipartUpload(completeMultipartUploadRequest);
    }

    private class PartUploader implements Runnable{

        private File localFile;
        private long startPos;
        private long partSize;
        private int partNumber;
        private String uploadId;
        private String key;

        public PartUploader(File file,long startPos,long partSize,int partNumber,String uploadId,String key){
            this.localFile=file;
            this.startPos=startPos;
            this.partSize=partSize;
            this.partNumber=partNumber;
            this.uploadId=uploadId;
            this.key=key;
        }

        @Override
        public void run() {

            InputStream instream=null;
            try{
                instream=new FileInputStream(this.localFile);
                instream.skip(this.startPos);
                UploadPartRequest uploadPartRequest=new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(key);
                uploadPartRequest.setUploadId(this.uploadId);
                uploadPartRequest.setInputStream(instream);
                uploadPartRequest.setPartSize(this.partSize);
                uploadPartRequest.setPartNumber(this.partNumber);

                UploadPartResult uploadPartResult=client.uploadPart(uploadPartRequest);
                logger.info("Part#"+this.partNumber+"done\n");
                synchronized (partETagList){
                    partETagList.add(uploadPartResult.getPartETag());
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally{
                if(instream!=null){
                    try{
                        instream.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }

        }
    }
//    public File createSampleFile() throws IOException {
//        File file = File.createTempFile("oss-java-sdk-", ".txt");
//        file.deleteOnExit();
//
//        Writer writer = new OutputStreamWriter(new FileOutputStream(file));
//        for (int i = 0; i < 100000; i++) {
//            writer.write("abcdefghijklmnopqrstuvwxyz\n");
//            writer.write("0123456789011234567890\n");
//        }
//        writer.close();
//
//        return file;
//    }
//

}

四、对自己编写的工具类进行junit测试

代码如下:

扫描二维码关注公众号,回复: 5790114 查看本文章
@Test
	public void sendTextToOss(){
		System.out.println("accessKey:");
		File file= null;
		try {
			file = File.createTempFile("415","txt");
			file.deleteOnExit();
			Writer writer = new OutputStreamWriter(new FileOutputStream(file));
			writer.write("5445455545sdufgusdgfuysadgfsaufgsdfuysgddfgusagufyugeuywuyfgygwequyfyuwegfuuewygfuuwyegfuyyuwegfygewuyfgewgewyygfewuygf" +
					"wefgwyeqfguywegfyuweyuf" +
					"wefweqgfuygewuyf" +
					"ewfhjuweqhf8ewhfhewqihfiuhwqehfi");
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		uploadUtil.sendMutinPart("12345678hauhaush9.txt",file);

	}

五、这里涉及到知识

1、多线程的知识:

一)、即thread和ExecutorService

ExecutorService运用线程池的形式进行线程的管理和线程的调用,其设计的思想就是多例模式,对线程数量进行限制,对线程统一管理。在这里不得不谈关于ExecutorService的关闭线程池的三个函数:shutdownNow()、shutdown()和awaitTermination(long timeout,TimeUnit unit)。

这三个函数的区别是:

shutdownNow()立即关闭线程池,不管是否还有线程未完成。其等级最高

shutdown()不会立即关闭线程池,直达想成完成后才将其关闭,其等级第二

awaitTermination(long timeout,TimeUnit unit)即等待阻塞线程完成,其时间通过timeout和时间单位unit进行设置。在上述代码中每5秒进行判断线程是否还有线程池是否终止,如果没有将继续进行循环处理。其通常和shutdown连用。其等级最低

2.关于集合线程安全的知识

什么是线程安全:对于一个全局变量而言,其所有的线程都能访问,其访问的先后顺序也不同。即线程a和线程b同时访问全局变量C,a去改全局变量C进行加一,而b去也去改全局变量C进行加一,在这个过程中可能会出现,线程b先读取数据C,线程a再读取数据C,并将其数值加一。这是线程b将数值也加一,可是其读取的数据时a改变之前的,最后结果就不对了。在这里也涉及到关于变量的可见性问题,对于每个线程都有自己的本地缓存池,其内存数值改变了,但线程中缓存值没有改变,这导致数据缓存不一致的问题。

回归正题:如何保证集合的线程安全:

1.运用Collections.synchronizedList(List)将对应的集合转变为加锁的集合。加锁就是同步锁,即线程其他线程的存在,多个线程按照相应的逻辑顺序进行共同合作完成业务,即同步问题,同步问题也往往包含互斥问题

2.运用线程安全的集合

猜你喜欢

转载自blog.csdn.net/weixin_39573518/article/details/88852764