阿里云oss文件上传(简单上传、服务端签名后直传)

前置:

自行开通阿里oss服务:

https://www.aliyun.com/product/oss?spm=a2c4g.11174283.J_8058803260.125.d9387da2TjNfP6

oss API:

https://help.aliyun.com/document_detail/32013.html?spm=a2c4g.11186623.6.956.65694697WhZebu

 一、简单的文件上传:

依赖:

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

 测试代码:

    @Test
    public void testOssUPLoad() throws Exception{
        // Endpoint以杭州为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-guangzhou.aliyuncs.com";
        // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。
        // 强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
        //LTAI4GKxxxxxekn2ZYLxab
        //9XnhRAnlxxxxxxTDMLpMxGLoQx6r
        String accessKeyId = "LTAI4GKxxxxxekn2ZYLxab";
        String accessKeySecret = "9XnhRAnlxxxxxxTDMLpMxGLoQx6r";
        String bucketName = "xxxx-oos-images";
        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
        String objectName = "C:\\Users\\Administrator\\Downloads\\6555c4f8ffa80914bc51b798e4a6dce6.jpeg";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        //以每天一个文件夹保存上传的文件(文件名称自行优化)
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String content = format+"/Hello OSS.jpeg";
        // 上传文件到指定的存储空间(bucketName)并将其保存为指定的文件名称(objectName)。
        ossClient.putObject(bucketName, content, new FileInputStream(objectName));

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

 二、使用spring-cloud-starter-alicloud-oss对文件直传进行改善

 2.1、starter用2.2.0RELEASE 如果使用依赖管理的默认2.2.3RELEASE则无法启动

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

 如果上边的starter依赖有冲突(启动失败)可以使用下边的依赖替换上边的依赖试试:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>aliyun-oss-spring-boot-starter</artifactId>
    <version>1.0.0</version>
    <exclusions>
	<exclusion>
	    <groupId>com.aliyun</groupId>
	    <artifactId>aliyun-java-sdk-oss</artifactId>
	</exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.5.7</version>
</dependency>

补充:项目使用的版本如下:(没有版本问题可不看)

    //1.spring boot 版本

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

   //2、spring cloud 以及spring cloud alibaba 版本,版本可以在properties里标注也直接在 
   //dependencyManagement 表明

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

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

 

2.2、配置OSS

spring:
  application:
    name: xxxx
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    alicloud:
      access-key: LTAI4GKzxxxxekn2ZYLxab
      secret-key: 9XnhRAxxxxxxxxxxxxxxxxxxLpMxGLoQx6r
      oss:
        endpoint: xxxxxxxxxxxxxxxxxxxxxxxx
server:
  port: 30000

2.3、测试

    //注入OSSClient
    @Autowired
    OSSClient ossClient;

    @Test
    void contextLoads() throws Exception {


        String objectName =     "C:\\Users\\Administrator\\Downloads\\6555c4f8ffa80914bc51b798e4a6dce6.jpeg";

        String bucketName = "xxx-oss-images";
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String content = format+"/ss335OSS.jpeg";

        ossClient.putObject(bucketName, content, new FileInputStream(objectName));

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

}

 

三、服务端签名后直传

阿里文档:

https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1738.442534f3qJ9Nb7

1、依赖(依赖版本同上 二)


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

2、配置

spring:
  cloud:
    alicloud:
      access-key: LTAI4xxxxxxxZYLxab
      secret-key: 9XnxxxxxxxxxxxxxxxxxxxxxGLoQx6r
      oss:
        endpoint: xxxxxxxxxxxxxxxxxxxxxx
        ## 自定义添加的属性
        bucket: mybucket

2、代码

@RestController
@RequestMapping("thirdparty/oss")
public class OSSController {
    @Autowired
    OSS ossClient;//这里不能写OSSClient,因为容器总注入的是OSS,而不是其OSSClient实现,可以参看OssContextAutoConfiguration

    @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;


    @RequestMapping("/policy")
    public R ossUpload() {
        // 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 = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);

            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            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("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);//阿里oss服务提供的签名
            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());
        } finally {
            ossClient.shutdown();
            return R.ok().put("data", respMap);
        }

    }

}

到这里可以使用idea自带的REST client 先测试后端是否可以正常获取到签名。

获取到的信息如下:

3、前端代码或者参考阿里提供的原生客户端:(https://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/86983/APP_zh/1537971352825/aliyun-oss-appserver-js-master.zip?spm=a2c4g.11186623.2.10.74c47403C0rJnK&file=aliyun-oss-appserver-js-master.zip

3.1异步获取签名

src/components/upload/policy.js文件如下:这里对异步方法axios进行了封装(自行使用原生axios或者ajax进行替换即可)

import http from '@/utils/httpRequest.js'
export function policy() {
   return  new Promise((resolve,reject)=>{
        http({
            url: http.adornUrl("/thirdparty/oss/policy"),
            method: "get",
            params: http.adornParams({})
        }).then(({ data }) => {
            resolve(data);
        })
    });
}

 3.2vue+element组件提供的上传组件

src/components/upload/singleUpload.vue文件如下

<template> 
  <div>
    <el-upload
      action="https://xxxxxx这里填 阿里oss提供 Bucket域名"
      :data="dataObj"
      list-type="picture"
      :multiple="false" 
      :show-file-list="showFileList"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :on-remove="handleRemove"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadFail"
      :on-preview="handlePreview">
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
    </el-upload>
    <!-- file-list上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}] -->
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="fileList[0].url" alt="">
    </el-dialog>
  </div>
</template>
<script>
   import {policy} from './policy'
   import { getUUID } from '@/utils'//uuid,随便自定义即可

  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: {
      handleUploadFail(){
          console.log("文件上传失败!!");
      },
      emitInput(val) {
        //this.$emit('input', val) 的意思是出发input事件(自定义事件也可以),val为input事件的参数
        this.$emit('input', val)
      },
      handleRemove(file, fileList) {
        this.emitInput('');
      },
      handlePreview(file) {
        this.dialogVisible = true;
      },
      //上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
      beforeUpload(file) {
        console.log(`文件详情:`,file);
        let _self = this;
        return new Promise((resolve, reject) => {
          policy().then(response => {
            _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.key = response.data.dir + getUUID()+file.name;//这样也是可以的
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            resolve(true)
          }).catch(err => {
            reject(false)
          })
        })
      },
      handleUploadSuccess(res, file) {
        //此代码用于文件上传完毕后,返回图片地址给
        //<single-upload v-model="dataForm.logo"></single-upload>
        console.log("上传成功...")
        this.showFileList = true;
        this.fileList.pop();//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>


 

3.3 测试组件test.vue

<template>
    <!-- 使用单文件上传组件 -->
    <single-upload v-model="image"></single-upload>  
</template>

<script>
import SingleUpload from "@/components/upload/singleUpload";
export default {
  data() {
    return {};
  },
  components: {
    SingleUpload,
  },
}

</script>

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值