操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。
常见的文件系统:FAT16/FAT32、NTFS、HFS、UFS、APFS、XFS、Ext4等 。
分布式文件系统(Distributed File System,DFS)
是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点(可简单的理解为一台计算机)相连;或是若干不同的逻辑磁盘分区或卷标组合在一起而形成的完整的有层次的文件系统。
DFS为分布在网络上任意位置的资源提供一个逻辑上的树形文件系统结构
,从而使用户访问分布在网络上的共享文件更加简便。
单独的 DFS共享文件夹的作用是相对于通过网络上的其他共享文件夹的访问点。
分布式文件系统
中的数据存储在多台机器上,这些专门用来存储数据的机器称之为存储节点
,由多个节点构成分布式集群
,节点上的小的分布式文件系统组合成总的分布式文件系统
,由主服务器对总的文件系统进行管理。用户任意访问某一台主机,都能获取到自己想要的目标文件。
分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经满足不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,另外我们还要做好数据备份、数据安全等。
采用分布式文件系统可以将多个地点的文件系统通过网络连接起来,组成一个文件系统网络,结点之间通过网络进行通信,一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算
共同传输。
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。
FastDFS是用c语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。
FastDFS专为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
FastDFS 系统有三个角色:跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client)。
NFS、GFS都是通用的分布式文件系统,通用的分布式文件系统
的优点
的是开发体验好
,但是系统复杂性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高
。
fastDFS非常适合存储图片等那些小文件
,fastDFS不对文件进行分块,所以它就没有分块合并的开销,fastDFS网络通信采用socket,通信速度很快。
FastDFS特点:
FastDFS架构包括 Tracker server和Storageserver。
客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。
1)Tracker
Tracker Server作用是负载均衡和调度
,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。
可以将tracker称为追踪服务器或调度服务器。
FastDFS集群中的Tracker server可以有多台,Tracker server之间是相互平等关系同时提供服务,Tracker server不存在单点故障。
客户端请求Tracker server采用轮询
方式,如果请求的tracker无法提供服务则换另一个tracker。
2)Storage
Storage Server作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的文件系统而是使用操作系统的文件系统来管理文件。可以将storage称为存储服务器
。
Storage集群采用了分组存储方式。storage集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,组内的Storage server之间是平等关系,不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的。一个组的存储容量为该组内存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。
采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由tracker进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。
3)Storage状态收集
Storage server会连接集群中所有的Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。
客户端上传文件后存储服务器
将文件ID
返回给客户端,此文件ID用于以后访问该文件的索引信息。
文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。
group1 /M00 /02/44/ wKgDrE34E8wAAAAAAAAGkEIYJK42378.sh
tracker根据请求的文件路径即文件ID 来快速定义文件。比如请求下边的文件:
详见:https://blog.csdn.net/qq_45740503/article/details/136086731
参考官方文档java版本的fastdfs-client地址在:https://github.com/happyfish100/fastdfs-client-java,参考此工程编写测试用例。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<groupId>com.orange</groupId>
<artifactId>fastDFSLearn01</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--fastdfs-client-java依赖需要自己手动打包上传到本地仓库-->
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.31-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>
在classpath:config下创建fastdfs-client.properties文件
## fastdfs-client.properties
#fastDFS连接超时时间,针对socket套接字函数connect
connect_timeout_in_seconds = 5
#fastDFS网络超时时间
network_timeout_in_seconds = 30
#编码格式
charset = UTF-8
#是否启用token验证(针对fdfs配置文件/etc/fdfs/http.conf,防盗链)
http_anti_steal_token = false
#连接密钥(http.conf要配置一样的密钥)
http_secret_key = FastDFS1234567890
#tracker服务器访问端口
http_tracker_http_port = 80
#tracker服务器地址,多个以逗号隔开
fastdfs.tracker_servers = 192.168.229.141:22122
/**
* 在此文件中通过fastDSF的client代码访问tracker和storage
* 通过client的api代码方便 访问 tracker和storage,它们中间走的socket协议
*/
public class TestFastDFSUpload {
//测试文件上传
@Test
public void Upload() {
//通过fastDSF的client代码访问tracker和storage
try {
//加载fastDFS客户端的配置 文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
//通过TrackerClient对象获取TrackerServer信息
//1.29版本以前的方法
//TrackerServer trackerServer = trackerClient.getConnection();
//没有trackerClient.getConnection()方法的问题解决
//1.29版本以后的fastdfs的方法更新
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
//每次调用的时候会重新new一个StorageClient()实例,这样每次请求拿到的就是不同的StorageClient,
//也就意味着每个请求会获取到不同的storageServer,这样就不存在共享变量,也就避免了出现并发的空指针问题
//最好的解决方案就是每次调用的时候new一个新的实例去使用。在使用FastDFS的时候,尽量不要重用StorageClient
//参考文章:https://blog.csdn.net/luckykapok918/article/details/80938257
//定义storage的客户端,建立与Storage服务器的连接
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
//文件元信息
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName", "52.png");
String path = "D:\\image\\52.png";
//执行上传
String fileInfoes = storageClient.upload_file1(path, "png", metaList);
System.out.println("upload success. file id is: " + fileInfoes);
//关闭storage客户端
storageClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
network_timeout=30000ms
charset=UTF-8
upload success. file id is: group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png
Process finished with exit code 0
cd /home/fastdfs/fdfs_storage/data/00/00
http://192.168.229.141/group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png
public class TestFastDFSQuery {
//测试文件查询
@Test
public void Query() {
//通过fastDSF的client代码访问tracker和storage
try {
//加载fastDFS客户端的配置 文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
//通过TrackerClient对象获取TrackerServer信息
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
//定义storage的客户端,建立与Storage服务器的连接
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
//查询文件
//upload success. file id is: group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png
String group_name = "group1";
String remoteFileName = "M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png";
String file_id = "group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png";
FileInfo fileInfo = storageClient.query_file_info(group_name, remoteFileName);
System.out.println(fileInfo);
FileInfo fileInfo1 = storageClient.query_file_info1(file_id);
System.out.println(fileInfo1);
//查询文件元信息
NameValuePair[] metadata = storageClient.get_metadata1(file_id);
for (NameValuePair pair : metadata) {
System.out.println("文件元信息 : " + pair.getName() + " ," + pair.getValue());
}
//关闭storage客户端
storageClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
network_timeout=30000ms
charset=UTF-8
fetch_from_server = true, file_type = 1, source_ip_addr = 192.168.229.141, file_size = 372928, create_timestamp = 2024-02-10 12:55:07, crc32 = -743583210
fetch_from_server = true, file_type = 1, source_ip_addr = 192.168.229.141, file_size = 372928, create_timestamp = 2024-02-10 12:55:07, crc32 = -743583210
文件元信息 : fileName ,52.png
Process finished with exit code 0
public class TestFastDFSDownload {
//测试文件下载
@Test
public void Download() {
//通过fastDSF的client代码访问tracker和storage
try {
//加载fastDFS客户端的配置 文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
//通过TrackerClient对象获取TrackerServer信息
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
//定义storage的客户端,建立与Storage服务器的连接
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
//查询文件
//upload success. file id is: group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png
String group_name = "group1";
String remoteFileName = "M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png";
String file_id = "group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png";
FileInfo fileInfo = storageClient.query_file_info(group_name, remoteFileName);
System.out.println("fileInfo = " + fileInfo);
if (fileInfo == null) {
System.out.println("您下载的文件信息不存在,请核对后再次下载......");
return;
}
byte[] bytes = storageClient.download_file1(file_id);
File file = new File("D:\\image\\a.png");
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.close();
//关闭storage客户端
storageClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
network_timeout=30000ms
charset=UTF-8
fileInfo = fetch_from_server = true, file_type = 1, source_ip_addr = 192.168.229.141, file_size = 372928, create_timestamp = 2024-02-10 12:55:07, crc32 = -743583210
Process finished with exit code 0
public class TestFastDFSDelete {
//测试文件删除
@Test
public void Delete() {
try {
//加载fastDFS客户端的配置 文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
//通过TrackerClient对象获取TrackerServer信息
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
//定义storage的客户端,建立与Storage服务器的连接
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
//查询文件
//upload success. file id is: group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png
String group_name = "group1";
String remoteFileName = "M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png";
String file_id = "group1/M00/00/00/wKjljWXHAauARHa2AAWwwNOt0hY257.png";
FileInfo fileInfo = storageClient.query_file_info(group_name, remoteFileName);
System.out.println("fileInfo = " + fileInfo);
if (fileInfo == null) {
System.out.println("您删除的文件信息不存在,请核对后再次删除......");
return;
}
storageClient.delete_file1(file_id);
System.out.println("删除成功");
//关闭storage客户端
storageClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
network_timeout=30000ms
charset=UTF-8
fileInfo = fetch_from_server = true, file_type = 1, source_ip_addr = 192.168.229.141, file_size = 372928, create_timestamp = 2024-02-10 12:55:07, crc32 = -743583210
删除成功
Process finished with exit code 0
network_timeout=30000ms
charset=UTF-8
java.io.IOException: recv body length: 70 is not correct, expect length: 40
at org.csource.fastdfs.ProtoCommon.recvHeader(ProtoCommon.java:186)
at org.csource.fastdfs.ProtoCommon.recvPackage(ProtoCommon.java:201)
at org.csource.fastdfs.TrackerClient.getStoreStorage(TrackerClient.java:130)
at org.csource.fastdfs.StorageClient.newWritableStorageConnection(StorageClient.java:1627)
at org.csource.fastdfs.StorageClient.do_upload_file(StorageClient.java:639)
at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:120)
at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:91)
at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:73)
at org.csource.fastdfs.StorageClient1.upload_file1(StorageClient1.java:64)
server 端使用 V6.11,fastdfs-clint-java需要使用最新的 V1.31
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.31-SNAPSHOT</version>
</dependency>
FastDFS java下载官网:https://github.com/happyfish100/fastdfs-client-java
源码及本人打包好的jar包:https://www.lanzv.com/b05ew922f 密码:deca
mvn -version
mvn clean install
mvn install:install-file -DgroupId=org.csource -DartifactId=fastdfs-client-java -Dversion=${version} -Dpackaging=jar -Dfile=fastdfs-client-java-${version}.jar
执行以下命令:【具体版本,路径按实际修改】
mvn install:install-file -DgroupId="org.csource" -DartifactId=fastdfs-client-java -Dversion="1.31-SNAPSHOT" -Dpackaging=jar -Dfile="D:\FastDFS-java\fastdfs-client-java-1.31\target\fastdfs-client-java-1.31-SNAPSHOT.jar"
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.31-SNAPSHOT</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<groupId>com.orange</groupId>
<artifactId>fastDFSLearn01</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--fastdfs-client-java依赖需要自己手动打包上传到本地仓库-->
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.31-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>
fastdfs-client.properties
## fastdfs-client.properties
#fastDFS连接超时时间,针对socket套接字函数connect
connect_timeout_in_seconds = 5
#fastDFS网络超时时间
network_timeout_in_seconds = 30
#编码格式
charset = UTF-8
#是否启用token验证(针对fdfs配置文件/etc/fdfs/http.conf,防盗链)
http_anti_steal_token = false
#连接密钥(http.conf要配置一样的密钥)
http_secret_key = FastDFS1234567890
#tracker服务器访问端口
http_tracker_http_port = 80
#tracker服务器地址,多个以逗号隔开
fastdfs.tracker_servers = 192.168.229.141:22122
@Configuration
public class CrossConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")// 对所有路径应用跨域配置,所有的当前站点的请求地址,都支持跨域访问。
//是否发送Cookie
.allowCredentials(true)
//放行哪些原始域
.allowedHeaders("*")
.allowedMethods("POST", "GET", "HEAD", "PUT", "OPTIONS", "DELETE")
.allowedOriginPatterns("*")// 所有的外部域都可跨域访问。
// 如果是localhost则很难配置,因为在跨域请求的时候,外部域的解析可能是localhost、127.0.0.1、主机名
.maxAge(3600);// 超时时长设置为1小时。 时间单位是秒。
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FileSystem {
private String fileId;
private String filePath;
private Long fileSize;
private String fileName;
private String fileType;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg; //响应信息 描述字符串
private Object data; //返回的数据
//增删改 成功响应
public static Result success(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
@Slf4j
@RestController
@RequestMapping("/filesystem")
public class FileServerController {
@Value("${orange-fastdfs.upload_location}")
private String upload_location;
@PostMapping("/uploadFile")
@ResponseBody
public Result upload(@RequestParam("file") MultipartFile file) throws IOException {
//将文件先存储在web服务器上(本机),在调用fastDFS的client将文件上传到 fastDFS服务器
FileSystem fileSystem = new FileSystem();
//文件原始名称
String originalFilename = file.getOriginalFilename();
//文件扩展名比如22.jpg
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
log.info("文件扩展名后缀 = {}", extension);//.jpg
String filenameExtension = StringUtils.getFilenameExtension(originalFilename);
log.info("文件类型 = {}", filenameExtension);//jpg
if (filenameExtension == null) {
return Result.error("此文件没有文件扩展名");
}
//新文件名称
String fileName = UUID.randomUUID().toString().replace("-", "") + "." + filenameExtension;
log.info("新文件名称 = {}", fileName);
//定义file,使用file存储上传的文件
//File file1 = new File("D:\\image\\upload\\" + fileName);
File file1 = new File(upload_location + fileName);
//指定照片上传路径,上传的文件写入到新的文件
file.transferTo(file1);
//获取新上传文件的物理路径
String newFilePath = file1.getAbsolutePath();
//通过fastDSF的client代码访问tracker和storage
try {
//加载fastDFS客户端的配置 文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
//通过TrackerClient对象获取TrackerServer信息
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
//定义storage的客户端,建立与Storage服务器的连接
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
//文件元信息
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName", "52.png");
//执行上传
String fileId = storageClient.upload_file1(newFilePath, filenameExtension, metaList);
System.out.println("upload success. file id is: " + fileId);
fileSystem.setFileId(fileId);
fileSystem.setFilePath(fileId);
fileSystem.setFileName(originalFilename);
fileSystem.setFileSize(file.getSize());
fileSystem.setFileType(filenameExtension);
//通过调用service及dao将文件的路径存储到数据库中
//关闭storage客户端
storageClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return Result.success(fileSystem);
}
}
@Slf4j
@RestController
@RequestMapping("/filesystem")
public class FileServerController {
@PostMapping("/uploadFile")
@ResponseBody
public Result upload(@RequestParam("file") MultipartFile file) throws IOException {
//将文件先存储在web服务器上(本机),在调用fastDFS的client将文件上传到 fastDFS服务器
FileSystem fileSystem = new FileSystem();
String contentType = file.getContentType();
log.info("上传的文件类型为:{}", contentType);
byte[] file_buff = null;
//把文件转成输入流
InputStream inputStream = file.getInputStream();
if (inputStream != null) {
//获取输入流中可读取的数据大小
int len = inputStream.available();
//创建足够大的缓冲区
file_buff = new byte[len];
//一次性把输入流中的数据全都读入到缓冲区file_buff,那file_buff就要足够大,占用内存也会很大
inputStream.read(file_buff);
}
//关闭输入流
inputStream.close();
//文件原始名称
String originalFilename = file.getOriginalFilename();
//文件扩展名比如22.jpg
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
log.info("文件扩展名后缀 = {}", extension);//.jpg
String filenameExtension = StringUtils.getFilenameExtension(originalFilename);
log.info("文件类型 = {}", filenameExtension);//jpg
if (filenameExtension == null) {
return Result.error("此文件没有文件扩展名");
}
//通过fastDSF的client代码访问tracker和storage
try {
//加载fastDFS客户端的配置 文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
//通过TrackerClient对象获取TrackerServer信息
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
//定义storage的客户端,建立与Storage服务器的连接
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
//文件元信息
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName", "52.png");
//执行上传
String fileId = storageClient.upload_file1(file_buff, filenameExtension, metaList);
System.out.println("upload success. file id is: " + fileId);
fileSystem.setFileId(fileId);
fileSystem.setFilePath(fileId);
fileSystem.setFileName(originalFilename);
fileSystem.setFileSize(file.getSize());
fileSystem.setFileType(contentType);
//通过调用service及dao将文件的路径存储到数据库中
//关闭storage客户端
storageClient.close();
} catch (Exception e) {
log.error("上传文件失败:", e);
e.printStackTrace();
}
return Result.success(fileSystem);
}
}
server:
port: 22100
orange-fastdfs:
#文件上传临时目录
upload_location: D:\\image\\upload\\
# linux临时文件目录
# mkdir -p /data/tmp/updatefile
spring:
servlet:
multipart:
location: /data/tmp/updatefile
@SpringBootApplication
public class FileServerApplication {
public static void main(String[] args) {
SpringApplication.run(FileServerApplication.class, args);
}
}
vue-axios|axios中文网:http://www.axios-js.com/zh-cn/docs/vue-axios.html
axios官网:https://www.axios-http.cn/docs/intro
npm install --save axios vue-axios
//报错时使用--legacy-peer-deps
npm install --save axios vue-axios --legacy-peer-deps
#在入口文件main.js中配置
//引入vue
import Vue from 'vue'
//引入axios
import axios from 'axios'
//引入VueAxios
//安装VueAxios模块后,不需要在每个组件中单独导入axios,只需将axios请求改为this.axios
import VueAxios from 'vue-axios'
//把axios挂载到vue上
Vue.prototype.$axios = axios;
//使用Vue.use来注册安装插件
Vue.use(VueAxios, axios)
new Vue({
el:'#app',
render: h => h(App),
})
按照这个顺序分别引入这三个文件: vue, axios and vue-axios
# 在入口文件main.js中配置
//引入Vue
import Vue from 'vue'
//引入axios
import axios from 'axios'
//把axios挂载到vue上
Vue.prototype.$axios = axios
new Vue({
el:'#app',
render: h => h(App),
})
# 第三步:使用案例
this.$axios.get('/user?id=888').then((response) => {
console.log(response.data)
}).catch( (error) => {
console.log(error);
});
#在入口文件main.js中配置
//引入Vue
import Vue from 'vue'
//引入axios
import axios from 'axios'
//引入VueAxios
import VueAxios from 'vue-axios'
//使用Vue.use来注册安装插件
Vue.use(VueAxios, axios)
new Vue({
el:'#app',
render: h => h(App),
})
#第三步:使用方式有如下三种
#方式1
Vue.axios.get(api).then((response) => {
console.log(response.data)
})
#方式2
this.axios.get(api).then((response) => {
console.log(response.data)
})
#方式3
this.$http.get(api).then((response) => {
console.log(response.data)
})
#在入口文件main.js中配置
//关闭Vue的生产提示
Vue.config.productionTip = false
新建一个router文件夹,在文件夹下新建一个index.js文件
Vue2使用v.3x
Vue Router官网【v3.x】:https://v3.router.vuejs.org/zh/
更新记录【3.x】https://github.com/vuejs/vue-router/releases
//报错时使用--legacy-peer-deps
//vue-router@3x 适用于 vue2
npm install vue-router@3
//指定版本号
npm install vue-router@3.5.2 --save
#在入口文件main.js中配置
//引入VueRouter
import VueRouter from 'vue-router'
//使用Vue.use来注册安装插件
Vue.use(VueRouter)
//新建一个router文件夹,在文件夹下新建一个index.js文件
//引入路由器
import router from './router/index'
// 创建和挂载根实例
new Vue({
router, //将路由器注入到new Vue实例中,建立关联
render: h => h(App),
}).$mount('#app');
ElementUI组件库官网:https://element.eleme.cn/#/zh-CN
npm i element-ui -S
//完整引入
//引入ElementUI组件库
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//使用ElementUI组件库
Vue.use(ElementUI)
import App from './App.vue'
//引入Vue
import Vue from 'vue'
//引入axios
import axios from 'axios'
//引入VueAxios
//安装VueAxios模块后,不需要在每个组件中单独导入axios,只需将axios请求改为this.axios
import VueAxios from 'vue-axios'
//引入VueRouter
import VueRouter from 'vue-router'
//完整引入
//引入ElementUI组件库
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
//新建一个router文件夹,在文件夹下新建一个index.js文件
//引入路由器
import router from './router/index'
//把axios挂载到vue上
Vue.prototype.$axios = axios;
//使用Vue.use来注册安装插件
Vue.use(VueRouter)
Vue.use(router)
Vue.use(VueAxios, axios)
//使用ElementUI组件库
Vue.use(ElementUI)
//关闭Vue的生产提示
Vue.config.productionTip = false
// 创建和挂载根实例
new Vue({
router, //将路由器注入到new Vue实例中,建立关联
render: h => h(App),
}).$mount('#app');
<template>
<div>
<el-form>
<el-form-item label="上传图片">
<el-upload
list-type="picture-card"
:multiple="false"
:action="uploadUrl"
:limit="1"
:on-success="onUploadSuccessIdCard"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "UploadImg",
data() {
return {
dialogImageUrl: "",
file_id: "",
dialogVisible: false,
uploadUrl: "http://localhost:22100/filesystem/uploadFile", //文件上传地址
datas: {},
};
},
methods: {
onUploadSuccessIdCard(response) {
this.file_id = response.data.fileId;
this.datas = response.data;
this.dialogImageUrl = "http://192.168.229.141/" + response.data.filePath;
},
},
};
</script>
<style scoped>
</style>
<template>
<div id="app">
<HelloWorld />
<!-- 导航链接 -->
<!-- 路由内容展示 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
<style>
</style>
//在路由文件router/index.js中配置
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import UploadImg from '@/components/UploadImg'//上传页
//创建路由
const routes = [
//定义路由
{
path: '/',
name: 'UploadImg',
component: UploadImg
},
]
//创建并暴露一个路由器
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
npm rn serve
vue-axios|axios中文网:http://www.axios-js.com/zh-cn/docs/vue-axios.html
axios官网:https://www.axios-http.cn/docs/intro
npm install --save axios vue-axios
//报错时使用--legacy-peer-deps
npm install --save axios vue-axios --legacy-peer-deps
#在入口文件main.js中配置
import { createApp } from 'vue'
import App from './App.vue'
//引入axios
import axios from 'axios'
//引入VueAxios
//安装VueAxios模块后,不需要在每个组件中单独导入axios,只需将axios请求改为this.axios
import VueAxios from 'vue-axios'
const app = createApp(App);
//使用Vue.use来注册安装插件
app.use(VueAxios, axios)
app.mount('#app')
//createApp(App).mount('#app')
按照这个顺序分别引入这三个文件: vue, axios and vue-axios
#在入口文件main.js中配置
//关闭Vue的生产提示
app.config.productionTip = false
新建一个router文件夹,在文件夹下新建一个index.js文件
Vue3使用v.4x
Vue Router官网【v4.x】:https://router.vuejs.org/zh/
更新记录【4.x】https://github.com/vuejs/router/releases
//vue-router4x 适用于 vue3
npm install vue-router@4
//指定版本号
npm install vue-router@4.2.5 --save
import { createApp } from 'vue'
import App from './App.vue'
//引入路由器
import router from './router/index'
const app = createApp(App);
//使用Vue.use来注册安装插件
app.use(router)
app.mount('#app')
Element Plus组件库官网:https://element-plus.gitee.io/zh-CN/
npm install element-plus --save
// main.ts
import { createApp } from 'vue'
//引入Element Plus组件库
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
import { createApp } from 'vue'
import App from './App.vue'
//引入axios
import axios from 'axios'
//引入VueAxios
//安装VueAxios模块后,不需要在每个组件中单独导入axios,只需将axios请求改为this.axios
import VueAxios from 'vue-axios'
//新建一个router文件夹,在文件夹下新建一个index.js文件
//引入路由器
import router from './router/index'
//引入Element Plus组件库
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App);
//关闭Vue的生产提示
app.config.productionTip = false
//使用Vue.use来注册安装插件
app.use(VueAxios, axios)
app.use(router)
app.use(ElementPlus)
app.mount('#app')
<template>
<div>
<el-form>
<el-form-item label="上传图片">
<el-upload
list-type="picture-card"
:multiple="false"
:action="uploadUrl"
:limit="1"
:on-success="onUploadSuccessIdCard"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "UploadImg",
data() {
return {
dialogImageUrl: "",
file_id: "",
dialogVisible: false,
uploadUrl: "http://localhost:22100/filesystem/uploadFile", //文件上传地址
datas: {},
};
},
methods: {
onUploadSuccessIdCard(response) {
this.file_id = response.data.fileId;
this.datas = response.data;
this.dialogImageUrl = "http://192.168.229.141/" + response.data.filePath;
},
},
};
</script>
<style scoped>
</style>
<template>
<div id="app">
<HelloWorld />
<!-- 导航链接 -->
<!-- 路由内容展示 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
<style>
</style>
import { createRouter, createWebHistory } from 'vue-router'
const routerHistory = createWebHistory(process.env.BASE_URL)
import UploadImg from '@/components/UploadImg'
// 定义路由
const routes = [
{
path: '/',
name: 'UploadImg',
component: UploadImg
},
]
// 创建路由器
const router = createRouter({
history: routerHistory,
routes: routes
})
export default router;
npm rn serve