java 使用 阿里云OSS云存储

文章目录

  • 阿里云开通云存储
  • 使用
    • 术语
    • 创建
    • 快速测试上传文件
    • java上传
      • 1 创建子用户
      • 2.1 方法1:(推荐方法2)
        • 步骤
        • 代码
          • pom
          • 上传文件
      • 2.2 方法2:
        • pom 引入依赖
        • yaml
        • 文件上传代码
    • 服务端签名后直传
      • 签名主要内容
      • yaml主要内容:
      • 编写controller,返回签名信息
      • 前端
        • 文件上传的组件:
          • 单文件:
          • 多文件:
          • 从后端获取签名
          • ==跨域问题==

分布式文件存储,浏览器上传的文件,统一存储到一个服务器

本文选择统一存储到云存储

阿里云开通云存储

  • 先贴计费,很便宜
    原文:https://www.aliyun.com/price/product?spm=5176.8465980.help.3.4e701450R42spo#/oss/detail/ossbag
    在这里插入图片描述

  • aliyun官网 - 产品 - oss对象存储
    在这里插入图片描述

  • 开通

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

  • 如果未实名认证,需要认证一下,支付宝认证,约一分钟就可以了

使用

术语

  • 存储空间 Bucket
    存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。
  • 对象/文件 Object
    对象是 OSS 存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。
  • 地域 Region
    地域表示 OSS 的数据中心所在物理位置。您可以根据费用、请求来源等综合选择数据存储的地域。详情请查看OSS已经开通的Region。
  • 访问域名 Endpoint
    Endpoint 表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。具体的内容请参见各个Region对应的Endpoint。
  • 访问密钥 AccessKey
    AccessKey,简称 AK,指的是访问身份验证中用到的AccessKeyId 和AccessKeySecret。OSS通过使用AccessKeyId 和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户,AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret 必须保密。

创建

  • 右侧点创建
    在这里插入图片描述
  • 选项(根据实际需要来选)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

快速测试上传文件

  • 上传,选择文件上传
    在这里插入图片描述
  • 查看图片
    在这里插入图片描述
    访问如下位置网址:
    在这里插入图片描述

java上传

java上传需要先把文件上传到后台,再由后台上传给oss对象存储,自己的服务器也存储了一遍文件,不划算。

服务端签名后上传(本文后面)是指从后台获得签名后直接从前端上传,效率更高。

1 创建子用户

  • 直接通过自己的用户名密码验证是不安全的,创建子用户,并对其授权
  • 网址 https://ram.console.aliyun.com/users
    在这里插入图片描述
  • 如图所示的两个内容相当于用户名密码,要复制下来,一会要用,一会再进来是看不到AccessKey Secret内容的!
    在这里插入图片描述
  • 授权
    1. 先返回
      在这里插入图片描述
    2. 添加权限
      在这里插入图片描述
    3. 添加如下权限
      在这里插入图片描述
    4. 成功
      在这里插入图片描述

2.1 方法1:(推荐方法2)

步骤

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

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

代码

pom
  • 在Maven项目中加入依赖项
    在Maven工程中使用OSS Java SDK,只需在pom.xml中加入相应依赖即可。以3.10.2版本为例,在中加入如下内容:
<dependency><groupId>com.aliyun.ossgroupId><artifactId>aliyun-sdk-ossartifactId><version>3.10.2version>
dependency>
  • 如果使用的是Java 9及以上的版本,则需要添加jaxb相关依赖。添加jaxb相关依赖示例代码如下:
<dependency><groupId>javax.xml.bindgroupId><artifactId>jaxb-apiartifactId><version>2.3.1version>
dependency>
<dependency><groupId>javax.activationgroupId><artifactId>activationartifactId><version>1.1.1version>
dependency>

