最近在用 vue3 + springboot 做项目,需要将图片存储到第三方OSS服务,我选择了熟悉的七牛云,并打算换一种上传方式,以前都是将文件发给业务服务器,由业务服务器上传文件给七牛云。这次我选择使用前端直传,就是前端发起上传请求,请求业务服务器并获取上传凭证,然后带着上传凭证等参数,直接上传文件到七牛云对象存储服务器
这样做的好处是减轻了服务器的压力,业务服务器不需要上传文件,只需要负责给客户端颁发上传凭据,获取文件链接并保存到数据库中。大致步骤如下:
一、前端选择要上传的文件,将要上传的文件的文件名发送给后端,后端收到文件名后生成上传凭证(前端代码略,这里主要展示后端代码)
在配置文件中配置密钥、bucket等信息
oss:
accessKey: yourAccessKey
secretKey: yourSecretKey
bucket: yourBucket
domain: yourDomain
新建配置类,使用注解@ConfigurationProperties(value = "oss")读取配置文件
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(value = "oss")
@Data
public class OssProperties {
private String accessKey;
private String secretKey;
private String bucket;
private String domain;
}
controller代码
@RestController
@RequestMapping("/...")
public class OssController {
private final OssProperties ossProperties;
public OssController(OssProperties ossProperties) {
this.ossProperties = ossProperties;
}
/**
* 获取上传凭证
*/
@PostMapping("/policy/{fileName}")
public Result getPolicyByQiNiuYun(@PathVariable("fileName") String fileName){
String accessKey = ossProperties.getAccessKey();
String secretKey = ossProperties.getSecretKey();
LocalDate localdate = LocalDate.parse(LocalDate.now().toString());
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String key = localdate.format(dtf) + "/" + fileName;
String bucket = ossProperties.getBucket();
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket, key);
MyPutRet put = new MyPutRet();
put.setKey(key);
put.setToken(upToken);
return Result.success(put);
}
}
二、前端得到key和token后,开始上传文件,上传成功后七牛云会返回key和hash
由于这里是前端直传,所以没有涉及后端代码
/**
* 上传文件
*/
export function uploadFileApi(
file: File,
token: string,
key: string
): AxiosPromise<HashAndKey> {
const formData = new FormData();
formData.append("file", file);
formData.append("token", token);
formData.append("key", key);
return request({
url: "http://upload-z0.qiniup.com",
method: "post",
data: formData,
headers: {
"Content-Type": "multipart/form-data",
},
});
}
七牛云给我们返回的这个key其实和第一步中后端代码中的key是一样的,都是路径+文件名
三、前端带着第二步返回的key向后端业务服务器发送请求,后端生成文件的url地址返回给前端
前端
/**
* 获取文件 url
*/
export function getDownloadUrl(key: KeyParam): AxiosPromise<string> {
return request({
url: "/third-party/oss/downloadUrl",
method: "get",
params: key,
});
}
后端 controller
/**
* 获取文件下载url
*/
@GetMapping("/downloadUrl")
public Result getDownloadUrl(@RequestParam("key") String key){
// domain 用户 bucket 绑定的下载域名 eg: mock.qiniu.com【必须】
// useHttps 是否使用 https【必须】
// key 下载资源在七牛云存储的 key【必须】
DownloadUrl url = new DownloadUrl(ossProperties.getDomain(), false, key);
String urlString = null;
try {
urlString = url.buildURL();
} catch (QiniuException e) {
throw new RuntimeException("buildURL Error");
}
return Result.success(urlString);
}
注意:只有七牛云的空间为公开才可以像我这样直接拼接生成url,如果是私有空间需要携带 token 请求七牛云获取文件下载链接,具体查看七牛云的开发文档