懒人系列--文件上传之OSS使用案例

Posted Huterox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了懒人系列--文件上传之OSS使用案例相关的知识,希望对你有一定的参考价值。

文章目录


.

前言

又到了愉快的水文时间了,那么今天的带来的是如何使用第三放服务去愉快完成文件的上传服务。问题来了,为啥我们需要去使用第三方的文件存储服务咧,貌似是没有这个需求哇。其实呢这个咋说呢,确实是需要结合具体的业务情况来说的。一般情况下,如果我们只是做一个很简单的xx系统,例如学生管理系统这样的玩意,如果是这样的玩意的话,那么我们直接去上传到我们的服务器也是可以的,一般情况下最简单的方案就是:


当然也有最直接的就是直接把文件也存到数据库里面,但是对于数据库来说并不是很友好,当然这个也是一种解决方案。
但是这里有一个问题啊,那就是来一个文件我们就进行存储,先不讨论个别朋友喜欢XSS。咱们就说如果用户上传的内容,例如用户上传一张图片作为头像,然后咱们直接保存,之后展示出来别的用户也可以看到那么,如果用户上传的图片不符合社会主义核心价值观怎么处理,那么这样一来我们就需要做一个图片过滤,那么这样一来,一方面是服务器成本的上升,另一方面是技术问题,我们可能需要训练一个CNN 或者ViTranformer模型用户文件过滤而且这个还只是针对图片的,实际上我们还有文本什么的,那么有需要设计出一套方案,之后再结合文件存储技术,这样做基本上是比较困难的、而且不是dome级别的设计。 所以这个时候我们就需要使用到第三方的存储服务了。

此外还有一个问题就是,假设我们什么都不考虑,包括什么文件过滤,只要把文件存好就行,例如开发一个某sex网站,那么一样的随着流量的增大,考虑分布式架构的时候,服务当中的文件数据并不是互通的,因此也需要一个专门的文件存储服务来做这些事情,然后又回到了刚刚的问题,只是可能不需要文件审核服务。

所以当我们需要做一个网站并且需要允许并展示用户上传的内容时,我们就需要用到功能更加强大的文件存储服务,并且这个服务我们可以选择自己搭建,但是前期的成本太高,而且不符合“懒人“设定,因此我们就需要使用到第三放服务来玩玩了。

那么今天的博文就是使用第三方的文件存储服务进行操作,这里是以图片的存储为例子。并且完成,图片的过滤,也就是安全内容审核。

环境准备

这里由于咱们都是使用SpringCloud Alibaba 所以的话,这边咱们的第三方组件也是使用阿里云的服务,因为有直接的支持嘛,那么我们这边就是使它的OSS,对象存储服务。
首先就是导入咱们的依赖,我这里是按照Alibaba的文档来的,但是它的文档是老版本的,也就是SpringCloud Alibaba 的版本还是2.1.x 的时候的,所以为了方便我这里还是返回了2.1.0 release 版本。

那么如果你还是2.2.6的话,那么如果你要导入的话,那么就这样导入:

<dependencies>
	<!--阿里云OSS-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>aliyun-oss-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
        </dependency>
</dependencies>

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>aliyun-spring-boot-dependencies</artifactId>
                <version>1.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

当然如果你是按照了我的博文来的搭建的环境的话,直接像官方文档一样,先把SpringCloud Alibaba 的版本改为2.1.0 release

然后再像官方文档一样:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</dependency>

阿里云服务开通

OSS服务开通

那么现在我们要做的就是开通服务,然后拿到这些东西:

进入阿里云,找到OSS服务,然后开通一下,之后的话我们可以见到这个:

之后的话,先创建一个bucket,这里的话注意设置为公开的权限就好了。

之后的话,你就可以看到你的这个玩意了,这个玩意相当于分组:


之后我们回到刚刚的页面,我们创建一个Accesskey


记住一定要保存好,因为之后那个对应的密码是看不到的。

之后是赋予权限,这个就看你自己的了。
我这里是这个:

之后:

跨域

由于之后我们需要让前端上传文件,所以的话我们需要去配置跨越:


如果不配的话,就会这样:

我们用示例代码测试一下:

之后我们可以在控制台看到文件上传成功:

那么到这里的话我们的服务是开通完了。

但是我们还需要有信息过滤。

内容安全服务

之后就是俺们的第二个内容,我们找到内容安全服务,然后开通之后到这个页面:

绑定好我们的OSS。然后配置服务。

我们去创建增量或者是存量扫描,你只需要去填写配置就好了。

之后我们去测试一下:

我们通过特殊手段获取了一张用于测试的图像

并且回到OSS存储中,你可以发现两个文件的属性已经发生了改变。

到此我们的服务是开通完了。

上传实现

接下来我们来看看上传的实现吧。参照官方文档:

我们使用授权访问的策略

也就是这样

那么我们这边捏是这样的

这个文档里面也有,我这边直接给代码了:

后端授权服务


/**
 * 对象存储
 */
