文件存储
简介:
文件上传是指,将本地图片,视频等文件上传到服务器,供其他用户浏览或下载的过程
文件上传在项目中应用非常广泛,我们经常发微博,发微信朋友圈都使用到了文件上传功能
文件上传前端三要素:
①必须要有file表单项
②表单提交方式为post
③表单的编码格式必须设置为(enctype):multipart/form-data
如果是默认值的情况下会提交文件名,不会提交文件内容
<form action="/upload" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="username"><br>
年龄:<input type="text" name="age"><br>
头像:<input type="file" name="image"><br>
<input type="submit" value="提交"><br>
</form>
后端接收:
①后端接收前端传来的文件使用MultipartFile类型的参数进行接收
②如果参数名与前端的name值属性不同时使用@requestparam进行注解
@postMapping("upload")
public Result upload(String name,@requestparam("image") MultipartFile image){
log.info("文件上传:{},{}",username,image);
return Result.success();
}
本地存储:
在服务器端接收到上传上来的文件后,将文件存储在本地服务器的磁盘中
@postMapping("upload")
public Result upload(String name,@requestparam("image") MultipartFile image)throws Exception
{
log.info("文件上传:{},{}",username,image);
/*
String imagename=image.getOrignalFilename();
将文件存储在E盘下面,动态拼接防止文件名重复
但是任然具有重复风险,如果文件名重复后面的文件会覆盖前面的文件
image.transferto(new File("E:\\image\\"+imagename)); */
int index=imagename.lastIndexOf(".");
String extname=imagename.substring(index);
String newimagename=UUID.randomUUID().toString+extname;
image.transferto(new File("E:\\image\\"+newimagename));
return Result.success();
}
UUID识别码:
UUID(Universally Unique Identifier,通用唯一识别码)是一种用于唯一标识信息的技术。它旨在确保在分布式系统中,每个实体(如文件、记录、用户等)都有一个全球唯一的标识符,从而避免命名冲突和混淆。
UUID的组成
UUID通常由32个十六进制数字组成,分为五组,并用四个连字符(-)分隔,形如:550e8400-e29b-41d4-a716-446655440000
。这种格式使得UUID易于阅读和复制。
UUID的版本
UUID根据其生成算法和用途的不同,分为多个版本。常见的版本包括:
-
版本1:基于时间和节点(通常是MAC地址)生成,可能会泄露生成UUID的机器的标识信息。
-
版本3:基于名字的散列值生成,需要提供一个命名空间(UUID)和一个名字。
-
版本4:完全基于随机数生成,是UUID中最常用和推荐用于大多数情况的版本,因为它不依赖于外部信息,具有更高的灵活性和安全性。
-
版本5:类似于版本3,但使用SHA-1散列算法而不是MD5。
UUID的用途
UUID在多个领域有广泛的应用,包括但不限于:
-
数据库:作为主键或唯一索引,确保每条记录的唯一性。
-
文件系统:为文件或目录分配唯一标识符,便于管理和访问。
-
Web应用:生成唯一的会话ID、令牌等,用于身份验证、授权和跟踪用户活动。
-
分布式系统:在分布式系统中唯一标识节点、服务或消息等。
许多编程语言和框架都提供了生成UUID的工具或库。例如,在Java中可以使用java.util.UUID
类,在Python中可以使用uuid
模块,在JavaScript中可以使用crypto.randomUUID()
方法等。
总之,UUID是一种强大且灵活的工具,可以帮助我们在分布式系统和其他领域中实现唯一标识的需求。然而,在使用UUID时也需要考虑其可能带来的缺点,如长度和可读性问题,并根据具体应用场景选择合适的UUID版本和生成工具。
对象存储
常见的对象存储服务
-
阿里云OSS:阿里云提供的对象存储服务,具有高可用性、高扩展性和低成本等特点。
-
亚马逊S3:亚马逊提供的对象存储服务,是全球最流行的对象存储解决方案之一。
-
腾讯云COS:腾讯云提供的对象存储服务,支持多种存储类型和访问方式。
-
华为云OBS:华为云提供的对象存储服务,适用于多种应用场景和存储需求。
对象存储OSS(Object Storage Service)是阿里云提供的海量、安全、低成本、高持久的云存储服务。其数据设计持久性不低于99.9999999999%(12个9),服务设计可用性不低于99.995%。OSS具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据
对象存储OSS提供标准、低频访问、归档和冷归档四种存储类型,全面覆盖从热到冷的各种数据存储场景。
-
标准存储类型
高持久、高可用、高性能的对象存储服务,支持频繁的数据访问。是各种社交、分享类的图片、音视频应用、大型网站、大数据分析的合适选择。
-
低频访问存储类型
适合长期保存不经常访问的数据(平均每月访问频率1到2次)。存储单价低于标准类型,适合各类移动应用、智能设备、企业数据的长期备份,支持实时数据访问。
-
归档存储类型
适合需要长期保存(建议半年以上)的归档数据,在存储周期内极少被访问,数据进入到可读取状态需要1分钟的解冻时间。适合需要长期保存的档案数据、医疗影像、科学资料、影视素材。
-
冷归档存储类型
适合需要超长时间存放的极冷数据。例如因合规要求需要长期留存的数据、大数据及人工智能领域长期积累的原始数据、影视行业长期留存的媒体资源、在线教育行业的归档视频等。
对象存储OSS的关键概念
-
Bucket(存储桶):存储桶是对象存储OSS中的基本存储单元,用于存储对象的容器。每个存储桶都有唯一的名称和地域属性。
-
Object(对象):对象是存储桶中的存储单元,由数据本身、元数据(如对象键、大小、修改时间等)和唯一标识符组成。
-
Access Key(访问密钥):用于访问和控制OSS资源的凭证,包括Access Key ID和Access Key Secret。
-
ACL(访问控制列表):用于控制对存储桶和对象的访问权限,可以设置不同用户或用户组的读写权限。
入门:
①在阿里云OSS(对象存储服务)的上下文中,ENDPOINT
是指访问OSS服务的网络地址。每个Bucket都有其对应的Endpoint,它决定了您如何通过网络连接到该Bucket。Endpoint通常由协议(如http
或https
)、Bucket所在的区域(如cn-hangzhou
)以及OSS服务的域名(如aliyuncs.com
)组成。
例如,如果您在华东1(杭州)区域创建了一个Bucket,那么该Bucket的Endpoint可能会类似于 https://oss-cn-hangzhou.aliyuncs.com
。这个Endpoint是您进行OSS操作(如上传、下载文件)时需要用到的网络地址。
②ACCESS_KEY_ID
是阿里云提供的一种身份验证机制中的一部分,用于访问阿里云的各种服务,包括对象存储服务(OSS)。它是阿里云账户下的一个访问密钥对的一部分,另一个部分是 ACCESS_KEY_SECRET
。
ACCESS_KEY_ID
和 ACCESS_KEY_SECRET
共同组成了一个访问密钥对,用于API级别的身份验证。当您使用阿里云的SDK或API来访问OSS或其他服务时,您需要提供这对密钥来进行身份验证,以确保只有授权的用户才能访问和操作您的资源。
③BUCKET_NAME
在阿里云对象存储服务(OSS)中指的是您创建的用于存储对象(如文件、图片等)的容器名称。每个Bucket都有一个全局唯一的名称,用于标识和访问存储在该Bucket中的对象。
当您使用阿里云OSS时,您需要创建一个或多个Bucket来组织和管理您的存储对象。BUCKET_NAME
是您在创建Bucket时指定的名称,它必须符合阿里云的命名规范,例如:
-
名称长度在3到63个字符之间。
-
只能包含小写字母、数字和短横线(-)。
-
不能以短横线开头或结尾。
-
在整个OSS范围内必须全局唯一。
④PutObjectRequest
对象封装了上传请求的所有必要信息,包括Bucket名称、对象键名和要上传的文件。然后,通过调用 ossClient.putObject(putObjectRequest)
方法来执行上传操作。
执行成功后,putObjectResult
对象将包含有关上传操作的结果信息,例如ETag(一个用于验证对象完整性的唯一标识符)。如果上传失败,将抛出异常,您可以在 catch
块中处理这些异常。
修改pom文件,添加相关的依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version> <!-- 请使用最新版本 -->
</dependency>
public class AliOssTest {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "oss-cn-shanghai.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "";
String accessKeySecret = "";
// 填写Bucket名称,例如examplebucket。
String bucketName = "";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 设置该属性可以返回response。如果不设置,则返回的response为空。
putObjectRequest.setProcess("true");
// 创建PutObject请求。
PutObjectResult result = ossClient.putObject(putObjectRequest);
// 如果上传成功,则返回200。
System.out.println(result.getResponse().getStatusCode());
} 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();
}
}
}
}
集成:
@Slf4j
@RestController
public class UploadController {
@Autowired
private AliOSSUtils aliOSSUtils;
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
//调用阿里云OSS工具类,将上传上来的文件存入阿里云
String url = aliOSSUtils.upload(image);
//将图片上传完成后的url返回,用于浏览器回显展示
return Result.success(url);
}
}
AliOssUtil工具类:
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
* 文件上传
*
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} 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();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}