<dependency><groupId>org.glassfish.jaxbgroupId><artifactId>jaxb-runtimeartifactId><version>2.3.3version>
dependency>
上传文件
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import java.io.File;public class Demo {public static void main(String[] args) throws Exception {// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。String accessKeyId = "yourAccessKeyId";String accessKeySecret = "yourAccessKeySecret";// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = "exampledir/exampleobject.txt";// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。String filePath= "D:\\localpath\\examplefile.txt";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);try {// 创建PutObjectRequest对象。            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。// ObjectMetadata metadata = new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传文件。ossClient.putObject(putObjectRequest);} 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());} 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());} finally {if (ossClient != null) {ossClient.shutdown();}}}
}            

2.2 方法2:

Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
原文:https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample

pom 引入依赖


<dependency><groupId>com.alibaba.cloudgroupId><artifactId>spring-cloud-starter-alicloud-ossartifactId><version>2.2.0.RELEASEversion>
dependency>
  • 附上官方文档的依赖,导入失败
<dependency><groupId>com.alibaba.cloudgroupId><artifactId>aliyun-oss-spring-boot-starterartifactId>
dependency>

yaml

  • 配置accessKeyId, secretAccessKey 和region,获取方法原文有
spring:cloud:alicloud:access-key: xxsecret-key: xxoss:endpoint: xx

文件上传代码

  • 文件上传
    @Resourceprivate OSSClient ossClient;@Testpublic void saveFile() {// 上传// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = "exampledir/exampleobject.txt";ossClient.putObject(new PutObjectRequest(bucketName, objectName, new File("C:\\Users\\AikeTech\\Pictures\\Saved Pictures\\20220223214433.jpg")));System.out.println("上传成功。。。");}

服务端签名后直传

原文:https://help.aliyun.com/document_detail/31926.html
在这里插入图片描述

签名主要内容

{
"accessid":"LTAI5tBDFVar1hoq****",
"host":"http://post-test.oss-cn-hangzhou.aliyuncs.com",
"policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDoyMzoyM1oiLCJjxb25kaXRpb25zIjpbWyJjcb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8i****",
"signature":"VsxOcOudx******z93CLaXPz+4s=",
"expire":1446727949,
"dir":"user-dirs/"
}

Body中的各字段说明如下:

accessid 用户请求的AccessKey ID。

host 用户发送上传请求的域名。

policy用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。详情请参见Post Policy。

signature 对Policy签名后的字符串。详情请参见Post Signature。

expire由服务器端指定的Policy过期时间,格式为Unix时间戳(自UTC时间1970年01月01号开始的秒数)。

dir限制上传的文件前缀。

yaml主要内容:

spring: cloud:alicloud:access-key: xxsecret-key: xxoss:endpoint: xx# 自定义属性bucketbucket: xx
server: port: 30000

编写controller,返回签名信息

@RestController
@Slf4j
public class OssController {@ResourceOSS ossClient;// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。@Value("${spring.cloud.alicloud.access-key}")String accessId ;@Value("${spring.cloud.alicloud.secret-key}")String accessKey ;// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。@Value("${spring.cloud.alicloud.oss.endpoint}")String endpoint ;// 填写Bucket名称,例如examplebucket。@Value("${spring.cloud.alicloud.oss.bucket}")String bucket ;// 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。//String callbackUrl = "https://192.168.0.0:8888";@RequestMapping("/oss/policy")protected R generatePostPolicy() {// 填写Host名称,格式为https://bucketname.endpoint。String host = "https://" + bucket + "." + endpoint;// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");String dir = format.format(new Date())  + "/";//注意,有/Map<String, String> respMap = new LinkedHashMap<String, String>();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.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));//            JSONObject jasonCallback = new JSONObject();
//            jasonCallback.put("callbackUrl", callbackUrl);
//            jasonCallback.put("callbackBody",
//                    "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
//            jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
//            String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
//            respMap.put("callback", base64CallbackBody);} catch (Exception e) {// Assert.fail(e.getMessage());log.info(e.getMessage());} finally {ossClient.shutdown();}return R.ok().put("data", respMap);}
}
  • 其中R是人人开源的类:

    /*** 返回数据** @author Mark sunlightcs@gmail.com*/
    public class R extends HashMap<String, Object> {private static final long serialVersionUID = 1L;public R() {put("code", 0);put("msg", "success");}public static R error() {return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");}public static R error(String msg) {return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);}public static R error(int code, String msg) {R r = new R();r.put("code", code);r.put("msg", msg);return r;}public static R ok(String msg) {R r = new R();r.put("msg", msg);return r;}public static R ok(Map<String, Object> map) {R r = new R();r.putAll(map);return r;}public static R ok() {return new R();}public R put(String key, Object value) {super.put(key, value);return this;}
    }
    
  • 附上原文签名上传代码供参考:(可忽略
    https://help.aliyun.com/document_detail/91868.htm?spm=a2c4g.11186623.0.0.1607c9277SiG3G#concept-ahk-rfz-2fb

    protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。String accessId = "yourAccessKeyId";      String accessKey = "yourAccessKeySecret"; // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "oss-cn-hangzhou.aliyuncs.com"; // 填写Bucket名称,例如examplebucket。String bucket = "examplebucket"; // 填写Host名称,格式为https://bucketname.endpoint。                   String host = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com"; // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。String callbackUrl = "https://192.168.0.0:8888";// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。String dir = "exampledir/"; // 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);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);Map<String, String> 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));JSONObject jasonCallback = new JSONObject();jasonCallback.put("callbackUrl", callbackUrl);jasonCallback.put("callbackBody","filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());respMap.put("callback", base64CallbackBody);JSONObject ja1 = JSONObject.fromObject(respMap);// System.out.println(ja1.toString());response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Methods", "GET, POST");response(request, response, ja1.toString());} catch (Exception e) {// Assert.fail(e.getMessage());System.out.println(e.getMessage());} finally { ossClient.shutdown();}
    }
    

前端

文件上传的组件:

单文件:

singleUpload.vue

<template> <div><el-uploadaction="http://gulimall.oss-cn-shanghai.aliyuncs.com":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 {policy} from './policy'import { getUUID } from '@/utils'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) => {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.dir = response.data.dir;_self.dataObj.host = response.data.host;resolve(true)}).catch(err => {reject(false)})})},handleUploadSuccess(res, file) {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>

action为你的oss对象存储的外网地址,一定要修改!!!
在这里插入图片描述
请确认你的响应体有如下内容,否则修改成自己的
在这里插入图片描述

多文件:

multiUpload.vue

<template><div><el-uploadaction="http://gulimall.oss-cn-shanghai.aliyuncs.com":data="dataObj"list-type="picture-card":file-list="fileList":before-upload="beforeUpload":on-remove="handleRemove":on-success="handleUploadSuccess":on-preview="handlePreview":limit="maxCount":on-exceed="handleExceed"><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 { policy } from "./policy";
import { getUUID } from '@/utils'
export default {name: "multiUpload",props: {//图片属性数组value: Array,//最大上传图片数量maxCount: {type: Number,default: 30}},data() {return {dataObj: {policy: "",signature: "",key: "",ossaccessKeyId: "",dir: "",host: "",uuid: ""},dialogVisible: false,dialogImageUrl: null};},computed: {fileList() {let fileList = [];for (let i = 0; i < this.value.length; i++) {fileList.push({ url: this.value[i] });}return fileList;}},mounted() {},methods: {emitInput(fileList) {let value = [];for (let i = 0; i < fileList.length; i++) {value.push(fileList[i].url);}this.$emit("input", value);},handleRemove(file, fileList) {this.emitInput(fileList);},handlePreview(file) {this.dialogVisible = true;this.dialogImageUrl = file.url;},beforeUpload(file) {let _self = this;return new Promise((resolve, reject) => {policy().then(response => {console.log("这是什么${filename}");_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(err => {console.log("出错了...",err)reject(false);});});},handleUploadSuccess(res, file) {this.fileList.push({name: file.name,// url: this.dataObj.host + "/" + this.dataObj.dir + "/" + file.name; 替换${filename}为真正的文件名url: this.dataObj.host + "/" + this.dataObj.key.replace("${filename}",file.name)});this.emitInput(this.fileList);},handleExceed(files, fileList) {this.$message({message: "最多只能上传" + this.maxCount + "张图片",type: "warning",duration: 1000});}}
};
</script>
<style>
</style>

action为你的oss对象存储的外网地址,一定要修改!!!
在这里插入图片描述
请确认你的响应体有如下内容,否则修改成自己的
在这里插入图片描述

从后端获取签名

policy.js

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);})});
}

url为你从前端获取签名信息的路径,如果不同,请修改
在这里插入图片描述

跨域问题

客户端进行表单直传到OSS时,会从浏览器向OSS发送带有Origin的请求消息。OSS对带有Origin头的请求消息会进行跨域规则(CORS)的验证。因此需要为Bucket设置跨域规则以支持Post方法。

  1. 登录OSS管理控制台。
  2. 单击Bucket列表,然后单击目标Bucket名称。
  3. 在左侧导航栏,选择权限管理 > 跨域设置,然后在跨域设置区域,单击设置。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  4. 规则如下
    在这里插入图片描述
  5. 成功
    在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部