阿里云文件上传工具类

文件实体类


@Data
public class UploadFile {
    private String fileName;
    private String fileType;
    private long fileSize;
    private String timeStampName;
    private int success;
    private String message;
    private String url;
    private Integer storageType;
    //切片上传相关参数
    private String taskId;
    private int chunkNumber;
    private long chunkSize;
    private int totalChunks;
    private String identifier;
    private long totalSize;
    private long currentChunkSize;


}

文件上传工具父类:


@Slf4j
public abstract class Uploader {
    

    public static final String ROOT_PATH = "upload";
    public static final String FILE_SEPARATOR = "/";
    // 文件大小限制,单位KB
    public final int maxSize = 10000000;


    public abstract List<UploadFile> upload(HttpServletRequest request, UploadFile uploadFile);
    public abstract void cancelUpload(UploadFile uploadFile);

    /**
     * 获取本地文件保存路径
     *
     * @return
     */
    protected String getLocalFileSavePath() {
        
        String path = ROOT_PATH;
        SimpleDateFormat formater = new SimpleDateFormat("yyyyMMdd");
        path = FILE_SEPARATOR + path + FILE_SEPARATOR + formater.format(new Date());

        String staticPath = PathUtil.getStaticPath();

        File dir = new File(staticPath + path);
        //LOG.error(PathUtil.getStaticPath() + path);
        if (!dir.exists()) {
            try {
                boolean isSuccessMakeDir = dir.mkdirs();
                if (!isSuccessMakeDir) {
                    log.error("目录创建失败:" + PathUtil.getStaticPath() + path);
                }
            } catch (Exception e) {
                log.error("目录创建失败" + PathUtil.getStaticPath() + path);
                return "";
            }
        }
        return path;
    }

    /**
     * 依据原始文件名生成新文件名
     *
     * @return
     */
    protected String getTimeStampName() {
        try {
            SecureRandom number = SecureRandom.getInstance("SHA1PRNG");
            return "" + number.nextInt(10000)
                    + System.currentTimeMillis();
        } catch (NoSuchAlgorithmException e) {
            log.error("生成安全随机数失败");
        }
        return ""
                + System.currentTimeMillis();

    }

    public synchronized boolean checkUploadStatus(UploadFile param, File confFile) throws IOException {
        RandomAccessFile confAccessFile = new RandomAccessFile(confFile, "rw");
        //设置文件长度
        confAccessFile.setLength(param.getTotalChunks());
        //设置起始偏移量
        confAccessFile.seek(param.getChunkNumber() - 1);
        //将指定的一个字节写入文件中 127,
        confAccessFile.write(Byte.MAX_VALUE);
        byte[] completeStatusList = FileUtils.readFileToByteArray(confFile);
        confAccessFile.close();//不关闭会造成无法占用
        //创建conf文件文件长度为总分片数,每上传一个分块即向conf文件中写入一个127,那么没上传的位置就是默认的0,已上传的就是127
        for (int i = 0; i < completeStatusList.length; i++) {
            if (completeStatusList[i] != Byte.MAX_VALUE) {
                return false;
            }
        }
        confFile.delete();
        return true;
    }

    protected String getFileName(String fileName){
        if (!fileName.contains(".")) {
            return fileName;
        }
        return fileName.substring(0, fileName.lastIndexOf("."));
    }
}

阿里云文件上传子类:

package com.qiwenshare.ufo.operation.upload.product;


import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.qiwenshare.common.util.FileUtil;
import com.qiwenshare.ufo.autoconfiguration.UFOAutoConfiguration;
import com.qiwenshare.ufo.autoconfiguration.UFOProperties;
import com.qiwenshare.ufo.exception.UploadException;
import com.qiwenshare.ufo.operation.upload.Uploader;
import com.qiwenshare.ufo.operation.upload.domain.UploadFile;
import com.qiwenshare.ufo.util.PathUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.*;

