1、 搭建fastDFS文件服务器
1)安装fastDFS tracker和storage
2)在storage server上安装nginx
在storage server上安装nginx的目的是对外通过http访问storage server上的文件。
使用nginx的模块FastDFS-nginx-module,它的作用是通过http方式访问storage中的文件,当storage本机没有要
找的文件时向源storage主机代理请求文件。
3)在安装图片服务代理
图片服务代理的作用是负载均衡,根据storage server的负载情况将图片浏览请求均匀的转发到storage server
上。
2、搭建文件管理服务
文件管理服务提供通过http方式上传文件,删除文件、查询文件的功能,管理员通过文件管理服务对文件服务器上
的文件进行管理。
文件管理服务采用Spring Boot开发,文件管理服务通过与fastDFS交互最终将用户上传的文件存储到fastDFS上。
在fastDFS入门程序上继续开发:
package com.shuang.fastdfs.controller;
import com.shuang.fastdfs.FileSystem;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
@RequestMapping("/filesystem")
public class FileServerController {
@Value("${fastdfs.upload_location}")
private String upload_location;
@PostMapping("/upload")
public FileSystem upload(@RequestParam("file") MultipartFile multipartFile) throws IOException {
// 将文件先存储在web服务器上(本机),在调用fastDFS的客户端将文件上传到fastDFS服务器
FileSystem fileSystem = new FileSystem();
// 得到文件的原始名称
String originalFilename = multipartFile.getOriginalFilename();
// 文件扩展名,也就是文件后缀 从“.”的位置开始取
String extention = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileNameNew = UUID.randomUUID()+extention;
// 定义file,使用file存储上传的文件
File file = new File(upload_location+fileNameNew);
multipartFile.transferTo(file);
// 获取新文件上传的物理路径
String newFilePath = file.getAbsolutePath();
try {
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 tc = new TrackerClient();
TrackerServer ts = tc.getConnection();
// 场景storage客户端
StorageServer ss = tc.getStoreStorage(ts);
StorageClient1 sc1 = new StorageClient1(ts, ss);
// 文件元信息
NameValuePair[] meta_list = new NameValuePair[1];
meta_list[0] = new NameValuePair("fileName",originalFilename);
// 执行上传,将上传成功的存在再web服务器(本机)上的文件上传到fastDFS
String fileid;
// 注意 extention这里设置为null,因为fastDFS会自动帮我们匹配文件拓展名,如果自己在添加一个就会多个点
fileid = sc1.upload_file1(newFilePath, extention, meta_list);
fileSystem.setFileId(fileid);
fileSystem.setFilePath(fileid);
fileSystem.setFileName(originalFilename);
// 通过调用service及dao将文件的路径存储到数据库中
// ...
System.out.println("Upload local file " + newFilePath + " ok, fileid=" + fileid);
ts.close();
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return null;
}
}
yml配置文件
server:
port: 22100
fastdfs:
# 文件上传临时目录
upload_location: D:\\upload\\
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 192.***.***.7:22122
3、前端
管理员通过管理系统前端上传文件、查询文件、删除文件等操作。
管理系统前端与文件管理服务器通过http交互,这当前流行的前后端分离的架构。
管理系统前端采用当前浏览器的vue.js前端框架实现。
这里注意几个小细节
我们使用了element-ui组件库的文件上传
1、ation是我们文件要上传的路径,也就是我们用springboot搭建的后端接收路径,这是个前后端分离的操作,所以后端要实现跨域可以在springboot的控制器类名前添加@CrossOrigin,或者通过nginx做代理进行映射
2、在el-upload 的内置属性:on-preview 通过回调函数会传一个file,这个file里面有个属性response包含了我们走通过action指定的路径返回结果
3、使用element-ui的el-upload组件会有一个图片回显的效果,同样是内置属性:on-preview 绑定的回调函数,通过双向数据绑定,在file.response.filePath中绑定路径,路径为远程虚拟机+fastDFS返回的fileId,而且必须在nginx设置了指定fastDFS映射路径才可以访问到图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试文件上传-图片</title>
</head>
<link rel="stylesheet" href="css/el/index.css"/>
<script src="js/vue/vue.min.js"></script>
<script src="css/el/index.js"></script>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--ation 是文件接收路径 -->
<el-upload
action="http://localhost:22100/filesystem/upload"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
</body>
</html>
<script>
const app = new Vue({
el: "#app",
data: {
msg: "1",
dialogImageUrl: '',
dialogVisible: false
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePictureCardPreview(file) {
console.log(file)
this.dialogImageUrl = "http://192.***.***.7/"+file.response.filePath;
this.dialogVisible = true;
}
},
computed: {},
components: {}
});
</script>
4、测试