通过Fastdfs进行文件上传服务(文件和图片的统一处理)
1、文件上传简单流程分析图:
2、Fastdfs介绍:
Fastdfs由两个角色组成:
Tracker(集群):调度(帮你找到有空闲的Storage)
Storage(集群):文件存储(帮你保存文件或获取需要的文件)
流程:
1.Storage和tracker 发送心跳连接。
2.客户端请求tracker,tracker调度一个Storage,返回Storage的ip和端口。
3.客户端请求Storage,上传文件。
4.Storage保存文件,生成file_id,并返回。
5.客户端接收到file_id并保存。
3、上传下载流程图:
上传:
下载:
4、Fastdfs上传具体实现步骤:
1. 在服务器上搭建好fastdfs环境:这个由运维人员操作,开发人员无需关心。
2. 在本地maven仓库导入fastdfs的jar包(该jar包在maven中央仓库中没有,无法通过idea自动下载,只能手动导入到本地仓库中去)
jar包下载地址(fastdfs_client_v1.20.jar):https://sourceforge.net/projects/fastdfs/files/Java%20Client%20API%20Library/Java%20Client%20Library%20V1.20%20%28compiled%20by%20JDK%201.6%29/fastdfs_client_v1.20.jar/download?use_mirror=liquidtelecom&download=&failedmirror=jaist.dl.sourceforge.net
导入本地仓库:
在jar包所在的目录打开cmd,然后输入以下命令,执行后即可在maven本地仓库导入jar包并在cmd显示出jar包在仓库中的路径。
mvn install:install-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs -Dversion=1.2 -Dpackaging=jar -Dfile= fastdfs_client_v1.20.jar |
3. 项目中引入
<dependency> <groupId>org.csource.fastdfs</groupId> <artifactId>fastdfs</artifactId> <version>1.2</version> </dependency>
4、项目中引入以下工具类:
fdfs_client.conf 文件(用于保存指向 tracker 的IP+端口(默认)):
tracker_server=172.16.2.274:22122
工具类:
import org.csource.common.NameValuePair; import org.csource.fastdfs.ClientGlobal; import org.csource.fastdfs.StorageClient; import org.csource.fastdfs.StorageServer; import org.csource.fastdfs.TrackerClient; import org.csource.fastdfs.TrackerServer; public class FastDfsApiOpr { public static String CONF_FILENAME = FastDfsApiOpr.class.getResource("/fdfs_client.conf").getFile(); /** * 上传文件 * @param file * @param extName * @return */ public static String upload(byte[] file,String extName) { try { ClientGlobal.init(CONF_FILENAME); TrackerClient tracker = new TrackerClient(); TrackerServer trackerServer = tracker.getConnection(); StorageServer storageServer = null; StorageClient storageClient = new StorageClient(trackerServer, storageServer); NameValuePair nvp [] = new NameValuePair[]{ new NameValuePair("age", "18"), new NameValuePair("sex", "male") }; String fileIds[] = storageClient.upload_file(file,extName,nvp); System.out.println(fileIds.length); System.out.println("组名:" + fileIds[0]); System.out.println("路径: " + fileIds[1]); return "/"+fileIds[0]+"/"+fileIds[1]; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 下载文件 * @param groupName * @param fileName * @return */ public static byte[] download(String groupName,String fileName) { try { ClientGlobal.init(CONF_FILENAME); TrackerClient tracker = new TrackerClient(); TrackerServer trackerServer = tracker.getConnection(); StorageServer storageServer = null; StorageClient storageClient = new StorageClient(trackerServer, storageServer); byte[] b = storageClient.download_file(groupName, fileName); return b; } catch (Exception e) { e.printStackTrace(); return null; } } // @Test // public void testGetFileInfo(){ // try { // ClientGlobal.init(conf_filename); // // TrackerClient tracker = new TrackerClient(); // TrackerServer trackerServer = tracker.getConnection(); // StorageServer storageServer = null; // // StorageClient storageClient = new StorageClient(trackerServer, storageServer); // FileInfo fi = storageClient.get_file_info("group1", "M00/00/00/wKgRcFV_08OAK_KCAAAA5fm_sy874.conf"); // System.out.println(fi.getSourceIpAddr()); // System.out.println(fi.getFileSize()); // System.out.println(fi.getCreateTimestamp()); // System.out.println(fi.getCrc32()); // } catch (Exception e) { // e.printStackTrace(); // } // } // @Test // public void testGetFileMate(){ // try { // ClientGlobal.init(conf_filename); // // TrackerClient tracker = new TrackerClient(); // TrackerServer trackerServer = tracker.getConnection(); // StorageServer storageServer = null; // // StorageClient storageClient = new StorageClient(trackerServer, // storageServer); // NameValuePair nvps [] = storageClient.get_metadata("group1", "M00/00/00/wKgRcFV_08OAK_KCAAAA5fm_sy874.conf"); // for(NameValuePair nvp : nvps){ // System.out.println(nvp.getName() + ":" + nvp.getValue()); // } // } catch (Exception e) { // e.printStackTrace(); // } // } /** * 删除文件 * @param groupName * @param fileName */ public static void delete(String groupName,String fileName){ try { ClientGlobal.init(CONF_FILENAME); TrackerClient tracker = new TrackerClient(); TrackerServer trackerServer = tracker.getConnection(); StorageServer storageServer = null; StorageClient storageClient = new StorageClient(trackerServer, storageServer); int i = storageClient.delete_file(groupName,fileName); System.out.println( i==0 ? "删除成功" : "删除失败:"+i); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("删除异常,"+e.getMessage()); } } }
5、在contorller中使用:
@RestController public class FileController { /** * 文件上传 MultipartFile 是SpringMVC封装好的API方便操作上传的文件的 * @param file * @return */ @PostMapping("/fastdfs") public AjaxResult upload(MultipartFile file){ try { //获取文件的扩展名 String filename = file.getOriginalFilename(); String extName = filename.substring(filename.lastIndexOf(".")+1); String file_id = FastDfsApiOpr.upload(file.getBytes(), extName); return AjaxResult.me().setSuccess(true).setMessage("上传成功!").setRestObj(file_id); } catch (Exception e) { e.printStackTrace(); return AjaxResult.me().setSuccess(false).setMessage("上传失败!"+e.getMessage()); } } /** * 删除文件 * @param file_id * @return */ @DeleteMapping("/fastdfs") public AjaxResult delete(String file_id){ try { // /group1/M00/00/01/rBACgF1euQiAEdrcAACbjnUEnrE193.jpg file_id = file_id.substring(1);// group1/M00/00/01/rBACgF1euQiAEdrcAACbjnUEnrE193.jpg String groupName = file_id.substring(0, file_id.indexOf("/")); String fileName = file_id.substring(file_id.indexOf("/")+1); FastDfsApiOpr.delete(groupName, fileName); return AjaxResult.me().setSuccess(true).setMessage("删除成功!"); } catch (Exception e) { e.printStackTrace(); return AjaxResult.me().setSuccess(false).setMessage("删除失败!"); } } }
5.1控制文件上传的大小
为了解决有些文件因大于默认上传文件大小的而无法上传的问题,可以在网关模块和引用Fastdfs的controller所在的模块的启动类上加上如下代码:
/** * 文件大小上传配置 * @return */ @Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); //单个文件最大 factory.setMaxFileSize("10240KB"); //KB,MB /// 设置总上传数据总大小 factory.setMaxRequestSize("102400KB"); return factory.createMultipartConfig(); }
6、前端页面代码
<el-form-item label="logo"> <el-upload class="upload-demo" action="http://localhost:6001/services/common/fastdfs" :file-list="addForm.logoList" list-type="picture" :on-success="logoUploadSuccess" :before-upload="handleBeforeUpload" :on-remove="handleLogoRemove"> <el-button size="small" type="primary">点击上传</el-button> </el-upload> </el-form-item>
methods: {
handleLogoRemove(file, fileList){
//file 删除的文件
//调用删除文件的接口
let file_id = file.response.restObj
this.$http.delete("/common/fastdfs?file_id="+file_id)
.then(res=>{
let {success,message,restObj} = res.data;
if(success){
//fileList 删除后的文件列表
this.addForm.logoList = fileList;
}else{
this.$message({
message:message,
type:"error"
})
}
})
},
//图片上传之前的回调
handleBeforeUpload(file){
if(this.addForm.logoList.length>0){
this.$message({
message:"只能上传一张图片!",
type:"warning"
})
return false;
}
},
//图片上传成功的回调
logoUploadSuccess(response, file, fileList){
//fileList = [{response:{success:true,restObj:''}},file,file]
this.addForm.logoList = fileList;
console.log(response)
}
}