@Slf4j
@Component
public class AliyunOSSUploader extends Uploader {

    // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
    public static Map<String, List<PartETag>> partETagsMap = new HashMap<String, List<PartETag>>();
    public static Map<String, UploadFileInfo> uploadPartRequestMap = new HashMap<>();

    public static Map<String, OSS> ossMap = new HashMap<>();

    @Override
    public List<UploadFile> upload(HttpServletRequest httpServletRequest, UploadFile uploadFile) {
        log.info("开始上传upload");

        List<UploadFile> saveUploadFileList = new ArrayList<>();
        StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) httpServletRequest;

        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (!isMultipart) {
            throw new UploadException("未包含文件上传域");
        }

        Iterator<String> iter = request.getFileNames();
        while (iter.hasNext()) {

            saveUploadFileList = doUpload(request, iter, uploadFile);
        }


        log.info("结束上传");
        return saveUploadFileList;
    }

    private List<UploadFile> doUpload(StandardMultipartHttpServletRequest standardMultipartHttpServletRequest, Iterator<String> iter, UploadFile uploadFile) {
        String savePath = getLocalFileSavePath();
        OSS ossClient = getClient(uploadFile);

        List<UploadFile> saveUploadFileList = new ArrayList<>();

        try {
            MultipartFile multipartfile = standardMultipartHttpServletRequest.getFile(iter.next());

            String timeStampName = getTimeStampName();
            String originalName = multipartfile.getOriginalFilename();
            String fileName = getFileName(originalName);
            String fileType = FileUtil.getFileExtendName(originalName);
            uploadFile.setFileName(fileName);
            uploadFile.setFileType(fileType);
            uploadFile.setTimeStampName(timeStampName);

            String ossFilePath = savePath + FILE_SEPARATOR + timeStampName + FILE_SEPARATOR + fileName + "." + fileType;
            String confFilePath = savePath + FILE_SEPARATOR + uploadFile.getIdentifier() + "." + "conf";
            File confFile = new File(PathUtil.getStaticPath() + FILE_SEPARATOR + confFilePath);

            synchronized (AliyunOSSUploader.class) {
                if (uploadPartRequestMap.get(uploadFile.getIdentifier()) == null) {
                    InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(UFOAutoConfiguration.aliyunConfig.getOss().getBucketName(), ossFilePath.substring(1));
                    InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
                    String uploadId = upresult.getUploadId();

                    UploadFileInfo uploadPartRequest = new UploadFileInfo();
                    uploadPartRequest.setBucketName(UFOAutoConfiguration.aliyunConfig.getOss().getBucketName());
                    uploadPartRequest.setKey(ossFilePath.substring(1));
                    uploadPartRequest.setUploadId(uploadId);
                    uploadPartRequestMap.put(uploadFile.getIdentifier(), uploadPartRequest);
                }

            }

            UploadFileInfo uploadFileInfo = uploadPartRequestMap.get(uploadFile.getIdentifier());
            UploadPartRequest uploadPartRequest = new UploadPartRequest();
            uploadPartRequest.setBucketName(uploadFileInfo.getBucketName());
            uploadPartRequest.setKey(uploadFileInfo.getKey());
            uploadPartRequest.setUploadId(uploadFileInfo.getUploadId());
            uploadPartRequest.setInputStream(multipartfile.getInputStream());
            uploadPartRequest.setPartSize(uploadFile.getCurrentChunkSize());
            uploadPartRequest.setPartNumber(uploadFile.getChunkNumber());
            log.info(JSON.toJSONString(uploadPartRequest));

            UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
            synchronized (AliyunOSSUploader.class) {
                log.info("上传结果:" + JSON.toJSONString(uploadPartResult));
                if (partETagsMap.get(uploadFile.getIdentifier()) == null) {
                    List<PartETag> partETags = new ArrayList<PartETag>();
                    partETags.add(uploadPartResult.getPartETag());
                    partETagsMap.put(uploadFile.getIdentifier(), partETags);
                } else {
                    partETagsMap.get(uploadFile.getIdentifier()).add(uploadPartResult.getPartETag());
                }
            }

            boolean isComplete = checkUploadStatus(uploadFile, confFile);
            if (isComplete) {
                log.info("分片上传完成");
                completeMultipartUpload(uploadFile);

                uploadFile.setUrl("/" + uploadPartRequestMap.get(uploadFile.getIdentifier()).getKey());
                uploadFile.setSuccess(1);
                uploadFile.setMessage("上传成功");
                partETagsMap.remove(uploadFile.getIdentifier());
                uploadPartRequestMap.remove(uploadFile.getIdentifier());
                ossMap.remove(uploadFile.getIdentifier());
            } else {
                uploadFile.setSuccess(0);
                uploadFile.setMessage("未完成");
            }

        } catch (Exception e) {
            log.error("上传出错:" + e);
            throw new UploadException(e);
        }

        uploadFile.setStorageType(1);

        uploadFile.setFileSize(uploadFile.getTotalSize());
        saveUploadFileList.add(uploadFile);
        return saveUploadFileList;
    }

    /**
     * 将文件分块进行升序排序并执行文件上传。
     */
    protected void completeMultipartUpload(UploadFile uploadFile) {

        List<PartETag> partETags = partETagsMap.get(uploadFile.getIdentifier());
        Collections.sort(partETags, Comparator.comparingInt(PartETag::getPartNumber));
        UploadFileInfo uploadFileInfo = uploadPartRequestMap.get(uploadFile.getIdentifier());
        CompleteMultipartUploadRequest completeMultipartUploadRequest =
                new CompleteMultipartUploadRequest(UFOAutoConfiguration.aliyunConfig.getOss().getBucketName(),
                        uploadFileInfo.getKey(),
                        uploadFileInfo.getUploadId(),
                        partETags);
        log.info("----:" + JSON.toJSONString(partETags));
        // 完成上传。
        CompleteMultipartUploadResult completeMultipartUploadResult = getClient(uploadFile).completeMultipartUpload(completeMultipartUploadRequest);
        log.info("----:" + JSON.toJSONString(completeMultipartUploadRequest));
        getClient(uploadFile).shutdown();

//
    }

    private void listFile(UploadFile uploadFile) {
        // 列举已上传的分片,其中uploadId来自于InitiateMultipartUpload返回的结果。
        ListPartsRequest listPartsRequest = new ListPartsRequest(UFOAutoConfiguration.aliyunConfig.getOss().getBucketName(), uploadPartRequestMap.get(uploadFile.getIdentifier()).getKey(), uploadPartRequestMap.get(uploadFile.getIdentifier()).getUploadId());
        // 设置uploadId。
        //listPartsRequest.setUploadId(uploadId);
        // 设置分页时每一页中分片数量为100个。默认列举1000个分片。
        listPartsRequest.setMaxParts(100);
        // 指定List的起始位置。只有分片号大于此参数值的分片会被列举。
//            listPartsRequest.setPartNumberMarker(1);
        PartListing partListing = getClient(uploadFile).listParts(listPartsRequest);

        for (PartSummary part : partListing.getParts()) {
            log.info("分片号:"+part.getPartNumber() + ", 分片数据大小: "+
                    part.getSize() + ",分片的ETag:"+part.getETag()
                    + ", 分片最后修改时间:"+ part.getLastModified());
            // 获取分片号。
            part.getPartNumber();
            // 获取分片数据大小。
            part.getSize();
            // 获取分片的ETag。
            part.getETag();
            // 获取分片的最后修改时间。
            part.getLastModified();
        }

    }

    /**
     * 取消上传
     */
    @Override
    public void cancelUpload(UploadFile uploadFile) {
        AbortMultipartUploadRequest abortMultipartUploadRequest =
                new AbortMultipartUploadRequest(UFOAutoConfiguration.aliyunConfig.getOss().getBucketName(), uploadPartRequestMap.get(uploadFile.getIdentifier()).getKey(), uploadPartRequestMap.get(uploadFile.getIdentifier()).getUploadId());
        getClient(uploadFile).abortMultipartUpload(abortMultipartUploadRequest);
    }

    private synchronized OSS getClient(UploadFile uploadFile) {
        OSS ossClient = null;
        if (ossMap.get(uploadFile.getIdentifier()) == null) {
            ossClient = new OSSClientBuilder().build(UFOAutoConfiguration.aliyunConfig.getOss().getEndpoint(), UFOAutoConfiguration.aliyunConfig.getOss().getAccessKeyId(), UFOAutoConfiguration.aliyunConfig.getOss().getAccessKeySecret());
            ossMap.put(uploadFile.getIdentifier(), ossClient);
        } else {
            ossClient = ossMap.get(uploadFile.getIdentifier());
        }
        return ossClient;
    }

    @Data
    public class UploadFileInfo {
        private String bucketName;
        private String key;
        private String uploadId;
    }

}

