Spring集成七牛/腾讯/阿里oss上传【三合一】

23 阅读8分钟

一、前言

由于项目需要根据不同机构,不同应用走不同的上传方式。整合完了做一个分享,需要的拿走

二、简要说明

基础应用表

@Data
@Alias("ImApplication")
@ApiModel("ImApplication")
public class ImApplication{

	@ApiModelProperty(value = "应用")
	private String id;

	@ApiModelProperty(value = "机构id")
	private String orgId;

	@ApiModelProperty(value = "应用id")
	private Long appId;

	@ApiModelProperty(value = "SK")
	private String secretKey;

	@ApiModelProperty(value = "创建时间")
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	private Date createTime;


	@ApiModelProperty("上传类型 0七牛 1腾讯云 2阿里云")
	private Integer uploadType;
	@ApiModelProperty("bucket空间")
	private String uploadBucket;
	@ApiModelProperty("公网访问地址")
	private String uploadFilePath;
	@ApiModelProperty("uploadAccessKey")
	private String uploadAccessKey;
	@ApiModelProperty("uploadSecretKey")
	private String uploadSecretKey;
	@ApiModelProperty("上传节点【腾讯云|阿里云】")
	private String uploadEndpoint;
	@ApiModelProperty("上传文件夹【腾讯云|阿里云】")
	private String uploadFolder;

}

代码说明注意事项:

1.RedisUtil 是Redis工具根据项目使用的情况自行调整

2.NonePrintException 为项目自行封装的Exception 项目是做了全局拦截NonePrintException.目的是统一resultful api接口提示,自行参考修改

三、七牛云

maven引入,具体版本根据情况修改

<dependency>
      <groupId>com.qiniu</groupId>
      <artifactId>qiniu-java-sdk</artifactId>
      <version>[7.4.0, 7.4.99]</version>
    </dependency>

七牛云上传工具类

/**
 * 七牛云存储 工具
 */
@Slf4j
public class QiNiuManager{

    private UploadManager uploadManager;
    private BucketManager bucketManager;
    private OperationManager operationManager;
    private ImApplication imApplication;

    public QiNiuManager(ImApplication imApplication) {
        this.imApplication = imApplication;
        com.qiniu.storage.Configuration cfg = new com.qiniu.storage.Configuration(getRegion());
        uploadManager = new UploadManager(cfg);
        Auth auth = getAuth();
        operationManager = new OperationManager(auth, cfg);
    }

    private static final String KEY = "QINIU:REDIS:KEY";
    private static final long EXP = 3600;//有效期秒

    public  String getToken(){
        String key = KEY + imApplication.getAppId();
        if(RedisUtil.hasKey(key)){
            return RedisUtil.getValue(key);
        }else{
            Auth auth = getAuth();
            StringMap putPolicy = new StringMap();
            putPolicy.put("returnBody", "{"key":"$(key)","hash":"$(etag)","bucket":"$(bucket)","fsize":$(fsize)}");
            String token = auth.uploadToken(imApplication.getUploadBucket(),null,EXP,putPolicy);
            RedisUtil.putValue(key,token,EXP-(2*60), TimeUnit.SECONDS);
            return token;
        }
    }

    private Auth getAuth() {
        return Auth.create(imApplication.getUploadAccessKey(), imApplication.getUploadSecretKey());
    }


    public  QiniuPutRet upload(File file) throws NonePrintException {
        return upload(file,null);
    }
    public  QiniuPutRet upload(File file,String key) throws NonePrintException {
        try {
             Response response = uploadManager.put(file, key, getToken());
            return new Gson().fromJson(response.bodyString(), QiniuPutRet.class);
        } catch (QiniuException e) {
            throw new NonePrintException("-79","云存储图片上传失败:"+e.getMessage());
        }
    }

