流程介绍

在这里插入图片描述和数据直传到OSS相比,以上方法有三个缺点:

  • 上传慢:用户数据需先上传到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用户数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。而且OSS采用BGP带宽,能保证各地各运营商之间的传输速度。
  • 扩展性差:如果后续用户多了,应用服务器会成为瓶颈。
  • 费用高:需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器。

技术方案

目前通过Web前端技术上传文件到OSS,有三种技术方案:

  • 利用OSS Browser.js SDK将文件上传到OSS

    该方案通过OSS Browser.js SDK直传数据到OSS,详细的SDK Demo请参见上传文件。在网络条件不好的状况下可以通过断点续传的方式上传大文件。该方案在个别浏览器上有兼容性问题,目前兼容IE10及以上版本浏览器,主流版本的Edge、Chrome、Firefox、Safari浏览器,以及大部分的Android、iOS、WindowsPhone手机上的浏览器。更多信息请参见安装Browser.js SDK。
    使用表单上传方式,将文件上传到OSS

  • 利用OSS提供的PostObject接口,使用表单上传方式将文件上传到OSS。该方案兼容大部分浏览器,但在网络状况不好的时候,如果单个文件上传失败,只能重试上传。操作方法请参见PostObject上传方案。

  • 通过小程序上传文件到OSS

  • 通过小程序,如微信小程序和支付宝小程序,利用OSS提供的PostObject接口来实现表单上传。操作方式请参见微信小程序直传实践和支付宝小程序直传实践。

一、开通“对象存储OSS”服务

为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS。

1、开通“对象存储OSS”服务

在这里插入图片描述
在这里插入图片描述

二、控制台使用

1、创建Bucket

命名:srb-file
读写权限:公共读

2、上传默认头像

创建文件夹avatar,上传默认的用户头像
在这里插入图片描述

三、使用RAM子用户

1、进入子用户管理页面

在这里插入图片描述
在这里插入图片描述

2、添加用户

在这里插入图片描述

3、获取子用户key

AccessKeyId, AccessKeySecret

4、设置用户权限

授权:AliyunOSSFullAccess
在这里插入图片描述

四、落地实现

1、创建模块

service-oss

2、配置pom.xml

<dependencies>

    <dependency>
        <groupId>com.atguigu</groupId>
        <artifactId>service-base</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!--lombok用来简化实体类:需要安装lombok插件-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <!--aliyunOSS-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
    </dependency>

    <!-- 日期工具栏依赖 -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>

    <!--让自定义的配置在application.yaml进行自动提示-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

3、配置application.yml

server:
  port: 8130 # 服务端口

spring:
  profiles:
    active: dev # 环境设置
  application:
    name: service-oss # 服务名

aliyun:
  oss:
    endpoint: 你的endponit
    keyId: 你的阿里云keyid
    keySecret: 你的阿里云keysecret
    bucketName: srb-file

五、实现文件上传

1、从配置文件读取常量

  • 创建常量读取工具类:OssProperties.java
package com.atguigu.srb.oss.util;

@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class OssProperties implements InitializingBean {

    private String endpoint;
    private String keyId;
    private String keySecret;
    private String bucketName;

    public static String ENDPOINT;
    public static String KEY_ID;
    public static String KEY_SECRET;
    public static String BUCKET_NAME;

    //当私有成员被赋值后,此方法自动被调用,从而初始化常量
    @Override
    public void afterPropertiesSet() throws Exception {
        ENDPOINT = endpoint;
        KEY_ID = keyId;
        KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
    }
}

2、文件上传业务

  • 创建Service接口:FileService.java
package com.atguigu.srb.oss.service;

import java.io.InputStream;

public interface FileService {

    /**
     * 文件上传至阿里云
     */
    String upload(InputStream inputStream, String module, String fileName);

    /**
     * 文件移除
     * @param url
     */
    void removeFile(String url);
}

  • 实现:FileServiceImpl.java
package com.atguigu.srb.oss.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CannedAccessControlList;
import com.atguigu.srb.oss.service.FileService;
import com.atguigu.srb.oss.util.OssProperties;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService {

    @Override
    public String upload(InputStream inputStream, String module, String fileName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(
                OssProperties.ENDPOINT,
                OssProperties.KEY_ID,
                OssProperties.KEY_SECRET);

        // 判断BUCKET_NAME是否存在
        if(!ossClient.doesBucketExist(OssProperties.BUCKET_NAME)){
            ossClient.createBucket(OssProperties.BUCKET_NAME);
            ossClient.setBucketAcl(OssProperties.BUCKET_NAME, CannedAccessControlList.PublicRead);
        }

        // 上传文件流。
        // 文件目录结构 "avatar/2021/02/27/uuid.jpg"
        //构建日期路径
        String timeFolder = new DateTime().toString("/yyyy/MM/dd/");
        //文件名生成
        fileName = UUID.randomUUID().toString() + fileName.substring(fileName.lastIndexOf("."));
        String key = module + timeFolder + fileName;
        ossClient.putObject(OssProperties.BUCKET_NAME, key, inputStream);

        // 关闭OSSClient。
        ossClient.shutdown();

        //文件的url地址
        //https:// bucketname   .  endpoint / + key
        return "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/" + key;
    }

    @Override
    public void removeFile(String url) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(
                OssProperties.ENDPOINT,
                OssProperties.KEY_ID,
                OssProperties.KEY_SECRET);

        // https://srb-file-200921.oss-cn-beijing.aliyuncs.com/
        // test/2021/02/27/f1673221-efb4-4356-98f4-9f0595caa927.jpg
        String host = "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/";
        String objectName = url.substring(host.length());

        // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
        ossClient.deleteObject(OssProperties.BUCKET_NAME, objectName);

        // 关闭OSSClient。
        ossClient.shutdown();
    }
}

3、控制层

  • 创建controller.admin:FileController.java
package com.atguigu.srb.oss.controller.api;


import com.atguigu.common.exception.BusinessException;
import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.srb.oss.service.FileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;

@Api(tags = "阿里云文件管理")
@CrossOrigin //跨域
@RestController
@RequestMapping("/api/oss/file")
public class FileController {

    @Resource
    private FileService fileService;

    @ApiOperation("文件上传")
    @PostMapping("/upload")
    public R upload(
            @ApiParam(value= "文件", required = true)
            @RequestParam("file") MultipartFile file,

            @ApiParam(value = "模块", required = true)
            @RequestParam("module") String module){

        try {
            InputStream inputStream = file.getInputStream();
            String originalFilename = file.getOriginalFilename();
            String url = fileService.upload(inputStream, module, originalFilename);

            return R.ok().message("文件上传成功").data("url", url);
        } catch (IOException e) {
           throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e);
        }
    }

    @ApiOperation("删除oss文件")
    @DeleteMapping("/remove")
    public R remove(
            @ApiParam(value = "要删除的文件", required = true)
            @RequestParam("url") String url){
        fileService.removeFile(url);
        return R.ok().message("删除成功");
    }
}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