阿里云oss上传下载删除工具类

工具类-阿里云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);
                    }
                }
            }
        }
    }

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值