    public  QiniuPutRet upload(byte[] uploadBytes) throws NonePrintException {
        return upload(uploadBytes,null);
    }
    public  QiniuPutRet upload(byte[] uploadBytes,String key) throws NonePrintException {
        try {
            Response response = uploadManager.put(uploadBytes, key, getToken());
            return new Gson().fromJson(response.bodyString(), QiniuPutRet.class);
        } catch (QiniuException e) {
            throw new NonePrintException("-79","云存储图片上传失败:"+e.getMessage());
        }
    }
    public  QiniuPutRet upload(InputStream stream) throws NonePrintException {
        return upload(stream,null);
    }
    public  QiniuPutRet upload(InputStream stream,String key) throws NonePrintException {
        try {
            Response response = uploadManager.put(stream, key, getToken(),null,null);
            return new Gson().fromJson(response.bodyString(), QiniuPutRet.class);
        } catch (QiniuException e) {
            throw new NonePrintException("-79","云存储图片上传失败:"+e.getMessage());
        }
    }

    public  void del(String key) {
        try {
            getBucketManager().delete(imApplication.getUploadBucket(),key);
        } catch (QiniuException e) {
            log.debug("七牛云删除图片失败"+key+e.getMessage());
            ExceptionCenter.addException(e,"七牛云删除图片失败",key);
        }
    }

    public  BucketManager getBucketManager() {
        if(BaseUtil.isEmpty(bucketManager)){
            com.qiniu.storage.Configuration cfg = new com.qiniu.storage.Configuration(getRegion());
            Auth auth = getAuth();
            bucketManager = new BucketManager(auth,cfg);
        }
        return bucketManager;
    }

    public  OperationManager getOperationManager(){
        if(BaseUtil.isEmpty(operationManager)){
            com.qiniu.storage.Configuration cfg = new com.qiniu.storage.Configuration(getRegion());
            uploadManager = new UploadManager(cfg);
            Auth auth = getAuth();
            operationManager = new OperationManager(auth, cfg);
        }
        return operationManager;
    }

    public  String getSaveAs(String newKey){
        return UrlSafeBase64.encodeToString(imApplication.getUploadBucket() + ":" + newKey);
    }

    public  String pfop(String key,String fops) throws QiniuException {
        StringMap putPolicy = new StringMap();
        putPolicy.put("pipeline", "mps-pipe"+key);
        return getOperationManager().pfop(imApplication.getUploadBucket(), key, fops, putPolicy);
    }

    public  OperationStatus getOperationStatus(String persistentId) throws QiniuException {
        return getOperationManager().prefop(persistentId);
    }

    public  FileInfo getFile(String key) throws QiniuException {
        return getBucketManager().stat(imApplication.getUploadBucket(),key);
    }

    private  Zone getRegion() {
        Zone zone;
        int type = Integer.parseInt(imApplication.getUploadEndpoint());
        switch (type){
            case 0:
                zone = Zone.huadong();
                break;
            case 1:
                zone = Zone.huabei();
                break;
            case 2:
                zone = Zone.huanan();
                break;
            case 3:
                zone = Zone.beimei();
                break;
            case 4:
                zone = Zone.xinjiapo();
                break;
            default:
                throw new NonePrintException("未知空间");
        }
        return zone;
    }
}

使用方式

//工具内含有上传与删除,持久化等方法,具体可查看官方SDK进行拓展
QiNiuManager qiniuManager = new QiNiuManager(imApplication);
qiniuManager.upload(File file,String key)
qiniuManager.upload(byte[] uploadBytes)
qiniuManager.upload(byte[] uploadBytes,String key)
qiniuManager.upload(InputStream stream)
qiniuManager.upload(InputStream stream,String key)
qiniuManager.del(String key)

三、阿里云

maven引入,具体版本根据情况修改

 <dependency>
      <groupId>com.aliyun.oss</groupId>
      <artifactId>aliyun-sdk-oss</artifactId>
      <version>3.15.1</version>
    </dependency>

阿里云Oss工具类

public class AliOssManager {

    private ImApplication imApplication;

    public AliOssManager(ImApplication imApplication) {
        this.imApplication = imApplication;
    }