路径工具类


import com.qiwenshare.common.constant.FileConstant;
import com.qiwenshare.ufo.autoconfiguration.UFOAutoConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

public class PathUtil {

    /**
     * 获取项目所在的根目录路径 resources路径
     * @return
     */
    public static String getProjectRootPath() {
        String absolutePath = null;
        try {
            String url = ResourceUtils.getURL("classpath:").getPath();
            absolutePath = urlDecode(new File(url).getAbsolutePath()) + File.separator;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        return absolutePath;
    }

    /**
     * 路径解码
     * @param url
     * @return
     */
    public static String urlDecode(String url){
        String decodeUrl = null;
        try {
            decodeUrl = URLDecoder.decode(url, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return  decodeUrl;
    }

    /**
     * 得到static路径
     *
     * @return
     */
    public static String getStaticPath() {
        String localStoragePath = UFOAutoConfiguration.localStoragePath;//PropertiesUtil.getProperty("qiwen-file.local-storage-path")
        if (StringUtils.isNotEmpty(localStoragePath)) {
            return localStoragePath;
        }else {
            String projectRootAbsolutePath = getProjectRootPath();

            int index = projectRootAbsolutePath.indexOf("file:");
            if (index != -1) {
                projectRootAbsolutePath = projectRootAbsolutePath.substring(0, index);
            }

            return projectRootAbsolutePath + "static" + File.separator;
        }


    }


    public static String getParentPath(String path) {
        return path.substring(0, path.lastIndexOf(FileConstant.pathSeparator));
    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用阿里云提供的 Java SDK 中的 `OSSClient` 类和 `PutObjectRequest` 类来上传文件到 OSS。下面是一个简单的 OSS 文件上传工具类: ```java import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.model.PutObjectRequest; import java.io.File; public class OSSUtil { private static final String endpoint = "yourEndpoint"; // OSS 服务的 Endpoint private static final String accessKeyId = "yourAccessKeyId"; // AccessKeyId private static final String accessKeySecret = "yourAccessKeySecret"; // AccessKeySecret private static final String bucketName = "yourBucketName"; // 存储空间名 private static final OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); public static void uploadFile(String objectName, File file) { PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file); ossClient.putObject(putObjectRequest); } public static void shutdown() { ossClient.shutdown(); } } ``` 其中,`uploadFile` 方法用于上传文件,`shutdown` 方法用于关闭 `OSSClient` 实例。 使用时,只需要调用 `uploadFile` 方法即可上传文件: ```java File file = new File("yourFilePath"); // 文件路径 String objectName = "yourObjectName"; // 文件在 OSS 上的唯一标识 OSSUtil.uploadFile(objectName, file); ``` 需要注意的是,由于 `OSSClient` 实例的创建和销毁都需要一定的时间和资源,因此最好将其作为单例对象使用,以减少创建和销毁的次数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值