@RestController
public class OssController 
    @Autowired
    OSS ossClient;

    @Value("$spring.cloud.alicloud.oss.endpoint")
    private String endpoint;
    @Value("$spring.cloud.alicloud.oss.bucket")
    private String bucket;
    @Value("$spring.cloud.alicloud.access-key")
    private String accessId;

    /**
     * Oss 获取服务端签名
     * @return
     */
    @RequestMapping("/oss/policy")
    public R policy() 

        // https://gulimall-hello.oss-cn-beijing.aliyuncs.com/hahaha.jpg  host的格式为 bucketname.endpoint
        String host = "https://" + bucket + "." + endpoint;
        // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
        // String callbackUrl = "http://88.88.88.88:8888";
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        // 用户上传文件时指定的前缀。
        String dir = format + "/";

        Map<String, String> respMap = null;
        try 
            long expireTime = 600;
            long expireEndTime = System.currentTimeMillis() + expireTime * 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);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));

         catch (Exception e) 
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        

        return R.ok().put("data", respMap);
    


这里 的话,因为服务还没做好,所以的话,后面的保存URL我们是没有做的。

前端代码

单文件上传

这个咱们是直接使用vue+axios+elementui 来做的。

<template>
  <div>
    <el-upload
      :action="dataObj.host"
      :data="dataObj"
      list-type="picture"
      :multiple="false" :show-file-list="showFileList"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :on-remove="handleRemove"
      :on-success="handleUploadSuccess"
      :on-preview="handlePreview">
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="fileList[0].url" alt="">
    </el-dialog>
  </div>
</template>
<script>
import getUUID from "./uuid";
import axios from "_axios@0.26.1@axios";
export default 
  name: 'singleUpload',
  props: 
    value: String
  ,
  computed: 
    imageUrl() 
      return this.value;
    ,
    imageName() 
      if (this.value != null && this.value !== '') 
        return this.value.substr(this.value.lastIndexOf("/") + 1);
       else 
        return null;
      
    ,
    fileList() 
      return [
        name: this.imageName,
        url: this.imageUrl
      ]
    ,
    showFileList: 
      get: function () 
        return this.value !== null && this.value !== ''&& this.value!==undefined;
      ,
      set: function (newValue) 
      
    
  ,
  data() 
    return 
      dataObj: 
        policy: '',
        signature: '',
        key: '',
        ossaccessKeyId: '',
        dir: '',
        host: '',
        // callback:'',
      ,
      dialogVisible: false
    ;
  ,
  methods: 
    emitInput(val) 
      this.$emit('input', val)
    ,
    handleRemove(file, fileList) 
      this.emitInput('');
    ,
    handlePreview(file) 
      this.dialogVisible = true;
    ,
    beforeUpload(file) 
      let _self = this;
      return new Promise((resolve, reject) => 
        axios
          .get('/third-part/oss/policy')
          .then(response => 
            response = response.data;
            _self.dataObj.policy = response.data.policy;
            _self.dataObj.signature = response.data.signature;
            _self.dataObj.ossaccessKeyId = response.data.accessid;
            _self.dataObj.key = response.data.dir +getUUID()+"_$filename";
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            resolve(true);
          )
          .catch(function (error) 
            reject(false);
          )
      );
    ,
    handleUploadSuccess(res, file) 
      console.log("数据获取为",this.dataObj)
      console.log("上传成功...")
      this.showFileList = true;
      this.fileList.pop();
      this.fileList.push(
        
          name: file.name,
          url: this.dataObj.host + '/' + this.dataObj.key.replace("$filename",file.name)

        
      );
      this.emitInput(this.fileList[0].url);
    
  

</script>
<style>

</style>

多文件上传

<template>
  <div>
    <el-upload
      :action="dataObj.host"
      :data="dataObj"
      :list-type="listType"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :on-remove="handleRemove"
      :on-success="handleUploadSuccess"
      :on-preview="handlePreview"
      :limit="maxCount"
      :on-exceed="handleExceed"
      :show-file-list="showFile"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="dialogImageUrl" alt />
    </el-dialog>
  </div>
</template>
<script>
import getUUID from "./uuid";
import axios from 'axios'
export default 
  name: "multiUpload",
  props: 
    //图片属性数组
    value: Array,
    //最大上传图片数量
    maxCount: 
      type: Number,
      default: 10
    ,
    listType:
      type: String,
      default: "picture-card"
    ,
    showFile:
      type: Boolean,
      default: true
    

  ,
  data() 
    return 
      dataObj: 
        policy: 以上是关于懒人系列--文件上传之OSS使用案例的主要内容,如果未能解决你的问题,请参考以下文章

猿创征文|技术成长之路-Java编程系列之文件OSS存储实践:Amazon S3实现文件上传下载

thinkphp集成系列之阿里云oss

thinkphp集成系列之阿里云oss

文件上传之oss服务器上传文件简笔

文件上传之oss服务器上传文件简笔

Android图片上传到阿里云OSS小案例