    public  String doUpload(File file, String fileName){
        // 创建OSSClient实例。
        OSS ossClient = getOssClient();
        String objectName = getObjectName(fileName);
        try {
            ossClient.putObject(imApplication.getUploadBucket(), objectName, file);
            return objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
            throw new NonePrintException("OSS上传失败:"+oe.getErrorMessage());
        } catch (ClientException ce) {
            System.out.println("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.");
            System.out.println("Error Message:" + ce.getMessage());
            throw new NonePrintException("OSS上传失败:"+ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    private  String getObjectName(String fileName) {
        return imApplication.getUploadFolder() + "/" + fileName;
    }

    private  OSS getOssClient() {
        return new OSSClientBuilder().build(imApplication.getUploadEndpoint(), imApplication.getUploadAccessKey(),imApplication.getUploadSecretKey());
    }

    public  String doUpload(byte[] bytes, String fileName) {
        OSS ossClient = getOssClient();
        String objectName = getObjectName(fileName);
        try {
            ossClient.putObject(imApplication.getUploadBucket(), objectName, new ByteArrayInputStream(bytes));
            return objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
            throw new NonePrintException("OSS上传失败:"+oe.getErrorMessage());
        } catch (ClientException ce) {
            System.out.println("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.");
            System.out.println("Error Message:" + ce.getMessage());
            throw new NonePrintException("OSS上传失败:"+ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

使用方式

new AliOssManager(imApplication).doUpload(file.getBytes(),fileName);

四、腾讯云

maven引入,具体版本根据情况修改

    <dependency>
      <groupId>com.qcloud</groupId>
      <artifactId>cos_api</artifactId>
      <version>5.6.213</version>
    </dependency>

腾讯云工具类

/**
 * 腾讯云OSS上传
 */
@Slf4j
public class TencentOssManager {

    private ImApplication imApplication;

    public TencentOssManager(ImApplication imApplication) {
        this.imApplication = imApplication;
    }

    public  String doUpload(byte[] bytes, String fileName) {
        TransferManager transferManager = createTransferManager();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        PutObjectRequest putObjectRequest = new PutObjectRequest(imApplication.getUploadBucket(), getObjectName(fileName), byteArrayInputStream,null);
        Upload upload = transferManager.upload(putObjectRequest);
        try {
            UploadResult uploadResult = upload.waitForUploadResult();
            log.debug("腾讯云OSS上传结果【{}】",JSON.toJSONString(uploadResult));
            return uploadResult.getKey();
        } catch (InterruptedException e) {
            throw new NonePrintException("腾讯云OSS上传文件失败");
        }finally {
            IOUtil.closeQuietly(byteArrayInputStream);
            transferManager.shutdownNow();
        }
    }

    public  String doUpload(File file, String fileName) {
        TransferManager transferManager = createTransferManager();
        PutObjectRequest putObjectRequest = new PutObjectRequest(imApplication.getUploadBucket(), getObjectName(fileName), file);
        Upload upload = transferManager.upload(putObjectRequest);
        try {
            UploadResult uploadResult = upload.waitForUploadResult();
            log.debug("腾讯云OSS上传结果【{}】",JSON.toJSONString(uploadResult));
            return uploadResult.getKey();
        } catch (InterruptedException e) {
            throw new NonePrintException("腾讯云OSS上传文件失败");
        }finally {
            transferManager.shutdownNow();
        }
    }

    private  String getObjectName(String fileName) {
        return imApplication.getUploadFolder() + "/" + fileName;
    }

    public  TransferManager createTransferManager() {
        // 创建一个 COSClient 实例,这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient();
        // 自定义线程池大小,建议在客户端与 COS 网络充足(例如使用腾讯云的 CVM,同地域上传 COS)的情况下,设置成16或32即可,可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况,建议减小该值,避免因网速过慢,造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);

        // 传入一个 threadpool, 若不传入线程池,默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);
        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别为 5MB 和 1MB
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(5*1024*1024);
        transferManagerConfiguration.setMinimumUploadPartSize(1*1024*1024);
        transferManager.setConfiguration(transferManagerConfiguration);

        return transferManager;
    }


    public  COSClient createCOSClient(){
        // 1 初始化用户身份信息(secretId, secretKey)。
        COSCredentials cred = new BasicCOSCredentials(imApplication.getUploadAccessKey(), imApplication.getUploadSecretKey());
        // 2 设置 bucket 的地域, COS 地域的简称请参见 https://cloud.tencent.com/document/product/436/6224
        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(imApplication.getUploadEndpoint());
        ClientConfig clientConfig = new ClientConfig(region);
        // 这里建议设置使用 https 协议
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        return cosClient;
    }


}

使用方式

new TencentOssManager(imApplication).doUpload(file.getBytes(),fileName)

五、整合上传

    @PostMapping(value="doUpload")
    @ApiOperation(value="上传文件")
    public Result doUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletResponse response) throws Exception {
        ImUser loginUser = getLoginUser();
        ImApplication imApplication = imApplicationService.getImApplication(loginUser.getAppId());
        if(BaseUtil.isEmpty(imApplication.getUploadType())){
            throw new NonePrintException("您暂未配置存储空间,请先前往127.0.0.1配置");
        }
        response.addHeader("Access-Control-Allow-Origin", "*");
        if(file.isEmpty()){
            throw new NonePrintException("100","上传文件为空,请先选择需要上传的文件");
        }
        return addResult(ImUploadUtil.doUploadFile(file,imApplication,loginUser));
    }

@Slf4j
public class ImUploadUtil {

    public static FileMedia doUploadFile(CommonsMultipartFile file, ImApplication imApplication, ImUser loginUser) throws Exception {
        String fileHash = UploadUtil.calculateFileHash(file);
        FileMedia existMedia = UploadUtil.existFile(fileHash);
        if(BaseUtil.isNotEmpty(existMedia)){
            return existMedia;
        }
        String fileFileName = file.getOriginalFilename();
        //上传的图片的类型
        String fileType = fileFileName.substring(fileFileName.lastIndexOf(".") + 1).toLowerCase();
        long fileSize = file.getSize();
        //1、检查文件类型
        String type = getWeixinFileType(fileType);
        String msg = verifyFile(fileType, fileSize, type);
        if(msg != null){
            log.error("uploadFile 验证文件错误"+msg);
            throw new NonePrintException("103",msg);
        }
        String newFileName = UUID.randomUUID().toString().replace("-", "").toLowerCase();
        String imagePath = null;
        FileMedia media = new FileMedia();
        media.setUploadType(imApplication.getUploadType());
        if(imApplication.getUploadType()==0){//七牛
            QiniuPutRet putRet = new QiNiuManager(imApplication).upload(file.getBytes(),newFileName+"."+fileType);
            imagePath = putRet.getKey();
        }else if(imApplication.getUploadType()==1){//腾讯oss
            imagePath = new TencentOssManager(imApplication).doUpload(file.getBytes(),newFileName+"."+fileType);
        }else if(imApplication.getUploadType()==2){//阿里oss
            imagePath = new AliOssManager(imApplication).doUpload(file.getBytes(),newFileName+"."+fileType);
        }else{
           throw new NonePrintException("暂未配置存储");
        }
        if (BaseUtil.isEmpty(imagePath)) {
            throw new NonePrintException("104","上传失败");
        }
        media.setId(newFileName);
        media.setType(type);
        media.setSourceType(0);
        media.setUrl(imApplication.getUploadFilePath()+File.separator+imagePath);
        media.setFileSize((int)fileSize);
        media.setFileName(fileFileName);
        media.setCreatePerson(loginUser.getId());
        media.setCreateTime(new Date());
        media.setStatus(0);
        media.setUpdateTime(new Date());
        media.setFileExt(fileType.toUpperCase());
        media.setFileSizeStr(convertFileSize(fileSize));
        media.setSort(System.currentTimeMillis());
        saveMedia(media);
        return media;
    }

    public static void saveMedia(FileMedia media) throws IOException, NonePrintException {
        UploadService uploadService = SpringContextUtil.getApplicationContext().getBean("FileMediaService", UploadService.class);
        uploadService.insert(media);
    }

    public static boolean isImagesFile(String fileType) {
        if(BaseUtil.isEmpty(fileType)) {
            return false;
        } else {
            String[] fileTypes = new String[]{"jpg", "png", "gif", "bmp", "tif", "jpeg"};
            for(int i = 0; i < fileTypes.length; ++i) {
                if(fileType.equalsIgnoreCase(fileTypes[i])) {
                    return true;
                }
            }
            return false;
        }
    }

    public static String verifyFile(String fileType, long size, String type) {
        /*if("image".equals(type)){
            if (size > Configuration.UPLOAD_IMAGE_MAX) {
                return "上传失败,图片文件不能超过" + Configuration.UPLOAD_IMAGE_MAX/1048576 + "M";
            }
        }
        else if("voice".equals(type)){
            if (size > Configuration.UPLOAD_VOICE_MAX) {
                return "上传失败,声音文件不能超过" + Configuration.UPLOAD_VOICE_MAX/1048576 + "M";
            }
        }
        else if("video".equals(type)){
            if (size > Configuration.UPLOAD_VIDEO_MAX) {
                return "上传失败,视频文件不能超过" + Configuration.UPLOAD_VIDEO_MAX/1048576 + "M";
            }
        }
        else{
            if (size > Configuration.UPLOAD_FILE_MAX) {
                return "上传失败,上传文件不能超过" + Configuration.UPLOAD_FILE_MAX/1048576 + "M";
            }
        }*/
        return null;
    }

    private static File multipartToFile(CommonsMultipartFile multfile) throws IOException {
        String path = getProjectPath()+ "/"+multfile.getOriginalFilename();// 设定文件保存的目录
        File f = new File(path);
        File fileParent = f.getParentFile();
        if(!fileParent.exists()){
            fileParent.mkdirs();
        }
        multfile.transferTo(f);
        return f;
    }

    public static String getWeixinFileType(String fileType) {
        fileType = fileType.toLowerCase();
        //图片
        if(isImagesFile(fileType)){
            return "image";
        }
        if("amr".equals(fileType)){
            return "voice";
        }
        if("mp4".equals(fileType)||"flv".equals(fileType)||"mov".equals(fileType)||"avi".equals(fileType) ||"wmv".equals(fileType) || "ts".equals(fileType) || "mpg".equals(fileType)){
            return "video";
        }
        return "file";
    }

    public static String getProjectPath() {
        java.net.URL url = UploadUtil.class .getProtectionDomain().getCodeSource().getLocation();
        String filePath = null ;
        try {
            filePath = java.net.URLDecoder.decode (url.getPath(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (filePath.indexOf(".jar")>-1) {
            int startint=0;
            if(filePath.indexOf("file:")>-1) {
                startint =   filePath.indexOf("file:") + 5 ;
            }

            filePath = filePath.substring(startint, filePath.lastIndexOf(".jar"));
            filePath = filePath.substring(0, filePath.lastIndexOf("/") + 1);
        }
        File file = new File(filePath);
        filePath = file.getAbsolutePath();
        if(filePath.lastIndexOf("\")>=0){
            return filePath.substring(0,filePath.lastIndexOf("\"));
        }else{
            return filePath.substring(0,filePath.lastIndexOf("/"));
        }
    }

    public static String convertFileSize(long filesize){
        String strUnit="Bytes";
        String strAfterComma="";
        int intDivisor=1;
        if(filesize>=1073741824){
            strUnit = "G";
            intDivisor=1073741824;
        }
        else if(filesize>=1048576){
            strUnit = "M";
            intDivisor=1048576;
        }
        else if(filesize>=1024){
            strUnit = "K";
            intDivisor=1024;
        }
        if(intDivisor==1) return filesize + " " + strUnit;
        strAfterComma = "" + 100 * (filesize % intDivisor) / intDivisor ;
        if(strAfterComma=="") strAfterComma=".0";
        return filesize / intDivisor + "." + strAfterComma + " " + strUnit;
    }


}

FileMedia 为项目保存到数据库的记录,不需要保留的话 直接删除代码返回链接即可

public class FileMedia {
    private String id;
    private Date createTime;
    private String createPerson;
    private String type;
    private Integer sourceType;
    private String url;
    private Integer fileSize;
    private String fileName;
    private Integer status;
    private Date updateTime;
    private String fileExt;
    private String fileSizeStr;
    private Long sort;
    private Integer uploadType;
}